Skip to content

Commit 5a99d3e

Browse files
authored
Merge pull request #498 from rustcoreutils/updates
[cc] Fix alignment, regalloc, and SSA lowering bugs
2 parents 02a2dd4 + 15db44f commit 5a99d3e

File tree

8 files changed

+545
-90
lines changed

8 files changed

+545
-90
lines changed

cc/arch/codegen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ impl<I: LirInst + EmitAsm> CodeGenBase<I> {
209209
// Check storage class - skip .globl for static
210210
let is_static = types.get(*typ).modifiers.contains(TypeModifiers::STATIC);
211211

212-
// Get alignment from type info
212+
// Get alignment from type info - use natural alignment per ABI
213213
let align = types.alignment(*typ) as u32;
214214

215215
// Use .comm for uninitialized external (non-static) globals

cc/arch/x86_64/regalloc.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ impl RegAlloc {
479479
let call_positions = find_call_positions(func);
480480

481481
self.spill_args_across_calls(func, &intervals, &call_positions);
482+
self.spill_args_across_constraints(func, &intervals, &constraint_points);
482483
self.allocate_alloca_to_stack(func);
483484
self.run_linear_scan(func, types, intervals, &call_positions, &constraint_points);
484485

@@ -603,6 +604,53 @@ impl RegAlloc {
603604
&self.spilled_args
604605
}
605606

607+
/// Spill arguments in registers that would be clobbered by constraint points (e.g., shifts)
608+
///
609+
/// For example, if the 4th parameter is in Rcx and the function contains variable shifts,
610+
/// Rcx will be clobbered when the shift count is loaded. We must spill such arguments
611+
/// to the stack before they get clobbered.
612+
fn spill_args_across_constraints(
613+
&mut self,
614+
_func: &Function,
615+
intervals: &[LiveInterval],
616+
constraint_points: &[ConstraintPoint<Reg>],
617+
) {
618+
// For each argument in a register, check if its interval is live across
619+
// any constraint point that clobbers that register
620+
let int_arg_regs_set: Vec<Reg> = Reg::arg_regs().to_vec();
621+
for interval in intervals {
622+
if let Some(Loc::Reg(reg)) = self.locations.get(&interval.pseudo) {
623+
if int_arg_regs_set.contains(reg) {
624+
// Check if this register is clobbered by any constraint point
625+
// while the interval is live (and the pseudo is not involved)
626+
let needs_spill = constraint_points.iter().any(|cp| {
627+
interval.start <= cp.position
628+
&& cp.position <= interval.end
629+
&& !cp.involved_pseudos.contains(&interval.pseudo)
630+
&& cp.clobbers.contains(reg)
631+
});
632+
633+
if needs_spill {
634+
let from_reg = *reg;
635+
self.stack_offset += 8;
636+
let to_stack_offset = self.stack_offset;
637+
638+
// Record the spill for codegen to emit stores in prologue
639+
self.spilled_args.push(SpilledArg {
640+
pseudo: interval.pseudo,
641+
from_reg,
642+
to_stack_offset,
643+
});
644+
645+
self.locations
646+
.insert(interval.pseudo, Loc::Stack(to_stack_offset));
647+
self.free_regs.push(from_reg);
648+
}
649+
}
650+
}
651+
}
652+
}
653+
606654
/// Force alloca results to stack to avoid clobbering issues
607655
fn allocate_alloca_to_stack(&mut self, func: &Function) {
608656
for block in &func.blocks {

cc/ir/dce.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -294,22 +294,25 @@ fn remove_unreachable_blocks(func: &mut Function) -> bool {
294294
let reachable = compute_reachable(func);
295295
let before = func.blocks.len();
296296

297+
// Compute unreachable set BEFORE removing blocks
298+
let all_block_ids: HashSet<_> = func.blocks.iter().map(|bb| bb.id).collect();
299+
let unreachable: HashSet<_> = all_block_ids.difference(&reachable).copied().collect();
300+
297301
// Remove unreachable blocks
298302
func.blocks.retain(|bb| reachable.contains(&bb.id));
299303

300304
// Update parent/child references to remove dead blocks
301-
let unreachable: HashSet<_> = func
302-
.blocks
303-
.iter()
304-
.map(|bb| bb.id)
305-
.collect::<HashSet<_>>()
306-
.difference(&reachable)
307-
.copied()
308-
.collect();
309-
310305
for bb in &mut func.blocks {
311306
bb.parents.retain(|p| !unreachable.contains(p));
312307
bb.children.retain(|c| !unreachable.contains(c));
308+
309+
// Also clean phi_list entries that reference removed blocks
310+
for insn in &mut bb.insns {
311+
if insn.op == Opcode::Phi {
312+
insn.phi_list
313+
.retain(|(pred, _)| !unreachable.contains(pred));
314+
}
315+
}
313316
}
314317

315318
func.blocks.len() < before

cc/ir/linearize.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,9 +1836,14 @@ impl<'a> Linearizer<'a> {
18361836
// Condition block
18371837
self.switch_bb(cond_bb);
18381838
let cond_val = self.linearize_expr(cond);
1839-
self.emit(Instruction::cbr(cond_val, body_bb, exit_bb));
1840-
self.link_bb(cond_bb, body_bb);
1841-
self.link_bb(cond_bb, exit_bb);
1839+
// After linearizing condition, current_bb may be different from cond_bb
1840+
// (e.g., if condition contains short-circuit operators like && or ||).
1841+
// Link the CURRENT block to body_bb and exit_bb.
1842+
if let Some(cond_end_bb) = self.current_bb {
1843+
self.emit(Instruction::cbr(cond_val, body_bb, exit_bb));
1844+
self.link_bb(cond_end_bb, body_bb);
1845+
self.link_bb(cond_end_bb, exit_bb);
1846+
}
18421847

18431848
// Body block
18441849
self.break_targets.push(exit_bb);
@@ -1895,9 +1900,14 @@ impl<'a> Linearizer<'a> {
18951900
// Condition block
18961901
self.switch_bb(cond_bb);
18971902
let cond_val = self.linearize_expr(cond);
1898-
self.emit(Instruction::cbr(cond_val, body_bb, exit_bb));
1899-
self.link_bb(cond_bb, body_bb);
1900-
self.link_bb(cond_bb, exit_bb);
1903+
// After linearizing condition, current_bb may be different from cond_bb
1904+
// (e.g., if condition contains short-circuit operators like && or ||).
1905+
// Link the CURRENT block to body_bb and exit_bb.
1906+
if let Some(cond_end_bb) = self.current_bb {
1907+
self.emit(Instruction::cbr(cond_val, body_bb, exit_bb));
1908+
self.link_bb(cond_end_bb, body_bb);
1909+
self.link_bb(cond_end_bb, exit_bb);
1910+
}
19011911

19021912
// Exit block
19031913
self.switch_bb(exit_bb);
@@ -1937,13 +1947,20 @@ impl<'a> Linearizer<'a> {
19371947
self.switch_bb(cond_bb);
19381948
if let Some(cond_expr) = cond {
19391949
let cond_val = self.linearize_expr(cond_expr);
1940-
self.emit(Instruction::cbr(cond_val, body_bb, exit_bb));
1950+
// After linearizing condition, current_bb may be different from cond_bb
1951+
// (e.g., if condition contains short-circuit operators like && or ||).
1952+
// Link the CURRENT block to body_bb and exit_bb.
1953+
if let Some(cond_end_bb) = self.current_bb {
1954+
self.emit(Instruction::cbr(cond_val, body_bb, exit_bb));
1955+
self.link_bb(cond_end_bb, body_bb);
1956+
self.link_bb(cond_end_bb, exit_bb);
1957+
}
19411958
} else {
19421959
// No condition = always true
19431960
self.emit(Instruction::br(body_bb));
1961+
self.link_bb(cond_bb, body_bb);
1962+
// No link to exit_bb since we always enter the body
19441963
}
1945-
self.link_bb(cond_bb, body_bb);
1946-
self.link_bb(cond_bb, exit_bb);
19471964

19481965
// Body block
19491966
self.break_targets.push(exit_bb);

0 commit comments

Comments
 (0)