From 1cf6b6679dd7dfd4e00cb55891970ce68f59c67d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 May 2021 21:10:06 +0100 Subject: [PATCH] Add custom basic dead instruction elimination pass --- src/llvm_backend.cpp | 28 ++++++------ src/llvm_backend_opt.cpp | 93 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 13 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 240e33c80..7bdc8b04a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3318,9 +3318,11 @@ void lb_end_procedure_body(lbProcedure *p) { LLVMBuildBr(p->builder, p->entry_block->block); LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + LLVMValueRef instr = nullptr; + // Make sure there is a "ret void" at the end of a procedure with no return type if (p->type->Proc.result_count == 0) { - LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); + instr = LLVMGetLastInstruction(p->curr_block->block); if (!lb_is_instr_terminating(instr)) { lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); LLVMBuildRetVoid(p->builder); @@ -3332,7 +3334,7 @@ void lb_end_procedure_body(lbProcedure *p) { // Make sure every block terminates, and if not, make it unreachable for (block = first_block; block != nullptr; block = LLVMGetNextBasicBlock(block)) { - LLVMValueRef instr = LLVMGetLastInstruction(block); + instr = LLVMGetLastInstruction(block); if (instr == nullptr || !lb_is_instr_terminating(instr)) { LLVMPositionBuilderAtEnd(p->builder, block); LLVMBuildUnreachable(p->builder); @@ -14045,7 +14047,7 @@ lbProcedure *lb_create_startup_type_info(lbModule *m) { LLVMVerifyFunction(p->value, LLVMAbortProcessAction); } - LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + lb_run_function_pass_manager(default_function_pass_manager, p); return p; } @@ -14134,7 +14136,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start LLVMVerifyFunction(p->value, LLVMAbortProcessAction); } - LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + lb_run_function_pass_manager(default_function_pass_manager, p); return p; } @@ -14251,7 +14253,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) LLVMVerifyFunction(p->value, LLVMAbortProcessAction); } - LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + lb_run_function_pass_manager(default_function_pass_manager, p); return p; } @@ -14376,26 +14378,26 @@ WORKER_TASK_PROC(lb_llvm_function_pass_worker_proc) { lbProcedure *p = m->procedures_to_generate[i]; if (p->body != nullptr) { // Build Procedure if (p->flags & lbProcedureFlag_WithoutMemcpyPass) { - LLVMRunFunctionPassManager(default_function_pass_manager_without_memcpy, p->value); + lb_run_function_pass_manager(default_function_pass_manager_without_memcpy, p); } else { if (p->entity && p->entity->kind == Entity_Procedure) { switch (p->entity->Procedure.optimization_mode) { case ProcedureOptimizationMode_None: case ProcedureOptimizationMode_Minimal: - LLVMRunFunctionPassManager(function_pass_manager_minimal, p->value); + lb_run_function_pass_manager(function_pass_manager_minimal, p); break; case ProcedureOptimizationMode_Size: - LLVMRunFunctionPassManager(function_pass_manager_size, p->value); + lb_run_function_pass_manager(function_pass_manager_size, p); break; case ProcedureOptimizationMode_Speed: - LLVMRunFunctionPassManager(function_pass_manager_speed, p->value); + lb_run_function_pass_manager(function_pass_manager_speed, p); break; default: - LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + lb_run_function_pass_manager(default_function_pass_manager, p); break; } } else { - LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + lb_run_function_pass_manager(default_function_pass_manager, p); } } } @@ -14403,11 +14405,11 @@ WORKER_TASK_PROC(lb_llvm_function_pass_worker_proc) { for_array(i, m->equal_procs.entries) { lbProcedure *p = m->equal_procs.entries[i].value; - LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + lb_run_function_pass_manager(default_function_pass_manager, p); } for_array(i, m->hasher_procs.entries) { lbProcedure *p = m->hasher_procs.entries[i].value; - LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + lb_run_function_pass_manager(default_function_pass_manager, p); } return 0; diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 6b7ca507a..fa9d3b456 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -248,3 +248,96 @@ void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPa LLVMAddCFGSimplificationPass(mpm); } + +void lb_run_remove_dead_instruction_pass(lbProcedure *p) { + isize removal_count = 0; + isize pass_count = 0; + isize const max_pass_count = 10; + // Custom remove dead instruction pass + for (; pass_count < max_pass_count; pass_count++) { + bool was_dead_instructions = false; + + // NOTE(bill): Iterate backwards + // reduces the number of passes as things later on will depend on things previously + for (LLVMBasicBlockRef block = LLVMGetLastBasicBlock(p->value); + block != nullptr; + block = LLVMGetPreviousBasicBlock(block)) { + // NOTE(bill): Iterate backwards + // reduces the number of passes as things later on will depend on things previously + for (LLVMValueRef instr = LLVMGetLastInstruction(block); + instr != nullptr; + /**/) { + LLVMValueRef curr_instr = instr; + instr = LLVMGetPreviousInstruction(instr); + + LLVMUseRef first_use = LLVMGetFirstUse(curr_instr); + if (first_use != nullptr) { + continue; + } + if (LLVMTypeOf(curr_instr) == nullptr) { + continue; + } + + // NOTE(bill): Explicit instructions are set here because some instructions could have side effects + switch (LLVMGetInstructionOpcode(curr_instr)) { + case LLVMAdd: + case LLVMFAdd: + case LLVMSub: + case LLVMFSub: + case LLVMMul: + case LLVMFMul: + case LLVMUDiv: + case LLVMSDiv: + case LLVMFDiv: + case LLVMURem: + case LLVMSRem: + case LLVMFRem: + case LLVMShl: + case LLVMLShr: + case LLVMAShr: + case LLVMAnd: + case LLVMOr: + case LLVMXor: + case LLVMAlloca: + case LLVMLoad: + case LLVMGetElementPtr: + case LLVMTrunc: + case LLVMZExt: + case LLVMSExt: + case LLVMFPToUI: + case LLVMFPToSI: + case LLVMUIToFP: + case LLVMSIToFP: + case LLVMFPTrunc: + case LLVMFPExt: + case LLVMPtrToInt: + case LLVMIntToPtr: + case LLVMBitCast: + case LLVMAddrSpaceCast: + case LLVMICmp: + case LLVMFCmp: + case LLVMSelect: + case LLVMExtractElement: + removal_count += 1; + LLVMInstructionEraseFromParent(curr_instr); + was_dead_instructions = true; + break; + } + } + } + + if (!was_dead_instructions) { + break; + } + } +} + + +void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) { + LLVMRunFunctionPassManager(fpm, p->value); + // NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM + // which means we cannot rely upon it + // This is also useful for read the .ll for debug purposes because a lot of instructions + // are not removed + lb_run_remove_dead_instruction_pass(p); +}