machinst: Avoid a lot of short-lived allocations in ABICall;
This commit is contained in:
@@ -1179,44 +1179,40 @@ impl AArch64ABICall {
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_stack(amount: u64, is_sub: bool) -> Vec<Inst> {
|
||||
if amount > 0 {
|
||||
fn adjust_stack<C: LowerCtx<I = Inst>>(ctx: &mut C, amount: u64, is_sub: bool) {
|
||||
if amount == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let sp_adjustment = if is_sub {
|
||||
amount as i64
|
||||
} else {
|
||||
-(amount as i64)
|
||||
};
|
||||
let adj_meta_insn = Inst::VirtualSPOffsetAdj {
|
||||
ctx.emit(Inst::VirtualSPOffsetAdj {
|
||||
offset: sp_adjustment,
|
||||
};
|
||||
});
|
||||
|
||||
let alu_op = if is_sub { ALUOp::Sub64 } else { ALUOp::Add64 };
|
||||
if let Some(imm12) = Imm12::maybe_from_u64(amount) {
|
||||
vec![
|
||||
adj_meta_insn,
|
||||
Inst::AluRRImm12 {
|
||||
ctx.emit(Inst::AluRRImm12 {
|
||||
alu_op,
|
||||
rd: writable_stack_reg(),
|
||||
rn: stack_reg(),
|
||||
imm12,
|
||||
},
|
||||
]
|
||||
})
|
||||
} else {
|
||||
let const_load = Inst::LoadConst64 {
|
||||
ctx.emit(Inst::LoadConst64 {
|
||||
rd: writable_spilltmp_reg(),
|
||||
const_data: amount,
|
||||
};
|
||||
let adj = Inst::AluRRRExtend {
|
||||
});
|
||||
ctx.emit(Inst::AluRRRExtend {
|
||||
alu_op,
|
||||
rd: writable_stack_reg(),
|
||||
rn: stack_reg(),
|
||||
rm: spilltmp_reg(),
|
||||
extendop: ExtendOp::UXTX,
|
||||
};
|
||||
vec![adj_meta_insn, const_load, adj]
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1227,64 +1223,82 @@ impl ABICall for AArch64ABICall {
|
||||
self.sig.args.len()
|
||||
}
|
||||
|
||||
fn gen_stack_pre_adjust(&self) -> Vec<Inst> {
|
||||
adjust_stack(self.sig.stack_arg_space as u64, /* is_sub = */ true)
|
||||
fn emit_stack_pre_adjust<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C) {
|
||||
adjust_stack(
|
||||
ctx,
|
||||
self.sig.stack_arg_space as u64,
|
||||
/* is_sub = */ true,
|
||||
)
|
||||
}
|
||||
|
||||
fn gen_stack_post_adjust(&self) -> Vec<Inst> {
|
||||
adjust_stack(self.sig.stack_arg_space as u64, /* is_sub = */ false)
|
||||
fn emit_stack_post_adjust<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C) {
|
||||
adjust_stack(
|
||||
ctx,
|
||||
self.sig.stack_arg_space as u64,
|
||||
/* is_sub = */ false,
|
||||
)
|
||||
}
|
||||
|
||||
fn gen_copy_reg_to_arg(&self, idx: usize, from_reg: Reg) -> Vec<Inst> {
|
||||
fn emit_copy_reg_to_arg<C: LowerCtx<I = Self::I>>(
|
||||
&self,
|
||||
ctx: &mut C,
|
||||
idx: usize,
|
||||
from_reg: Reg,
|
||||
) {
|
||||
match &self.sig.args[idx] {
|
||||
&ABIArg::Reg(reg, ty) => vec![Inst::gen_move(
|
||||
&ABIArg::Reg(reg, ty) => ctx.emit(Inst::gen_move(
|
||||
Writable::from_reg(reg.to_reg()),
|
||||
from_reg,
|
||||
ty,
|
||||
)],
|
||||
&ABIArg::Stack(off, ty) => vec![store_stack(MemArg::SPOffset(off), from_reg, ty)],
|
||||
)),
|
||||
&ABIArg::Stack(off, ty) => ctx.emit(store_stack(MemArg::SPOffset(off), from_reg, ty)),
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_copy_retval_to_reg(&self, idx: usize, into_reg: Writable<Reg>) -> Inst {
|
||||
fn emit_copy_retval_to_reg<C: LowerCtx<I = Self::I>>(
|
||||
&self,
|
||||
ctx: &mut C,
|
||||
idx: usize,
|
||||
into_reg: Writable<Reg>,
|
||||
) {
|
||||
match &self.sig.rets[idx] {
|
||||
&ABIArg::Reg(reg, ty) => Inst::gen_move(into_reg, reg.to_reg(), ty),
|
||||
&ABIArg::Reg(reg, ty) => ctx.emit(Inst::gen_move(into_reg, reg.to_reg(), ty)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_call(&self) -> Vec<Inst> {
|
||||
fn emit_call<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C) {
|
||||
let (uses, defs) = (self.uses.clone(), self.defs.clone());
|
||||
match &self.dest {
|
||||
&CallDest::ExtName(ref name, RelocDistance::Near) => vec![Inst::Call {
|
||||
&CallDest::ExtName(ref name, RelocDistance::Near) => ctx.emit(Inst::Call {
|
||||
dest: name.clone(),
|
||||
uses,
|
||||
defs,
|
||||
loc: self.loc,
|
||||
opcode: self.opcode,
|
||||
}],
|
||||
&CallDest::ExtName(ref name, RelocDistance::Far) => vec![
|
||||
Inst::LoadExtName {
|
||||
}),
|
||||
&CallDest::ExtName(ref name, RelocDistance::Far) => {
|
||||
ctx.emit(Inst::LoadExtName {
|
||||
rd: writable_spilltmp_reg(),
|
||||
name: name.clone(),
|
||||
offset: 0,
|
||||
srcloc: self.loc,
|
||||
},
|
||||
Inst::CallInd {
|
||||
});
|
||||
ctx.emit(Inst::CallInd {
|
||||
rn: spilltmp_reg(),
|
||||
uses,
|
||||
defs,
|
||||
loc: self.loc,
|
||||
opcode: self.opcode,
|
||||
},
|
||||
],
|
||||
&CallDest::Reg(reg) => vec![Inst::CallInd {
|
||||
});
|
||||
}
|
||||
&CallDest::Reg(reg) => ctx.emit(Inst::CallInd {
|
||||
rn: reg,
|
||||
uses,
|
||||
defs,
|
||||
loc: self.loc,
|
||||
opcode: self.opcode,
|
||||
}],
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1285,26 +1285,18 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(ctx: &mut C, insn: IRIns
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
for inst in abi.gen_stack_pre_adjust().into_iter() {
|
||||
ctx.emit(inst);
|
||||
}
|
||||
abi.emit_stack_pre_adjust(ctx);
|
||||
assert!(inputs.len() == abi.num_args());
|
||||
for (i, input) in inputs.iter().enumerate() {
|
||||
let arg_reg = input_to_reg(ctx, *input, NarrowValueMode::None);
|
||||
for inst in abi.gen_copy_reg_to_arg(i, arg_reg) {
|
||||
ctx.emit(inst);
|
||||
}
|
||||
}
|
||||
for inst in abi.gen_call().into_iter() {
|
||||
ctx.emit(inst);
|
||||
abi.emit_copy_reg_to_arg(ctx, i, arg_reg);
|
||||
}
|
||||
abi.emit_call(ctx);
|
||||
for (i, output) in outputs.iter().enumerate() {
|
||||
let retval_reg = output_to_reg(ctx, *output);
|
||||
ctx.emit(abi.gen_copy_retval_to_reg(i, retval_reg));
|
||||
}
|
||||
for inst in abi.gen_stack_post_adjust().into_iter() {
|
||||
ctx.emit(inst);
|
||||
abi.emit_copy_retval_to_reg(ctx, i, retval_reg);
|
||||
}
|
||||
abi.emit_stack_post_adjust(ctx);
|
||||
}
|
||||
|
||||
Opcode::GetPinnedReg => {
|
||||
|
||||
@@ -135,19 +135,29 @@ pub trait ABICall {
|
||||
/// Get the number of arguments expected.
|
||||
fn num_args(&self) -> usize;
|
||||
|
||||
/// Copy an argument value from a source register, prior to the call.
|
||||
fn gen_copy_reg_to_arg(&self, idx: usize, from_reg: Reg) -> Vec<Self::I>;
|
||||
/// Emit a copy of an argument value from a source register, prior to the call.
|
||||
fn emit_copy_reg_to_arg<C: LowerCtx<I = Self::I>>(
|
||||
&self,
|
||||
ctx: &mut C,
|
||||
idx: usize,
|
||||
from_reg: Reg,
|
||||
);
|
||||
|
||||
/// Copy a return value into a destination register, after the call returns.
|
||||
fn gen_copy_retval_to_reg(&self, idx: usize, into_reg: Writable<Reg>) -> Self::I;
|
||||
/// Emit a copy a return value into a destination register, after the call returns.
|
||||
fn emit_copy_retval_to_reg<C: LowerCtx<I = Self::I>>(
|
||||
&self,
|
||||
ctx: &mut C,
|
||||
idx: usize,
|
||||
into_reg: Writable<Reg>,
|
||||
);
|
||||
|
||||
/// Pre-adjust the stack, prior to argument copies and call.
|
||||
fn gen_stack_pre_adjust(&self) -> Vec<Self::I>;
|
||||
/// Emit code to pre-adjust the stack, prior to argument copies and call.
|
||||
fn emit_stack_pre_adjust<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C);
|
||||
|
||||
/// Post-adjust the satck, after call return and return-value copies.
|
||||
fn gen_stack_post_adjust(&self) -> Vec<Self::I>;
|
||||
/// Emit code to post-adjust the satck, after call return and return-value copies.
|
||||
fn emit_stack_post_adjust<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C);
|
||||
|
||||
/// Generate the call itself.
|
||||
/// Emit the call itself.
|
||||
///
|
||||
/// The returned instruction should have proper use- and def-sets according
|
||||
/// to the argument registers, return-value registers, and clobbered
|
||||
@@ -157,5 +167,5 @@ pub trait ABICall {
|
||||
/// registers are also logically defs, but should never be read; their
|
||||
/// values are "defined" (to the regalloc) but "undefined" in every other
|
||||
/// sense.)
|
||||
fn gen_call(&self) -> Vec<Self::I>;
|
||||
fn emit_call<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user