diff --git a/backend/remill/include/remill/BC/HelperMacro.h b/backend/remill/include/remill/BC/HelperMacro.h index 76bde85..5b82b6f 100644 --- a/backend/remill/include/remill/BC/HelperMacro.h +++ b/backend/remill/include/remill/BC/HelperMacro.h @@ -1,8 +1,6 @@ #pragma once -// #define LIFT_DEBUG 1 // #define LIFT_CALLSTACK_DEBUG 1 -// #define LIFT_INSN_DEBUG 1 // #define LIFT_MEMORY_VALUE_CHANGE 1 // #define ELFCONV_SYSCALL_DEBUG 1 @@ -10,4 +8,4 @@ // #define OPT_ALGO_DEBUG 1 // #define OPT_GEN_IR_DEBUG 1 // #define OPT_CALL_FUNC_DEBUG 1 -// #define OPT_REAL_REGS_DEBUG 1 +// #define OPT_REAL_REGS_DEBUG 1 \ No newline at end of file diff --git a/backend/remill/include/remill/BC/InstructionLifter.h b/backend/remill/include/remill/BC/InstructionLifter.h index da1bb66..f2192de 100644 --- a/backend/remill/include/remill/BC/InstructionLifter.h +++ b/backend/remill/include/remill/BC/InstructionLifter.h @@ -159,7 +159,8 @@ class EcvReg { static std::pair GetRegInfo(const std::string &_reg_name); std::string GetRegName(EcvRegClass ecv_reg_class) const; - bool CheckNoChangedReg() const; + bool CheckPassedArgsRegs() const; + bool CheckPassedReturnRegs() const; class Hash { public: @@ -195,6 +196,8 @@ class BBRegInfoNode { // Save the args registers by semantic functions (for debug) std::unordered_map>> sema_func_args_reg_map; + // Save the pc of semantics functions (for debug) + std::unordered_map sema_func_pc_map; std::unordered_map> post_update_regs; @@ -214,14 +217,12 @@ class InstructionLifterIntf : public OperandLifter { // this instruction will execute within the delay slot of another instruction. virtual LiftStatus LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, BBRegInfoNode *bb_reg_info_node, - uint64_t debug_insn_addr = UINT64_MAX, bool is_delayed = false) = 0; // Lift a single instruction into a basic block. `is_delayed` signifies that // this instruction will execute within the delay slot of another instruction. LiftStatus LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block, - BBRegInfoNode *bb_reg_info_node, uint64_t debug_insn_addr = UINT64_MAX, - bool is_delayed = false); + BBRegInfoNode *bb_reg_info_node, bool is_delayed = false); }; // Wraps the process of lifting an instruction into a block. This resolves @@ -244,7 +245,6 @@ class InstructionLifter : public InstructionLifterIntf { // this instruction will execute within the delay slot of another instruction. virtual LiftStatus LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, BBRegInfoNode *bb_reg_info_node, - uint64_t debug_insn_addr = UINT64_MAX, bool is_delayed = false) override; diff --git a/backend/remill/include/remill/BC/SleighLifter.h b/backend/remill/include/remill/BC/SleighLifter.h index 38301c2..fdbd688 100644 --- a/backend/remill/include/remill/BC/SleighLifter.h +++ b/backend/remill/include/remill/BC/SleighLifter.h @@ -95,7 +95,7 @@ class SleighLifterWithState final : public InstructionLifterIntf { // this instruction will execute within the delay slot of another instruction. virtual LiftStatus LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, BBRegInfoNode *bb_reg_info_node, - uint64_t __debug_insn_addr, bool is_delayed = false) override; + bool is_delayed = false) override; virtual llvm::Value *LoadRegValueBeforeInst(llvm::BasicBlock *block, llvm::Value *state_ptr, std::string_view reg_name, diff --git a/backend/remill/include/remill/BC/TraceLifter.h b/backend/remill/include/remill/BC/TraceLifter.h index 1e41ac3..29cb697 100644 --- a/backend/remill/include/remill/BC/TraceLifter.h +++ b/backend/remill/include/remill/BC/TraceLifter.h @@ -108,11 +108,11 @@ class TraceManager { class PhiRegsBBBagNode { public: PhiRegsBBBagNode(EcvRegMap __preceding_load_reg_map, - EcvRegMap &&__succeeding_load_reg_map, + EcvRegMap __succeeding_load_reg_map, EcvRegMap &&__within_store_reg_map, std::set &&__in_bbs) - : bag_preceding_load_reg_map(std::move(__preceding_load_reg_map)), - bag_succeeding_load_reg_map(std::move(__succeeding_load_reg_map)), + : bag_preceding_load_reg_map(__preceding_load_reg_map), + bag_succeeding_load_reg_map(__succeeding_load_reg_map), bag_preceding_store_reg_map(std::move(__within_store_reg_map)), in_bbs(std::move(__in_bbs)), converted_bag(nullptr) {} @@ -127,11 +127,14 @@ class PhiRegsBBBagNode { static void GetPrecedingVirtualRegsBags(llvm::BasicBlock *root_bb); static void GetSucceedingVirtualRegsBags(llvm::BasicBlock *root_bb); static void RemoveLoop(llvm::BasicBlock *bb); - static void GetPhiRegsBags(llvm::BasicBlock *root_bb); + static void + GetPhiRegsBags(llvm::BasicBlock *root_bb, + std::unordered_map &bb_info_node_map); static inline std::unordered_map bb_regs_bag_map = {}; static inline std::size_t bag_num = 0; static inline std::unordered_map debug_bag_map = {}; + // The register set which should be passed from caller function. PhiRegsBBBagNode *GetTrueBag(); void MergePrecedingRegMap(PhiRegsBBBagNode *moved_bag); @@ -196,16 +199,37 @@ class VirtualRegsOpt { relay_bb_cache({}), phi_val_order(0), fun_vma(__fun_vma) { - for (auto &arg : func->args()) { - if (arg.getName() == "state") { - arg_state_val = &arg; - } else if (arg.getName() == "runtime_manager") { - arg_runtime_val = &arg; + arg_state_val = NULL; + arg_runtime_val = NULL; + // only declared function. + if (func->getName().str() == "__remill_function_call") { + auto args = func->args().begin(); + for (size_t i = 0; i < func->arg_size(); i++) { + if (0 == i) { + CHECK(llvm::dyn_cast(args[i].getType())); + arg_state_val = &args[i]; + } else if (2 == i) { + CHECK(llvm::dyn_cast(args[i].getType())); + arg_runtime_val = &args[i]; + } } } - CHECK(arg_state_val) << "[Bug] state arg is empty at the initialization of VirtualRegsOpt."; + // lifted function. + else { + for (auto &arg : func->args()) { + if (arg.getName() == "state") { + arg_state_val = &arg; + } else if (arg.getName() == "runtime_manager") { + arg_runtime_val = &arg; + } + } + } + CHECK(arg_state_val) + << "[Bug] state arg is empty at the initialization of VirtualRegsOpt. target func: " + << func->getName().str(); CHECK(arg_runtime_val) - << "[Bug] runtime_manager arg is empty at the initialization of VirtualRegsOpt."; + << "[Bug] runtime_manager arg is empty at the initialization of VirtualRegsOpt. target func: " + << func->getName().str(); } VirtualRegsOpt() {} ~VirtualRegsOpt() {} @@ -223,8 +247,15 @@ class VirtualRegsOpt { std::unordered_map, EcvReg::Hash> &cache_map); + void AnalyzeRegsBags(); + static void CalPassedCallerRegForBJump(); + void OptimizeVirtualRegsUsage(); + static inline std::unordered_map func_v_r_opt_map = {}; + static inline std::unordered_map> + b_jump_callees_map = {}; + llvm::Function *func; TraceLifter::Impl *impl; llvm::Value *arg_state_val; @@ -242,13 +273,19 @@ class VirtualRegsOpt { uint64_t phi_val_order; + std::unordered_map bb_regs_bag_map; + EcvRegMap passed_caller_reg_map; + EcvRegMap passed_callee_ret_reg_map; + + std::set ret_inst_set; + // for debug uint64_t fun_vma; uint64_t block_num; std::string func_name; // map llvm::Value* and the corresponding CPU register. std::unordered_map> value_reg_map; - static inline std::set debug_reg_set = {}; + std::set debug_reg_set = {}; void InsertDebugVmaAndRegisters( llvm::Instruction *inst_at_before, @@ -365,7 +402,6 @@ class TraceLifter::Impl { std::string inst_bytes; Instruction inst; Instruction delayed_inst; - std::set control_flow_debug_fnvma_set; DecoderWorkList trace_work_list; DecoderWorkList inst_work_list; DecoderWorkList dead_inst_work_list; @@ -373,7 +409,6 @@ class TraceLifter::Impl { std::map blocks; VirtualRegsOpt *virtual_regs_opt; - std::unordered_map func_virtual_regs_opt_map; std::set no_indirect_lifted_funcs; std::set lifted_funcs; diff --git a/backend/remill/lib/BC/InstructionLifter.cpp b/backend/remill/lib/BC/InstructionLifter.cpp index e52bc4a..5e82fe1 100644 --- a/backend/remill/lib/BC/InstructionLifter.cpp +++ b/backend/remill/lib/BC/InstructionLifter.cpp @@ -154,9 +154,12 @@ std::string EcvReg::GetRegName(EcvRegClass ecv_reg_class) const { return ""; } -bool EcvReg::CheckNoChangedReg() const { - return STATE_ORDER == number || RUNTIME_ORDER == number || IGNORE_WRITE_TO_WZR_ORDER == number || - IGNORE_WRITE_TO_XZR_ORDER == number; +bool EcvReg::CheckPassedArgsRegs() const { + return (0 <= number && number <= 7) || SP_ORDER == number; +} + +bool EcvReg::CheckPassedReturnRegs() const { + return (0 <= number && number <= 1) || SP_ORDER == number; } std::string EcvRegClass2String(EcvRegClass ecv_reg_class) { @@ -234,7 +237,9 @@ BBRegInfoNode::BBRegInfoNode(llvm::Function *func, llvm::Value *state_val, void BBRegInfoNode::join_reg_info_node(BBRegInfoNode *child) { // Join bb_load_reg_map for (auto [_ecv_reg, _ecv_reg_class] : child->bb_load_reg_map) { - bb_load_reg_map.insert({_ecv_reg, _ecv_reg_class}); + if (!bb_store_reg_map.contains(_ecv_reg)) { + bb_load_reg_map.insert({_ecv_reg, _ecv_reg_class}); + } } // Join bb_store_reg_map for (auto [_ecv_reg, _ecv_reg_class] : child->bb_store_reg_map) { @@ -258,6 +263,10 @@ void BBRegInfoNode::join_reg_info_node(BBRegInfoNode *child) { for (auto key_value : child->sema_func_args_reg_map) { sema_func_args_reg_map.insert(key_value); } + // Join sema_func_pc_map + for (auto key_value : child->sema_func_pc_map) { + sema_func_pc_map.insert(key_value); + } } InstructionLifter::Impl::Impl(const Arch *arch_, const IntrinsicTable *intrinsics_) @@ -286,10 +295,9 @@ InstructionLifter::InstructionLifter(const Arch *arch_, const IntrinsicTable *in // Lift a single instruction into a basic block. `is_delayed` signifies that // this instruction will execute within the delay slot of another instruction. LiftStatus InstructionLifterIntf::LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block, - BBRegInfoNode *bb_reg_info_node, - uint64_t debug_insn_addr, bool is_delayed) { + BBRegInfoNode *bb_reg_info_node, bool is_delayed) { return LiftIntoBlock(inst, block, NthArgument(block->getParent(), kStatePointerArgNum), - bb_reg_info_node, debug_insn_addr, is_delayed); + bb_reg_info_node, is_delayed); } llvm::Type *get_llvm_type(llvm::LLVMContext &context, EcvRegClass ecv_reg_class) { @@ -338,8 +346,7 @@ llvm::Type *get_llvm_type(llvm::LLVMContext &context, EcvRegClass ecv_reg_class) // Lift a single instruction into a basic block. LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, llvm::BasicBlock *block, llvm::Value *state_ptr, BBRegInfoNode *bb_reg_info_node, - - uint64_t debug_insn_addr, bool is_delayed) { + bool is_delayed) { llvm::Function *const func = block->getParent(); llvm::Module *const module = func->getParent(); auto &context = func->getContext(); @@ -565,6 +572,8 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, llvm::BasicB << "Unexpected to multiple lift the call instruction."; bb_reg_info_node->sema_call_written_reg_map.insert({sema_inst, write_regs}); + bb_reg_info_node->sema_func_pc_map.insert({sema_inst, arch_inst.pc}); + // Update pre-post index for the target register. if (!arch_inst.updated_addr_reg.name.empty()) { const auto [update_reg_ptr_reg, _] = @@ -610,17 +619,15 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, llvm::BasicB // ir.CreateStore(ir.CreateCall(impl->intrinsics->delay_slot_end, temp_args), mem_ptr_ref); } - /* append debug_insn function call */ - if (UINT64_MAX != debug_insn_addr) { - llvm::IRBuilder<> __debug_ir(block); + /* append `debug_memory_value_change` function call */ #if defined(LIFT_MEMORY_VALUE_CHANGE) - auto _debug_memory_value_change_fn = module->getFunction(debug_memory_value_change_name); - auto [runtime_manager_ptr, _] = LoadRegAddress(block, state_ptr, kRuntimeVariableName); - __debug_ir.CreateCall(_debug_memory_value_change_fn, - {__debug_ir.CreateLoad(llvm::Type::getInt64PtrTy(module->getContext()), - runtime_manager_ptr)}); + llvm::IRBuilder<> __debug_ir(block); + auto _debug_memory_value_change_fn = module->getFunction(debug_memory_value_change_name); + auto [runtime_manager_ptr, _] = LoadRegAddress(block, state_ptr, kRuntimeVariableName); + __debug_ir.CreateCall(_debug_memory_value_change_fn, + {__debug_ir.CreateLoad(llvm::Type::getInt64PtrTy(module->getContext()), + runtime_manager_ptr)}); #endif - } return status; } diff --git a/backend/remill/lib/BC/SleighLifter.cpp b/backend/remill/lib/BC/SleighLifter.cpp index c610fff..3eff766 100644 --- a/backend/remill/lib/BC/SleighLifter.cpp +++ b/backend/remill/lib/BC/SleighLifter.cpp @@ -1665,8 +1665,7 @@ SleighLifterWithState::SleighLifterWithState(sleigh::MaybeBranchTakenVar btaken_ // this instruction will execute within the delay slot of another instruction. LiftStatus SleighLifterWithState::LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block, llvm::Value *state_ptr, - BBRegInfoNode *bb_reg_info_node, - uint64_t __debug_insn_addr, bool is_delayed) { + BBRegInfoNode *bb_reg_info_node, bool is_delayed) { return this->lifter->LiftIntoBlockWithSleighState(inst, block, state_ptr, is_delayed, this->btaken, this->context_values); } diff --git a/backend/remill/lib/BC/TraceLifter.cpp b/backend/remill/lib/BC/TraceLifter.cpp index 0901913..aac1b85 100644 --- a/backend/remill/lib/BC/TraceLifter.cpp +++ b/backend/remill/lib/BC/TraceLifter.cpp @@ -49,7 +49,8 @@ namespace remill { ecv_reg.GetRegName(ecv_reg_class) + "_" + to_string(phi_val_order++) #else # define DEBUG_PC_AND_REGISTERS(...) -# define VAR_NAME(...) "" +# define VAR_NAME(ecv_reg, ecv_reg_class) \ + ecv_reg.GetRegName(ecv_reg_class) + "_" + to_string(phi_val_order++) #endif std::ostringstream ECV_DEBUG_STREAM; @@ -350,7 +351,7 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, CHECK(func->isDeclaration()); virtual_regs_opt = new VirtualRegsOpt(func, this, trace_addr); virtual_regs_opt->func_name = func->getName().str(); - func_virtual_regs_opt_map.insert({func, virtual_regs_opt}); + VirtualRegsOpt::func_v_r_opt_map.insert({func, virtual_regs_opt}); // Fill in the function, and make sure the block with all register // variables jumps to the block that will contain the first instruction @@ -437,17 +438,8 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, std::ignore = arch->DecodeInstruction(inst_addr, inst_bytes, inst, this->arch->CreateInitialContext()); -#if defined(LIFT_DEBUG) - (void) new llvm::StoreInst(llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), inst_addr), - LoadProgramCounterRef(block), block); -#endif - // Lift instruction - auto lift_status = - control_flow_debug_fnvma_set.contains(trace_addr) - ? inst.GetLifter()->LiftIntoBlock(inst, block, state_ptr, bb_reg_info_node, inst_addr) - : inst.GetLifter()->LiftIntoBlock(inst, block, state_ptr, bb_reg_info_node, - UINT64_MAX); + auto lift_status = inst.GetLifter()->LiftIntoBlock(inst, block, state_ptr, bb_reg_info_node); if (!tmp_patch_fn_check && manager._io_file_xsputn_vma == trace_addr) { llvm::IRBuilder<> ir(block); @@ -520,6 +512,16 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, // sacrifice in correctness is made. case Instruction::kCategoryDirectJump: try_add_delay_slot(true, block); + if (!manager.isWithinFunction(trace_addr, inst.branch_taken_pc)) { + auto callee_def_func = get_trace_decl(inst.branch_taken_pc); + if (callee_def_func) { + if (VirtualRegsOpt::b_jump_callees_map.contains(func)) { + VirtualRegsOpt::b_jump_callees_map.at(func).push_back(callee_def_func); + } else { + VirtualRegsOpt::b_jump_callees_map.insert({func, {callee_def_func}}); + } + } + } DirectBranchWithSaveParents(GetOrCreateBranchTakenBlock(), block); break; @@ -689,12 +691,16 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, } while (false); break; - case Instruction::kCategoryFunctionReturn: + case Instruction::kCategoryFunctionReturn: { try_add_delay_slot(true, block); AddTerminatingTailCall( block, intrinsics->function_return, *intrinsics, trace_addr, llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), trace_addr)); - break; + auto ret_inst = llvm::dyn_cast(block->getTerminator()); + CHECK(ret_inst) << "ret_inst must be ReturnInst. inst: " << LLVMThingToString(ret_inst); + virtual_regs_opt->ret_inst_set.insert(ret_inst); + + } break; case Instruction::kCategoryConditionalFunctionReturn: { CHECK(ArchName::kArchAArch64LittleEndian != arch->arch_name) @@ -858,7 +864,6 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, // Add StoreInst for the every semantics functions. auto &inst_lifter = inst.GetLifter(); - for (auto &bb : *func) { auto inst = &*bb.begin(); auto t_bb_reg_info_node = virtual_regs_opt->bb_reg_info_node_map.at(&bb); @@ -866,6 +871,13 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, auto call_inst = llvm::dyn_cast(inst); inst = inst->getNextNode(); if (t_bb_reg_info_node->sema_call_written_reg_map.contains(call_inst)) { +#if defined(OPT_REAL_REGS_DEBUG) + auto debug_llvmir_u64_fn = module->getFunction("debug_llvmir_u64value"); + auto sema_pc = t_bb_reg_info_node->sema_func_pc_map.at(call_inst); + llvm::CallInst::Create( + debug_llvmir_u64_fn, + {llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), sema_pc)}, "", call_inst); +#endif auto &write_regs = t_bb_reg_info_node->sema_call_written_reg_map.at(call_inst); auto call_next_inst = call_inst->getNextNode(); if (write_regs.size() == 1) { @@ -911,6 +923,23 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, } } } + + // Add passed_caller_reg_map and passed_callee_ret_reg_map. + for (int i = 0; i < 8; i++) { + virtual_regs_opt->passed_caller_reg_map.insert( + {EcvReg(RegKind::General, i), EcvRegClass::RegX}); + virtual_regs_opt->passed_caller_reg_map.insert( + {EcvReg(RegKind::Vector, i), EcvRegClass::RegV}); + virtual_regs_opt->passed_callee_ret_reg_map.insert( + {EcvReg(RegKind::General, i), EcvRegClass::RegX}); + virtual_regs_opt->passed_callee_ret_reg_map.insert( + {EcvReg(RegKind::Vector, i), EcvRegClass::RegV}); + } + virtual_regs_opt->passed_caller_reg_map.insert( + {EcvReg(RegKind::Special, SP_ORDER), EcvRegClass::RegX}); + virtual_regs_opt->passed_callee_ret_reg_map.insert( + {EcvReg(RegKind::Special, SP_ORDER), EcvRegClass::RegX}); + } else { no_indirect_lifted_funcs.insert(func); } @@ -935,7 +964,7 @@ void TraceLifter::Impl::Optimize() { inst.Reset(); arch->InstanceInstAArch64(inst); - // Optimization of the usage of the LLVM IR virtual registers for the CPU registers instead of the memory usage. + // Opt: AnalyzeRegsBags. int opt_cnt = 1; for (auto lifted_func : no_indirect_lifted_funcs) { std::cout << "\r[" @@ -943,14 +972,46 @@ void TraceLifter::Impl::Optimize() { << "INFO" << "\033[0m" << "]" - << " Opt Pass: [" << opt_cnt << "/" << no_indirect_lifted_funcs.size() << "]" + << " Opt Pass 1: [" << opt_cnt << "/" << no_indirect_lifted_funcs.size() << "]" << std::flush; - auto virtual_regs_opt = func_virtual_regs_opt_map[lifted_func]; - virtual_regs_opt->OptimizeVirtualRegsUsage(); + auto virtual_regs_opt = VirtualRegsOpt::func_v_r_opt_map[lifted_func]; + virtual_regs_opt->AnalyzeRegsBags(); opt_cnt++; } std::cout << std::endl; + // Add __remill_function_call to func_v_r_opt_map for register store selection of calling it. + auto __remill_func_call_fn = module->getFunction("__remill_function_call"); + auto __remill_func_call_v_r_o = new VirtualRegsOpt(__remill_func_call_fn, this, 0xffffff); + for (int i = 0; i < 8; i++) { + __remill_func_call_v_r_o->passed_caller_reg_map.insert( + {EcvReg(RegKind::General, i), EcvRegClass::RegX}); + __remill_func_call_v_r_o->passed_caller_reg_map.insert( + {EcvReg(RegKind::Vector, i), EcvRegClass::RegV}); + } + __remill_func_call_v_r_o->passed_caller_reg_map.insert( + {EcvReg(RegKind::Special, SP_ORDER), EcvRegClass::RegX}); + VirtualRegsOpt::func_v_r_opt_map.insert({__remill_func_call_fn, __remill_func_call_v_r_o}); + + // re-calculate passed_caller_reg_map considering direct jump function. + VirtualRegsOpt::CalPassedCallerRegForBJump(); + + // Opt: OptimizeVirtualRegsUsage. + int opt_cnt2 = 1; + for (auto lifted_func : no_indirect_lifted_funcs) { + std::cout << "\r[" + << "\033[1;32m" + << "INFO" + << "\033[0m" + << "]" + << " Opt Pass 2: [" << opt_cnt2 << "/" << no_indirect_lifted_funcs.size() << "]" + << std::flush; + auto virtual_regs_opt = VirtualRegsOpt::func_v_r_opt_map[lifted_func]; + virtual_regs_opt->OptimizeVirtualRegsUsage(); + opt_cnt2++; + } + std::cout << std::endl; + // Insert `debug_string` for the every function #if defined(OPT_CALL_FUNC_DEBUG) || defined(OPT_REAL_REGS_DEBUG) for (auto lifted_func : lifted_funcs) { @@ -972,1587 +1033,1706 @@ void TraceLifter::Impl::Optimize() { #endif } -llvm::Value *VirtualRegsOpt::CastFromInst(EcvReg target_ecv_reg, llvm::Value *from_inst, - llvm::Type *to_inst_ty, llvm::Instruction *inst_at_before, - llvm::Value *to_inst) { - auto &context = func->getContext(); - auto twine_null = llvm::Twine::createNull(); - - llvm::Value *t_from_inst; - - if (from_inst->getType() == to_inst_ty) { - CHECK(to_inst) << "[Bug] to_inst must not be NULL when from_inst_ty == to_inst_ty."; - return to_inst; - } else if (from_inst->getType() == llvm::Type::getVoidTy(context)) { - auto store_from_inst = llvm::dyn_cast(from_inst); - CHECK(store_from_inst) - << "[Bug] If the type of the from_inst is `void`, from_inst must be llvm::StoreInst at CastFromInst. from_inst: " - << LLVMThingToString(from_inst) << "\n" - << ECV_DEBUG_STREAM.str(); - t_from_inst = store_from_inst->getValueOperand(); - } else { - t_from_inst = from_inst; +PhiRegsBBBagNode *PhiRegsBBBagNode::GetTrueBag() { + auto res = this; + while (res != res->converted_bag) { + res = res->converted_bag; } + return res; +} - auto t_from_inst_size = impl->data_layout.getTypeAllocSizeInBits(t_from_inst->getType()); - auto t_from_inst_ty = t_from_inst->getType(); - auto to_inst_size = impl->data_layout.getTypeAllocSizeInBits(to_inst_ty); - - auto type_asserct_check = [&t_from_inst, &to_inst_ty](bool condition, const char *message) { - CHECK(condition) << "[ERROR]: from_inst: " << LLVMThingToString(t_from_inst) - << ", to_inst type: " << LLVMThingToString(to_inst_ty) << "\n" - << message << "\n" - << ECV_DEBUG_STREAM.str(); - }; - - if (t_from_inst_size < to_inst_size) { - if (RegKind::General == target_ecv_reg.reg_kind) { - type_asserct_check(to_inst_ty->isIntegerTy() && t_from_inst_ty->isIntegerTy(), - "RegKind::General register should have only the integer type."); - return new llvm::ZExtInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); - } else if (RegKind::Vector == target_ecv_reg.reg_kind) { - if (t_from_inst_ty->isVectorTy() || t_from_inst_ty->isFloatingPointTy()) { - auto mono_from = - new llvm::BitCastInst(t_from_inst, llvm::Type::getIntNTy(context, t_from_inst_size), - twine_null, inst_at_before); - auto zext_mono_from = new llvm::ZExtInst( - mono_from, llvm::Type::getIntNTy(context, to_inst_size), twine_null, inst_at_before); - return new llvm::BitCastInst(zext_mono_from, to_inst_ty, twine_null, inst_at_before); - } else { - auto zext_mono_from = new llvm::ZExtInst( - t_from_inst, llvm::Type::getIntNTy(context, to_inst_size), twine_null, inst_at_before); - return new llvm::BitCastInst(zext_mono_from, to_inst_ty, twine_null, inst_at_before); +void PhiRegsBBBagNode::MergePrecedingRegMap(PhiRegsBBBagNode *moved_bag) { + // Merge bag_preceding_load_reg_map + for (auto [pre_load_r, pre_load_r_c] : moved_bag->bag_preceding_load_reg_map) { + if (bag_preceding_load_reg_map.contains(pre_load_r)) { + if (GetRegClassSize(bag_preceding_load_reg_map.at(pre_load_r)) < + GetRegClassSize(pre_load_r_c)) { + bag_preceding_load_reg_map.insert_or_assign(pre_load_r, pre_load_r_c); } - } else if (RegKind::Special == target_ecv_reg.reg_kind) { - type_asserct_check( - /* 8 bit of the ECV_NZCV */ t_from_inst_ty->isIntegerTy(8) && to_inst_ty->isIntegerTy(), - "RegKind::Special register must not be used different types other than ECV_NZCV."); - return new llvm::ZExtInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); + } else { + bag_preceding_load_reg_map.insert({pre_load_r, pre_load_r_c}); } - } else if (t_from_inst_size > to_inst_size) { - if (RegKind::General == target_ecv_reg.reg_kind) { - type_asserct_check(to_inst_ty->isIntegerTy() && t_from_inst_ty->isIntegerTy(), - "RegKind::General register should have only the integer type."); - return new llvm::TruncInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); - } else if (RegKind::Vector == target_ecv_reg.reg_kind) { - if (t_from_inst_ty->isVectorTy() || t_from_inst_ty->isFloatingPointTy()) { - auto mono_from = - new llvm::BitCastInst(t_from_inst, llvm::Type::getIntNTy(context, t_from_inst_size), - twine_null, inst_at_before); - auto trunc_mono_from = new llvm::TruncInst( - mono_from, llvm::Type::getIntNTy(context, to_inst_size), twine_null, inst_at_before); - return new llvm::BitCastInst(trunc_mono_from, to_inst_ty, twine_null, inst_at_before); - } else { - auto trunc_mono_from = new llvm::TruncInst( - t_from_inst, llvm::Type::getIntNTy(context, to_inst_size), twine_null, inst_at_before); - return new llvm::BitCastInst(trunc_mono_from, to_inst_ty, twine_null, inst_at_before); + } + // Merge bag_preceding_load_reg_map + for (auto [pre_store_r, pre_store_r_c] : moved_bag->bag_preceding_store_reg_map) { + if (bag_preceding_store_reg_map.contains(pre_store_r)) { + if (GetRegClassSize(bag_preceding_store_reg_map.at(pre_store_r)) < + GetRegClassSize(pre_store_r_c)) { + bag_preceding_store_reg_map.insert_or_assign(pre_store_r, pre_store_r_c); } - return new llvm::TruncInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); - } else if (RegKind::Special == target_ecv_reg.reg_kind) { - type_asserct_check( - t_from_inst_ty->isIntegerTy(8) && to_inst_ty->isIntegerTy(), - "RegKind::Special register must not be used different types other than ECV_NZCV."); - return new llvm::ZExtInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); - } - } else { - if (t_from_inst->getType()->isPointerTy()) { - return new llvm::PtrToIntInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); } else { - return new llvm::BitCastInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); + bag_preceding_store_reg_map.insert({pre_store_r, pre_store_r_c}); } } - - std::terminate(); + // Merge bag_within_store } -llvm::Value *VirtualRegsOpt::GetRegValueFromCacheMap( - EcvReg target_ecv_reg, llvm::Type *to_type, llvm::Instruction *inst_at_before, - std::unordered_map, EcvReg::Hash> - &cache_map) { - llvm::Value *res_value; - - auto [_, from_value, from_order] = cache_map.at(target_ecv_reg); - if (to_type == from_value->getType()) { - res_value = from_value; - } else { - // Need to cast the from_inst to match the type of the load_inst. - if (llvm::dyn_cast(from_value->getType()) || - llvm::dyn_cast(from_value->getType())) { - auto from_extracted_inst = llvm::ExtractValueInst::Create( - from_value, {from_order}, llvm::Twine::createNull(), inst_at_before); - res_value = CastFromInst(target_ecv_reg, from_extracted_inst, to_type, inst_at_before, - from_extracted_inst); - // for debug - value_reg_map.insert({from_extracted_inst, - {target_ecv_reg, GetRegZFromLLVMType(from_extracted_inst->getType())}}); - } else if (isu128v2Ty(impl->context, from_value->getType())) { - auto from_extracted_inst = llvm::ExtractElementInst::Create( - from_value, llvm::ConstantInt::get(llvm::Type::getInt64Ty(impl->context), from_order), "", - inst_at_before); - res_value = CastFromInst(target_ecv_reg, from_extracted_inst, to_type, inst_at_before, - from_extracted_inst); - // for debug - value_reg_map.insert({from_extracted_inst, - {target_ecv_reg, GetRegZFromLLVMType(from_extracted_inst->getType())}}); - } else { - res_value = CastFromInst(target_ecv_reg, from_value, to_type, inst_at_before); - } +void PhiRegsBBBagNode::MergeFamilyConvertedBags(PhiRegsBBBagNode *merged_bag) { + for (auto merged_par : merged_bag->parents) { + auto true_merged_par = merged_par->GetTrueBag(); + parents.insert(true_merged_par); + true_merged_par->children.insert(this); + } + for (auto merged_child : merged_bag->children) { + auto true_merged_child = merged_child->GetTrueBag(); + children.insert(true_merged_child); + true_merged_child->parents.insert(this); } - - return res_value; } -void VirtualRegsOpt::OptimizeVirtualRegsUsage() { +void PhiRegsBBBagNode::RemoveLoop(llvm::BasicBlock *root_bb) { - auto &inst_lifter = impl->inst.GetLifter(); - impl->virtual_regs_opt = this; - ECV_LOG_NL(std::hex, - "[DEBUG LOG]. func: VirtualRegsOpt::OptimizeVritualRegsUsage. target function: ", - func->getName().str(), "."); + ECV_LOG_NL(std::dec, "[DEBUG LOG]: ", "func: PhiRegsBBbagNode::RemoveLoop. target func: ", + root_bb->getParent()->getName().str()); + { - // Flatten the control flow graph - llvm::BasicBlock *target_bb; // the parent bb of the joined bb - std::queue bb_queue; - std::set visited; - auto entry_bb = &func->getEntryBlock(); - auto entry_terminator_br = llvm::dyn_cast(entry_bb->getTerminator()); - CHECK(nullptr != entry_terminator_br) - << "entry block of the lifted function must have the terminator instruction."; - CHECK(1 == entry_terminator_br->getNumSuccessors()) - << "entry block terminator must have the one jump basic block."; - target_bb = entry_terminator_br->getSuccessor(0); - bb_queue.push(target_bb); +#define TUPLE_ELEM_T \ + PhiRegsBBBagNode *, std::vector, std::set + std::stack> bag_stack; + auto root_bag = bb_regs_bag_map.at(root_bb); + bag_stack.emplace( + std::make_tuple((remill::PhiRegsBBBagNode *) root_bag, {}, + {})); // Why (remill::PhiResgBBBagNode *) is needed? - auto push_successor_bb_queue = [&bb_queue, &visited](llvm::BasicBlock *successor_bb) { - if (!visited.contains(successor_bb)) { - bb_queue.push(successor_bb); + std::set finished; + uint32_t bag_i = 0; + + for (auto [_, bag] : bb_regs_bag_map) { + CHECK(!bag->converted_bag) << ECV_DEBUG_STREAM.str(); + bag->converted_bag = bag; + debug_bag_map.insert({bag, bag_i++}); } - }; - while (!bb_queue.empty()) { - auto target_bb = bb_queue.front(); - bb_queue.pop(); - visited.insert(target_bb); - auto target_terminator = target_bb->getTerminator(); - auto child_num = target_terminator->getNumSuccessors(); - if (2 < child_num) { - LOG(FATAL) - << "Every block of the lifted function by elfconv must not have the child blocks more than two." - << ECV_DEBUG_STREAM.str(); - } else if (2 == child_num) { - push_successor_bb_queue(target_terminator->getSuccessor(0)); - push_successor_bb_queue(target_terminator->getSuccessor(1)); - } else if (1 == child_num) { - auto candidate_bb = target_terminator->getSuccessor(0); - auto &candidate_bb_parents = bb_parents.at(candidate_bb); - if (1 == candidate_bb_parents.size()) { - // join candidate_bb to the target_bb - auto joined_bb = candidate_bb; - auto target_terminator = target_bb->getTerminator(); - CHECK(llvm::dyn_cast(target_terminator)) - << "The parent basic block of the lifted function must terminate by the branch instruction."; - // delete the branch instruction of the target_bb and joined_bb - target_terminator->eraseFromParent(); - // transfer the all instructions (target_bb = target_bb & joined_bb) - target_bb->splice(target_bb->end(), joined_bb); - // join BBRegInfoNode - auto joined_bb_reg_info_node = bb_reg_info_node_map.extract(joined_bb).mapped(); - bb_reg_info_node_map.at(target_bb)->join_reg_info_node(joined_bb_reg_info_node); - // update bb_parents - bb_parents.erase(joined_bb); - target_terminator = target_bb->getTerminator(); - if (llvm::dyn_cast(target_terminator)) { - // joined_bb has children - for (uint32_t i = 0; i < target_terminator->getNumSuccessors(); i++) { - bb_parents.at(target_terminator->getSuccessor(i)).erase(joined_bb); - bb_parents.at(target_terminator->getSuccessor(i)).insert(target_bb); - } - bb_queue.push(target_bb); + while (!bag_stack.empty()) { + auto target_bag = std::get(bag_stack.top())->GetTrueBag(); + auto pre_path = std::get>(bag_stack.top()); + auto visited = std::get>(bag_stack.top()); + bag_stack.pop(); + if (finished.contains(target_bag)) { + continue; + } + DEBUG_REMOVE_LOOP_GRAPH(target_bag); + bool loop_found = false; + std::set true_visited; + for (auto _bag : visited) { + auto true_bag = _bag->GetTrueBag(); + if (true_bag == target_bag) { + loop_found = true; } - // delete the joined block - joined_bb->eraseFromParent(); - } else { - push_successor_bb_queue(candidate_bb); + true_visited.insert(true_bag); } - } else /* if (0 == child_num)*/ { - CHECK(llvm::dyn_cast(target_terminator)) - << "The basic block which doesn't have the successors must be ReturnInst."; - } - } + visited = true_visited; - DebugStreamReset(); - ECV_LOG_NL("target_func: ", func->getName().str()); + if (loop_found) { + auto it_loop_bag = pre_path.rbegin(); + std::set true_deleted_bags; + for (;;) { + CHECK(!pre_path.empty()) << ECV_DEBUG_STREAM.str(); + it_loop_bag = pre_path.rbegin(); + auto moved_bag = (*it_loop_bag)->GetTrueBag(); + pre_path.pop_back(); - // Initialize the Graph of PhiRegsBBBagNode. - for (auto &[bb, bb_reg_info_node] : bb_reg_info_node_map) { - auto phi_regs_bag = new PhiRegsBBBagNode(bb_reg_info_node->bb_load_reg_map, - std::move(bb_reg_info_node->bb_load_reg_map), - std::move(bb_reg_info_node->bb_store_reg_map), {bb}); - PhiRegsBBBagNode::bb_regs_bag_map.insert({bb, phi_regs_bag}); - } - PhiRegsBBBagNode::bag_num = PhiRegsBBBagNode::bb_regs_bag_map.size(); + if (target_bag == moved_bag) { + break; + } else if (true_deleted_bags.contains(moved_bag)) { + continue; + } - for (auto [bb, pars] : bb_parents) { - for (auto par : pars) { - auto par_phi_regs_bag = PhiRegsBBBagNode::bb_regs_bag_map.at(par); - auto child_phi_regs_bag = PhiRegsBBBagNode::bb_regs_bag_map.at(bb); - // Remove self-loop because it is not needed for the PhiRegsBBBagNode* Graph. - if (par_phi_regs_bag == child_phi_regs_bag) { - continue; - } - par_phi_regs_bag->children.insert(child_phi_regs_bag); - child_phi_regs_bag->parents.insert(par_phi_regs_bag); - } - } + true_deleted_bags.insert(moved_bag); - // Calculate the registers which needs to get on the phi nodes for every basic block. - PhiRegsBBBagNode::GetPhiRegsBags(&func->getEntryBlock()); + // translates moved_bag + target_bag->MergePrecedingRegMap(moved_bag); + target_bag->MergeFamilyConvertedBags(moved_bag); + for (auto moved_bb : moved_bag->in_bbs) { + target_bag->in_bbs.insert(moved_bb); + } - ECV_LOG_NL(OutLLVMFunc(func).str().c_str()); + // update cache + moved_bag->converted_bag = target_bag; + visited.erase(moved_bag); + bag_num--; -// stdout the specified registers for the every semantics function. -#if defined(OPT_REAL_REGS_DEBUG) - for (size_t i = 0; i < 31; i++) { - debug_reg_set.insert({EcvReg(RegKind::General, i)}); - // debug_reg_set.insert({EcvReg(RegKind::Vector, i)}); - } - // debug_reg_set.insert({EcvReg(RegKind::General, 3)}); - // debug_reg_set.insert({EcvReg(RegKind::General, 1)}); - // debug_reg_set.insert({EcvReg(RegKind::General, 21)}); - // debug_reg_set.insert({EcvReg(RegKind::General, 24)}); - // debug_reg_set.insert({EcvReg(RegKind::Special, ECV_NZCV_ORDER)}); -#endif + if (it_loop_bag == pre_path.rend()) { + LOG(FATAL) << "Unexpected path route on the PhiRegsBBBagNode::RemoveLoop()." + << ECV_DEBUG_STREAM.str(); + } + } - // Add the phi nodes to the every basic block. - std::set finished; - auto state_ptr = NthArgument(func, kStatePointerArgNum); + // re-search this target_bag + visited.erase(target_bag); + bag_stack.emplace(target_bag, pre_path, visited); + } else { - phi_bb_queue.push(&func->getEntryBlock()); + // push the children + bool search_finished = true; + for (auto __child_bag : target_bag->children) { + auto child_bag = __child_bag->GetTrueBag(); + if (finished.contains(child_bag) || child_bag == target_bag) { + continue; + } + search_finished = false; + auto child_pre_path = pre_path; + auto child_visited = visited; + child_pre_path.push_back(target_bag); + child_visited.insert(target_bag); + bag_stack.emplace(child_bag, child_pre_path, child_visited); + } - while (!phi_bb_queue.empty()) { - auto target_bb = phi_bb_queue.front(); - phi_bb_queue.pop(); - if (finished.contains(target_bb) || relay_bb_cache.contains(target_bb)) { - continue; + // finish the target_bag if all children are finished. + if (search_finished) { + finished.insert(target_bag); + } + } } - ECV_LOG_NL(target_bb, ":"); - auto target_phi_regs_bag = PhiRegsBBBagNode::bb_regs_bag_map.at(target_bb); - auto target_bb_reg_info_node = bb_reg_info_node_map.at(target_bb); - auto ®_latest_inst_map = bb_reg_info_node_map.at(target_bb)->reg_latest_inst_map; - auto ®_derived_added_inst_map = - bb_reg_info_node_map.at(target_bb)->reg_derived_added_inst_map; - auto &referred_able_added_inst_reg_map = - bb_reg_info_node_map.at(target_bb)->referred_able_added_inst_reg_map; - - EcvRegMap> ascend_reg_inst_map = { - {EcvReg(RegKind::Special, STATE_ORDER), - std::make_tuple(EcvRegClass::RegP, arg_state_val, 0)}, - {EcvReg(RegKind::Special, RUNTIME_ORDER), - std::make_tuple(EcvRegClass::RegP, arg_runtime_val, - 0)}}; // %state and %runtime_manager is defined as the argument - - llvm::BranchInst *br_inst = nullptr; - llvm::ReturnInst *ret_inst = nullptr; - - // Add the phi node for the every register included in the bag_phi_reg_map. - auto inst_start_it = &*target_bb->begin(); - for (auto &req_ecv_reg_info : target_phi_regs_bag->bag_req_reg_map) { - auto &[target_ecv_reg, target_ecv_reg_class] = req_ecv_reg_info; - llvm::Value *reg_derived_inst; - // This phi has been already added. - if (reg_derived_added_inst_map.contains(target_ecv_reg)) { - auto no_casted_reg_derived_inst = reg_derived_added_inst_map.at(target_ecv_reg); - reg_derived_inst = CastFromInst( - target_ecv_reg, no_casted_reg_derived_inst, GetLLVMTypeFromRegZ(target_ecv_reg_class), - llvm::dyn_cast(no_casted_reg_derived_inst)->getNextNode(), - no_casted_reg_derived_inst); - // Update cache. - if (no_casted_reg_derived_inst != reg_derived_inst) { - referred_able_added_inst_reg_map.insert({reg_derived_inst, req_ecv_reg_info}); - CHECK(reg_derived_inst->getType() == GetLLVMTypeFromRegZ(target_ecv_reg_class)); + // Update all bags to the true bags. + std::set deleted_bag_set; + for (auto [bb, bag] : bb_regs_bag_map) { + // Update bag + auto target_true_bag = bag->GetTrueBag(); + if (bag != target_true_bag) { + bb_regs_bag_map.insert_or_assign(bb, target_true_bag); + deleted_bag_set.insert(bag); + } + // Update parents + std::set new_pars; + for (auto par : target_true_bag->parents) { + auto t_par = par->GetTrueBag(); + if (t_par == target_true_bag) { + continue; } - // for debug - value_reg_map.insert({reg_derived_inst, req_ecv_reg_info}); + new_pars.insert(t_par); } - // Generate the new phi node. - else { - auto phi_op_type = GetLLVMTypeFromRegZ(target_ecv_reg_class); - auto reg_derived_phi = - llvm::PHINode::Create(phi_op_type, bb_parents.at(target_bb).size(), - VAR_NAME(target_ecv_reg, target_ecv_reg_class), inst_start_it); - // Add this phi to the reg_latest_inst_map (to avoid the infinity loop when running Impl::GetValueFromTargetBBAndReg). - reg_latest_inst_map.insert( - {target_ecv_reg, std::make_tuple(target_ecv_reg_class, reg_derived_phi, 0)}); + target_true_bag->parents = new_pars; + // Update children + std::set new_children; + for (auto child : target_true_bag->children) { + auto t_child = child->GetTrueBag(); + if (t_child == target_true_bag) { + continue; + } + new_children.insert(t_child); + } + target_true_bag->children = new_children; + } + // Delete the all unneccesary bags. + for (auto deleted_bag : deleted_bag_set) { + delete (deleted_bag); + } + } - // Get the every virtual register from all the parent bb. - auto par_bb_it = bb_parents.at(target_bb).begin(); - std::set _finished; - while (par_bb_it != bb_parents.at(target_bb).end()) { - auto par_bb = *par_bb_it; - if (_finished.contains(par_bb)) { - ++par_bb_it; - continue; +#if defined(OPT_ALGO_DEBUG) + + // Check the consistency of the parents and children + { + std::set bag_set; + for (auto [_, bag] : bb_regs_bag_map) { + if (!bag_set.contains(bag)) { + bag_set.insert(bag); + for (auto par : bag->parents) { + if (!par->children.contains(bag)) { + LOG(FATAL) << "parent: " << par << " must have the child: " << bag << "\n"; } - auto derived_reg_value = GetValueFromTargetBBAndReg(par_bb, target_bb, req_ecv_reg_info); - // if the relay_bb is added as the parent of the target_bb, `par_bb` is not the parent. - if (auto from_inst = llvm::dyn_cast(derived_reg_value)) { - auto true_par = from_inst->getParent(); - reg_derived_phi->addIncoming(derived_reg_value, true_par); - _finished.insert(true_par); - if (par_bb != true_par) { - par_bb_it = bb_parents.at(target_bb).begin(); - continue; - } - } else { - reg_derived_phi->addIncoming(derived_reg_value, par_bb); - _finished.insert(par_bb); + } + for (auto child : bag->children) { + if (!child->parents.contains(bag)) { + LOG(FATAL) << "child: " << child << " must have the parent: " << bag << "\n"; } - ++par_bb_it; } - referred_able_added_inst_reg_map.insert({reg_derived_phi, req_ecv_reg_info}); - // for debug - value_reg_map.insert({reg_derived_phi, req_ecv_reg_info}); - reg_derived_inst = reg_derived_phi; } - // Add this phi to the ascend_reg_inst_map - ascend_reg_inst_map.insert( - {target_ecv_reg, std::make_tuple(target_ecv_reg_class, reg_derived_inst, 0)}); - CHECK(GetLLVMTypeFromRegZ(target_ecv_reg_class) == reg_derived_inst->getType()); } + } - reg_latest_inst_map.clear(); - auto target_inst_it = inst_start_it; - ECV_LOG_NL("insts:"); + // Check whether G of PhiregsBBBagNode* doesn't have loop. (for debug) + { + std::stack bag_stack; + std::set visited, finished; + bag_stack.push(bb_regs_bag_map.at(root_bb)); - // Replace all the `load` to the CPU registers memory with the value of the phi nodes. - while (target_inst_it) { - ECV_LOG_NL("\t", LLVMThingToString(target_inst_it)); - // The target instruction was added. only update cache. - if (referred_able_added_inst_reg_map.contains(&*target_inst_it)) { - auto &[added_ecv_reg, added_ecv_reg_class] = - referred_able_added_inst_reg_map.at(&*target_inst_it); - ascend_reg_inst_map.insert_or_assign( - added_ecv_reg, std::make_tuple(added_ecv_reg_class, target_inst_it, 0)); - CHECK(target_inst_it->getType() == GetLLVMTypeFromRegZ(added_ecv_reg_class)); - target_inst_it = target_inst_it->getNextNode(); - } else { - // Target: llvm::LoadInst - if (auto *load_inst = llvm::dyn_cast(target_inst_it)) { - const auto &load_reg_name = load_inst->getPointerOperand()->getName().str(); - auto [target_ecv_reg, load_ecv_reg_class] = EcvReg::GetRegInfo(load_reg_name); - - llvm::Value *new_ecv_reg_inst; - - // Can replace this load with existig accessed value. - if (ascend_reg_inst_map.contains(target_ecv_reg)) { - new_ecv_reg_inst = GetRegValueFromCacheMap(target_ecv_reg, load_inst->getType(), - load_inst, ascend_reg_inst_map); - target_inst_it = llvm::dyn_cast(load_inst)->getNextNode(); - // Replace all the Users. - load_inst->replaceAllUsesWith(new_ecv_reg_inst); - CHECK(new_ecv_reg_inst->getType() == GetLLVMTypeFromRegZ(load_ecv_reg_class)); - // Delete load_inst. - load_inst->eraseFromParent(); - } - // Should load this register because it is first access. - else { - new_ecv_reg_inst = load_inst; - target_inst_it = llvm::dyn_cast(load_inst)->getNextNode(); - // Update cache. - ascend_reg_inst_map.insert_or_assign( - target_ecv_reg, std::make_tuple(load_ecv_reg_class, new_ecv_reg_inst, 0)); - } - - // for debug - value_reg_map.insert( - {new_ecv_reg_inst, {target_ecv_reg, GetRegZFromLLVMType(load_inst->getType())}}); - } - // Target: llvm::CallInst - else if (auto call_inst = llvm::dyn_cast(target_inst_it)) { - // Call the lifted function (includes `__remill_function_call`). - if (lifted_func_caller_set.contains(call_inst)) { - // Store already stored `bb_store_reg_map` - for (auto [within_store_ecv_reg, ascend_value] : ascend_reg_inst_map) { - if (within_store_ecv_reg.CheckNoChangedReg() || - !target_bb_reg_info_node->bb_store_reg_map.contains(within_store_ecv_reg)) { - continue; - } - auto within_store_ecv_reg_class = std::get(ascend_value); - inst_lifter->StoreRegValueBeforeInst( - target_bb, state_ptr, within_store_ecv_reg.GetRegName(within_store_ecv_reg_class), - GetRegValueFromCacheMap(within_store_ecv_reg, - GetWholeLLVMTypeFromRegZ(within_store_ecv_reg), call_inst, - ascend_reg_inst_map), - call_inst); - } - // Store `preceding_store_map` - for (auto [preceding_store_ecv_reg, preceding_store_ecv_reg_class] : - target_phi_regs_bag->bag_preceding_store_reg_map) { - if (preceding_store_ecv_reg.CheckNoChangedReg() || - target_bb_reg_info_node->bb_store_reg_map.contains(preceding_store_ecv_reg)) { - continue; - } - inst_lifter->StoreRegValueBeforeInst( - target_bb, state_ptr, - preceding_store_ecv_reg.GetRegName(preceding_store_ecv_reg_class), - GetRegValueFromCacheMap(preceding_store_ecv_reg, - GetWholeLLVMTypeFromRegZ(preceding_store_ecv_reg), - call_inst, ascend_reg_inst_map), - call_inst); - } - auto call_next_inst = call_inst->getNextNode(); - // Load `preceding_store_map` + `load_map` - for (auto [req_ecv_reg, tuple_set] : ascend_reg_inst_map) { - if (req_ecv_reg.CheckNoChangedReg()) { - continue; - } - auto [req_r_c, userd_val, order] = tuple_set; - auto req_load = llvm::dyn_cast(inst_lifter->LoadRegValueBeforeInst( - target_bb, state_ptr, req_ecv_reg.GetRegName(req_r_c), call_next_inst)); - // Replace with new loaded register. - std::set fin_users; - auto user = userd_val->user_begin(); - while (userd_val->user_end() != user) { - if (fin_users.contains(*user)) { - user++; - continue; - } - auto user_inst = llvm::dyn_cast(*user); - if (user_inst->getParent() != target_bb) { - CHECK(0 == order); - user_inst->replaceUsesOfWith(userd_val, req_load); - fin_users.insert(*user); - user = userd_val->user_begin(); - continue; - } else if (req_load->comesBefore(user_inst)) { - // user_inst is ExtractValueInst. - if (auto extrv_user = llvm::dyn_cast(user_inst)) { - if (extrv_user->getIndices()[0] == order) { - CHECK(req_load->getType() == extrv_user->getType()) - << "req_load: " << LLVMThingToString(req_load) - << ", userd_val: " << LLVMThingToString(extrv_user) << "\n"; - extrv_user->replaceAllUsesWith(req_load); - // extr_user->eraseFromParent(); - } else { - user++; - continue; - } - } else if (auto extre_user = - llvm::dyn_cast(user_inst)) { - auto extre_order = - llvm::dyn_cast(extre_user->getIndexOperand()) - ->getZExtValue(); - if (extre_order == order) { - CHECK(req_load->getType() == extre_user->getType()) - << "req_load: " << LLVMThingToString(req_load) - << ", userd_val: " << LLVMThingToString(extre_user) << "\n"; - extre_user->replaceAllUsesWith(req_load); - // extre_user->eraseFromParent(); - } else { - user++; - continue; - } - } else { - CHECK(order == 0); - user_inst->replaceUsesOfWith(userd_val, req_load); - } - fin_users.insert(*user); - user = userd_val->user_begin(); - continue; - } - user++; - } - // Update cache. - ascend_reg_inst_map.insert_or_assign(req_ecv_reg, - std::make_tuple(req_r_c, req_load, 0)); - CHECK(GetLLVMTypeFromRegZ(req_r_c) == req_load->getType()); - // for debug - value_reg_map.insert({req_load, {req_ecv_reg, req_r_c}}); - } - target_inst_it = call_next_inst; - } - // Call the `emulate_system_call` semantic function. - else if (call_inst->getCalledFunction()->getName().str() == "emulate_system_call") { - // Store target: x0 ~ x5, x8 - for (auto [within_store_ecv_reg, ascend_value] : ascend_reg_inst_map) { - if (!(within_store_ecv_reg.number < 6 || within_store_ecv_reg.number == 8) || - !target_bb_reg_info_node->bb_store_reg_map.contains(within_store_ecv_reg)) { - continue; - } - auto within_store_ecv_reg_class = std::get(ascend_value); - inst_lifter->StoreRegValueBeforeInst( - target_bb, state_ptr, within_store_ecv_reg.GetRegName(within_store_ecv_reg_class), - GetRegValueFromCacheMap(within_store_ecv_reg, - GetWholeLLVMTypeFromRegZ(within_store_ecv_reg), call_inst, - ascend_reg_inst_map), - call_inst); - } - // Store target: x0 ~ x5, x8 - for (auto [preceding_store_ecv_reg, preceding_store_ecv_reg_class] : - target_phi_regs_bag->bag_preceding_store_reg_map) { - if (!(preceding_store_ecv_reg.number < 6 || preceding_store_ecv_reg.number == 8) || - target_bb_reg_info_node->bb_store_reg_map.contains(preceding_store_ecv_reg)) { - continue; - } - inst_lifter->StoreRegValueBeforeInst( - target_bb, state_ptr, - preceding_store_ecv_reg.GetRegName(preceding_store_ecv_reg_class), - GetRegValueFromCacheMap(preceding_store_ecv_reg, - GetWholeLLVMTypeFromRegZ(preceding_store_ecv_reg), - call_inst, ascend_reg_inst_map), - call_inst); - } - auto call_next_inst = call_inst->getNextNode(); - // Load target: x0 - for (auto [req_ecv_reg, tuple_set] : ascend_reg_inst_map) { - if (0 != req_ecv_reg.number) { - continue; - } - auto [req_r_c, userd_val, order] = tuple_set; - auto req_load = llvm::dyn_cast(inst_lifter->LoadRegValueBeforeInst( - target_bb, state_ptr, req_ecv_reg.GetRegName(req_r_c), call_next_inst)); - // Replace with new loaded register. - std::set fin_users; - auto user = userd_val->user_begin(); - while (userd_val->user_end() != user) { - if (fin_users.contains(*user)) { - user++; - continue; - } - auto user_inst = llvm::dyn_cast(*user); - if (user_inst->getParent() != target_bb) { - CHECK(0 == order); - user_inst->replaceUsesOfWith(userd_val, req_load); - fin_users.insert(*user); - user = userd_val->user_begin(); - continue; - } else if (req_load->comesBefore(user_inst)) { - // user_inst is ExtractValueInst. - if (auto extr_user = llvm::dyn_cast(user_inst)) { - if (extr_user->getIndices()[0] == order) { - CHECK(req_load->getType() == extr_user->getType()) - << "req_load: " << LLVMThingToString(req_load) - << ", userd_val: " << LLVMThingToString(extr_user) << "\n"; - extr_user->replaceAllUsesWith(req_load); - // extr_user->eraseFromParent(); - } else { - user++; - continue; - } - } else if (auto extre_user = - llvm::dyn_cast(user_inst)) { - auto extre_order = - llvm::dyn_cast(extre_user->getIndexOperand()) - ->getZExtValue(); - if (extre_order == order) { - CHECK(req_load->getType() == extre_user->getType()) - << "req_load: " << LLVMThingToString(req_load) - << ", userd_val: " << LLVMThingToString(extre_user) << "\n"; - extre_user->replaceAllUsesWith(req_load); - // extre_user->eraseFromParent(); - } else { - user++; - continue; - } - } else { - CHECK(order == 0); - user_inst->replaceUsesOfWith(userd_val, req_load); - } - fin_users.insert(*user); - user = userd_val->user_begin(); - continue; - } - user++; - } - // Update cache. - ascend_reg_inst_map.insert_or_assign(req_ecv_reg, - std::make_tuple(req_r_c, req_load, 0)); - CHECK(GetLLVMTypeFromRegZ(req_r_c) == req_load->getType()); - // for debug - value_reg_map.insert({req_load, {req_ecv_reg, req_r_c}}); - } - target_inst_it = call_next_inst; - DEBUG_PC_AND_REGISTERS(call_next_inst, ascend_reg_inst_map, 0xffff'ff); - } - // Call the general semantic functions. - else { - if (target_bb_reg_info_node->sema_call_written_reg_map.contains(call_inst)) { - auto &sema_func_write_regs = - target_bb_reg_info_node->sema_call_written_reg_map.at(call_inst); - // Load all the referenced registers. - for (std::size_t i = 0; i < sema_func_write_regs.size(); i++) { - ascend_reg_inst_map.insert_or_assign( - sema_func_write_regs[i].first, - std::make_tuple(sema_func_write_regs[i].second, call_inst, i)); - } - // for debug - // if the return type is struct, this key value is not used. - if (!sema_func_write_regs.empty()) { - value_reg_map.insert( - {call_inst, {sema_func_write_regs[0].first, sema_func_write_regs[0].second}}); - } - } - target_inst_it = call_inst->getNextNode(); - DEBUG_PC_AND_REGISTERS(call_inst->getNextNode(), ascend_reg_inst_map, - Sema_func_vma_map.contains(call_inst) - ? Sema_func_vma_map.at(call_inst) - : 0xffff'ff); - } - } - // Target: llvm::StoreInst - else if (auto store_inst = llvm::dyn_cast(target_inst_it)) { - auto stored_value = store_inst->getValueOperand(); - auto stored_reg_name = store_inst->getPointerOperand()->getName().str(); - auto [store_ecv_reg, store_ecv_reg_class] = EcvReg::GetRegInfo(stored_reg_name); - // Update cache. - ascend_reg_inst_map.insert_or_assign( - store_ecv_reg, std::make_tuple(store_ecv_reg_class, stored_value, 0)); - CHECK(stored_value->getType() == GetLLVMTypeFromRegZ(store_ecv_reg_class)); - target_inst_it = store_inst->getNextNode(); - store_inst->eraseFromParent(); - } - // Target: llvm::BranchInst - else if (auto __br_inst = llvm::dyn_cast(target_inst_it)) { - CHECK(!br_inst) << "There are multiple branch instructions in the one BB."; - br_inst = __br_inst; - target_inst_it = br_inst->getNextNode(); - } - // Target: llvm::CastInst - else if (auto cast_inst = llvm::dyn_cast(target_inst_it)) { - auto cast_op = cast_inst->getOperand(0); - // for debug - value_reg_map.insert({cast_inst, value_reg_map.at(cast_op)}); - target_inst_it = cast_inst->getNextNode(); - } - // Target: llvm::BinaryOperator - else if (auto binary_inst = llvm::dyn_cast(target_inst_it)) { - if (target_bb_reg_info_node->post_update_regs.contains(binary_inst)) { - auto [bin_e_r, bin_e_r_c] = target_bb_reg_info_node->post_update_regs.at(binary_inst); - ascend_reg_inst_map.insert_or_assign(bin_e_r, - std::make_tuple(bin_e_r_c, binary_inst, 0)); - } - target_inst_it = target_inst_it->getNextNode(); - // for debug - auto lhs = binary_inst->getOperand(0); - // (FIXME) should check the second operand too. - value_reg_map.insert({binary_inst, value_reg_map.at(lhs)}); - } - // Target: llvm::ReturnInst - else if (auto __ret_inst = llvm::dyn_cast(target_inst_it)) { - // Store already stored `within_store_map` - CHECK(!ret_inst) << "Found the multiple llvm::ReturnInst at the one Basic Block." - << ECV_DEBUG_STREAM.str(); - ret_inst = __ret_inst; - for (auto [within_store_ecv_reg, ascend_value] : ascend_reg_inst_map) { - if (within_store_ecv_reg.CheckNoChangedReg() || - !target_bb_reg_info_node->bb_store_reg_map.contains(within_store_ecv_reg)) { - continue; - } - auto within_store_ecv_reg_class = std::get(ascend_value); - inst_lifter->StoreRegValueBeforeInst( - target_bb, state_ptr, within_store_ecv_reg.GetRegName(within_store_ecv_reg_class), - GetRegValueFromCacheMap(within_store_ecv_reg, - GetWholeLLVMTypeFromRegZ(within_store_ecv_reg), ret_inst, - ascend_reg_inst_map), - ret_inst); - } - // Store `preceding_store_map` - for (auto [preceding_store_ecv_reg, preceding_store_ecv_reg_class] : - target_phi_regs_bag->bag_preceding_store_reg_map) { - if (preceding_store_ecv_reg.CheckNoChangedReg() || - target_bb_reg_info_node->bb_store_reg_map.contains(preceding_store_ecv_reg)) { - continue; - } - inst_lifter->StoreRegValueBeforeInst( - target_bb, state_ptr, - preceding_store_ecv_reg.GetRegName(preceding_store_ecv_reg_class), - GetRegValueFromCacheMap(preceding_store_ecv_reg, - GetWholeLLVMTypeFromRegZ(preceding_store_ecv_reg), ret_inst, - ascend_reg_inst_map), - ret_inst); - } - target_inst_it = target_inst_it->getNextNode(); - } - // Target: The instructions that can be ignored. - else if (llvm::dyn_cast(target_inst_it) || - llvm::dyn_cast(target_inst_it) || - llvm::dyn_cast(target_inst_it)) { - CHECK(true); - target_inst_it = target_inst_it->getNextNode(); - } else { - LOG(FATAL) << "Unexpected inst when adding phi nodes." << ECV_DEBUG_STREAM.str(); - } - } - } - - reg_latest_inst_map = ascend_reg_inst_map; - - finished.insert(target_bb); - // Add the children to the queue - if (br_inst) { - for (std::size_t i = 0; i < br_inst->getNumSuccessors(); i++) { - phi_bb_queue.push(br_inst->getSuccessor(i)); + while (!bag_stack.empty()) { + auto target_bag = bag_stack.top(); + bag_stack.pop(); + if (finished.contains(target_bag)) { + continue; } - } - CHECK((br_inst != nullptr) ^ (ret_inst != nullptr)) - << "Not found the Branch or Return instruction in the Basic Block." - << ECV_DEBUG_STREAM.str(); - } - -// Check -#if defined(OPT_GEN_IR_DEBUG) - // Check the parent-child relationship - for (auto &bb : *func) { - auto inst_terminator = bb.getTerminator(); - for (size_t i = 0; i < inst_terminator->getNumSuccessors(); i++) { - CHECK(bb_parents.at(inst_terminator->getSuccessor(i)).contains(&bb)); - } - } - // Check the optimized LLVM IR. - for (auto &bb : *func) { - auto bb_reg_info_node_2 = bb_reg_info_node_map.at(&bb); - for (auto &inst : bb) { - if (auto call_inst = llvm::dyn_cast(&inst); - call_inst && !lifted_func_caller_set.contains(call_inst)) { - if (bb_reg_info_node_2->sema_func_args_reg_map.contains(call_inst)) { - auto sema_isel_args = bb_reg_info_node_2->sema_func_args_reg_map.at(call_inst); - for (size_t i = 0; i < sema_isel_args.size(); i++) { - auto sema_isel_arg_i = sema_isel_args[i]; - if (EcvRegClass::RegNULL == sema_isel_arg_i.second || - // `%state` is not loaded even before optimization, so can ignore. - STATE_ORDER == sema_isel_arg_i.first.number || - llvm::dyn_cast(call_inst->getOperand(i))) { - continue; - } - auto actual_arg_i = call_inst->getOperand(i); - auto [actual_arg_ecv_reg, actual_arg_ecv_reg_class] = value_reg_map.at(actual_arg_i); - CHECK(actual_arg_ecv_reg.number == sema_isel_arg_i.first.number) - << "i: " << i - << ", actual arg ecv_reg number: " << to_string(actual_arg_ecv_reg.number) - << ", sema func arg ecv_reg: " << to_string(sema_isel_arg_i.first.number) << "\n"; - CHECK(actual_arg_ecv_reg_class == sema_isel_arg_i.second) - << "EcvRegClass Mismatch. actual arg ecv_reg_class: " - << EcvRegClass2String(actual_arg_ecv_reg_class) - << ", sema isel arg ecv_reg_class: " << EcvRegClass2String(sema_isel_arg_i.second) - << " at value: " << LLVMThingToString(actual_arg_i) - << ", sema func: " << LLVMThingToString(call_inst) - << ", func: " << func->getName().str() << "\n"; + if (visited.contains(target_bag)) { + for (auto child : target_bag->children) { + if (!finished.contains(child)) { + LOG(FATAL) + << "[Bug] The loop was detected from the G of PhiRegsBBBagNode* after PhiRegsBBBagNode::RemoveLoop." + << ECV_DEBUG_STREAM.str(); } } + finished.insert(target_bag); + continue; } - } - } - if (func->size() != finished.size() + relay_bb_cache.size()) { - std::cout << "No optimized blocks!\n"; - for (auto &bb : *func) { - if (!finished.contains(&bb) && !relay_bb_cache.contains(&bb)) { - std::cout << std::hex << &bb << ":\n"; - for (auto &inst : bb) { - llvm::outs() << " " << inst << "\n"; + visited.insert(target_bag); + // after searching all children, re-search this target_bag. + bag_stack.push(target_bag); + for (auto child : target_bag->children) { + if (!finished.contains(child)) { + bag_stack.push(child); } } } - LOG(FATAL) << "func->size: " << func->size() << ", finished size: " << finished.size() - << ", relay_bb_num: " << relay_bb_cache.size() << "\n" - << ECV_DEBUG_STREAM.str(); + CHECK(bag_num == finished.size()) + << "[Bug] bag_num: " << bag_num << ", finished.size(): " << finished.size() + << ". They should be equal at PhiRegsBBBagNode::RemoveLoop." << ECV_DEBUG_STREAM.str(); } -#endif - // Reset PhiRegsBBBagNode. - PhiRegsBBBagNode::Reset(); DebugStreamReset(); +#endif } -void VirtualRegsOpt::InsertDebugVmaAndRegisters( - llvm::Instruction *inst_at_before, - EcvRegMap> &ascend_reg_inst_map, uint64_t pc) { - if (!debug_reg_set.empty()) { - auto debug_vma_and_regiters_fun = impl->module->getFunction("debug_vma_and_registers"); - - std::vector args; - args.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(impl->context), pc)); - args.push_back(nullptr); +void PhiRegsBBBagNode::GetPrecedingVirtualRegsBags(llvm::BasicBlock *root_bb) { + ECV_LOG_NL("[DEBUG LOG]: ", "func: PhiRegsBBbagNode::GetPrecedingVirtualRegsBags. target func: ", + root_bb->getParent()->getName().str()); + std::queue bag_queue; + std::unordered_map finished_pars_num_map; + std::set finished; + bag_queue.push(bb_regs_bag_map.at(root_bb)); - for (auto debug_ecv_reg : debug_reg_set) { - if (ascend_reg_inst_map.contains(debug_ecv_reg)) { - llvm::GlobalVariable *reg_name_gvar; - if (RegKind::General == debug_ecv_reg.reg_kind) { - reg_name_gvar = - impl->module->getGlobalVariable("debug_X" + to_string(debug_ecv_reg.number)); - } else if (RegKind::Vector == debug_ecv_reg.reg_kind) { - reg_name_gvar = - impl->module->getGlobalVariable("debug_V" + to_string(debug_ecv_reg.number)); - } else { - // (FIXME) - CHECK(ECV_NZCV_ORDER == debug_ecv_reg.number); - reg_name_gvar = impl->module->getGlobalVariable("debug_ECV_NZCV"); + while (!bag_queue.empty()) { + auto target_bag = bag_queue.front(); + bag_queue.pop(); + if (finished.contains(target_bag)) { + continue; + } + finished_pars_num_map.insert({target_bag, 0}); + if (target_bag->parents.size() == finished_pars_num_map.at(target_bag)) { + // can finish the target_bag. + for (auto par_bag : target_bag->parents) { + // preceding load reg. priority: target_bag > par_bag. + for (auto ecv_reg_info : par_bag->bag_preceding_load_reg_map) { + target_bag->bag_preceding_load_reg_map.insert(ecv_reg_info); + } + // preceding store reg. priority: target_bag > par_bag. + for (auto ecv_reg_info : par_bag->bag_preceding_store_reg_map) { + target_bag->bag_preceding_store_reg_map.insert(ecv_reg_info); } - args.push_back(reg_name_gvar); - args.push_back(GetRegValueFromCacheMap(debug_ecv_reg, - GetWholeLLVMTypeFromRegZ(debug_ecv_reg), - inst_at_before, ascend_reg_inst_map)); } - } - - args[1] = llvm::ConstantInt::get(llvm::Type::getInt64Ty(impl->context), args.size() - 2); - llvm::CallInst::Create(debug_vma_and_regiters_fun, args, llvm::Twine::createNull(), - inst_at_before); - } -} - -llvm::Type *VirtualRegsOpt::GetLLVMTypeFromRegZ(EcvRegClass ecv_reg_class) { - auto &context = func->getContext(); - switch (ecv_reg_class) { - case EcvRegClass::RegW: return llvm::Type::getInt32Ty(context); - case EcvRegClass::RegX: return llvm::Type::getInt64Ty(context); - case EcvRegClass::RegB: return llvm::Type::getInt8Ty(context); - case EcvRegClass::RegH: return llvm::Type::getInt16Ty(context); - case EcvRegClass::RegS: return llvm::Type::getFloatTy(context); - case EcvRegClass::RegD: return llvm::Type::getDoubleTy(context); - case EcvRegClass::RegQ: return llvm::Type::getInt128Ty(context); - case EcvRegClass::RegV: - return llvm::VectorType::get(llvm::Type::getInt128Ty(context), 1, false); - case EcvRegClass::Reg8B: return llvm::VectorType::get(llvm::Type::getInt8Ty(context), 8, false); - case EcvRegClass::Reg16B: - return llvm::VectorType::get(llvm::Type::getInt8Ty(context), 16, false); - case EcvRegClass::Reg4H: - return llvm::VectorType::get(llvm::Type::getInt16Ty(context), 4, false); - case EcvRegClass::Reg8H: - return llvm::VectorType::get(llvm::Type::getInt16Ty(context), 8, false); - case EcvRegClass::Reg2S: - return llvm::VectorType::get(llvm::Type::getInt32Ty(context), 2, false); - case EcvRegClass::Reg2SF: - return llvm::VectorType::get(llvm::Type::getFloatTy(context), 2, false); - case EcvRegClass::Reg4S: - return llvm::VectorType::get(llvm::Type::getInt32Ty(context), 4, false); - case EcvRegClass::Reg4SF: - return llvm::VectorType::get(llvm::Type::getFloatTy(context), 4, false); - case EcvRegClass::Reg1D: - return llvm::VectorType::get(llvm::Type::getInt64Ty(context), 1, false); - case EcvRegClass::Reg1DF: - return llvm::VectorType::get(llvm::Type::getDoubleTy(context), 1, false); - case EcvRegClass::Reg2D: - return llvm::VectorType::get(llvm::Type::getInt64Ty(context), 2, false); - case EcvRegClass::Reg2DF: - return llvm::VectorType::get(llvm::Type::getDoubleTy(context), 2, false); - case EcvRegClass::RegP: return llvm::Type::getInt64PtrTy(context); - default: break; - } - - LOG(FATAL) - << "[Bug] Reach the unreachable code at VirtualRegsOpt::GetLLVMTypeFromRegZ. ecv_reg_class: " - << std::underlying_type::type(ecv_reg_class) << "\n" - << ECV_DEBUG_STREAM.str(); - return nullptr; -} - -llvm::Type *VirtualRegsOpt::GetWholeLLVMTypeFromRegZ(EcvReg ecv_reg) { - auto &context = func->getContext(); - auto t_reg_kind = ecv_reg.reg_kind; - if (RegKind::General == t_reg_kind || RegKind::Special == t_reg_kind) { - CHECK(ecv_reg.number != STATE_ORDER && ecv_reg.number != RUNTIME_ORDER); - return llvm::Type::getInt64Ty(context); - } else /* RegKind::Vector */ { - return llvm::Type::getInt128Ty(context); + // target_bag was finished. + finished.insert(target_bag); + // update the finised_pars_map for all the childlen of this target_bag. + // push all the no finished children + for (auto child : target_bag->children) { + finished_pars_num_map.insert_or_assign(child, finished_pars_num_map[child] + 1); + if (!finished.contains(child)) { + bag_queue.push(child); + } + } + } } -} -EcvRegClass VirtualRegsOpt::GetRegZFromLLVMType(llvm::Type *value_type) { - auto &context = func->getContext(); - if (llvm::Type::getInt32Ty(context) == value_type) { - return EcvRegClass::RegW; - } else if (llvm::Type::getInt64Ty(context) == value_type) { - return EcvRegClass::RegX; - } else if (llvm::Type::getInt8Ty(context) == value_type) { - return EcvRegClass::RegB; - } else if (llvm::Type::getInt16Ty(context) == value_type) { - return EcvRegClass::RegH; - } else if (llvm::Type::getFloatTy(context) == value_type) { - return EcvRegClass::RegS; - } else if (llvm::Type::getDoubleTy(context) == value_type) { - return EcvRegClass::RegD; - } else if (llvm::Type::getInt128Ty(context) == value_type) { - return EcvRegClass::RegQ; - } else if (llvm::VectorType::get(llvm::Type::getInt128Ty(context), 1, false) == value_type) { - return EcvRegClass::RegV; - } else if (llvm::VectorType::get(llvm::Type::getInt8Ty(context), 8, false) == value_type) { - return EcvRegClass::Reg8B; - } else if (llvm::VectorType::get(llvm::Type::getInt8Ty(context), 16, false) == value_type) { - return EcvRegClass::Reg16B; - } else if (llvm::VectorType::get(llvm::Type::getInt16Ty(context), 4, false) == value_type) { - return EcvRegClass::Reg4H; - } else if (llvm::VectorType::get(llvm::Type::getInt16Ty(context), 8, false) == value_type) { - return EcvRegClass::Reg8H; - } else if (llvm::VectorType::get(llvm::Type::getInt32Ty(context), 2, false) == value_type) { - return EcvRegClass::Reg2S; - } else if (llvm::VectorType::get(llvm::Type::getFloatTy(context), 2, false) == value_type) { - return EcvRegClass::Reg2SF; - } else if (llvm::VectorType::get(llvm::Type::getInt32Ty(context), 4, false) == value_type) { - return EcvRegClass::Reg4S; - } else if (llvm::VectorType::get(llvm::Type::getFloatTy(context), 4, false) == value_type) { - return EcvRegClass::Reg4SF; - } else if (llvm::VectorType::get(llvm::Type::getInt64Ty(context), 1, false) == value_type) { - return EcvRegClass::Reg1D; - } else if (llvm::VectorType::get(llvm::Type::getDoubleTy(context), 1, false) == value_type) { - return EcvRegClass::Reg1DF; - } else if (llvm::VectorType::get(llvm::Type::getInt64Ty(context), 2, false) == value_type) { - return EcvRegClass::Reg2D; - } else if (llvm::VectorType::get(llvm::Type::getDoubleTy(context), 2, false) == value_type) { - return EcvRegClass::Reg2DF; - } else if (llvm::Type::getInt64PtrTy(context) == value_type) { - return EcvRegClass::RegP; - } + CHECK(finished.size() == bag_num) + << "[Bug] bag_num: " << bag_num << ", finished_bag.size(): " << finished.size() + << ". They should be equal after PhiRegsBBagNode::GetPrecedingVirtualRegsBags." + << ECV_DEBUG_STREAM.str(); - LOG(FATAL) << "[Bug] Reach the unreachable code at VirtualregsOpt::GetRegZfromLLVMType. Type: " - << LLVMThingToString(value_type) << "\n" - << ECV_DEBUG_STREAM.str(); + DebugStreamReset(); } -llvm::Value * -VirtualRegsOpt::GetValueFromTargetBBAndReg(llvm::BasicBlock *target_bb, - llvm::BasicBlock *request_bb, - std::pair ecv_reg_info) { - auto &[target_ecv_reg, req_ecv_reg_class] = ecv_reg_info; - auto target_phi_regs_bag = PhiRegsBBBagNode::bb_regs_bag_map.at(target_bb); - auto target_bb_reg_info_node = bb_reg_info_node_map.at(target_bb); +void PhiRegsBBBagNode::GetSucceedingVirtualRegsBags(llvm::BasicBlock *root_bb) { + ECV_LOG_NL("[DEBUG LOG]: ", "func: PhiRegsBBbagNode::GetSucceedingVirtualRegsBags. target func: ", + root_bb->getParent()->getName().str()); + std::stack bag_stack; + std::unordered_map finished_children_num_map; + std::set finished; + bag_stack.push(bb_regs_bag_map.at(root_bb)); - const llvm::DataLayout data_layout(impl->module); + while (!bag_stack.empty()) { + auto target_bag = bag_stack.top(); + bag_stack.pop(); + if (finished.contains(target_bag)) { + continue; + } + finished_children_num_map.insert({target_bag, 0}); + if (target_bag->children.size() == finished_children_num_map.at(target_bag)) { + // Can finish the target_bag. + for (auto child_bag : target_bag->children) { + // succeeding load reg. priority: target_bag > child_bag + for (auto ecv_reg_info : child_bag->bag_succeeding_load_reg_map) { + target_bag->bag_succeeding_load_reg_map.insert(ecv_reg_info); + } + } + // The target_bag was finished. + finished.insert(target_bag); + // Update the finised_children_map for all the parents of this target_bag. + for (auto parent_bag : target_bag->parents) { + finished_children_num_map.insert_or_assign(parent_bag, + finished_children_num_map[parent_bag] + 1); + } + continue; + } + // After searching all children, re-search the target_bag. + bag_stack.push(target_bag); + for (auto child_bag : target_bag->children) { + if (!finished.contains(child_bag)) { + bag_stack.push(child_bag); + } + } + } - auto target_terminator = target_bb->getTerminator(); - llvm::Value *req_value = nullptr; + CHECK(finished.size() == finished_children_num_map.size() && finished.size() == bag_num) + << "[Bug] Search argorithm is incorrect of PhiRegsBBBagNode::GetPhiDerivedRegsBags: Search is insufficient." + << ECV_DEBUG_STREAM.str(); - // The target_bb already has the target virtual register. - if (target_bb_reg_info_node->reg_latest_inst_map.contains(target_ecv_reg)) { - auto &[_, from_inst, from_order] = - target_bb_reg_info_node->reg_latest_inst_map.at(target_ecv_reg); - if (from_inst->getType() == GetLLVMTypeFromRegZ(req_ecv_reg_class)) { - req_value = from_inst; - } else { - if (llvm::dyn_cast(from_inst->getType()) || - llvm::dyn_cast(from_inst->getType())) { - auto from_extracted_inst = llvm::ExtractValueInst::Create( - from_inst, {from_order}, llvm::Twine::createNull(), target_terminator); - auto from_extracted_inst_reg_class = GetRegZFromLLVMType(from_extracted_inst->getType()); - // Update cache. - target_bb_reg_info_node->referred_able_added_inst_reg_map.insert( - {from_extracted_inst, {target_ecv_reg, from_extracted_inst_reg_class}}); - target_bb_reg_info_node->reg_latest_inst_map.insert_or_assign( - target_ecv_reg, std::make_tuple(from_extracted_inst_reg_class, from_extracted_inst, 0)); - req_value = CastFromInst(target_ecv_reg, from_extracted_inst, - GetLLVMTypeFromRegZ(req_ecv_reg_class), target_terminator, - from_extracted_inst); - // for debug - value_reg_map.insert( - {from_extracted_inst, {target_ecv_reg, from_extracted_inst_reg_class}}); - } else if (isu128v2Ty(impl->context, from_inst->getType())) { - auto from_extracted_inst = llvm::ExtractElementInst::Create( - from_inst, llvm::ConstantInt::get(llvm::Type::getInt64Ty(impl->context), from_order), - "", target_terminator); - auto from_extracted_inst_reg_class = GetRegZFromLLVMType(from_extracted_inst->getType()); - // Update cache. - target_bb_reg_info_node->referred_able_added_inst_reg_map.insert( - {from_extracted_inst, {target_ecv_reg, from_extracted_inst_reg_class}}); - target_bb_reg_info_node->reg_latest_inst_map.insert_or_assign( - target_ecv_reg, std::make_tuple(from_extracted_inst_reg_class, from_extracted_inst, 0)); - req_value = CastFromInst(target_ecv_reg, from_extracted_inst, - GetLLVMTypeFromRegZ(req_ecv_reg_class), target_terminator, - from_extracted_inst); - // for debug - value_reg_map.insert( - {from_extracted_inst, {target_ecv_reg, from_extracted_inst_reg_class}}); + DebugStreamReset(); +} + +void PhiRegsBBBagNode::GetPhiRegsBags( + llvm::BasicBlock *root_bb, + std::unordered_map &bb_reg_info_node_map) { + // Remove loop from the graph of PhiRegsBBBagNode. + PhiRegsBBBagNode::RemoveLoop(root_bb); + // Prepare the bug_succeeding_load_reg_map. + for (auto [_, bag] : bb_regs_bag_map) { + if (bag->bag_succeeding_load_reg_map.empty()) { + bag->bag_succeeding_load_reg_map = bag->bag_preceding_load_reg_map; + } + } + // Calculate the bag_preceding_(load | store)_reg_map for the every PhiRegsBBBagNode. + PhiRegsBBBagNode::GetPrecedingVirtualRegsBags(root_bb); + // Calculate the bag_succeeding_load_reg_map for the every PhiRegsBBBagNode. + PhiRegsBBBagNode::GetSucceedingVirtualRegsBags(root_bb); + // Calculate the bag_req_reg_map. + std::set finished; + for (auto [_, phi_regs_bag] : bb_regs_bag_map) { + if (!finished.contains(phi_regs_bag)) { + auto &succeeding_load_reg_map = phi_regs_bag->bag_succeeding_load_reg_map; + auto &preceding_load_reg_map = phi_regs_bag->bag_preceding_load_reg_map; + auto &more_small_reg_map = succeeding_load_reg_map.size() <= preceding_load_reg_map.size() + ? succeeding_load_reg_map + : preceding_load_reg_map; + phi_regs_bag->bag_req_reg_map = phi_regs_bag->bag_preceding_store_reg_map; + for (auto &[ecv_reg, _] : more_small_reg_map) { + if (succeeding_load_reg_map.contains(ecv_reg) && preceding_load_reg_map.contains(ecv_reg)) { + auto t_ecv_r_c = succeeding_load_reg_map.at(ecv_reg); + if (phi_regs_bag->bag_req_reg_map.contains(ecv_reg) && + GetRegClassSize(phi_regs_bag->bag_req_reg_map.at(ecv_reg)) < + GetRegClassSize(t_ecv_r_c)) { + phi_regs_bag->bag_req_reg_map.insert_or_assign(ecv_reg, t_ecv_r_c); + } else { + phi_regs_bag->bag_req_reg_map.insert({ecv_reg, t_ecv_r_c}); + } + } } + finished.insert(phi_regs_bag); + } + } - else { - req_value = CastFromInst(target_ecv_reg, from_inst, GetLLVMTypeFromRegZ(req_ecv_reg_class), - target_terminator); + // Calculate bag_passed_caller_reg_map. + auto func = root_bb->getParent(); + auto t_fun_v_r_o = VirtualRegsOpt::func_v_r_opt_map.at(func); + for (auto &bb : *func) { + if (&bb == root_bb) { + continue; + } + auto t_bb = &bb; + auto t_bag = bb_regs_bag_map.at(t_bb); + auto t_bb_info_node = bb_reg_info_node_map.at(t_bb); + for (auto [e_r, n_e_r_c] : t_bb_info_node->bb_load_reg_map) { + bool already_load_flag = false; + for (auto p_bag : t_bag->parents) { + already_load_flag |= p_bag->bag_req_reg_map.contains(e_r); + } + if (!already_load_flag) { + t_fun_v_r_o->passed_caller_reg_map.insert({e_r, n_e_r_c}); } - // for debug - value_reg_map.insert({req_value, {target_ecv_reg, req_ecv_reg_class}}); } + t_fun_v_r_o->passed_caller_reg_map.insert( + {EcvReg(RegKind::Special, SP_ORDER), EcvRegClass::RegX}); } - // The bag_req_reg_map of the target_bb includes the target register. - else if (target_phi_regs_bag->bag_req_reg_map.contains(target_ecv_reg)) { - auto start_inst = target_bb->begin(); - auto phi_ecv_reg_class = target_phi_regs_bag->bag_req_reg_map.at(target_ecv_reg); - auto phi_op_type = GetLLVMTypeFromRegZ(phi_ecv_reg_class); - auto reg_phi = llvm::PHINode::Create(phi_op_type, bb_parents.at(target_bb).size(), - VAR_NAME(target_ecv_reg, phi_ecv_reg_class), &*start_inst); - // Update phi cache. - // must update reg_latest_inst_map before addIncoming to correspond to the loop bbs. - target_bb_reg_info_node->reg_latest_inst_map.insert( - {target_ecv_reg, {phi_ecv_reg_class, reg_phi, 0}}); - // Get the every virtual register from all the parent bb. - auto par_bb_it = bb_parents.at(target_bb).begin(); - std::set _finished; - while (par_bb_it != bb_parents.at(target_bb).end()) { - auto par_bb = *par_bb_it; - if (_finished.contains(par_bb)) { - ++par_bb_it; - continue; + + // Calculate passed_callee_ret_reg_map. + auto &ret_set = t_fun_v_r_o->ret_inst_set; + if (!ret_set.empty()) { + auto ret_inst_bg_bag = bb_regs_bag_map.at((*ret_set.begin())->getParent()); + for (auto [e_r, e_r_c] : ret_inst_bg_bag->bag_preceding_store_reg_map) { + bool is_ret_reg = true; + for (auto iter = ret_set.begin(); iter != ret_set.end(); iter++) { + auto t_bag = bb_regs_bag_map.at((*iter)->getParent()); + is_ret_reg &= t_bag->bag_preceding_store_reg_map.contains(e_r); } - auto derived_reg_value = - GetValueFromTargetBBAndReg(par_bb, target_bb, {target_ecv_reg, phi_ecv_reg_class}); - if (auto from_inst = llvm::dyn_cast(derived_reg_value)) { - auto from_inst_par = from_inst->getParent(); - reg_phi->addIncoming(derived_reg_value, from_inst_par); - _finished.insert(from_inst_par); - if (from_inst_par != par_bb) { - par_bb_it = bb_parents.at(target_bb).begin(); + if (is_ret_reg) { + t_fun_v_r_o->passed_callee_ret_reg_map.insert({e_r, e_r_c}); + } + } + } + + // if (func->getName().starts_with("_IO_file_xsputn")) { + // std::cout << func->getName().str() << std::endl; + // for (auto [e_r, e_r_c] : bag_passed_caller_reg_map) { + // std::cout << e_r.GetRegName(e_r_c) << ", "; + // } + // std::cout << std::endl; + // } + + // (FIXME) + if (func->getName().starts_with("_IO_do_write")) { + t_fun_v_r_o->passed_caller_reg_map.insert({EcvReg(RegKind::General, 1), EcvRegClass::RegX}); + t_fun_v_r_o->passed_caller_reg_map.insert({EcvReg(RegKind::General, 3), EcvRegClass::RegX}); + } +} + +void PhiRegsBBBagNode::DebugGraphStruct(PhiRegsBBBagNode *target_bag) { + ECV_LOG_NL("target bag: ", debug_bag_map.at(target_bag)); + std::set __bags; + ECV_LOG("PhiRegsBBBagNode * G Parents: "); + // stdout PhiRegsBBBagNode* G. + for (auto [__bag, __bag_i] : debug_bag_map) { + auto __t_bag = __bag->GetTrueBag(); + if (__bags.contains(__t_bag)) { + continue; + } else { + __bags.insert(__t_bag); + ECV_LOG("[[", debug_bag_map[__t_bag], "] -> ["); + auto _p_bag = __t_bag->children.begin(); + std::set __t_out_bags; + while (_p_bag != __t_bag->children.end()) { + auto _t_p_bag = (*_p_bag)->GetTrueBag(); + if (__t_out_bags.contains(_t_p_bag)) { + ++_p_bag; continue; } - } else { - reg_phi->addIncoming(derived_reg_value, par_bb); + if (_p_bag != __t_bag->children.begin()) { + ECV_LOG(", "); + } + ECV_LOG(debug_bag_map.at(_t_p_bag)); + __t_out_bags.insert(_t_p_bag); + if (++_p_bag == __t_bag->children.end()) { + break; + } } - ++par_bb_it; + ECV_LOG("]] "); } - // Cast to the req_ecv_reg_class if necessary. - req_value = CastFromInst(target_ecv_reg, reg_phi, GetLLVMTypeFromRegZ(req_ecv_reg_class), - target_terminator, reg_phi); - // for debug - value_reg_map.insert({reg_phi, {target_ecv_reg, phi_ecv_reg_class}}); - value_reg_map.insert({req_value, {target_ecv_reg, req_ecv_reg_class}}); - // Update cache. - target_bb_reg_info_node->reg_derived_added_inst_map.insert({target_ecv_reg, reg_phi}); - target_bb_reg_info_node->referred_able_added_inst_reg_map.insert( - {reg_phi, {target_ecv_reg, phi_ecv_reg_class}}); - CHECK(reg_phi->getType() == GetLLVMTypeFromRegZ(phi_ecv_reg_class)); } - // The target_bb doesn't have the target register, so need to `load` the register. - else { - bool relay_bb_need = false; - auto load_e_r_c = req_ecv_reg_class; - for (std::size_t i = 0; i < target_terminator->getNumSuccessors(); i++) { - auto &succi_bag_req_reg_map = - PhiRegsBBBagNode::bb_regs_bag_map.at(target_terminator->getSuccessor(i))->bag_req_reg_map; - relay_bb_need |= !succi_bag_req_reg_map.contains(target_ecv_reg); - if (succi_bag_req_reg_map.contains(target_ecv_reg) && - GetRegClassSize(load_e_r_c) < GetRegClassSize(succi_bag_req_reg_map.at(target_ecv_reg))) { - load_e_r_c = succi_bag_req_reg_map.at(target_ecv_reg); - } - } + ECV_LOG_NL(); + ECV_LOG_NL(); +} - // Need to insert `relay_bb` - if (relay_bb_need) { - // Create `relay_bb` and insert `load` to it. - auto relay_bb = llvm::BasicBlock::Create(impl->context, llvm::Twine::createNull(), func); - impl->DirectBranchWithSaveParents(request_bb, relay_bb); - for (std::size_t i = 0; i < target_terminator->getNumSuccessors(); i++) { - if (target_terminator->getSuccessor(i) == request_bb) { - target_terminator->setSuccessor(i, relay_bb); - auto &request_pars = bb_parents.at(request_bb); - request_pars.erase(target_bb); - bb_parents.insert({relay_bb, {target_bb}}); +void VirtualRegsOpt::CalPassedCallerRegForBJump() { + std::stack func_stack; + std::set finished; + for (auto [caller, _] : b_jump_callees_map) { + func_stack.push(caller); + } + while (!func_stack.empty()) { + auto t_fun = func_stack.top(); + func_stack.pop(); + if (finished.contains(t_fun)) { + continue; + } + if (b_jump_callees_map.contains(t_fun)) { + bool callee_fin = true; + for (auto callee : b_jump_callees_map.at(t_fun)) { + callee_fin &= finished.contains(callee); + } + if (callee_fin) { + auto t_fun_v_r_o = func_v_r_opt_map.at(t_fun); + for (auto callee : b_jump_callees_map.at(t_fun)) { + auto callee_v_r_o = func_v_r_opt_map.at(callee); + for (auto [e_r, e_r_c] : callee_v_r_o->passed_caller_reg_map) { + t_fun_v_r_o->passed_caller_reg_map.insert({e_r, e_r_c}); + } + } + finished.insert(t_fun); + } else { + func_stack.push(t_fun); + for (auto callee : b_jump_callees_map.at(t_fun)) { + if (!finished.contains(callee)) { + func_stack.push(callee); + } } } - relay_bb_cache.insert(relay_bb); + } else { + finished.insert(t_fun); + } + } +} - // Add relay_bb to the PhiRegsBBBagNode and BBRegInfoNode. - auto request_phi_regs_bag = PhiRegsBBBagNode::bb_regs_bag_map.at(request_bb); - PhiRegsBBBagNode::bb_regs_bag_map.insert({relay_bb, request_phi_regs_bag}); - auto relay_bb_reg_info_node = new BBRegInfoNode(func, arg_state_val, arg_runtime_val); - bb_reg_info_node_map.insert({relay_bb, relay_bb_reg_info_node}); +void VirtualRegsOpt::AnalyzeRegsBags() { - auto relay_terminator = relay_bb->getTerminator(); + impl->virtual_regs_opt = this; - // Fix all the aleady derived phi nodes on the request_bb from the target_bb. - auto request_bb_reg_info_node = bb_reg_info_node_map.at(request_bb); - auto request_bb_inst_it = request_bb->begin(); - while (auto request_phi_inst = llvm::dyn_cast(&*request_bb_inst_it)) { - for (size_t i = 0; i < request_phi_inst->getNumIncomingValues(); ++i) { - if (request_phi_inst->getIncomingBlock(i) == target_bb) { - auto [request_ecv_reg, request_ecv_reg_class] = - request_bb_reg_info_node->referred_able_added_inst_reg_map.at(request_phi_inst); - // Generate the new phi node on the relay_bb. - auto relay_phi_inst = - llvm::PHINode::Create(GetLLVMTypeFromRegZ(request_ecv_reg_class), 1, - llvm::Twine::createNull(), relay_terminator); - relay_phi_inst->addIncoming(request_phi_inst->getIncomingValue(i), target_bb); - // re-set the new value and bb of relay_bb for the request_phi_inst. - request_phi_inst->setIncomingBlock(i, relay_bb); - request_phi_inst->setIncomingValue(i, relay_phi_inst); + ECV_LOG_NL(std::hex, + "[DEBUG LOG]. func: VirtualRegsOpt::OptimizeVritualRegsUsage. target function: ", + func->getName().str(), "."); - // Update cache (relay_phi_inst). - relay_bb_reg_info_node->reg_latest_inst_map.insert( - {request_ecv_reg, {request_ecv_reg_class, relay_phi_inst, 0}}); - // for debug - value_reg_map.insert({relay_phi_inst, {request_ecv_reg, request_ecv_reg_class}}); + // Flatten the control flow graph + llvm::BasicBlock *target_bb; // the parent bb of the joined bb + std::queue bb_queue; + std::set visited; + auto entry_bb = &func->getEntryBlock(); + auto entry_terminator_br = llvm::dyn_cast(entry_bb->getTerminator()); + CHECK(nullptr != entry_terminator_br) + << "entry block of the lifted function must have the terminator instruction."; + CHECK(1 == entry_terminator_br->getNumSuccessors()) + << "entry block terminator must have the one jump basic block."; + target_bb = entry_terminator_br->getSuccessor(0); + bb_queue.push(target_bb); + + auto push_successor_bb_queue = [&bb_queue, &visited](llvm::BasicBlock *successor_bb) { + if (!visited.contains(successor_bb)) { + bb_queue.push(successor_bb); + } + }; + + while (!bb_queue.empty()) { + auto target_bb = bb_queue.front(); + bb_queue.pop(); + visited.insert(target_bb); + auto target_terminator = target_bb->getTerminator(); + auto child_num = target_terminator->getNumSuccessors(); + if (2 < child_num) { + LOG(FATAL) + << "Every block of the lifted function by elfconv must not have the child blocks more than two." + << ECV_DEBUG_STREAM.str(); + } else if (2 == child_num) { + push_successor_bb_queue(target_terminator->getSuccessor(0)); + push_successor_bb_queue(target_terminator->getSuccessor(1)); + } else if (1 == child_num) { + auto candidate_bb = target_terminator->getSuccessor(0); + auto &candidate_bb_parents = bb_parents.at(candidate_bb); + if (1 == candidate_bb_parents.size()) { + // join candidate_bb to the target_bb + auto joined_bb = candidate_bb; + auto target_terminator = target_bb->getTerminator(); + CHECK(llvm::dyn_cast(target_terminator)) + << "The parent basic block of the lifted function must terminate by the branch instruction."; + // delete the branch instruction of the target_bb and joined_bb + target_terminator->eraseFromParent(); + // transfer the all instructions (target_bb = target_bb & joined_bb) + target_bb->splice(target_bb->end(), joined_bb); + // join BBRegInfoNode + auto joined_bb_reg_info_node = bb_reg_info_node_map.extract(joined_bb).mapped(); + bb_reg_info_node_map.at(target_bb)->join_reg_info_node(joined_bb_reg_info_node); + // update bb_parents + bb_parents.erase(joined_bb); + target_terminator = target_bb->getTerminator(); + if (llvm::dyn_cast(target_terminator)) { + // joined_bb has children + for (uint32_t i = 0; i < target_terminator->getNumSuccessors(); i++) { + bb_parents.at(target_terminator->getSuccessor(i)).erase(joined_bb); + bb_parents.at(target_terminator->getSuccessor(i)).insert(target_bb); } + bb_queue.push(target_bb); } - ++request_bb_inst_it; + // delete the joined block + joined_bb->eraseFromParent(); + } else { + push_successor_bb_queue(candidate_bb); } + } else /* if (0 == child_num)*/ { + CHECK(llvm::dyn_cast(target_terminator)) + << "The basic block which doesn't have the successors must be ReturnInst."; + } + } - // load all the required registers that the target_bag doesn't require. - auto state_ptr = NthArgument(func, kStatePointerArgNum); - for (auto &[need_ecv_reg, need_ecv_reg_class] : request_phi_regs_bag->bag_req_reg_map) { - if (!target_bb_reg_info_node->reg_latest_inst_map.contains(need_ecv_reg) && - !target_phi_regs_bag->bag_req_reg_map.contains(need_ecv_reg)) { - auto load_value = impl->inst.GetLifter()->LoadRegValueBeforeInst( - relay_bb, state_ptr, need_ecv_reg.GetRegName(need_ecv_reg_class), relay_terminator, - VAR_NAME(need_ecv_reg, need_ecv_reg_class)); - // Update cache. - relay_bb_reg_info_node->reg_latest_inst_map.insert( - {need_ecv_reg, {need_ecv_reg_class, load_value, 0}}); - if (target_ecv_reg == need_ecv_reg) { - req_value = load_value; - } - // for debug - value_reg_map.insert( - {load_value, {need_ecv_reg, GetRegZFromLLVMType(load_value->getType())}}); - value_reg_map.insert({req_value, {need_ecv_reg, need_ecv_reg_class}}); - } + DebugStreamReset(); + ECV_LOG_NL("target_func: ", func->getName().str()); + + // Initialize the Graph of PhiRegsBBBagNode. + for (auto &[bb, bb_reg_info_node] : bb_reg_info_node_map) { + auto phi_regs_bag = + new PhiRegsBBBagNode(bb_reg_info_node->bb_load_reg_map, bb_reg_info_node->bb_load_reg_map, + std::move(bb_reg_info_node->bb_store_reg_map), {bb}); + PhiRegsBBBagNode::bb_regs_bag_map.insert({bb, phi_regs_bag}); + } + PhiRegsBBBagNode::bag_num = PhiRegsBBBagNode::bb_regs_bag_map.size(); + + for (auto [bb, pars] : bb_parents) { + for (auto par : pars) { + auto par_phi_regs_bag = PhiRegsBBBagNode::bb_regs_bag_map.at(par); + auto child_phi_regs_bag = PhiRegsBBBagNode::bb_regs_bag_map.at(bb); + // Remove self-loop because it is not needed for the PhiRegsBBBagNode* Graph. + if (par_phi_regs_bag == child_phi_regs_bag) { + continue; } + par_phi_regs_bag->children.insert(child_phi_regs_bag); + child_phi_regs_bag->parents.insert(par_phi_regs_bag); + } + } - auto relay_bb_br_inst = llvm::dyn_cast(relay_bb->getTerminator()); - if (relay_bb_br_inst) { - phi_bb_queue.push(relay_bb_br_inst->getSuccessor(0)); + // Calculate the registers which needs to get on the phi nodes for every basic block. + PhiRegsBBBagNode::GetPhiRegsBags(&func->getEntryBlock(), bb_reg_info_node_map); + bb_regs_bag_map = PhiRegsBBBagNode::bb_regs_bag_map; + + // Reset static data of PhiRegsBBBagNode. + PhiRegsBBBagNode::Reset(); + + ECV_LOG_NL(OutLLVMFunc(func).str().c_str()); + DebugStreamReset(); +} + +llvm::Value *VirtualRegsOpt::CastFromInst(EcvReg target_ecv_reg, llvm::Value *from_inst, + llvm::Type *to_inst_ty, llvm::Instruction *inst_at_before, + llvm::Value *to_inst) { + auto &context = func->getContext(); + auto twine_null = llvm::Twine::createNull(); + + llvm::Value *t_from_inst; + + if (from_inst->getType() == to_inst_ty) { + CHECK(to_inst) << "[Bug] to_inst must not be NULL when from_inst_ty == to_inst_ty."; + return to_inst; + } else if (from_inst->getType() == llvm::Type::getVoidTy(context)) { + auto store_from_inst = llvm::dyn_cast(from_inst); + CHECK(store_from_inst) + << "[Bug] If the type of the from_inst is `void`, from_inst must be llvm::StoreInst at CastFromInst. from_inst: " + << LLVMThingToString(from_inst) << "\n" + << ECV_DEBUG_STREAM.str(); + t_from_inst = store_from_inst->getValueOperand(); + } else { + t_from_inst = from_inst; + } + + auto t_from_inst_size = impl->data_layout.getTypeAllocSizeInBits(t_from_inst->getType()); + auto t_from_inst_ty = t_from_inst->getType(); + auto to_inst_size = impl->data_layout.getTypeAllocSizeInBits(to_inst_ty); + + auto type_asserct_check = [&t_from_inst, &to_inst_ty](bool condition, const char *message) { + CHECK(condition) << "[ERROR]: from_inst: " << LLVMThingToString(t_from_inst) + << ", to_inst type: " << LLVMThingToString(to_inst_ty) << "\n" + << message << "\n" + << ECV_DEBUG_STREAM.str(); + }; + + if (t_from_inst_size < to_inst_size) { + if (RegKind::General == target_ecv_reg.reg_kind) { + type_asserct_check(to_inst_ty->isIntegerTy() && t_from_inst_ty->isIntegerTy(), + "RegKind::General register should have only the integer type."); + return new llvm::ZExtInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); + } else if (RegKind::Vector == target_ecv_reg.reg_kind) { + if (t_from_inst_ty->isVectorTy() || t_from_inst_ty->isFloatingPointTy()) { + auto mono_from = + new llvm::BitCastInst(t_from_inst, llvm::Type::getIntNTy(context, t_from_inst_size), + twine_null, inst_at_before); + auto zext_mono_from = new llvm::ZExtInst( + mono_from, llvm::Type::getIntNTy(context, to_inst_size), twine_null, inst_at_before); + return new llvm::BitCastInst(zext_mono_from, to_inst_ty, twine_null, inst_at_before); + } else { + auto zext_mono_from = new llvm::ZExtInst( + t_from_inst, llvm::Type::getIntNTy(context, to_inst_size), twine_null, inst_at_before); + return new llvm::BitCastInst(zext_mono_from, to_inst_ty, twine_null, inst_at_before); + } + } else if (RegKind::Special == target_ecv_reg.reg_kind) { + type_asserct_check( + /* 8 bit of the ECV_NZCV */ t_from_inst_ty->isIntegerTy(8) && to_inst_ty->isIntegerTy(), + "RegKind::Special register must not be used different types other than ECV_NZCV."); + return new llvm::ZExtInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); + } + } else if (t_from_inst_size > to_inst_size) { + if (RegKind::General == target_ecv_reg.reg_kind) { + type_asserct_check(to_inst_ty->isIntegerTy() && t_from_inst_ty->isIntegerTy(), + "RegKind::General register should have only the integer type."); + return new llvm::TruncInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); + } else if (RegKind::Vector == target_ecv_reg.reg_kind) { + if (t_from_inst_ty->isVectorTy() || t_from_inst_ty->isFloatingPointTy()) { + auto mono_from = + new llvm::BitCastInst(t_from_inst, llvm::Type::getIntNTy(context, t_from_inst_size), + twine_null, inst_at_before); + auto trunc_mono_from = new llvm::TruncInst( + mono_from, llvm::Type::getIntNTy(context, to_inst_size), twine_null, inst_at_before); + return new llvm::BitCastInst(trunc_mono_from, to_inst_ty, twine_null, inst_at_before); + } else { + auto trunc_mono_from = new llvm::TruncInst( + t_from_inst, llvm::Type::getIntNTy(context, to_inst_size), twine_null, inst_at_before); + return new llvm::BitCastInst(trunc_mono_from, to_inst_ty, twine_null, inst_at_before); } + return new llvm::TruncInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); + } else if (RegKind::Special == target_ecv_reg.reg_kind) { + type_asserct_check( + t_from_inst_ty->isIntegerTy(8) && to_inst_ty->isIntegerTy(), + "RegKind::Special register must not be used different types other than ECV_NZCV."); + return new llvm::ZExtInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); } - // Can insert `load` to the target_bb. - else { - // Add `load` instruction. - auto state_ptr = NthArgument(func, kStatePointerArgNum); - auto load_value = impl->inst.GetLifter()->LoadRegValueBeforeInst( - target_bb, state_ptr, target_ecv_reg.GetRegName(load_e_r_c), target_terminator, - VAR_NAME(target_ecv_reg, load_e_r_c)); - req_value = CastFromInst(target_ecv_reg, load_value, GetLLVMTypeFromRegZ(req_ecv_reg_class), - target_terminator, load_value); - // Update cache. - target_bb_reg_info_node->reg_latest_inst_map.insert( - {target_ecv_reg, {load_e_r_c, load_value, 0}}); - target_bb_reg_info_node->referred_able_added_inst_reg_map.insert( - {req_value, {target_ecv_reg, req_ecv_reg_class}}); - // for debug - value_reg_map.insert({load_value, {target_ecv_reg, load_e_r_c}}); - value_reg_map.insert({req_value, {target_ecv_reg, req_ecv_reg_class}}); + } else { + if (t_from_inst->getType()->isPointerTy()) { + return new llvm::PtrToIntInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); + } else { + return new llvm::BitCastInst(t_from_inst, to_inst_ty, twine_null, inst_at_before); } } - CHECK(req_value); - return req_value; + std::terminate(); } -PhiRegsBBBagNode *PhiRegsBBBagNode::GetTrueBag() { - auto res = this; - while (res != res->converted_bag) { - res = res->converted_bag; - } - return res; -} +llvm::Value *VirtualRegsOpt::GetRegValueFromCacheMap( + EcvReg target_ecv_reg, llvm::Type *to_type, llvm::Instruction *inst_at_before, + std::unordered_map, EcvReg::Hash> + &cache_map) { + llvm::Value *res_value; -void PhiRegsBBBagNode::MergePrecedingRegMap(PhiRegsBBBagNode *moved_bag) { - // Merge bag_preceding_load_reg_map - for (auto [pre_load_r, pre_load_r_c] : moved_bag->bag_preceding_load_reg_map) { - if (bag_preceding_load_reg_map.contains(pre_load_r)) { - if (GetRegClassSize(bag_preceding_load_reg_map.at(pre_load_r)) < - GetRegClassSize(pre_load_r_c)) { - bag_preceding_load_reg_map.insert_or_assign(pre_load_r, pre_load_r_c); - } - } else { - bag_preceding_load_reg_map.insert({pre_load_r, pre_load_r_c}); - } - } - // Merge bag_preceding_load_reg_map - for (auto [pre_store_r, pre_store_r_c] : moved_bag->bag_preceding_store_reg_map) { - if (bag_preceding_store_reg_map.contains(pre_store_r)) { - if (GetRegClassSize(bag_preceding_store_reg_map.at(pre_store_r)) < - GetRegClassSize(pre_store_r_c)) { - bag_preceding_store_reg_map.insert_or_assign(pre_store_r, pre_store_r_c); - } + auto [_, from_value, from_order] = cache_map.at(target_ecv_reg); + if (to_type == from_value->getType()) { + res_value = from_value; + } else { + // Need to cast the from_inst to match the type of the load_inst. + if (llvm::dyn_cast(from_value->getType()) || + llvm::dyn_cast(from_value->getType())) { + auto from_extracted_inst = llvm::ExtractValueInst::Create( + from_value, {from_order}, llvm::Twine::createNull(), inst_at_before); + res_value = CastFromInst(target_ecv_reg, from_extracted_inst, to_type, inst_at_before, + from_extracted_inst); + // for debug + value_reg_map.insert({from_extracted_inst, + {target_ecv_reg, GetRegZFromLLVMType(from_extracted_inst->getType())}}); + } else if (isu128v2Ty(impl->context, from_value->getType())) { + auto from_extracted_inst = llvm::ExtractElementInst::Create( + from_value, llvm::ConstantInt::get(llvm::Type::getInt64Ty(impl->context), from_order), "", + inst_at_before); + res_value = CastFromInst(target_ecv_reg, from_extracted_inst, to_type, inst_at_before, + from_extracted_inst); + // for debug + value_reg_map.insert({from_extracted_inst, + {target_ecv_reg, GetRegZFromLLVMType(from_extracted_inst->getType())}}); } else { - bag_preceding_store_reg_map.insert({pre_store_r, pre_store_r_c}); + res_value = CastFromInst(target_ecv_reg, from_value, to_type, inst_at_before); } } - // Merge bag_within_store + + return res_value; } -void PhiRegsBBBagNode::MergeFamilyConvertedBags(PhiRegsBBBagNode *merged_bag) { - for (auto merged_par : merged_bag->parents) { - auto true_merged_par = merged_par->GetTrueBag(); - parents.insert(true_merged_par); - true_merged_par->children.insert(this); - } - for (auto merged_child : merged_bag->children) { - auto true_merged_child = merged_child->GetTrueBag(); - children.insert(true_merged_child); - true_merged_child->parents.insert(this); +void VirtualRegsOpt::OptimizeVirtualRegsUsage() { + + impl->virtual_regs_opt = this; + auto &inst_lifter = impl->inst.GetLifter(); + +// stdout the specified registers for the every semantics function. +#if defined(OPT_REAL_REGS_DEBUG) + for (size_t i = 0; i < 31; i++) { + debug_reg_set.insert({EcvReg(RegKind::General, i)}); + // debug_reg_set.insert({EcvReg(RegKind::Vector, i)}); } -} + debug_reg_set.insert({EcvReg(RegKind::Special, SP_ORDER)}); +#endif -void PhiRegsBBBagNode::RemoveLoop(llvm::BasicBlock *root_bb) { + // Add the phi nodes to the every basic block. + std::set finished; + auto state_ptr = NthArgument(func, kStatePointerArgNum); - ECV_LOG_NL(std::dec, "[DEBUG LOG]: ", "func: PhiRegsBBbagNode::RemoveLoop. target func: ", - root_bb->getParent()->getName().str()); - { + phi_bb_queue.push(&func->getEntryBlock()); -#define TUPLE_ELEM_T \ - PhiRegsBBBagNode *, std::vector, std::set - std::stack> bag_stack; - auto root_bag = bb_regs_bag_map.at(root_bb); - bag_stack.emplace( - std::make_tuple((remill::PhiRegsBBBagNode *) root_bag, {}, - {})); // Why (remill::PhiResgBBBagNode *) is needed? + while (!phi_bb_queue.empty()) { + auto target_bb = phi_bb_queue.front(); + phi_bb_queue.pop(); + if (finished.contains(target_bb) || relay_bb_cache.contains(target_bb)) { + continue; + } + ECV_LOG_NL(target_bb, ":"); + auto target_phi_regs_bag = bb_regs_bag_map.at(target_bb); + auto target_bb_reg_info_node = bb_reg_info_node_map.at(target_bb); + auto ®_latest_inst_map = target_bb_reg_info_node->reg_latest_inst_map; + auto ®_derived_added_inst_map = target_bb_reg_info_node->reg_derived_added_inst_map; + auto &referred_able_added_inst_reg_map = + target_bb_reg_info_node->referred_able_added_inst_reg_map; + + EcvRegMap> ascend_reg_inst_map = { + {EcvReg(RegKind::Special, STATE_ORDER), + std::make_tuple(EcvRegClass::RegP, arg_state_val, 0)}, + {EcvReg(RegKind::Special, RUNTIME_ORDER), + std::make_tuple(EcvRegClass::RegP, arg_runtime_val, + 0)}}; // %state and %runtime_manager is defined as the argument + + llvm::BranchInst *br_inst = nullptr; + llvm::ReturnInst *ret_inst = nullptr; + + // Add the phi node for the every register included in the bag_phi_reg_map. + auto inst_start_it = &*target_bb->begin(); + for (auto &req_ecv_reg_info : target_phi_regs_bag->bag_req_reg_map) { + auto &[target_ecv_reg, target_ecv_reg_class] = req_ecv_reg_info; + llvm::Value *reg_derived_inst; + // This phi has been already added. + if (reg_derived_added_inst_map.contains(target_ecv_reg)) { + auto no_casted_reg_derived_inst = reg_derived_added_inst_map.at(target_ecv_reg); + reg_derived_inst = CastFromInst( + target_ecv_reg, no_casted_reg_derived_inst, GetLLVMTypeFromRegZ(target_ecv_reg_class), + llvm::dyn_cast(no_casted_reg_derived_inst)->getNextNode(), + no_casted_reg_derived_inst); + + // Update cache. + if (no_casted_reg_derived_inst != reg_derived_inst) { + referred_able_added_inst_reg_map.insert({reg_derived_inst, req_ecv_reg_info}); + CHECK(reg_derived_inst->getType() == GetLLVMTypeFromRegZ(target_ecv_reg_class)); + } + // for debug + value_reg_map.insert({reg_derived_inst, req_ecv_reg_info}); + } + // Generate the new phi node. + else { + auto phi_op_type = GetLLVMTypeFromRegZ(target_ecv_reg_class); + auto reg_derived_phi = + llvm::PHINode::Create(phi_op_type, bb_parents.at(target_bb).size(), + VAR_NAME(target_ecv_reg, target_ecv_reg_class), inst_start_it); + // Add this phi to the reg_latest_inst_map (to avoid the infinity loop when running Impl::GetValueFromTargetBBAndReg). + reg_latest_inst_map.insert( + {target_ecv_reg, std::make_tuple(target_ecv_reg_class, reg_derived_phi, 0)}); + + // Get the every virtual register from all the parent bb. + auto par_bb_it = bb_parents.at(target_bb).begin(); + std::set _finished; + while (par_bb_it != bb_parents.at(target_bb).end()) { + auto par_bb = *par_bb_it; + if (_finished.contains(par_bb)) { + ++par_bb_it; + continue; + } + auto derived_reg_value = GetValueFromTargetBBAndReg(par_bb, target_bb, req_ecv_reg_info); + // if the relay_bb is added as the parent of the target_bb, `par_bb` is not the parent. + if (auto from_inst = llvm::dyn_cast(derived_reg_value)) { + auto true_par = from_inst->getParent(); + reg_derived_phi->addIncoming(derived_reg_value, true_par); + _finished.insert(true_par); + if (par_bb != true_par) { + par_bb_it = bb_parents.at(target_bb).begin(); + continue; + } + } else { + reg_derived_phi->addIncoming(derived_reg_value, par_bb); + _finished.insert(par_bb); + } + ++par_bb_it; + } + referred_able_added_inst_reg_map.insert({reg_derived_phi, req_ecv_reg_info}); + // for debug + value_reg_map.insert({reg_derived_phi, req_ecv_reg_info}); + reg_derived_inst = reg_derived_phi; + } + // Add this phi to the ascend_reg_inst_map + ascend_reg_inst_map.insert( + {target_ecv_reg, std::make_tuple(target_ecv_reg_class, reg_derived_inst, 0)}); + CHECK(GetLLVMTypeFromRegZ(target_ecv_reg_class) == reg_derived_inst->getType()); + } + + reg_latest_inst_map.clear(); + auto target_inst_it = inst_start_it; + ECV_LOG_NL("insts:"); + + // Replace all the `load` to the CPU registers memory with the value of the phi nodes. + while (target_inst_it) { + ECV_LOG_NL("\t", LLVMThingToString(target_inst_it)); + // The target instruction was added. only update cache. + if (referred_able_added_inst_reg_map.contains(&*target_inst_it)) { + auto &[added_ecv_reg, added_ecv_reg_class] = + referred_able_added_inst_reg_map.at(&*target_inst_it); + ascend_reg_inst_map.insert_or_assign( + added_ecv_reg, std::make_tuple(added_ecv_reg_class, target_inst_it, 0)); + CHECK(target_inst_it->getType() == GetLLVMTypeFromRegZ(added_ecv_reg_class)); + target_inst_it = target_inst_it->getNextNode(); + } else { + // Target: llvm::LoadInst + if (auto *load_inst = llvm::dyn_cast(target_inst_it)) { + const auto &load_reg_name = load_inst->getPointerOperand()->getName().str(); + auto [target_ecv_reg, load_ecv_reg_class] = EcvReg::GetRegInfo(load_reg_name); - std::set finished; - uint32_t bag_i = 0; + llvm::Value *new_ecv_reg_inst; - for (auto [_, bag] : bb_regs_bag_map) { - CHECK(!bag->converted_bag) << ECV_DEBUG_STREAM.str(); - bag->converted_bag = bag; - debug_bag_map.insert({bag, bag_i++}); - } + // Can replace this load with existig accessed value. + if (ascend_reg_inst_map.contains(target_ecv_reg)) { + new_ecv_reg_inst = GetRegValueFromCacheMap(target_ecv_reg, load_inst->getType(), + load_inst, ascend_reg_inst_map); + target_inst_it = llvm::dyn_cast(load_inst)->getNextNode(); + // Replace all the Users. + load_inst->replaceAllUsesWith(new_ecv_reg_inst); + CHECK(new_ecv_reg_inst->getType() == GetLLVMTypeFromRegZ(load_ecv_reg_class)); + // Delete load_inst. + load_inst->eraseFromParent(); + } + // Should load this register because it is first access. + else { + new_ecv_reg_inst = load_inst; + target_inst_it = llvm::dyn_cast(load_inst)->getNextNode(); + // Update cache. + ascend_reg_inst_map.insert_or_assign( + target_ecv_reg, std::make_tuple(load_ecv_reg_class, new_ecv_reg_inst, 0)); + } - while (!bag_stack.empty()) { - auto target_bag = std::get(bag_stack.top())->GetTrueBag(); - auto pre_path = std::get>(bag_stack.top()); - auto visited = std::get>(bag_stack.top()); - bag_stack.pop(); - if (finished.contains(target_bag)) { - continue; - } - DEBUG_REMOVE_LOOP_GRAPH(target_bag); - bool loop_found = false; - std::set true_visited; - for (auto _bag : visited) { - auto true_bag = _bag->GetTrueBag(); - if (true_bag == target_bag) { - loop_found = true; + // for debug + value_reg_map.insert( + {new_ecv_reg_inst, {target_ecv_reg, GetRegZFromLLVMType(load_inst->getType())}}); } - true_visited.insert(true_bag); - } - visited = true_visited; - - if (loop_found) { - auto it_loop_bag = pre_path.rbegin(); - std::set true_deleted_bags; - for (;;) { - CHECK(!pre_path.empty()) << ECV_DEBUG_STREAM.str(); - it_loop_bag = pre_path.rbegin(); - auto moved_bag = (*it_loop_bag)->GetTrueBag(); - pre_path.pop_back(); + // Target: llvm::CallInst + else if (auto call_inst = llvm::dyn_cast(target_inst_it)) { - if (target_bag == moved_bag) { - break; - } else if (true_deleted_bags.contains(moved_bag)) { - continue; + // Call the lifted function (includes `__remill_function_call`). + if (lifted_func_caller_set.contains(call_inst)) { + // Store already stored `bb_store_reg_map` + for (auto [within_store_ecv_reg, ascend_value] : ascend_reg_inst_map) { + if ( + // !func_v_r_opt_map.at(call_inst->getCalledFunction()) + // ->passed_caller_reg_map.contains(within_store_ecv_reg) || + !within_store_ecv_reg.CheckPassedArgsRegs() || + !target_bb_reg_info_node->bb_store_reg_map.contains(within_store_ecv_reg)) { + continue; + } + auto within_store_ecv_reg_class = std::get(ascend_value); + inst_lifter->StoreRegValueBeforeInst( + target_bb, state_ptr, within_store_ecv_reg.GetRegName(within_store_ecv_reg_class), + GetRegValueFromCacheMap(within_store_ecv_reg, + GetWholeLLVMTypeFromRegZ(within_store_ecv_reg), call_inst, + ascend_reg_inst_map), + call_inst); + } + // Store `preceding_store_map` + for (auto [preceding_store_ecv_reg, preceding_store_ecv_reg_class] : + target_phi_regs_bag->bag_preceding_store_reg_map) { + if ( + // !func_v_r_opt_map.at(call_inst->getCalledFunction()) + // ->passed_caller_reg_map.contains(preceding_store_ecv_reg) || + !preceding_store_ecv_reg.CheckPassedArgsRegs() || + target_bb_reg_info_node->bb_store_reg_map.contains(preceding_store_ecv_reg)) { + continue; + } + inst_lifter->StoreRegValueBeforeInst( + target_bb, state_ptr, + preceding_store_ecv_reg.GetRegName(preceding_store_ecv_reg_class), + GetRegValueFromCacheMap(preceding_store_ecv_reg, + GetWholeLLVMTypeFromRegZ(preceding_store_ecv_reg), + call_inst, ascend_reg_inst_map), + call_inst); + } + auto call_next_inst = call_inst->getNextNode(); + // Load `preceding_store_map` + `load_map` + for (auto [req_ecv_reg, tuple_set] : ascend_reg_inst_map) { + if (!req_ecv_reg.CheckPassedReturnRegs() + // || !func_v_r_opt_map.at(call_inst->getParent()->getParent()) + // ->passed_callee_ret_reg_map.contains(req_ecv_reg) + ) { + continue; + } + auto [req_r_c, userd_val, order] = tuple_set; + auto req_load = llvm::dyn_cast(inst_lifter->LoadRegValueBeforeInst( + target_bb, state_ptr, req_ecv_reg.GetRegName(req_r_c), call_next_inst)); + // Replace with new loaded register. + std::set fin_users; + auto user = userd_val->user_begin(); + while (userd_val->user_end() != user) { + if (fin_users.contains(*user)) { + user++; + continue; + } + auto user_inst = llvm::dyn_cast(*user); + if (user_inst->getParent() != target_bb) { + CHECK(0 == order); + user_inst->replaceUsesOfWith(userd_val, req_load); + fin_users.insert(*user); + user = userd_val->user_begin(); + continue; + } else if (req_load->comesBefore(user_inst)) { + // user_inst is ExtractValueInst. + if (auto extrv_user = llvm::dyn_cast(user_inst)) { + if (extrv_user->getIndices()[0] == order) { + CHECK(req_load->getType() == extrv_user->getType()) + << "req_load: " << LLVMThingToString(req_load) + << ", userd_val: " << LLVMThingToString(extrv_user) << "\n"; + extrv_user->replaceAllUsesWith(req_load); + // extr_user->eraseFromParent(); + } else { + user++; + continue; + } + } else if (auto extre_user = + llvm::dyn_cast(user_inst)) { + auto extre_order = + llvm::dyn_cast(extre_user->getIndexOperand()) + ->getZExtValue(); + if (extre_order == order) { + CHECK(req_load->getType() == extre_user->getType()) + << "req_load: " << LLVMThingToString(req_load) + << ", userd_val: " << LLVMThingToString(extre_user) << "\n"; + extre_user->replaceAllUsesWith(req_load); + // extre_user->eraseFromParent(); + } else { + user++; + continue; + } + } else { + CHECK(order == 0); + user_inst->replaceUsesOfWith(userd_val, req_load); + } + fin_users.insert(*user); + user = userd_val->user_begin(); + continue; + } + user++; + } + // Update cache. + ascend_reg_inst_map.insert_or_assign(req_ecv_reg, + std::make_tuple(req_r_c, req_load, 0)); + CHECK(GetLLVMTypeFromRegZ(req_r_c) == req_load->getType()); + // for debug + value_reg_map.insert({req_load, {req_ecv_reg, req_r_c}}); + } + target_inst_it = call_next_inst; + } + // Call the `emulate_system_call` semantic function. + else if (call_inst->getCalledFunction()->getName().str() == "emulate_system_call") { + // Store target: x0 ~ x5, x8 + for (auto [within_store_ecv_reg, ascend_value] : ascend_reg_inst_map) { + if (!(within_store_ecv_reg.number < 6 || within_store_ecv_reg.number == 8) || + !target_bb_reg_info_node->bb_store_reg_map.contains(within_store_ecv_reg)) { + continue; + } + auto within_store_ecv_reg_class = std::get(ascend_value); + inst_lifter->StoreRegValueBeforeInst( + target_bb, state_ptr, within_store_ecv_reg.GetRegName(within_store_ecv_reg_class), + GetRegValueFromCacheMap(within_store_ecv_reg, + GetWholeLLVMTypeFromRegZ(within_store_ecv_reg), call_inst, + ascend_reg_inst_map), + call_inst); + } + // Store target: x0 ~ x5, x8 + for (auto [preceding_store_ecv_reg, preceding_store_ecv_reg_class] : + target_phi_regs_bag->bag_preceding_store_reg_map) { + if (!(preceding_store_ecv_reg.number < 6 || preceding_store_ecv_reg.number == 8) || + target_bb_reg_info_node->bb_store_reg_map.contains(preceding_store_ecv_reg)) { + continue; + } + inst_lifter->StoreRegValueBeforeInst( + target_bb, state_ptr, + preceding_store_ecv_reg.GetRegName(preceding_store_ecv_reg_class), + GetRegValueFromCacheMap(preceding_store_ecv_reg, + GetWholeLLVMTypeFromRegZ(preceding_store_ecv_reg), + call_inst, ascend_reg_inst_map), + call_inst); + } + auto call_next_inst = call_inst->getNextNode(); + // Load target: x0 + for (auto [req_ecv_reg, tuple_set] : ascend_reg_inst_map) { + if (0 != req_ecv_reg.number) { + continue; + } + auto [req_r_c, userd_val, order] = tuple_set; + auto req_load = llvm::dyn_cast(inst_lifter->LoadRegValueBeforeInst( + target_bb, state_ptr, req_ecv_reg.GetRegName(req_r_c), call_next_inst)); + // Replace with new loaded register. + std::set fin_users; + auto user = userd_val->user_begin(); + while (userd_val->user_end() != user) { + if (fin_users.contains(*user)) { + user++; + continue; + } + auto user_inst = llvm::dyn_cast(*user); + if (user_inst->getParent() != target_bb) { + CHECK(0 == order); + user_inst->replaceUsesOfWith(userd_val, req_load); + fin_users.insert(*user); + user = userd_val->user_begin(); + continue; + } else if (req_load->comesBefore(user_inst)) { + // user_inst is ExtractValueInst. + if (auto extr_user = llvm::dyn_cast(user_inst)) { + if (extr_user->getIndices()[0] == order) { + CHECK(req_load->getType() == extr_user->getType()) + << "req_load: " << LLVMThingToString(req_load) + << ", userd_val: " << LLVMThingToString(extr_user) << "\n"; + extr_user->replaceAllUsesWith(req_load); + // extr_user->eraseFromParent(); + } else { + user++; + continue; + } + } else if (auto extre_user = + llvm::dyn_cast(user_inst)) { + auto extre_order = + llvm::dyn_cast(extre_user->getIndexOperand()) + ->getZExtValue(); + if (extre_order == order) { + CHECK(req_load->getType() == extre_user->getType()) + << "req_load: " << LLVMThingToString(req_load) + << ", userd_val: " << LLVMThingToString(extre_user) << "\n"; + extre_user->replaceAllUsesWith(req_load); + // extre_user->eraseFromParent(); + } else { + user++; + continue; + } + } else { + CHECK(order == 0); + user_inst->replaceUsesOfWith(userd_val, req_load); + } + fin_users.insert(*user); + user = userd_val->user_begin(); + continue; + } + user++; + } + // Update cache. + ascend_reg_inst_map.insert_or_assign(req_ecv_reg, + std::make_tuple(req_r_c, req_load, 0)); + CHECK(GetLLVMTypeFromRegZ(req_r_c) == req_load->getType()); + // for debug + value_reg_map.insert({req_load, {req_ecv_reg, req_r_c}}); + } + target_inst_it = call_next_inst; + DEBUG_PC_AND_REGISTERS(call_next_inst, ascend_reg_inst_map, 0xdeadbeef); } - - true_deleted_bags.insert(moved_bag); - - // translates moved_bag - target_bag->MergePrecedingRegMap(moved_bag); - target_bag->MergeFamilyConvertedBags(moved_bag); - for (auto moved_bb : moved_bag->in_bbs) { - target_bag->in_bbs.insert(moved_bb); + // Call the general semantic functions. + else { + auto call_next_inst = call_inst->getNextNode(); + if (target_bb_reg_info_node->sema_call_written_reg_map.contains(call_inst)) { + auto &sema_func_write_regs = + target_bb_reg_info_node->sema_call_written_reg_map.at(call_inst); + // Load all the referenced registers. + for (std::size_t i = 0; i < sema_func_write_regs.size(); i++) { + ascend_reg_inst_map.insert_or_assign( + sema_func_write_regs[i].first, + std::make_tuple(sema_func_write_regs[i].second, call_inst, i)); + } + // for debug + // if the return type is struct, this key value is not used. + if (!sema_func_write_regs.empty()) { + value_reg_map.insert( + {call_inst, {sema_func_write_regs[0].first, sema_func_write_regs[0].second}}); + } + DEBUG_PC_AND_REGISTERS(call_next_inst, ascend_reg_inst_map, + Sema_func_vma_map.contains(call_inst) + ? Sema_func_vma_map.at(call_inst) + : 0xffff'ffff); + } + target_inst_it = call_next_inst; } - - // update cache - moved_bag->converted_bag = target_bag; - visited.erase(moved_bag); - bag_num--; - - if (it_loop_bag == pre_path.rend()) { - LOG(FATAL) << "Unexpected path route on the PhiRegsBBBagNode::RemoveLoop()." - << ECV_DEBUG_STREAM.str(); + } + // Target: llvm::StoreInst + else if (auto store_inst = llvm::dyn_cast(target_inst_it)) { + auto stored_value = store_inst->getValueOperand(); + auto stored_reg_name = store_inst->getPointerOperand()->getName().str(); + auto [store_ecv_reg, store_ecv_reg_class] = EcvReg::GetRegInfo(stored_reg_name); + // Update cache. + ascend_reg_inst_map.insert_or_assign( + store_ecv_reg, std::make_tuple(store_ecv_reg_class, stored_value, 0)); + CHECK(stored_value->getType() == GetLLVMTypeFromRegZ(store_ecv_reg_class)); + target_inst_it = store_inst->getNextNode(); + store_inst->eraseFromParent(); + } + // Target: llvm::BranchInst + else if (auto __br_inst = llvm::dyn_cast(target_inst_it)) { + CHECK(!br_inst) << "There are multiple branch instructions in the one BB."; + br_inst = __br_inst; + target_inst_it = br_inst->getNextNode(); + } + // Target: llvm::CastInst + else if (auto cast_inst = llvm::dyn_cast(target_inst_it)) { + auto cast_op = cast_inst->getOperand(0); + // for debug + value_reg_map.insert({cast_inst, value_reg_map.at(cast_op)}); + target_inst_it = cast_inst->getNextNode(); + } + // Target: llvm::BinaryOperator + else if (auto binary_inst = llvm::dyn_cast(target_inst_it)) { + if (target_bb_reg_info_node->post_update_regs.contains(binary_inst)) { + auto [bin_e_r, bin_e_r_c] = target_bb_reg_info_node->post_update_regs.at(binary_inst); + ascend_reg_inst_map.insert_or_assign(bin_e_r, + std::make_tuple(bin_e_r_c, binary_inst, 0)); } + target_inst_it = target_inst_it->getNextNode(); + // for debug + auto lhs = binary_inst->getOperand(0); + // (FIXME) should check the second operand too. + value_reg_map.insert({binary_inst, value_reg_map.at(lhs)}); } - - // re-search this target_bag - visited.erase(target_bag); - bag_stack.emplace(target_bag, pre_path, visited); - } else { - - // push the children - bool search_finished = true; - for (auto __child_bag : target_bag->children) { - auto child_bag = __child_bag->GetTrueBag(); - if (finished.contains(child_bag) || child_bag == target_bag) { - continue; + // Target: llvm::ReturnInst + else if (auto __ret_inst = llvm::dyn_cast(target_inst_it)) { + // Store already stored `within_store_map` + CHECK(!ret_inst) << "Found the multiple llvm::ReturnInst at the one Basic Block." + << ECV_DEBUG_STREAM.str(); + ret_inst = __ret_inst; + for (auto [within_store_ecv_reg, ascend_value] : ascend_reg_inst_map) { + if ( + // !func_v_r_opt_map.at(ret_inst->getParent()->getParent()) + // ->passed_callee_ret_reg_map.contains(within_store_ecv_reg) || + !within_store_ecv_reg.CheckPassedReturnRegs() || + !target_bb_reg_info_node->bb_store_reg_map.contains(within_store_ecv_reg)) { + continue; + } + auto within_store_ecv_reg_class = std::get(ascend_value); + inst_lifter->StoreRegValueBeforeInst( + target_bb, state_ptr, within_store_ecv_reg.GetRegName(within_store_ecv_reg_class), + GetRegValueFromCacheMap(within_store_ecv_reg, + GetWholeLLVMTypeFromRegZ(within_store_ecv_reg), ret_inst, + ascend_reg_inst_map), + ret_inst); } - search_finished = false; - auto child_pre_path = pre_path; - auto child_visited = visited; - child_pre_path.push_back(target_bag); - child_visited.insert(target_bag); - bag_stack.emplace(child_bag, child_pre_path, child_visited); + // Store `preceding_store_map` + for (auto [preceding_store_ecv_reg, preceding_store_ecv_reg_class] : + target_phi_regs_bag->bag_preceding_store_reg_map) { + if ( + // !func_v_r_opt_map.at(ret_inst->getParent()->getParent()) + // ->passed_callee_ret_reg_map.contains(preceding_store_ecv_reg) || + !preceding_store_ecv_reg.CheckPassedReturnRegs() || + target_bb_reg_info_node->bb_store_reg_map.contains(preceding_store_ecv_reg)) { + continue; + } + inst_lifter->StoreRegValueBeforeInst( + target_bb, state_ptr, + preceding_store_ecv_reg.GetRegName(preceding_store_ecv_reg_class), + GetRegValueFromCacheMap(preceding_store_ecv_reg, + GetWholeLLVMTypeFromRegZ(preceding_store_ecv_reg), ret_inst, + ascend_reg_inst_map), + ret_inst); + } + target_inst_it = target_inst_it->getNextNode(); } - - // finish the target_bag if all children are finished. - if (search_finished) { - finished.insert(target_bag); + // Target: The instructions that can be ignored. + else if (llvm::dyn_cast(target_inst_it) || + llvm::dyn_cast(target_inst_it) || + llvm::dyn_cast(target_inst_it)) { + CHECK(true); + target_inst_it = target_inst_it->getNextNode(); + } else { + LOG(FATAL) << "Unexpected inst when adding phi nodes." << ECV_DEBUG_STREAM.str(); } } } - // Update all bags to the true bags. - std::set deleted_bag_set; - for (auto [bb, bag] : bb_regs_bag_map) { - // Update bag - auto target_true_bag = bag->GetTrueBag(); - if (bag != target_true_bag) { - bb_regs_bag_map.insert_or_assign(bb, target_true_bag); - deleted_bag_set.insert(bag); - } - // Update parents - std::set new_pars; - for (auto par : target_true_bag->parents) { - auto t_par = par->GetTrueBag(); - if (t_par == target_true_bag) { - continue; - } - new_pars.insert(t_par); - } - target_true_bag->parents = new_pars; - // Update children - std::set new_children; - for (auto child : target_true_bag->children) { - auto t_child = child->GetTrueBag(); - if (t_child == target_true_bag) { - continue; - } - new_children.insert(t_child); + reg_latest_inst_map = ascend_reg_inst_map; + + finished.insert(target_bb); + // Add the children to the queue + if (br_inst) { + for (std::size_t i = 0; i < br_inst->getNumSuccessors(); i++) { + phi_bb_queue.push(br_inst->getSuccessor(i)); } - target_true_bag->children = new_children; - } - // Delete the all unneccesary bags. - for (auto deleted_bag : deleted_bag_set) { - delete (deleted_bag); } + CHECK((br_inst != nullptr) ^ (ret_inst != nullptr)) + << "Not found the Branch or Return instruction in the Basic Block." + << ECV_DEBUG_STREAM.str(); } -#if defined(OPT_ALGO_DEBUG) - - // Check the consistency of the parents and children - { - std::set bag_set; - for (auto [_, bag] : bb_regs_bag_map) { - if (!bag_set.contains(bag)) { - bag_set.insert(bag); - for (auto par : bag->parents) { - if (!par->children.contains(bag)) { - LOG(FATAL) << "parent: " << par << " must have the child: " << bag << "\n"; - } - } - for (auto child : bag->children) { - if (!child->parents.contains(bag)) { - LOG(FATAL) << "child: " << child << " must have the parent: " << bag << "\n"; - } - } - } +// Check +#if defined(OPT_GEN_IR_DEBUG) + // Check the parent-child relationship + for (auto &bb : *func) { + auto inst_terminator = bb.getTerminator(); + for (size_t i = 0; i < inst_terminator->getNumSuccessors(); i++) { + CHECK(bb_parents.at(inst_terminator->getSuccessor(i)).contains(&bb)); } } - - // Check whether G of PhiregsBBBagNode* doesn't have loop. (for debug) - { - std::stack bag_stack; - std::set visited, finished; - bag_stack.push(bb_regs_bag_map.at(root_bb)); - - while (!bag_stack.empty()) { - auto target_bag = bag_stack.top(); - bag_stack.pop(); - if (finished.contains(target_bag)) { - continue; - } - if (visited.contains(target_bag)) { - for (auto child : target_bag->children) { - if (!finished.contains(child)) { - LOG(FATAL) - << "[Bug] The loop was detected from the G of PhiRegsBBBagNode* after PhiRegsBBBagNode::RemoveLoop." - << ECV_DEBUG_STREAM.str(); + // Check the optimized LLVM IR. + for (auto &bb : *func) { + auto bb_reg_info_node_2 = bb_reg_info_node_map.at(&bb); + for (auto &inst : bb) { + if (auto call_inst = llvm::dyn_cast(&inst); + call_inst && !lifted_func_caller_set.contains(call_inst)) { + if (bb_reg_info_node_2->sema_func_args_reg_map.contains(call_inst)) { + auto sema_isel_args = bb_reg_info_node_2->sema_func_args_reg_map.at(call_inst); + for (size_t i = 0; i < sema_isel_args.size(); i++) { + auto sema_isel_arg_i = sema_isel_args[i]; + if (EcvRegClass::RegNULL == sema_isel_arg_i.second || + // `%state` is not loaded even before optimization, so can ignore. + STATE_ORDER == sema_isel_arg_i.first.number || + llvm::dyn_cast(call_inst->getOperand(i))) { + continue; + } + auto actual_arg_i = call_inst->getOperand(i); + auto [actual_arg_ecv_reg, actual_arg_ecv_reg_class] = value_reg_map.at(actual_arg_i); + CHECK(actual_arg_ecv_reg.number == sema_isel_arg_i.first.number) + << "i: " << i + << ", actual arg ecv_reg number: " << to_string(actual_arg_ecv_reg.number) + << ", sema func arg ecv_reg: " << to_string(sema_isel_arg_i.first.number) << "\n"; + CHECK(actual_arg_ecv_reg_class == sema_isel_arg_i.second) + << "EcvRegClass Mismatch. actual arg ecv_reg_class: " + << EcvRegClass2String(actual_arg_ecv_reg_class) + << ", sema isel arg ecv_reg_class: " << EcvRegClass2String(sema_isel_arg_i.second) + << " at value: " << LLVMThingToString(actual_arg_i) + << ", sema func: " << LLVMThingToString(call_inst) + << ", func: " << func->getName().str() << "\n"; } } - finished.insert(target_bag); - continue; } - visited.insert(target_bag); - // after searching all children, re-search this target_bag. - bag_stack.push(target_bag); - for (auto child : target_bag->children) { - if (!finished.contains(child)) { - bag_stack.push(child); + } + } + if (func->size() != finished.size() + relay_bb_cache.size()) { + std::cout << "No optimized blocks!\n"; + for (auto &bb : *func) { + if (!finished.contains(&bb) && !relay_bb_cache.contains(&bb)) { + std::cout << std::hex << &bb << ":\n"; + for (auto &inst : bb) { + llvm::outs() << " " << inst << "\n"; } } } - CHECK(bag_num == finished.size()) - << "[Bug] bag_num: " << bag_num << ", finished.size(): " << finished.size() - << ". They should be equal at PhiRegsBBBagNode::RemoveLoop." << ECV_DEBUG_STREAM.str(); + LOG(FATAL) << "func->size: " << func->size() << ", finished size: " << finished.size() + << ", relay_bb_num: " << relay_bb_cache.size() << "\n" + << ECV_DEBUG_STREAM.str(); } +#endif DebugStreamReset(); -#endif } -void PhiRegsBBBagNode::GetPrecedingVirtualRegsBags(llvm::BasicBlock *root_bb) { - ECV_LOG_NL("[DEBUG LOG]: ", "func: PhiRegsBBbagNode::GetPrecedingVirtualRegsBags. target func: ", - root_bb->getParent()->getName().str()); - std::queue bag_queue; - std::unordered_map finished_pars_num_map; - std::set finished; - bag_queue.push(bb_regs_bag_map.at(root_bb)); +void VirtualRegsOpt::InsertDebugVmaAndRegisters( + llvm::Instruction *inst_at_before, + EcvRegMap> &ascend_reg_inst_map, uint64_t pc) { + if (!debug_reg_set.empty()) { + auto debug_vma_and_regiters_fun = impl->module->getFunction("debug_vma_and_registers"); - while (!bag_queue.empty()) { - auto target_bag = bag_queue.front(); - bag_queue.pop(); - if (finished.contains(target_bag)) { - continue; - } - finished_pars_num_map.insert({target_bag, 0}); - if (target_bag->parents.size() == finished_pars_num_map.at(target_bag)) { - // can finish the target_bag. - for (auto par_bag : target_bag->parents) { - // preceding load reg. priority: target_bag > par_bag. - for (auto ecv_reg_info : par_bag->bag_preceding_load_reg_map) { - target_bag->bag_preceding_load_reg_map.insert(ecv_reg_info); - } - // preceding store reg. priority: target_bag > par_bag. - for (auto ecv_reg_info : par_bag->bag_preceding_store_reg_map) { - target_bag->bag_preceding_store_reg_map.insert(ecv_reg_info); + std::vector args; + args.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(impl->context), pc)); + args.push_back(nullptr); + + for (auto debug_ecv_reg : debug_reg_set) { + if (ascend_reg_inst_map.contains(debug_ecv_reg)) { + llvm::GlobalVariable *reg_name_gvar = NULL; + if (RegKind::General == debug_ecv_reg.reg_kind) { + reg_name_gvar = + impl->module->getGlobalVariable("debug_X" + to_string(debug_ecv_reg.number)); + } else if (RegKind::Vector == debug_ecv_reg.reg_kind) { + reg_name_gvar = + impl->module->getGlobalVariable("debug_V" + to_string(debug_ecv_reg.number)); + } else { + if (ECV_NZCV_ORDER == debug_ecv_reg.number) { + reg_name_gvar = impl->module->getGlobalVariable("debug_ECV_NZCV"); + } else if (SP_ORDER == debug_ecv_reg.number) { + reg_name_gvar = impl->module->getGlobalVariable("debug_SP"); + } } + args.push_back(reg_name_gvar); + args.push_back(GetRegValueFromCacheMap(debug_ecv_reg, + GetWholeLLVMTypeFromRegZ(debug_ecv_reg), + inst_at_before, ascend_reg_inst_map)); } - // target_bag was finished. - finished.insert(target_bag); - // update the finised_pars_map for all the childlen of this target_bag. - // push all the no finished children - for (auto child : target_bag->children) { - finished_pars_num_map.insert_or_assign(child, finished_pars_num_map[child] + 1); - if (!finished.contains(child)) { - bag_queue.push(child); - } + } + + args[1] = llvm::ConstantInt::get(llvm::Type::getInt64Ty(impl->context), args.size() - 2); + llvm::CallInst::Create(debug_vma_and_regiters_fun, args, llvm::Twine::createNull(), + inst_at_before); + } +} + +llvm::Type *VirtualRegsOpt::GetLLVMTypeFromRegZ(EcvRegClass ecv_reg_class) { + auto &context = func->getContext(); + switch (ecv_reg_class) { + case EcvRegClass::RegW: return llvm::Type::getInt32Ty(context); + case EcvRegClass::RegX: return llvm::Type::getInt64Ty(context); + case EcvRegClass::RegB: return llvm::Type::getInt8Ty(context); + case EcvRegClass::RegH: return llvm::Type::getInt16Ty(context); + case EcvRegClass::RegS: return llvm::Type::getFloatTy(context); + case EcvRegClass::RegD: return llvm::Type::getDoubleTy(context); + case EcvRegClass::RegQ: return llvm::Type::getInt128Ty(context); + case EcvRegClass::RegV: + return llvm::VectorType::get(llvm::Type::getInt128Ty(context), 1, false); + case EcvRegClass::Reg8B: return llvm::VectorType::get(llvm::Type::getInt8Ty(context), 8, false); + case EcvRegClass::Reg16B: + return llvm::VectorType::get(llvm::Type::getInt8Ty(context), 16, false); + case EcvRegClass::Reg4H: + return llvm::VectorType::get(llvm::Type::getInt16Ty(context), 4, false); + case EcvRegClass::Reg8H: + return llvm::VectorType::get(llvm::Type::getInt16Ty(context), 8, false); + case EcvRegClass::Reg2S: + return llvm::VectorType::get(llvm::Type::getInt32Ty(context), 2, false); + case EcvRegClass::Reg2SF: + return llvm::VectorType::get(llvm::Type::getFloatTy(context), 2, false); + case EcvRegClass::Reg4S: + return llvm::VectorType::get(llvm::Type::getInt32Ty(context), 4, false); + case EcvRegClass::Reg4SF: + return llvm::VectorType::get(llvm::Type::getFloatTy(context), 4, false); + case EcvRegClass::Reg1D: + return llvm::VectorType::get(llvm::Type::getInt64Ty(context), 1, false); + case EcvRegClass::Reg1DF: + return llvm::VectorType::get(llvm::Type::getDoubleTy(context), 1, false); + case EcvRegClass::Reg2D: + return llvm::VectorType::get(llvm::Type::getInt64Ty(context), 2, false); + case EcvRegClass::Reg2DF: + return llvm::VectorType::get(llvm::Type::getDoubleTy(context), 2, false); + case EcvRegClass::RegP: return llvm::Type::getInt64PtrTy(context); + default: break; + } + + LOG(FATAL) + << "[Bug] Reach the unreachable code at VirtualRegsOpt::GetLLVMTypeFromRegZ. ecv_reg_class: " + << std::underlying_type::type(ecv_reg_class) << "\n" + << ECV_DEBUG_STREAM.str(); + return nullptr; +} + +llvm::Type *VirtualRegsOpt::GetWholeLLVMTypeFromRegZ(EcvReg ecv_reg) { + auto &context = func->getContext(); + auto t_reg_kind = ecv_reg.reg_kind; + if (RegKind::General == t_reg_kind || RegKind::Special == t_reg_kind) { + CHECK(ecv_reg.number != STATE_ORDER && ecv_reg.number != RUNTIME_ORDER); + return llvm::Type::getInt64Ty(context); + } else /* RegKind::Vector */ { + return llvm::Type::getInt128Ty(context); + } +} + +EcvRegClass VirtualRegsOpt::GetRegZFromLLVMType(llvm::Type *value_type) { + auto &context = func->getContext(); + if (llvm::Type::getInt32Ty(context) == value_type) { + return EcvRegClass::RegW; + } else if (llvm::Type::getInt64Ty(context) == value_type) { + return EcvRegClass::RegX; + } else if (llvm::Type::getInt8Ty(context) == value_type) { + return EcvRegClass::RegB; + } else if (llvm::Type::getInt16Ty(context) == value_type) { + return EcvRegClass::RegH; + } else if (llvm::Type::getFloatTy(context) == value_type) { + return EcvRegClass::RegS; + } else if (llvm::Type::getDoubleTy(context) == value_type) { + return EcvRegClass::RegD; + } else if (llvm::Type::getInt128Ty(context) == value_type) { + return EcvRegClass::RegQ; + } else if (llvm::VectorType::get(llvm::Type::getInt128Ty(context), 1, false) == value_type) { + return EcvRegClass::RegV; + } else if (llvm::VectorType::get(llvm::Type::getInt8Ty(context), 8, false) == value_type) { + return EcvRegClass::Reg8B; + } else if (llvm::VectorType::get(llvm::Type::getInt8Ty(context), 16, false) == value_type) { + return EcvRegClass::Reg16B; + } else if (llvm::VectorType::get(llvm::Type::getInt16Ty(context), 4, false) == value_type) { + return EcvRegClass::Reg4H; + } else if (llvm::VectorType::get(llvm::Type::getInt16Ty(context), 8, false) == value_type) { + return EcvRegClass::Reg8H; + } else if (llvm::VectorType::get(llvm::Type::getInt32Ty(context), 2, false) == value_type) { + return EcvRegClass::Reg2S; + } else if (llvm::VectorType::get(llvm::Type::getFloatTy(context), 2, false) == value_type) { + return EcvRegClass::Reg2SF; + } else if (llvm::VectorType::get(llvm::Type::getInt32Ty(context), 4, false) == value_type) { + return EcvRegClass::Reg4S; + } else if (llvm::VectorType::get(llvm::Type::getFloatTy(context), 4, false) == value_type) { + return EcvRegClass::Reg4SF; + } else if (llvm::VectorType::get(llvm::Type::getInt64Ty(context), 1, false) == value_type) { + return EcvRegClass::Reg1D; + } else if (llvm::VectorType::get(llvm::Type::getDoubleTy(context), 1, false) == value_type) { + return EcvRegClass::Reg1DF; + } else if (llvm::VectorType::get(llvm::Type::getInt64Ty(context), 2, false) == value_type) { + return EcvRegClass::Reg2D; + } else if (llvm::VectorType::get(llvm::Type::getDoubleTy(context), 2, false) == value_type) { + return EcvRegClass::Reg2DF; + } else if (llvm::Type::getInt64PtrTy(context) == value_type) { + return EcvRegClass::RegP; + } + + LOG(FATAL) << "[Bug] Reach the unreachable code at VirtualregsOpt::GetRegZfromLLVMType. Type: " + << LLVMThingToString(value_type) << "\n" + << ECV_DEBUG_STREAM.str(); +} + +llvm::Value * +VirtualRegsOpt::GetValueFromTargetBBAndReg(llvm::BasicBlock *target_bb, + llvm::BasicBlock *request_bb, + std::pair ecv_reg_info) { + auto &[target_ecv_reg, req_ecv_reg_class] = ecv_reg_info; + auto target_phi_regs_bag = bb_regs_bag_map.at(target_bb); + auto target_bb_reg_info_node = bb_reg_info_node_map.at(target_bb); + + const llvm::DataLayout data_layout(impl->module); + + auto target_terminator = target_bb->getTerminator(); + llvm::Value *req_value = nullptr; + + // The target_bb already has the target virtual register. + if (target_bb_reg_info_node->reg_latest_inst_map.contains(target_ecv_reg)) { + auto &[_, from_inst, from_order] = + target_bb_reg_info_node->reg_latest_inst_map.at(target_ecv_reg); + if (from_inst->getType() == GetLLVMTypeFromRegZ(req_ecv_reg_class)) { + req_value = from_inst; + } else { + if (llvm::dyn_cast(from_inst->getType()) || + llvm::dyn_cast(from_inst->getType())) { + auto from_extracted_inst = llvm::ExtractValueInst::Create( + from_inst, {from_order}, llvm::Twine::createNull(), target_terminator); + auto from_extracted_inst_reg_class = GetRegZFromLLVMType(from_extracted_inst->getType()); + // Update cache. + target_bb_reg_info_node->referred_able_added_inst_reg_map.insert( + {from_extracted_inst, {target_ecv_reg, from_extracted_inst_reg_class}}); + target_bb_reg_info_node->reg_latest_inst_map.insert_or_assign( + target_ecv_reg, std::make_tuple(from_extracted_inst_reg_class, from_extracted_inst, 0)); + req_value = CastFromInst(target_ecv_reg, from_extracted_inst, + GetLLVMTypeFromRegZ(req_ecv_reg_class), target_terminator, + from_extracted_inst); + // for debug + value_reg_map.insert( + {from_extracted_inst, {target_ecv_reg, from_extracted_inst_reg_class}}); + } else if (isu128v2Ty(impl->context, from_inst->getType())) { + auto from_extracted_inst = llvm::ExtractElementInst::Create( + from_inst, llvm::ConstantInt::get(llvm::Type::getInt64Ty(impl->context), from_order), + "", target_terminator); + auto from_extracted_inst_reg_class = GetRegZFromLLVMType(from_extracted_inst->getType()); + // Update cache. + target_bb_reg_info_node->referred_able_added_inst_reg_map.insert( + {from_extracted_inst, {target_ecv_reg, from_extracted_inst_reg_class}}); + target_bb_reg_info_node->reg_latest_inst_map.insert_or_assign( + target_ecv_reg, std::make_tuple(from_extracted_inst_reg_class, from_extracted_inst, 0)); + req_value = CastFromInst(target_ecv_reg, from_extracted_inst, + GetLLVMTypeFromRegZ(req_ecv_reg_class), target_terminator, + from_extracted_inst); + // for debug + value_reg_map.insert( + {from_extracted_inst, {target_ecv_reg, from_extracted_inst_reg_class}}); + } + + else { + req_value = CastFromInst(target_ecv_reg, from_inst, GetLLVMTypeFromRegZ(req_ecv_reg_class), + target_terminator); } + // for debug + value_reg_map.insert({req_value, {target_ecv_reg, req_ecv_reg_class}}); } } - - CHECK(finished.size() == bag_num) - << "[Bug] bag_num: " << bag_num << ", finished_bag.size(): " << finished.size() - << ". They should be equal after PhiRegsBBagNode::GetPrecedingVirtualRegsBags." - << ECV_DEBUG_STREAM.str(); - - DebugStreamReset(); -} - -void PhiRegsBBBagNode::GetSucceedingVirtualRegsBags(llvm::BasicBlock *root_bb) { - ECV_LOG_NL("[DEBUG LOG]: ", "func: PhiRegsBBbagNode::GetSucceedingVirtualRegsBags. target func: ", - root_bb->getParent()->getName().str()); - std::stack bag_stack; - std::unordered_map finished_children_num_map; - std::set finished; - bag_stack.push(bb_regs_bag_map.at(root_bb)); - - while (!bag_stack.empty()) { - auto target_bag = bag_stack.top(); - bag_stack.pop(); - if (finished.contains(target_bag)) { - continue; - } - finished_children_num_map.insert({target_bag, 0}); - if (target_bag->children.size() == finished_children_num_map.at(target_bag)) { - // Can finish the target_bag. - for (auto child_bag : target_bag->children) { - // succeeding load reg. priority: target_bag > child_bag - for (auto ecv_reg_info : child_bag->bag_succeeding_load_reg_map) { - target_bag->bag_succeeding_load_reg_map.insert(ecv_reg_info); - } + // The bag_req_reg_map of the target_bb includes the target register. + else if (target_phi_regs_bag->bag_req_reg_map.contains(target_ecv_reg)) { + auto start_inst = target_bb->begin(); + auto phi_ecv_reg_class = target_phi_regs_bag->bag_req_reg_map.at(target_ecv_reg); + auto phi_op_type = GetLLVMTypeFromRegZ(phi_ecv_reg_class); + auto reg_phi = llvm::PHINode::Create(phi_op_type, bb_parents.at(target_bb).size(), + VAR_NAME(target_ecv_reg, phi_ecv_reg_class), &*start_inst); + // Update phi cache. + // must update reg_latest_inst_map before addIncoming to correspond to the loop bbs. + target_bb_reg_info_node->reg_latest_inst_map.insert( + {target_ecv_reg, {phi_ecv_reg_class, reg_phi, 0}}); + // Get the every virtual register from all the parent bb. + auto par_bb_it = bb_parents.at(target_bb).begin(); + std::set _finished; + while (par_bb_it != bb_parents.at(target_bb).end()) { + auto par_bb = *par_bb_it; + if (_finished.contains(par_bb)) { + ++par_bb_it; + continue; } - // The target_bag was finished. - finished.insert(target_bag); - // Update the finised_children_map for all the parents of this target_bag. - for (auto parent_bag : target_bag->parents) { - finished_children_num_map.insert_or_assign(parent_bag, - finished_children_num_map[parent_bag] + 1); + auto derived_reg_value = + GetValueFromTargetBBAndReg(par_bb, target_bb, {target_ecv_reg, phi_ecv_reg_class}); + if (auto from_inst = llvm::dyn_cast(derived_reg_value)) { + auto from_inst_par = from_inst->getParent(); + reg_phi->addIncoming(derived_reg_value, from_inst_par); + _finished.insert(from_inst_par); + if (from_inst_par != par_bb) { + par_bb_it = bb_parents.at(target_bb).begin(); + continue; + } + } else { + reg_phi->addIncoming(derived_reg_value, par_bb); } - continue; + ++par_bb_it; } - // After searching all children, re-search the target_bag. - bag_stack.push(target_bag); - for (auto child_bag : target_bag->children) { - if (!finished.contains(child_bag)) { - bag_stack.push(child_bag); + CHECK(reg_phi->getNumIncomingValues() == bb_parents.at(target_bb).size()); + // Cast to the req_ecv_reg_class if necessary. + req_value = CastFromInst(target_ecv_reg, reg_phi, GetLLVMTypeFromRegZ(req_ecv_reg_class), + target_terminator, reg_phi); + // for debug + value_reg_map.insert({reg_phi, {target_ecv_reg, phi_ecv_reg_class}}); + value_reg_map.insert({req_value, {target_ecv_reg, req_ecv_reg_class}}); + // Update cache. + target_bb_reg_info_node->reg_derived_added_inst_map.insert({target_ecv_reg, reg_phi}); + target_bb_reg_info_node->referred_able_added_inst_reg_map.insert( + {reg_phi, {target_ecv_reg, phi_ecv_reg_class}}); + CHECK(reg_phi->getType() == GetLLVMTypeFromRegZ(phi_ecv_reg_class)); + } + // The target_bb doesn't have the target register, so need to `load` the register. + else { + bool relay_bb_need = false; + auto load_e_r_c = req_ecv_reg_class; + for (std::size_t i = 0; i < target_terminator->getNumSuccessors(); i++) { + auto &succi_bag_req_reg_map = + bb_regs_bag_map.at(target_terminator->getSuccessor(i))->bag_req_reg_map; + relay_bb_need |= !succi_bag_req_reg_map.contains(target_ecv_reg); + if (succi_bag_req_reg_map.contains(target_ecv_reg) && + GetRegClassSize(load_e_r_c) < GetRegClassSize(succi_bag_req_reg_map.at(target_ecv_reg))) { + load_e_r_c = succi_bag_req_reg_map.at(target_ecv_reg); } } - } - CHECK(finished.size() == finished_children_num_map.size() && finished.size() == bag_num) - << "[Bug] Search argorithm is incorrect of PhiRegsBBBagNode::GetPhiDerivedRegsBags: Search is insufficient." - << ECV_DEBUG_STREAM.str(); + // Need to insert `relay_bb` + if (relay_bb_need) { + // Create `relay_bb` and insert `load` to it. + auto relay_bb = llvm::BasicBlock::Create(impl->context, llvm::Twine::createNull(), func); + impl->DirectBranchWithSaveParents(request_bb, relay_bb); + for (std::size_t i = 0; i < target_terminator->getNumSuccessors(); i++) { + if (target_terminator->getSuccessor(i) == request_bb) { + target_terminator->setSuccessor(i, relay_bb); + auto &request_pars = bb_parents.at(request_bb); + request_pars.erase(target_bb); + bb_parents.insert({relay_bb, {target_bb}}); + } + } + relay_bb_cache.insert(relay_bb); - DebugStreamReset(); -} + // Add relay_bb to the PhiRegsBBBagNode and BBRegInfoNode. + auto request_phi_regs_bag = bb_regs_bag_map.at(request_bb); + bb_regs_bag_map.insert({relay_bb, request_phi_regs_bag}); + auto relay_bb_reg_info_node = new BBRegInfoNode(func, arg_state_val, arg_runtime_val); + bb_reg_info_node_map.insert({relay_bb, relay_bb_reg_info_node}); -void PhiRegsBBBagNode::GetPhiRegsBags(llvm::BasicBlock *root_bb) { - // Remove loop from the graph of PhiRegsBBBagNode. - PhiRegsBBBagNode::RemoveLoop(root_bb); - // Prepare the bug_succeeding_load_reg_map. - for (auto [_, bag] : bb_regs_bag_map) { - if (bag->bag_succeeding_load_reg_map.empty()) { - bag->bag_succeeding_load_reg_map = bag->bag_preceding_load_reg_map; - } - } - // Calculate the bag_preceding_(load | store)_reg_map for the every PhiRegsBBBagNode. - PhiRegsBBBagNode::GetPrecedingVirtualRegsBags(root_bb); - // Calculate the bag_succeeding_load_reg_map for the every PhiRegsBBBagNode. - PhiRegsBBBagNode::GetSucceedingVirtualRegsBags(root_bb); - // Calculate the bag_req_reg_map. - std::set finished; - for (auto [_, phi_regs_bag] : bb_regs_bag_map) { - if (!finished.contains(phi_regs_bag)) { - auto &succeeding_load_reg_map = phi_regs_bag->bag_succeeding_load_reg_map; - auto &preceding_load_reg_map = phi_regs_bag->bag_preceding_load_reg_map; - auto &more_small_reg_map = succeeding_load_reg_map.size() <= preceding_load_reg_map.size() - ? succeeding_load_reg_map - : preceding_load_reg_map; - phi_regs_bag->bag_req_reg_map = phi_regs_bag->bag_preceding_store_reg_map; - for (auto &[ecv_reg, _] : more_small_reg_map) { - if (succeeding_load_reg_map.contains(ecv_reg) && preceding_load_reg_map.contains(ecv_reg)) { - auto t_ecv_r_c = succeeding_load_reg_map.at(ecv_reg); - if (phi_regs_bag->bag_req_reg_map.contains(ecv_reg) && - GetRegClassSize(phi_regs_bag->bag_req_reg_map.at(ecv_reg)) < - GetRegClassSize(t_ecv_r_c)) { - phi_regs_bag->bag_req_reg_map.insert_or_assign(ecv_reg, t_ecv_r_c); - } else { - phi_regs_bag->bag_req_reg_map.insert({ecv_reg, t_ecv_r_c}); + auto relay_terminator = relay_bb->getTerminator(); + + // Fix all the aleady derived phi nodes on the request_bb from the target_bb. + auto request_bb_reg_info_node = bb_reg_info_node_map.at(request_bb); + auto request_bb_inst_it = request_bb->begin(); + while (auto request_phi_inst = llvm::dyn_cast(&*request_bb_inst_it)) { + for (size_t i = 0; i < request_phi_inst->getNumIncomingValues(); ++i) { + if (request_phi_inst->getIncomingBlock(i) == target_bb) { + auto [request_ecv_reg, request_ecv_reg_class] = + request_bb_reg_info_node->referred_able_added_inst_reg_map.at(request_phi_inst); + // Generate the new phi node on the relay_bb. + auto relay_phi_inst = + llvm::PHINode::Create(GetLLVMTypeFromRegZ(request_ecv_reg_class), 1, + llvm::Twine::createNull(), relay_terminator); + relay_phi_inst->addIncoming(request_phi_inst->getIncomingValue(i), target_bb); + // re-set the new value and bb of relay_bb for the request_phi_inst. + request_phi_inst->setIncomingBlock(i, relay_bb); + request_phi_inst->setIncomingValue(i, relay_phi_inst); + + // Update cache (relay_phi_inst). + relay_bb_reg_info_node->reg_latest_inst_map.insert( + {request_ecv_reg, {request_ecv_reg_class, relay_phi_inst, 0}}); + // for debug + value_reg_map.insert({relay_phi_inst, {request_ecv_reg, request_ecv_reg_class}}); } } + ++request_bb_inst_it; } - finished.insert(phi_regs_bag); - } - } -} -void PhiRegsBBBagNode::DebugGraphStruct(PhiRegsBBBagNode *target_bag) { - ECV_LOG_NL("target bag: ", debug_bag_map.at(target_bag)); - std::set __bags; - ECV_LOG("PhiRegsBBBagNode * G Parents: "); - // stdout PhiRegsBBBagNode* G. - for (auto [__bag, __bag_i] : debug_bag_map) { - auto __t_bag = __bag->GetTrueBag(); - if (__bags.contains(__t_bag)) { - continue; - } else { - __bags.insert(__t_bag); - ECV_LOG("[[", debug_bag_map[__t_bag], "] -> ["); - auto _p_bag = __t_bag->children.begin(); - std::set __t_out_bags; - while (_p_bag != __t_bag->children.end()) { - auto _t_p_bag = (*_p_bag)->GetTrueBag(); - if (__t_out_bags.contains(_t_p_bag)) { - ++_p_bag; - continue; - } - if (_p_bag != __t_bag->children.begin()) { - ECV_LOG(", "); - } - ECV_LOG(debug_bag_map.at(_t_p_bag)); - __t_out_bags.insert(_t_p_bag); - if (++_p_bag == __t_bag->children.end()) { - break; + // load all the required registers that the target_bag doesn't require. + auto state_ptr = NthArgument(func, kStatePointerArgNum); + for (auto &[need_ecv_reg, need_ecv_reg_class] : request_phi_regs_bag->bag_req_reg_map) { + if (!target_bb_reg_info_node->reg_latest_inst_map.contains(need_ecv_reg) && + !target_phi_regs_bag->bag_req_reg_map.contains(need_ecv_reg)) { + auto load_value = impl->inst.GetLifter()->LoadRegValueBeforeInst( + relay_bb, state_ptr, need_ecv_reg.GetRegName(need_ecv_reg_class), relay_terminator, + VAR_NAME(need_ecv_reg, need_ecv_reg_class)); + // Update cache. + relay_bb_reg_info_node->reg_latest_inst_map.insert( + {need_ecv_reg, {need_ecv_reg_class, load_value, 0}}); + if (target_ecv_reg == need_ecv_reg) { + req_value = load_value; + } + // for debug + value_reg_map.insert( + {load_value, {need_ecv_reg, GetRegZFromLLVMType(load_value->getType())}}); + value_reg_map.insert({req_value, {need_ecv_reg, need_ecv_reg_class}}); } } - ECV_LOG("]] "); + + auto relay_bb_br_inst = llvm::dyn_cast(relay_bb->getTerminator()); + if (relay_bb_br_inst) { + phi_bb_queue.push(relay_bb_br_inst->getSuccessor(0)); + } + } + // Can insert `load` to the target_bb. + else { + // Add `load` instruction. + auto state_ptr = NthArgument(func, kStatePointerArgNum); + auto load_value = impl->inst.GetLifter()->LoadRegValueBeforeInst( + target_bb, state_ptr, target_ecv_reg.GetRegName(load_e_r_c), target_terminator, + VAR_NAME(target_ecv_reg, load_e_r_c)); + req_value = CastFromInst(target_ecv_reg, load_value, GetLLVMTypeFromRegZ(req_ecv_reg_class), + target_terminator, load_value); + // Update cache. + target_bb_reg_info_node->reg_latest_inst_map.insert( + {target_ecv_reg, {load_e_r_c, load_value, 0}}); + target_bb_reg_info_node->referred_able_added_inst_reg_map.insert( + {req_value, {target_ecv_reg, req_ecv_reg_class}}); + // for debug + value_reg_map.insert({load_value, {target_ecv_reg, load_e_r_c}}); + value_reg_map.insert({req_value, {target_ecv_reg, req_ecv_reg_class}}); } } - ECV_LOG_NL(); - ECV_LOG_NL(); + + CHECK(req_value); + return req_value; } } // namespace remill diff --git a/backend/remill/lib/BC/Util.cpp b/backend/remill/lib/BC/Util.cpp index 38e92e1..f8338eb 100644 --- a/backend/remill/lib/BC/Util.cpp +++ b/backend/remill/lib/BC/Util.cpp @@ -2345,7 +2345,7 @@ bool isu128v2Ty(llvm::LLVMContext &context, llvm::Type *arg_type) { std::stringstream OutLLVMFunc(llvm::Function *func) { std::stringstream ss; - ss << "define " << LLVMThingToString(func->getReturnType()) << " " << func->getName().str() + ss << "define " << LLVMThingToString(func->getReturnType()) << " @" << func->getName().str() << " ("; auto arg_iter = func->args().begin(); for (;;) { diff --git a/examples/eratosthenes_sieve/cal.c b/examples/eratosthenes_sieve/cal.c index d0338d3..0022b2a 100644 --- a/examples/eratosthenes_sieve/cal.c +++ b/examples/eratosthenes_sieve/cal.c @@ -37,22 +37,22 @@ int mhex(int num) { return res; } -void simple_cal_1() { - char s[SLENGTH]; - for (int i = 0; i < 100; i++) { - for (int j = i; j < 120; j += 2) { - s[j] = 'a'; - } - } - int a = 10; - for (int i = 0; i < 5; i++) { - a *= 10; - mhex(a); - } - s[119] = 'm'; - s[120] = '\n'; - write_stdout(s, SLENGTH); -} +// void simple_cal_1() { +// char s[SLENGTH]; +// for (int i = 0; i < 100; i++) { +// for (int j = i; j < 120; j += 2) { +// s[j] = 'a'; +// } +// } +// int a = 10; +// for (int i = 0; i < 5; i++) { +// a *= 10; +// mhex(a); +// } +// s[119] = 'm'; +// s[120] = '\n'; +// write_stdout(s, SLENGTH); +// } void prime_cal() { diff --git a/lifter/Lift.cpp b/lifter/Lift.cpp index 42e0943..56b58d2 100644 --- a/lifter/Lift.cpp +++ b/lifter/Lift.cpp @@ -85,23 +85,6 @@ int main(int argc, char *argv[]) { std::unordered_map addr_fn_map; -#if defined(LIFT_DEBUG) - std::cout << "[\033[32mINFO\033[0m] DEBUG MODE ON." << std::endl; -#endif - - /* target function control flow */ - std::set control_flow_debug_fnvma_set = {0x423360}; - if (!FLAGS_dbg_fun_cfg.empty()) { - for (auto &[fn_addr, dasm_func] : manager.disasm_funcs) { - /* append the address of necesarry debug function */ - if (strncmp(dasm_func.func_name.substr(0, FLAGS_dbg_fun_cfg.length() + 4).c_str(), - (FLAGS_dbg_fun_cfg + "_____").c_str(), FLAGS_dbg_fun_cfg.length() + 4) == 0) { - control_flow_debug_fnvma_set.insert(fn_addr); - break; - } - } - } - main_lifter.SetControlFlowDebugList(control_flow_debug_fnvma_set); /* declare debug function */ main_lifter.DeclareDebugFunction(); /* declare helper function for lifted LLVM bitcode */ diff --git a/lifter/MainLifter.cpp b/lifter/MainLifter.cpp index cbcd8b1..aa8c2c8 100644 --- a/lifter/MainLifter.cpp +++ b/lifter/MainLifter.cpp @@ -59,11 +59,6 @@ void MainLifter::Optimize() { static_cast(impl.get())->Optimize(); } -/* Set Control Flow debug list */ -void MainLifter::SetControlFlowDebugList(std::set &__control_flow_debug_fnvma_set) { - static_cast(impl.get())->SetControlFlowDebugList(__control_flow_debug_fnvma_set); -} - /* Declare debug function */ void MainLifter::DeclareDebugFunction() { static_cast(impl.get())->DeclareDebugFunction(); @@ -282,12 +277,6 @@ void MainLifter::WrapImpl::AddTestFailedBlock() { elfconv_runtime_error("%s must be called by derived class.\n", __func__); } -/* Set control flow debug list */ -void MainLifter::WrapImpl::SetControlFlowDebugList( - std::set &__control_flow_debug_fnvma_set) { - control_flow_debug_fnvma_set = __control_flow_debug_fnvma_set; -} - /* Declare debug function */ llvm::Function *MainLifter::WrapImpl::DeclareDebugFunction() { @@ -362,11 +351,15 @@ void MainLifter::WrapImpl::SetRegisterNames() { llvm::GlobalVariable::ExternalLinkage, v_reg_name_i_val, "debug_" + v_reg_name_i); } - + // ECV_NZCV auto ecv_nzcv_name_val = llvm::ConstantDataArray::getString(context, "ECV_NZCV", true); new llvm::GlobalVariable(*module, ecv_nzcv_name_val->getType(), true, llvm::GlobalVariable::ExternalLinkage, ecv_nzcv_name_val, "debug_ECV_NZCV"); + // SP + auto ecv_sp_name_val = llvm::ConstantDataArray::getString(context, "SP", true); + new llvm::GlobalVariable(*module, ecv_sp_name_val->getType(), true, + llvm::GlobalVariable::ExternalLinkage, ecv_sp_name_val, "debug_SP"); } /* Set lifted function symbol name table */ diff --git a/lifter/MainLifter.h b/lifter/MainLifter.h index 11a1427..8b1b1f7 100644 --- a/lifter/MainLifter.h +++ b/lifter/MainLifter.h @@ -121,8 +121,6 @@ class MainLifter : public TraceLifter { void AddTestFailedBlock() override; /* debug helper */ - /* Set control flow debug list */ - void SetControlFlowDebugList(std::set &__control_flow_debug_fnvma_set); /* Declare debug function */ llvm::Function *DeclareDebugFunction(); /* Set lifted function symbol name table */ @@ -154,7 +152,6 @@ class MainLifter : public TraceLifter { void Optimize(); /* debug */ - void SetControlFlowDebugList(std::set &control_flow_debug_fnvma_set); void DeclareDebugFunction(); void SetFuncSymbolNameTable(std::unordered_map &addr_fn_map); void SetRegisterNames(); diff --git a/runtime/Entry.cpp b/runtime/Entry.cpp index cf5ea59..a263c15 100644 --- a/runtime/Entry.cpp +++ b/runtime/Entry.cpp @@ -2,12 +2,6 @@ #include #include -#include -#if defined(LIFT_DEBUG) && defined(__linux__) -# include -# include -# include -#endif #include #include #include @@ -21,14 +15,6 @@ int main(int argc, char *argv[]) { std::vector mapped_memorys; -#if defined(LIFT_DEBUG) && defined(__linux__) - struct sigaction segv_action = {0}; - segv_action.sa_flags = SA_SIGINFO; - segv_action.sa_sigaction = segv_debug_state_machine; - if (sigaction(SIGSEGV, &segv_action, NULL) < 0) - elfconv_runtime_error("sigaction for SIGSEGV failed.\n"); -#endif - /* allocate Stack */ auto mapped_stack = MappedMemory::VMAStackEntryInit(argc, argv, &g_state); /* allocate Heap */ diff --git a/runtime/VmIntrinsics.cpp b/runtime/VmIntrinsics.cpp index 0ee3006..a9ab37a 100644 --- a/runtime/VmIntrinsics.cpp +++ b/runtime/VmIntrinsics.cpp @@ -240,7 +240,7 @@ extern "C" void debug_call_stack_pop(RuntimeManager *runtime_manager, uint64_t f // observe the value change of runtime memory extern "C" void debug_memory_value_change(RuntimeManager *runtime_manager) { // step 1. set target vma - static uint64_t target_vma = 0x499f18; + static uint64_t target_vma = 0x495060; if (0 == target_vma) return; static uint64_t old_value = 0; diff --git a/utils/elfconv.cpp b/utils/elfconv.cpp index fbbc364..4ce7c78 100644 --- a/utils/elfconv.cpp +++ b/utils/elfconv.cpp @@ -97,12 +97,3 @@ extern "C" void debug_insn() { extern "C" void debug_reach() { std::cout << "Reach!" << std::endl; } - -#if defined(LIFT_DEBUG) && defined(__linux__) -extern "C" void segv_debug_state_machine(int sig, siginfo_t *info, void *ctx) { - std::cout << "[ERROR] Segmantation Fault." << std::endl; - std::cout << "signo: " << info->si_signo << " code: " << info->si_code << std::endl; - debug_state_machine(); - exit(0); -} -#endif \ No newline at end of file diff --git a/utils/elfconv.h b/utils/elfconv.h index f5fcdaa..daf4bc1 100644 --- a/utils/elfconv.h +++ b/utils/elfconv.h @@ -2,7 +2,7 @@ #include #include -#if defined(LIFT_DEBUG) && defined(__linux__) +#if defined(RUNTIME_SIGSEGV_DEBUG) && defined(__linux__) # include #endif @@ -10,6 +10,3 @@ extern "C" void debug_state_machine(); extern "C" void debug_state_machine_vectors(); extern "C" void debug_insn(); -#if defined(LIFT_DEBUG) && defined(__linux__) -extern "C" void segv_debug_state_machine(int sig, siginfo_t *info, void *ctx); -#endif \ No newline at end of file