Index: llvm/test/tools/llvm-reduce/reduce-invoke.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-reduce/reduce-invoke.ll @@ -0,0 +1,129 @@ +; Test the invoke reduction standalone, dead blocks are not removed +; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=invokes --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t.0 +; RUN: FileCheck --check-prefixes=CHECK,RESULT,RESULT-SINGLE %s < %t.0 + +; Test the full reduction pipeline, which cleans up unreachable blocks +; RUN: llvm-reduce --abort-on-invalid-reduction --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t.1 +; RUN: FileCheck --check-prefixes=CHECK,RESULT,RESULT-FULL %s < %t.1 + + +define i32 @maybe_throwing_callee(i32 %arg) { + call void @thrown() + ret i32 %arg +} + +declare void @did_not_throw(i32) + +declare void @thrown() + +; CHECK-LABEL: define void @invoke_keep_landingpad_block(i32 %arg) personality ptr @__gxx_personality_v0 { +; INTERESTING: i32 @maybe_throwing_callee( + +; RESULT-SINGLE: %i0 = call i32 @maybe_throwing_callee(i32 %arg), !some.metadata !0 +; RESULT-SINGLE-NEXT: br label %bb3 + +; RESULT-FULL: %i0 = call i32 @maybe_throwing_callee() +; RESULT-FULL-NEXT: br label %bb4 + + +; RESULT-SINGLE: bb1: ; No predecessors! +; RESULT-SINGLE-NEXT: %landing = landingpad { ptr, i32 } +; RESULT-SINGLE-NEXT: catch ptr null +; RESULT-SINGLE-NEXT: call void @thrown() +define void @invoke_keep_landingpad_block(i32 %arg) personality ptr @__gxx_personality_v0 { +bb: + %i0 = invoke i32 @maybe_throwing_callee(i32 %arg) + to label %bb3 unwind label %bb1, !some.metadata !0 + +bb1: ; preds = %bb + %landing = landingpad { ptr, i32 } + catch ptr null + ; INTERESTING: call void @thrown() + call void @thrown() + br label %bb4 + +bb3: ; preds = %bb + call void @did_not_throw(i32 %i0) + br label %bb4 + +bb4: ; preds = %bb3, %bb1 + ret void +} + +; CHECK-LABEL: define void @invoke_drop_landingpad_block(i32 %arg) personality ptr @__gxx_personality_v0 { +; INTERESTING: i32 @maybe_throwing_callee( + +; RESULT-SINGLE: %i0 = call i32 @maybe_throwing_callee(i32 %arg), !some.metadata !0 +; RESULT-SINGLE-NEXT: br label %bb3 + +; RESULT-SINGLE: bb1: ; No predecessors! +; RESULT-SINGLE-NEXT: %landing = landingpad { ptr, i32 } + +; RESULT-SINGLE: bb3: +; RESULT-SINGLE-NEXT: call void @did_not_throw(i32 %i0) + +; RESULT-FULL: %i0 = call i32 @maybe_throwing_callee() +; RESULT-FULL-NEXT: call void @did_not_throw() +; RESULT-FULL-NEXT: ret void +define void @invoke_drop_landingpad_block(i32 %arg) personality ptr @__gxx_personality_v0 { +bb: + %i0 = invoke i32 @maybe_throwing_callee(i32 %arg) + to label %bb3 unwind label %bb1, !some.metadata !0 + +bb1: ; preds = %bb + %landing = landingpad { ptr, i32 } + catch ptr null + call void @thrown() + br label %bb4 + +bb3: ; preds = %bb + ; INTERESTING: call void @did_not_throw( + call void @did_not_throw(i32 %i0) + br label %bb4 + +bb4: ; preds = %bb3, %bb1 + ret void +} + +declare i32 @another_maybe_throwing_callee(i32 %arg) + +; Test the same landing pad block is used by multiple invokes +; CHECK-LABEL: define i32 @multi_invoke_caller(i32 %arg) personality ptr @__gxx_personality_v0 { +define i32 @multi_invoke_caller(i32 %arg) personality ptr @__gxx_personality_v0 { +bb: + %i0 = invoke i32 @maybe_throwing_callee(i32 %arg) + to label %bb3 unwind label %bb1, !some.metadata !0 + +; RESULT: bb1: ; preds = %bb4 +; RESULT-NEXT: %landing = landingpad { ptr, i32 } +; RESULT-NEXT: catch ptr null +bb1: ; preds = %bb + %landing = landingpad { ptr, i32 } + catch ptr null + ; INTERESTING: call void @thrown() + call void @thrown() + br label %bb4 + +bb3: ; preds = %bb + call void @did_not_throw(i32 %i0) + br label %bb4 + +bb4: ; preds = %bb3, %bb1 + ; INTERESTING: invoke i32 @another_maybe_throwing_callee( + + ; RESULT-SINGLE: %i1 = invoke i32 @another_maybe_throwing_callee(i32 %arg) + ; RESULT-SINGLE-NEXT: to label %bb5 unwind label %bb1, !some.metadata !1 + + ; RESULT-FULL: %i1 = invoke i32 @another_maybe_throwing_callee(i32 0) + ; RESULT-FULL-NEXT: to label %bb5 unwind label %bb1{{$}} + %i1 = invoke i32 @another_maybe_throwing_callee(i32 %arg) + to label %bb5 unwind label %bb1, !some.metadata !1 + +bb5: + ret i32 %i1 +} + +declare i32 @__gxx_personality_v0(...) + +!0 = !{!"arst"} +!1 = !{!"arstarst"} Index: llvm/tools/llvm-reduce/CMakeLists.txt =================================================================== --- llvm/tools/llvm-reduce/CMakeLists.txt +++ llvm/tools/llvm-reduce/CMakeLists.txt @@ -38,6 +38,7 @@ deltas/ReduceGlobalVars.cpp deltas/ReduceInstructions.cpp deltas/ReduceInstructionFlags.cpp + deltas/ReduceInvokes.cpp deltas/ReduceMetadata.cpp deltas/ReduceModuleData.cpp deltas/ReduceMemoryOperations.cpp Index: llvm/tools/llvm-reduce/DeltaManager.cpp =================================================================== --- llvm/tools/llvm-reduce/DeltaManager.cpp +++ llvm/tools/llvm-reduce/DeltaManager.cpp @@ -31,6 +31,7 @@ #include "deltas/ReduceInstructionFlagsMIR.h" #include "deltas/ReduceInstructions.h" #include "deltas/ReduceInstructionsMIR.h" +#include "deltas/ReduceInvokes.h" #include "deltas/ReduceMemoryOperations.h" #include "deltas/ReduceMetadata.h" #include "deltas/ReduceModuleData.h" @@ -76,6 +77,7 @@ DELTA_PASS("aliases", reduceAliasesDeltaPass) \ DELTA_PASS("simplify-conditionals-true", reduceConditionalsTrueDeltaPass) \ DELTA_PASS("simplify-conditionals-false", reduceConditionalsFalseDeltaPass)\ + DELTA_PASS("invokes", reduceInvokesDeltaPass) \ DELTA_PASS("unreachable-basic-blocks", reduceUnreachableBasicBlocksDeltaPass) \ DELTA_PASS("basic-blocks", reduceBasicBlocksDeltaPass) \ DELTA_PASS("simplify-cfg", reduceUsingSimplifyCFGDeltaPass) \ Index: llvm/tools/llvm-reduce/deltas/ReduceInvokes.h =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/deltas/ReduceInvokes.h @@ -0,0 +1,18 @@ +//===- ReduceInvokes.h - Specialized Delta Pass -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINVOKES_H +#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINVOKES_H + +#include "TestRunner.h" + +namespace llvm { +void reduceInvokesDeltaPass(TestRunner &Test); +} // namespace llvm + +#endif Index: llvm/tools/llvm-reduce/deltas/ReduceInvokes.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/deltas/ReduceInvokes.cpp @@ -0,0 +1,39 @@ +//===- ReduceInvokes.cpp - Specialized Delta Pass -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Try to replace invokes with calls. +// +//===----------------------------------------------------------------------===// + +#include "ReduceInvokes.h" +#include "Delta.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Transforms/Utils/Local.h" + +static void reduceInvokesInFunction(Oracle &O, Function &F) { + for (BasicBlock &BB : F) { + InvokeInst *Invoke = dyn_cast(BB.getTerminator()); + if (Invoke && !O.shouldKeep()) + changeToCall(Invoke); + } + + // TODO: We most likely are leaving behind dead landingpad blocks. Should we + // delete unreachable blocks now, or leave that for the unreachable block + // reduction. +} + +static void reduceInvokesInModule(Oracle &O, Module &Mod) { + for (Function &F : Mod) { + if (F.hasPersonalityFn()) + reduceInvokesInFunction(O, F); + } +} + +void llvm::reduceInvokesDeltaPass(TestRunner &Test) { + runDeltaPass(Test, reduceInvokesInModule, "Reducing Invokes"); +}