diff --git a/include/bleach/lifter/block-ir-builder.hpp b/include/bleach/lifter/block-ir-builder.hpp index a02a479..bd53c33 100644 --- a/include/bleach/lifter/block-ir-builder.hpp +++ b/include/bleach/lifter/block-ir-builder.hpp @@ -57,7 +57,7 @@ class mbb2bb final : private DenseMap { void fill_ir_for_bb(MachineBasicBlock &mbb, reg2vals &rmap, const instr_impl &instrs, const LLVMTargetMachine &tm, - const target &tgt, const mbb2bb &m2b); + const target &tgt, const mbb2bb &m2b, StructType &state); struct basic_block { MachineBasicBlock *mbb; BasicBlock *bb; diff --git a/lib/lifter/block-ir-builder.cpp b/lib/lifter/block-ir-builder.cpp index 3f9b78f..e0cd13c 100644 --- a/lib/lifter/block-ir-builder.cpp +++ b/lib/lifter/block-ir-builder.cpp @@ -95,14 +95,18 @@ void fill_module_with_instrs(Module &m, const instr_impl &instrs) { Linker::linkModules(m, std::move(first)); } +auto get_current_state(Function &func) -> Value * { + constexpr auto gpr_array_idx = 0u; + return func.getArg(gpr_array_idx); +} + void materialize_registers(MachineFunction &mf, Function &func, reg2vals &rmap, const LLVMTargetMachine &target_machine, StructType &state) { if (mf.empty()) return; auto &ctx = func.getContext(); - constexpr auto gpr_array_idx = 0u; - Value *state_arg = func.getArg(gpr_array_idx); + auto *state_arg = get_current_state(func); auto *array_type = *state.element_begin(); assert(!func.empty()); auto &first_block = func.front(); @@ -147,12 +151,12 @@ auto *generate_function_object(Module &m, MachineFunction &mf, reg2vals &rmap, } void save_registers(BasicBlock &block, BasicBlock::iterator pos, reg2vals &rmap, + StructType &state) { auto &ctx = block.getContext(); IRBuilder builder(block.getContext()); builder.SetInsertPoint(pos); - constexpr auto gpr_array_idx = 0u; - Value *state_arg = block.getParent()->getArg(gpr_array_idx); + auto *state_arg = get_current_state(*block.getParent()); auto *array_type = *state.element_begin(); // GPR array is the first field auto *const_zero = ConstantInt::get(ctx, APInt(64, 0)); @@ -190,7 +194,7 @@ auto generate_function(Module &m, MachineFunction &mf, const instr_impl &instrs, create_basic_blocks_for_mfunc(mf, dst, m2b); materialize_registers(mf, *func, rmap, mmi.getTarget(), state); for (auto &mbb : dst) - fill_ir_for_bb(mbb, rmap, instrs, mmi.getTarget(), tgt, m2b); + fill_ir_for_bb(mbb, rmap, instrs, mmi.getTarget(), tgt, m2b, state); save_registers_before_return(*func, rmap, m2b, state); } @@ -278,11 +282,28 @@ auto generate_branch(const MachineInstr &minst, BasicBlock &bb, reg2vals &rmap, return builder.CreateCondBr(cond, if_true, if_false); } +auto operand_to_value(const MachineOperand &mop, BasicBlock &block, reg2vals &rmap) -> Value * { + IRBuilder builder (block.getContext()); + builder.SetInsertPoint(&block); + if (mop.isReg()) { + assert(mop.isUse()); + auto *reg_addr = rmap[mop.getReg()]; + auto *reg_val = builder.CreateLoad(Type::getIntNTy(block.getContext(), 64), reg_addr); + return reg_val; + } + if (mop.isImm()) { + auto val = mop.getImm(); + auto *imm = ConstantInt::get(block.getContext(), APInt(64, val)); + return imm; + } + throw std::runtime_error("Unsupported operand type"); +} + auto generate_instruction(const MachineInstr &minst, BasicBlock &bb, reg2vals &rmap, const instr_impl &instrs, LLVMContext &ctx, const LLVMTargetMachine &target_machine, - const target &tgt, const mbb2bb &m2b) -> Value * { + const target &tgt, const mbb2bb &m2b, StructType &state) -> Value * { auto *iinfo = target_machine.getMCInstrInfo(); auto name = get_instruction_name(minst, *iinfo); IRBuilder builder(ctx); @@ -306,19 +327,23 @@ auto generate_instruction(const MachineInstr &minst, BasicBlock &bb, } return builder.CreateRetVoid(); } + if (minst.isCall()) { + assert(minst.getNumOperands() >= 1); + auto op = minst.getOperand(0); + assert(op.isGlobal()); + auto *callee = const_cast(dyn_cast(op.getGlobal())); + assert(callee); + auto *call = builder.CreateCall(callee->getFunctionType(), callee, ArrayRef{get_current_state(*bb.getParent())}); + save_registers(bb, call->getIterator(), rmap, state); + return call; + } auto &instr_module = instrs.get(name); auto *func = instr_module.getFunction(name); if (!func) throw std::runtime_error("Could not find \"" + name + "\" in module"); - std::vector args; - for (auto &&use : minst.uses() | ranges::views::reverse) { - assert(use.isUse()); - if (!use.isReg()) - throw std::runtime_error("Only register operands are supported"); - auto *reg_addr = rmap[use.getReg()]; - auto *reg_val = builder.CreateLoad(Type::getIntNTy(ctx, 64), reg_addr); - args.push_back(reg_val); - } + auto op_to_val = [&](auto&mop){ return operand_to_value(mop, bb, rmap);}; + auto values = minst.uses() | ranges::views::reverse | ranges::views::transform(op_to_val); + std::vector args(values.begin(), values.end()); auto *call = builder.CreateCall(func->getFunctionType(), func, args); for (auto &def : minst.defs()) { assert(def.isDef()); @@ -333,12 +358,12 @@ auto generate_instruction(const MachineInstr &minst, BasicBlock &bb, void fill_ir_for_bb(MachineBasicBlock &mbb, reg2vals &rmap, const instr_impl &instrs, const LLVMTargetMachine &target_machine, const target &tgt, - const mbb2bb &m2b) { + const mbb2bb &m2b, StructType& state) { auto *bb = m2b[&mbb]; assert(bb); for (auto &minst : mbb) { generate_instruction(minst, *bb, rmap, instrs, bb->getContext(), - target_machine, tgt, m2b); + target_machine, tgt, m2b, state); } } diff --git a/test/tools/llvm-bleach/inputs/functions.mir b/test/tools/llvm-bleach/inputs/functions.mir new file mode 100644 index 0000000..7d6e019 --- /dev/null +++ b/test/tools/llvm-bleach/inputs/functions.mir @@ -0,0 +1,523 @@ +--- | + ; ModuleID = 'main' + source_filename = "main" + target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" + target triple = "riscv64-unknown-linux-gnu" + + ; Materializable + define void @SnippyFunction() { + ret void + } + + ; Materializable + define internal void @fun1() { + ret void + } + + ; Materializable + define internal void @fun2() { + ret void + } + + ; Materializable + define internal void @fun3() { + ret void + } + +... +--- +name: SnippyFunction +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: false +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: [] +liveins: + - {reg: '$x0', virtual-reg: '' } + - {reg: '$x1', virtual-reg: '' } + - {reg: '$x2', virtual-reg: '' } + - {reg: '$x3', virtual-reg: '' } + - {reg: '$x4', virtual-reg: '' } + - {reg: '$x5', virtual-reg: '' } + - {reg: '$x6', virtual-reg: '' } + - {reg: '$x7', virtual-reg: '' } + - {reg: '$x8', virtual-reg: '' } + - {reg: '$x9', virtual-reg: '' } + - {reg: '$x11', virtual-reg: '' } + - {reg: '$x12', virtual-reg: '' } + - {reg: '$x13', virtual-reg: '' } + - {reg: '$x14', virtual-reg: '' } + - {reg: '$x15', virtual-reg: '' } + - {reg: '$x16', virtual-reg: '' } + - {reg: '$x17', virtual-reg: '' } + - {reg: '$x18', virtual-reg: '' } + - {reg: '$x19', virtual-reg: '' } + - {reg: '$x20', virtual-reg: '' } + - {reg: '$x21', virtual-reg: '' } + - {reg: '$x22', virtual-reg: '' } + - {reg: '$x23', virtual-reg: '' } + - {reg: '$x24', virtual-reg: '' } + - {reg: '$x25', virtual-reg: '' } + - {reg: '$x26', virtual-reg: '' } + - {reg: '$x27', virtual-reg: '' } + - {reg: '$x28', virtual-reg: '' } + - {reg: '$x29', virtual-reg: '' } + - {reg: '$x30', virtual-reg: '' } + - {reg: '$x31', virtual-reg: '' } + +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +body: | + bb.6: + successors: %bb.0(0x80000000) + liveins: $x14 + + $x16 = ADD $x0, $x0 + $x16 = ADD $x16, $x2 + $x14 = ADDI $x0, 0 + $x14 = ADD $x14, $x2 + $x30 = ADD $x18, $x29 + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + $x8 = ADD $x0, $x4 + $x12 = ADD $x0, $x0 + PseudoBR %bb.0 + + bb.0: + successors: %bb.7(0x40000000), %bb.0(0x40000000) + + $x8 = ADD $x8, $x0 + BNE $x8, $x12, %bb.0 + PseudoBR %bb.7 + + bb.7: + successors: %bb.1(0x80000000) + + $x9 = ADD $x19, $x8 + $x13 = ADD $x0, $x4 + $x3 = ADD $x0, $x0 + PseudoBR %bb.1 + + bb.1: + successors: %bb.8(0x40000000), %bb.1(0x40000000) + + $x19 = MUL $x7, $x29 + $x28 = ADD $x21, $x12 + $x13 = ADD $x13, $x1 + BNE $x13, $x3, %bb.1 + PseudoBR %bb.8 + + bb.8: + successors: %bb.2(0x80000000) + + $x31 = MUL $x9, $x2 + $x6 = MUL $x26, $x17 + $x30 = ADD $x0, $x4 + $x2 = ADD $x0, $x0 + PseudoBR %bb.2 + + bb.2: + successors: %bb.9(0x40000000), %bb.2(0x40000000) + + $x7 = MUL $x29, $x12 + $x26 = MUL $x28, $x10 + $x30 = ADD $x30, $x1 + BNE $x30, $x2, %bb.2 + PseudoBR %bb.9 + + bb.9: + successors: %bb.3(0x80000000) + + $x10 = ADD $x4, $x25 + $x9 = MUL $x2, $x21 + $x24 = ADD $x0, $x4 + $x19 = ADD $x0, $x0 + PseudoBR %bb.3 + + bb.3: + successors: %bb.4(0x40000000), %bb.3(0x40000000) + + $x24 = ADD $x24, $x1 + BNE $x24, $x19, %bb.3 + PseudoBR %bb.4 + + bb.4: + successors: %bb.5(0x80000000) + + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + BNE $x21, $x11, %bb.5 + PseudoBR %bb.5 + + bb.5: + $x23 = MUL $x31, $x14 + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + $x25 = ADD $x1, $x20 + $x25 = ADD $x25, $x16 + $x14 = LD $x25, 0 + PseudoRET + +... +--- +name: fun1 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: false +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: [] +liveins: [] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +body: | + bb.3: + successors: %bb.0(0x80000000) + liveins: $x5, $x31, $x19, $x11, $x1 + + $x14 = ADDI $x14, -16 + SD $x5, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x31, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x19, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x11, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x1, $x14, 0 + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + $x11 = ADDI $x0, 4 + $x5 = ADDI $x0, 0 + PseudoBR %bb.0 + + bb.0: + successors: %bb.1(0x40000000), %bb.0(0x40000000) + + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + $x11 = ADDI $x11, -1 + BNE $x11, $x5, %bb.0 + PseudoBR %bb.1 + + bb.1: + successors: %bb.2(0x80000000) + + BNE $x4, $x23, %bb.2 + PseudoBR %bb.2 + + bb.2: + $x19 = ADD $x0, $x24 + $x31 = MUL $x6, $x15 + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + PseudoCALL target-flags(riscv-call) @fun2, implicit-def $x1 + $x1 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x11 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x19 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x31 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x5 = LD $x14, 0 + $x14 = ADDI $x14, 16 + PseudoRET + +... +--- +name: fun2 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: false +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: [] +liveins: [] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +body: | + bb.3: + successors: %bb.0(0x80000000) + liveins: $x22, $x12, $x0, $x9, $x30, $x1, $x8 + + $x14 = ADDI $x14, -16 + SD $x22, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x12, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x0, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x9, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x30, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x1, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x8, $x14, 0 + $x12 = ADD $x28, $x8 + PseudoCALL target-flags(riscv-call) @fun3, implicit-def $x1 + $x9 = ADD $x31, $x2 + PseudoCALL target-flags(riscv-call) @fun3, implicit-def $x1 + $x22 = ADDI $x0, 4 + $x8 = ADDI $x0, 0 + PseudoBR %bb.0 + + bb.0: + successors: %bb.1(0x40000000), %bb.0(0x40000000) + + PseudoCALL target-flags(riscv-call) @fun3, implicit-def $x1 + $x0 = ADD $x22, $x18 + $x22 = ADDI $x22, -1 + BNE $x22, $x8, %bb.0 + PseudoBR %bb.1 + + bb.1: + successors: %bb.2(0x80000000) + + $x30 = MUL $x1, $x14 + BNE $x28, $x3, %bb.2 + PseudoBR %bb.2 + + bb.2: + PseudoCALL target-flags(riscv-call) @fun3, implicit-def $x1 + $x8 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x1 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x30 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x9 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x0 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x12 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x22 = LD $x14, 0 + $x14 = ADDI $x14, 16 + PseudoRET + +... +--- +name: fun3 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: false +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: [] +liveins: [] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +body: | + bb.3: + successors: %bb.0(0x80000000) + liveins: $x17, $x7, $x2, $x9, $x30, $x6, $x13, $x20 + + $x14 = ADDI $x14, -16 + SD $x17, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x7, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x2, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x9, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x30, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x6, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x13, $x14, 0 + $x14 = ADDI $x14, -16 + SD $x20, $x14, 0 + $x13 = MUL $x8, $x31 + $x13 = ADD $x29, $x6 + $x20 = ADDI $x0, 4 + $x6 = ADDI $x0, 0 + PseudoBR %bb.0 + + bb.0: + successors: %bb.1(0x40000000), %bb.0(0x40000000) + + $x20 = ADDI $x20, -1 + BNE $x20, $x6, %bb.0 + PseudoBR %bb.1 + + bb.1: + successors: %bb.2(0x80000000) + + $x9 = ADD $x29, $x19 + $x30 = MUL $x14, $x29 + BNE $x8, $x20, %bb.2 + PseudoBR %bb.2 + + bb.2: + $x7 = ADD $x12, $x9 + $x2 = ADD $x6, $x2 + $x17 = ADD $x12, $x22 + $x7 = MUL $x5, $x3 + $x20 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x13 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x6 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x30 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x9 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x2 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x7 = LD $x14, 0 + $x14 = ADDI $x14, 16 + $x17 = LD $x14, 0 + $x14 = ADDI $x14, 16 + PseudoRET + +... diff --git a/test/tools/llvm-bleach/inputs/logical.yaml b/test/tools/llvm-bleach/inputs/logical.yaml index 6f07c3f..e9ef726 100644 --- a/test/tools/llvm-bleach/inputs/logical.yaml +++ b/test/tools/llvm-bleach/inputs/logical.yaml @@ -86,3 +86,39 @@ instructions: %3 = mul nsw i64 %0, %1 ret i64 %3 } + - MUL: + func: | + ; ModuleID = 'addsub' + source_filename = "addsub" + ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable + define dso_local signext i64 @MUL(i64 noundef signext %0, i64 noundef signext %1) local_unnamed_addr #0 { + %3 = mul nsw i64 %0, %1 + ret i64 %3 + } + - ADDI: + func: | + ; ModuleID = 'addsub' + source_filename = "addsub" + ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable + define dso_local signext i64 @ADDI(i64 noundef signext %0, i64 noundef signext %1) local_unnamed_addr #0 { + %3 = mul nsw i64 %0, %1 + ret i64 %3 + } + - LD: + func: | + ; ModuleID = 'addsub' + source_filename = "addsub" + ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable + define dso_local signext i64 @LD(i64 noundef signext %0, i64 noundef signext %1) local_unnamed_addr #0 { + %3 = mul nsw i64 %0, %1 + ret i64 %3 + } + - SD: + func: | + ; ModuleID = 'addsub' + source_filename = "addsub" + ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable + define dso_local signext i64 @SD(i64 noundef signext %0, i64 noundef signext %1) local_unnamed_addr #0 { + %3 = mul nsw i64 %0, %1 + ret i64 %3 + }