diff --git a/cranelift/codegen/src/isa/aarch64/abi.rs b/cranelift/codegen/src/isa/aarch64/abi.rs index 88aa60f8af..131bd6ee42 100644 --- a/cranelift/codegen/src/isa/aarch64/abi.rs +++ b/cranelift/codegen/src/isa/aarch64/abi.rs @@ -497,6 +497,16 @@ impl ABIBody for AArch64ABIBody { store_stack(fp_off, from_reg, ty) } + fn stackslot_addr(&self, slot: StackSlot, offset: u32, into_reg: Writable) -> Inst { + // Offset from beginning of stackslot area, which is at FP - stackslots_size. + let stack_off = self.stackslots[slot.as_u32() as usize] as i64; + let fp_off: i64 = -(self.stackslots_size as i64) + stack_off + (offset as i64); + Inst::LoadAddr { + rd: into_reg, + mem: MemArg::FPOffset(fp_off), + } + } + // Load from a spillslot. fn load_spillslot(&self, slot: SpillSlot, ty: Type, into_reg: Writable) -> Inst { // Note that when spills/fills are generated, we don't yet know how many diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs index f01746543c..644785b1fd 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs @@ -6,11 +6,10 @@ use crate::ir::types::*; use crate::ir::TrapCode; use crate::isa::aarch64::inst::*; -use core::convert::TryFrom; - use regalloc::{Reg, RegClass, Writable}; use alloc::vec::Vec; +use core::convert::TryFrom; /// Memory label/reference finalization: convert a MemLabel to a PC-relative /// offset, possibly emitting relocation(s) as necessary. @@ -1275,6 +1274,40 @@ impl MachInstEmit for Inst { sink.add_reloc(srcloc, Reloc::Abs8, name, offset); sink.put8(0); } + &Inst::LoadAddr { rd, ref mem } => match *mem { + MemArg::FPOffset(fp_off) => { + let alu_op = if fp_off < 0 { + ALUOp::Sub64 + } else { + ALUOp::Add64 + }; + if let Some(imm12) = Imm12::maybe_from_u64(u64::try_from(fp_off.abs()).unwrap()) + { + let inst = Inst::AluRRImm12 { + alu_op, + rd, + imm12, + rn: fp_reg(), + }; + inst.emit(sink); + } else { + let tmp = writable_spilltmp_reg(); + let const_insts = + Inst::load_constant(tmp, u64::try_from(fp_off.abs()).unwrap()); + for inst in const_insts { + inst.emit(sink); + } + let inst = Inst::AluRRR { + alu_op, + rd, + rn: fp_reg(), + rm: tmp.to_reg(), + }; + inst.emit(sink); + } + } + _ => unimplemented!("{:?}", mem), + }, } } } diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs index ee55f3394f..6775f98b2d 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs @@ -707,6 +707,12 @@ pub enum Inst { srcloc: SourceLoc, offset: i64, }, + + /// Load address referenced by `mem` into `rd`. + LoadAddr { + rd: Writable, + mem: MemArg, + }, } fn count_zero_half_words(mut value: u64) -> usize { @@ -1089,6 +1095,9 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) { &Inst::LoadConst64 { rd, .. } | &Inst::LoadExtName { rd, .. } => { collector.add_def(rd); } + &Inst::LoadAddr { rd, mem: _ } => { + collector.add_def(rd); + } } } @@ -1643,6 +1652,13 @@ fn aarch64_map_regs( &mut Inst::LoadExtName { ref mut rd, .. } => { map_wr(d, rd); } + &mut Inst::LoadAddr { + ref mut rd, + ref mut mem, + } => { + map_wr(d, rd); + map_mem(u, mem); + } } } @@ -2536,6 +2552,12 @@ impl ShowWithRRU for Inst { let rd = rd.show_rru(mb_rru); format!("ldr {}, 8 ; b 12 ; data {:?} + {}", rd, name, offset) } + &Inst::LoadAddr { rd, ref mem } => { + let rd = rd.show_rru(mb_rru); + let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru); + let mem = mem.show_rru(mb_rru); + format!("{}load_addr {}, {}", mem_str, rd, mem) + } } } } diff --git a/cranelift/codegen/src/isa/aarch64/lower.rs b/cranelift/codegen/src/isa/aarch64/lower.rs index 92760a81bb..209b3d6c83 100644 --- a/cranelift/codegen/src/isa/aarch64/lower.rs +++ b/cranelift/codegen/src/isa/aarch64/lower.rs @@ -22,6 +22,7 @@ use crate::isa::aarch64::AArch64Backend; use regalloc::{Reg, RegClass, Writable}; use alloc::vec::Vec; +use core::convert::TryFrom; use smallvec::SmallVec; //============================================================================ @@ -1546,7 +1547,24 @@ fn lower_insn_to_regs>(ctx: &mut C, insn: IRInst) { }); } - Opcode::StackLoad | Opcode::StackStore | Opcode::StackAddr => { + Opcode::StackAddr => { + let (stack_slot, offset) = match *ctx.data(insn) { + InstructionData::StackLoad { + opcode: Opcode::StackAddr, + stack_slot, + offset, + } => (stack_slot, offset), + _ => unreachable!(), + }; + let rd = output_to_reg(ctx, outputs[0]); + let offset: i32 = offset.into(); + let inst = ctx + .abi() + .stackslot_addr(stack_slot, u32::try_from(offset).unwrap(), rd); + ctx.emit(inst); + } + + Opcode::StackLoad | Opcode::StackStore => { panic!("Direct stack memory access not supported; should not be used by Wasm"); } diff --git a/cranelift/codegen/src/machinst/abi.rs b/cranelift/codegen/src/machinst/abi.rs index 11a96c58b2..1410f4265b 100644 --- a/cranelift/codegen/src/machinst/abi.rs +++ b/cranelift/codegen/src/machinst/abi.rs @@ -56,6 +56,9 @@ pub trait ABIBody { /// Update with the clobbered registers, post-regalloc. fn set_clobbered(&mut self, clobbered: Set>); + /// Get the address of a stackslot. + fn stackslot_addr(&self, slot: StackSlot, offset: u32, into_reg: Writable) -> Self::I; + /// Load from a stackslot. fn load_stackslot( &self, diff --git a/cranelift/codegen/src/machinst/lower.rs b/cranelift/codegen/src/machinst/lower.rs index 0d8fb1ff0e..393c1bdd43 100644 --- a/cranelift/codegen/src/machinst/lower.rs +++ b/cranelift/codegen/src/machinst/lower.rs @@ -31,6 +31,8 @@ pub trait LowerCtx { fn data(&self, ir_inst: Inst) -> &InstructionData; /// Get the controlling type for a polymorphic IR instruction. fn ty(&self, ir_inst: Inst) -> Type; + /// Get the `ABIBody`. + fn abi(&mut self) -> &dyn ABIBody; /// Emit a machine instruction. fn emit(&mut self, mach_inst: Self::I); /// Indicate that an IR instruction has been merged, and so one of its @@ -527,6 +529,10 @@ impl<'a, I: VCodeInst> LowerCtx for Lower<'a, I> { self.f.dfg.ctrl_typevar(ir_inst) } + fn abi(&mut self) -> &dyn ABIBody { + self.vcode.abi() + } + /// Emit a machine instruction. fn emit(&mut self, mach_inst: I) { self.vcode.push(mach_inst);