Skip to content

Commit d447f39

Browse files
committed
riscv64: Split clobber save/restore SP adjustment for compressed instructions
When the Zca extension is enabled, split the SP adjustment in function prologues/epilogues so callee-saved stores use small SP-relative offsets that fit in c.sdsp's 504-byte encoding range. This allows all callee-save stores/loads to compress from 4-byte sd/ld to 2-byte c.sdsp/c.ldsp. Without Zca, the original combined SP decrement is preserved to avoid adding an extra instruction with no compression benefit. Also adds isa_flags parameter to the ABIMachineSpec gen_clobber_save and gen_clobber_restore trait methods so implementations can make ISA-specific decisions. Fixes #7190.
1 parent fabee3a commit d447f39

9 files changed

Lines changed: 545 additions & 44 deletions

File tree

cranelift/codegen/src/isa/aarch64/abi.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
774774
fn gen_clobber_save(
775775
call_conv: isa::CallConv,
776776
flags: &settings::Flags,
777+
_isa_flags: &aarch64_settings::Flags,
777778
frame_layout: &FrameLayout,
778779
) -> SmallVec<[Inst; 16]> {
779780
let (clobbered_int, clobbered_vec) = frame_layout.clobbered_callee_saves_by_class();
@@ -1020,6 +1021,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
10201021
fn gen_clobber_restore(
10211022
call_conv: isa::CallConv,
10221023
_flags: &settings::Flags,
1024+
_isa_flags: &aarch64_settings::Flags,
10231025
frame_layout: &FrameLayout,
10241026
) -> SmallVec<[Inst; 16]> {
10251027
let mut insts = SmallVec::new();

cranelift/codegen/src/isa/aarch64/inst/emit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3661,6 +3661,7 @@ fn emit_return_call_common_sequence<T>(
36613661
for inst in AArch64MachineDeps::gen_clobber_restore(
36623662
CallConv::Tail,
36633663
&emit_info.flags,
3664+
&emit_info.isa_flags,
36643665
state.frame_layout(),
36653666
) {
36663667
inst.emit(sink, emit_info, state);

cranelift/codegen/src/isa/pulley_shared/abi.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ where
433433
fn gen_clobber_save(
434434
_call_conv: isa::CallConv,
435435
_flags: &settings::Flags,
436+
_isa_flags: &PulleyFlags,
436437
_frame_layout: &FrameLayout,
437438
) -> SmallVec<[Self::I; 16]> {
438439
// Note that this is intentionally empty because everything necessary
@@ -443,6 +444,7 @@ where
443444
fn gen_clobber_restore(
444445
_call_conv: isa::CallConv,
445446
_flags: &settings::Flags,
447+
_isa_flags: &PulleyFlags,
446448
_frame_layout: &FrameLayout,
447449
) -> SmallVec<[Self::I; 16]> {
448450
// Intentionally empty as restores happen for Pulley in `gen_return`.

cranelift/codegen/src/isa/riscv64/abi.rs

Lines changed: 79 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ impl ABIMachineSpec for Riscv64MachineDeps {
431431
fn gen_clobber_save(
432432
_call_conv: isa::CallConv,
433433
flags: &settings::Flags,
434+
isa_flags: &RiscvFlags,
434435
frame_layout: &FrameLayout,
435436
) -> SmallVec<[Inst; 16]> {
436437
let mut insts = SmallVec::new();
@@ -479,61 +480,91 @@ impl ABIMachineSpec for Riscv64MachineDeps {
479480
});
480481
}
481482

482-
// Adjust the stack pointer downward for clobbers, the function fixed
483-
// frame (spillslots and storage slots), and outgoing arguments.
484-
let stack_size = frame_layout.clobber_size
485-
+ frame_layout.fixed_frame_storage_size
486-
+ frame_layout.outgoing_args_size;
487-
488-
// Store each clobbered register in order at offsets from SP,
489-
// placing them above the fixed frame slots.
490-
if stack_size > 0 {
491-
insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32)));
492-
493-
let mut cur_offset = 0;
494-
for reg in &frame_layout.clobbered_callee_saves {
495-
let r_reg = reg.to_reg();
496-
let ty = match r_reg.class() {
497-
RegClass::Int => I64,
498-
RegClass::Float => F64,
499-
RegClass::Vector => I8X16,
500-
};
501-
cur_offset = align_to(cur_offset, ty.bytes());
502-
insts.push(Inst::gen_store(
503-
AMode::SPOffset(i64::from(stack_size - cur_offset - ty.bytes())),
504-
Reg::from(reg.to_reg()),
505-
ty,
506-
MemFlagsData::trusted(),
507-
));
483+
let clobber_size = frame_layout.clobber_size;
484+
let remaining_frame_size =
485+
frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size;
508486

509-
if flags.unwind_info() {
510-
insts.push(Inst::Unwind {
511-
inst: UnwindInst::SaveReg {
512-
clobber_offset: frame_layout.clobber_size - cur_offset - ty.bytes(),
513-
reg: r_reg,
514-
},
515-
});
516-
}
487+
// When the Zca extension is available, split the SP adjustment so
488+
// callee-save stores use small offsets that fit in c.sdsp (≤504 bytes).
489+
// Without Zca, use a single combined decrement to avoid an extra instruction.
490+
let split_adjustment = isa_flags.has_zca() && clobber_size > 0 && remaining_frame_size > 0;
491+
492+
if split_adjustment {
493+
insts.extend(Self::gen_sp_reg_adjust(-(clobber_size as i32)));
494+
} else {
495+
let stack_size = clobber_size + remaining_frame_size;
496+
if stack_size > 0 {
497+
insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32)));
498+
}
499+
}
500+
501+
let store_base = if split_adjustment {
502+
clobber_size
503+
} else {
504+
clobber_size + remaining_frame_size
505+
};
506+
507+
let mut cur_offset = 0;
508+
for reg in &frame_layout.clobbered_callee_saves {
509+
let r_reg = reg.to_reg();
510+
let ty = match r_reg.class() {
511+
RegClass::Int => I64,
512+
RegClass::Float => F64,
513+
RegClass::Vector => I8X16,
514+
};
515+
cur_offset = align_to(cur_offset, ty.bytes());
516+
insts.push(Inst::gen_store(
517+
AMode::SPOffset(i64::from(store_base - cur_offset - ty.bytes())),
518+
Reg::from(reg.to_reg()),
519+
ty,
520+
MemFlagsData::trusted(),
521+
));
517522

518-
cur_offset += ty.bytes();
519-
assert!(cur_offset <= stack_size);
523+
if flags.unwind_info() {
524+
insts.push(Inst::Unwind {
525+
inst: UnwindInst::SaveReg {
526+
clobber_offset: clobber_size - cur_offset - ty.bytes(),
527+
reg: r_reg,
528+
},
529+
});
520530
}
531+
532+
cur_offset += ty.bytes();
533+
assert!(cur_offset <= clobber_size);
521534
}
535+
536+
if split_adjustment {
537+
insts.extend(Self::gen_sp_reg_adjust(-(remaining_frame_size as i32)));
538+
}
539+
522540
insts
523541
}
524542

525543
fn gen_clobber_restore(
526544
_call_conv: isa::CallConv,
527545
_flags: &settings::Flags,
546+
isa_flags: &RiscvFlags,
528547
frame_layout: &FrameLayout,
529548
) -> SmallVec<[Inst; 16]> {
530549
let mut insts = SmallVec::new();
531550

532-
let stack_size = frame_layout.clobber_size
533-
+ frame_layout.fixed_frame_storage_size
534-
+ frame_layout.outgoing_args_size;
535-
let mut cur_offset = 0;
551+
let clobber_size = frame_layout.clobber_size;
552+
let remaining_frame_size =
553+
frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size;
554+
555+
let split_adjustment = isa_flags.has_zca() && clobber_size > 0 && remaining_frame_size > 0;
536556

557+
if split_adjustment {
558+
insts.extend(Self::gen_sp_reg_adjust(remaining_frame_size as i32));
559+
}
560+
561+
let load_base = if split_adjustment {
562+
clobber_size
563+
} else {
564+
clobber_size + remaining_frame_size
565+
};
566+
567+
let mut cur_offset = 0;
537568
for reg in &frame_layout.clobbered_callee_saves {
538569
let rreg = reg.to_reg();
539570
let ty = match rreg.class() {
@@ -544,15 +575,20 @@ impl ABIMachineSpec for Riscv64MachineDeps {
544575
cur_offset = align_to(cur_offset, ty.bytes());
545576
insts.push(Inst::gen_load(
546577
reg.map(Reg::from),
547-
AMode::SPOffset(i64::from(stack_size - cur_offset - ty.bytes())),
578+
AMode::SPOffset(i64::from(load_base - cur_offset - ty.bytes())),
548579
ty,
549580
MemFlagsData::trusted(),
550581
));
551582
cur_offset += ty.bytes();
552583
}
553584

554-
if stack_size > 0 {
555-
insts.extend(Self::gen_sp_reg_adjust(stack_size as i32));
585+
let restore_size = if split_adjustment {
586+
clobber_size
587+
} else {
588+
clobber_size + remaining_frame_size
589+
};
590+
if restore_size > 0 {
591+
insts.extend(Self::gen_sp_reg_adjust(restore_size as i32));
556592
}
557593

558594
insts

cranelift/codegen/src/isa/s390x/abi.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ impl ABIMachineSpec for S390xMachineDeps {
698698
fn gen_clobber_save(
699699
call_conv: isa::CallConv,
700700
flags: &settings::Flags,
701+
_isa_flags: &s390x_settings::Flags,
701702
frame_layout: &FrameLayout,
702703
) -> SmallVec<[Inst; 16]> {
703704
let mut insts = SmallVec::new();
@@ -860,6 +861,7 @@ impl ABIMachineSpec for S390xMachineDeps {
860861
fn gen_clobber_restore(
861862
call_conv: isa::CallConv,
862863
_flags: &settings::Flags,
864+
_isa_flags: &s390x_settings::Flags,
863865
frame_layout: &FrameLayout,
864866
) -> SmallVec<[Inst; 16]> {
865867
let mut insts = SmallVec::new();

cranelift/codegen/src/isa/x64/abi.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
653653
fn gen_clobber_save(
654654
_call_conv: isa::CallConv,
655655
flags: &settings::Flags,
656+
_isa_flags: &x64_settings::Flags,
656657
frame_layout: &FrameLayout,
657658
) -> SmallVec<[Self::I; 16]> {
658659
let mut insts = SmallVec::new();
@@ -764,6 +765,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
764765
fn gen_clobber_restore(
765766
_call_conv: isa::CallConv,
766767
_flags: &settings::Flags,
768+
_isa_flags: &x64_settings::Flags,
767769
frame_layout: &FrameLayout,
768770
) -> SmallVec<[Self::I; 16]> {
769771
let mut insts = SmallVec::new();

cranelift/codegen/src/isa/x64/inst/emit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1880,7 +1880,7 @@ fn emit_return_call_common_sequence<T>(
18801880
let tmp = call_info.tmp.to_writable_reg();
18811881

18821882
for inst in
1883-
X64ABIMachineSpec::gen_clobber_restore(CallConv::Tail, &info.flags, state.frame_layout())
1883+
X64ABIMachineSpec::gen_clobber_restore(CallConv::Tail, &info.flags, &info.isa_flags, state.frame_layout())
18841884
{
18851885
inst.emit(sink, info, state);
18861886
}

cranelift/codegen/src/machinst/abi.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ pub trait ABIMachineSpec {
542542
fn gen_clobber_save(
543543
call_conv: isa::CallConv,
544544
flags: &settings::Flags,
545+
isa_flags: &Self::F,
545546
frame_layout: &FrameLayout,
546547
) -> SmallVec<[Self::I; 16]>;
547548

@@ -552,6 +553,7 @@ pub trait ABIMachineSpec {
552553
fn gen_clobber_restore(
553554
call_conv: isa::CallConv,
554555
flags: &settings::Flags,
556+
isa_flags: &Self::F,
555557
frame_layout: &FrameLayout,
556558
) -> SmallVec<[Self::I; 16]>;
557559

@@ -2287,6 +2289,7 @@ impl<M: ABIMachineSpec> Callee<M> {
22872289
insts.extend(M::gen_clobber_save(
22882290
self.call_conv,
22892291
&self.flags,
2292+
&self.isa_flags,
22902293
&frame_layout,
22912294
));
22922295

@@ -2306,6 +2309,7 @@ impl<M: ABIMachineSpec> Callee<M> {
23062309
insts.extend(M::gen_clobber_restore(
23072310
self.call_conv,
23082311
&self.flags,
2312+
&self.isa_flags,
23092313
&frame_layout,
23102314
));
23112315

0 commit comments

Comments
 (0)