fn __do_isel_inst()

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!(),
    }
}