@@ -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 ;
0 commit comments