Skip to content

Commit 8dbe011

Browse files
committed
[cc] aarch64: codegen fixes
1 parent c6ad329 commit 8dbe011

File tree

2 files changed

+166
-0
lines changed

2 files changed

+166
-0
lines changed

cc/arch/aarch64/codegen.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,6 +2398,16 @@ impl Aarch64CodeGen {
23982398
None => return,
23992399
};
24002400
let dst_loc = self.get_location(target);
2401+
2402+
// Check if this is an FP load
2403+
let is_fp =
2404+
insn.typ.as_ref().is_some_and(|t| t.is_float()) || matches!(dst_loc, Loc::VReg(_));
2405+
2406+
if is_fp {
2407+
self.emit_fp_load(insn, frame_size);
2408+
return;
2409+
}
2410+
24012411
let dst_reg = match &dst_loc {
24022412
Loc::Reg(r) => *r,
24032413
_ => Reg::X9,
@@ -2518,6 +2528,119 @@ impl Aarch64CodeGen {
25182528
}
25192529
}
25202530

2531+
/// Emit a floating-point load instruction
2532+
fn emit_fp_load(&mut self, insn: &Instruction, frame_size: i32) {
2533+
let size = insn.size.max(32);
2534+
let addr = match insn.src.first() {
2535+
Some(&s) => s,
2536+
None => return,
2537+
};
2538+
let target = match insn.target {
2539+
Some(t) => t,
2540+
None => return,
2541+
};
2542+
let dst_loc = self.get_location(target);
2543+
let dst_vreg = match &dst_loc {
2544+
Loc::VReg(v) => *v,
2545+
_ => VReg::V17,
2546+
};
2547+
let addr_loc = self.get_location(addr);
2548+
2549+
let fp_size = if size <= 32 {
2550+
FpSize::Single
2551+
} else {
2552+
FpSize::Double
2553+
};
2554+
2555+
match addr_loc {
2556+
Loc::Reg(r) => {
2557+
self.push_lir(Aarch64Inst::LdrFp {
2558+
size: fp_size,
2559+
addr: MemAddr::BaseOffset {
2560+
base: r,
2561+
offset: insn.offset as i32,
2562+
},
2563+
dst: dst_vreg,
2564+
});
2565+
}
2566+
Loc::Stack(offset) => {
2567+
// Check if the address operand is a symbol (local variable) or a temp (spilled address)
2568+
let is_symbol = self
2569+
.pseudos
2570+
.iter()
2571+
.find(|p| p.id == addr)
2572+
.is_some_and(|p| matches!(p.kind, PseudoKind::Sym(_)));
2573+
2574+
if is_symbol {
2575+
// Local variable - load directly from stack slot
2576+
let total_offset = frame_size + offset + insn.offset as i32;
2577+
self.push_lir(Aarch64Inst::LdrFp {
2578+
size: fp_size,
2579+
addr: MemAddr::BaseOffset {
2580+
base: Reg::sp(),
2581+
offset: total_offset,
2582+
},
2583+
dst: dst_vreg,
2584+
});
2585+
} else {
2586+
// Spilled address - load address first, then load from that address
2587+
let adjusted = frame_size + offset;
2588+
self.push_lir(Aarch64Inst::Ldr {
2589+
size: OperandSize::B64,
2590+
addr: MemAddr::BaseOffset {
2591+
base: Reg::sp(),
2592+
offset: adjusted,
2593+
},
2594+
dst: Reg::X16,
2595+
});
2596+
self.push_lir(Aarch64Inst::LdrFp {
2597+
size: fp_size,
2598+
addr: MemAddr::BaseOffset {
2599+
base: Reg::X16,
2600+
offset: insn.offset as i32,
2601+
},
2602+
dst: dst_vreg,
2603+
});
2604+
}
2605+
}
2606+
Loc::Global(name) => {
2607+
// Load FP value from global using ADRP + LDR
2608+
let sym = if name.starts_with('.') {
2609+
Symbol::local(&name)
2610+
} else {
2611+
Symbol::global(&name)
2612+
};
2613+
let (scratch0, _) = Reg::scratch_regs();
2614+
self.push_lir(Aarch64Inst::Adrp {
2615+
sym: sym.clone(),
2616+
dst: scratch0,
2617+
});
2618+
self.push_lir(Aarch64Inst::LdrFpSymOffset {
2619+
size: fp_size,
2620+
sym,
2621+
base: scratch0,
2622+
dst: dst_vreg,
2623+
});
2624+
}
2625+
_ => {
2626+
self.emit_move(addr, Reg::X16, 64, frame_size);
2627+
self.push_lir(Aarch64Inst::LdrFp {
2628+
size: fp_size,
2629+
addr: MemAddr::BaseOffset {
2630+
base: Reg::X16,
2631+
offset: insn.offset as i32,
2632+
},
2633+
dst: dst_vreg,
2634+
});
2635+
}
2636+
}
2637+
2638+
// Move to final destination if needed
2639+
if !matches!(&dst_loc, Loc::VReg(v) if *v == dst_vreg) {
2640+
self.emit_fp_move_to_loc(dst_vreg, &dst_loc, size, frame_size);
2641+
}
2642+
}
2643+
25212644
fn emit_store(&mut self, insn: &Instruction, frame_size: i32) {
25222645
// Use actual size for memory stores (8, 16, 32, 64 bits)
25232646
let mem_size = insn.size;

cc/arch/aarch64/lir.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,16 @@ pub enum Aarch64Inst {
636636
dst: VReg,
637637
},
638638

639+
/// LDR (FP) with symbol page offset (used with ADRP for global FP loads)
640+
/// macOS: ldr dst, [base, symbol@PAGEOFF]
641+
/// Linux: ldr dst, [base, :lo12:symbol]
642+
LdrFpSymOffset {
643+
size: FpSize,
644+
sym: Symbol,
645+
base: Reg,
646+
dst: VReg,
647+
},
648+
639649
/// STR (FP) - Store FP register
640650
StrFp {
641651
size: FpSize,
@@ -1350,6 +1360,39 @@ impl EmitAsm for Aarch64Inst {
13501360
let _ = writeln!(out, " str {}, {}", name, addr.format());
13511361
}
13521362

1363+
Aarch64Inst::LdrFpSymOffset {
1364+
size,
1365+
sym,
1366+
base,
1367+
dst,
1368+
} => {
1369+
let sym_name = sym.format_for_target(target);
1370+
let fp_name = match size {
1371+
FpSize::Single => dst.name_s(),
1372+
FpSize::Double => dst.name_d(),
1373+
};
1374+
match target.os {
1375+
Os::MacOS => {
1376+
let _ = writeln!(
1377+
out,
1378+
" ldr {}, [{}, {}@PAGEOFF]",
1379+
fp_name,
1380+
base.name64(),
1381+
sym_name
1382+
);
1383+
}
1384+
Os::Linux | Os::FreeBSD => {
1385+
let _ = writeln!(
1386+
out,
1387+
" ldr {}, [{}, :lo12:{}]",
1388+
fp_name,
1389+
base.name64(),
1390+
sym_name
1391+
);
1392+
}
1393+
}
1394+
}
1395+
13531396
Aarch64Inst::Fadd {
13541397
size,
13551398
src1,

0 commit comments

Comments
 (0)