Browse Source

Add custom basic dead instruction elimination pass

gingerBill 4 years ago
parent
commit
1cf6b6679d
2 changed files with 108 additions and 13 deletions
  1. 15 13
      src/llvm_backend.cpp
  2. 93 0
      src/llvm_backend_opt.cpp

+ 15 - 13
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;

+ 93 - 0
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);
+}