in lwcb/bpfir/src/be/isel.rs [337:509]
fn __do_isel_inst(
builder: &mut ISelFunctionBuilder,
ctx: &Context,
inst: Inst,
iblock: &mut ISelBlock,
) {
let insts = &ctx.func.dfg.insts;
let pool = &ctx.func.dfg.value_lists;
let data = &ctx.func.dfg.insts[inst];
let dfg = &ctx.func.dfg;
let op = data.opcode();
let mut operands = vec![];
// The following commands should be executed by isel even if the value is not used.
// return, store, call
let is_important = op.is_return()
|| op.can_store()
|| op.is_call()
|| if ctx.func.dfg.has_results(inst) {
let val = ctx.func.dfg.first_result(inst);
builder.is_used_value(val)
} else {
false
};
if !is_important {
return;
}
match data {
InstructionData::Store {
opcode: _,
args,
flags: _,
offset: _,
} => {
let (is_stack, base, offset) = builder.addr_value2offset(ctx, args[1]);
let bi;
if let Some((x, y)) = get_imm_by_value(ctx, args[0]) {
bi = BPFInst::Store(BPFSize::from_bits(y.bits()), base, offset, x as i32);
if is_stack {
operands.push(use_operand(base.into(), cons_fixed_reg(10)));
} else {
operands.push(use_operand(base.into(), cons_reg()));
}
} else {
todo!()
// builder.use_value(args[0]);
// let vreg = builder.value_regs[&args[0]];
// bi = BPFInst::StoreX(BPFSize::DW, builder.fp, vreg, offset);
// operands = vec![use_operand(vreg.into(), cons_any())];
}
iblock.insts.push(bi);
iblock.operands.push(operands);
}
InstructionData::Load {
opcode: _,
arg,
flags: _,
offset: _,
} => {
let dst = ctx.func.dfg.first_result(inst);
let dst_reg = builder.value_regs[&dst];
let src_inst = ctx.func.dfg.value_def(*arg).inst().unwrap();
let src_inst_data = insts[src_inst];
match src_inst_data {
// source data address is constructed by base + offset(imm)
InstructionData::Binary { opcode: _, args } => {
if let Some((off, _)) = get_imm_by_value(ctx, args[1]) {
builder.use_value(args[0]);
let base_reg = builder.value_regs[&args[0]];
let bi = BPFInst::LoadX(
BPFSize::from_bits(dfg.value_type(dst).bits()),
dst_reg,
base_reg,
off as i16,
);
let operands = [
def_operand(dst_reg.into(), cons_any()),
use_operand(base_reg.into(), cons_any()),
];
iblock.insts.push(bi);
iblock.operands.push(operands.to_vec());
}
}
// imm source data is handled by Unary instruction
_ => unreachable!("{:?}", src_inst_data),
}
}
InstructionData::StackStore { .. } => unreachable!(),
InstructionData::Call {
opcode: _,
args,
func_ref,
} => {
let id = get_call_helperid(ctx, *func_ref);
let bi = BPFInst::Call(id);
for (idx, arg) in args.as_slice(pool).iter().enumerate() {
operands.push(use_operand(
builder.value_regs[arg].into(),
cons_fixed_reg((idx + 1) as u8),
));
builder.use_value(*arg);
}
let tmp = builder.value_regs[&ctx.func.dfg.first_result(inst)];
operands.push(def_operand(tmp.into(), cons_fixed_reg(0)));
iblock.insts.push(bi);
iblock.operands.push(operands);
}
InstructionData::Brif {
opcode,
arg,
blocks,
} => {
todo!()
}
InstructionData::MultiAry { opcode, args } => {
assert!(opcode.is_return());
assert!(args.len(&pool) == 1);
let val = args.first(&pool).unwrap();
builder.use_value(val);
let reg = builder.value_regs[&val];
operands.push(use_operand(reg.into(), cons_fixed_reg(0)));
iblock.insts.push(BPFInst::Exit);
iblock.operands.push(operands);
}
InstructionData::UnaryImm { opcode: _, imm } => {
let dst_reg = builder.value_regs[&dfg.first_result(inst)];
let imm_val = imm.bits();
let bi = if imm_val > i32::MAX as i64 {
// we should use BPFInst::load64 to load this imm.
BPFInst::Load64(dst_reg, imm_val)
} else {
BPFInst::Mov(dst_reg, imm_val as i32)
};
iblock.insts.push(bi);
iblock
.operands
.push(vec![def_operand(dst_reg.into(), cons_reg())]);
}
InstructionData::StackLoad {
opcode: _,
stack_slot,
offset: _,
} => {
let addr_reg = builder.value_regs[&ctx.func.dfg.first_result(inst)];
let inter_reg = builder.new_reg();
let bi1 = BPFInst::MovX(inter_reg, builder.fp);
let offset = builder.stackslots.get(stack_slot).unwrap();
let bi2 = BPFInst::Alu64(BPFBOp::Sub, addr_reg, (*offset) as i32);
iblock.insts.push(bi2);
iblock.operands.push(vec![
def_operand(addr_reg.into(), cons_reuse(1)),
use_operand(inter_reg.into(), cons_reg()),
]);
iblock.insts.push(bi1);
iblock.operands.push(vec![
def_operand(inter_reg.into(), cons_reg()),
use_operand(builder.fp.into(), cons_fixed_reg(10)),
]);
}
_ => todo!(),
}
}