diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1808,10 +1808,19 @@ } const Instruction *I0 = Insts.front(); - for (auto *I : Insts) + for (auto *I : Insts) { if (!I->isSameOperationAs(I0)) return false; + // swifterror pointers can only be used by a load or store; sinking a load + // or store would require introducing a select for the pointer operand, + // which isn't allowed for swifterror pointers. + if (isa(I) && I->getOperand(1)->isSwiftError()) + return false; + if (isa(I) && I->getOperand(0)->isSwiftError()) + return false; + } + // All instructions in Insts are known to be the same opcode. If they have a // use, check that the only user is a PHI or in the same block as the // instruction, because if a user is in the same block as an instruction we're diff --git a/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll b/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll --- a/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll +++ b/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll @@ -1,14 +1,27 @@ -; RUN: opt -passes='simplifycfg,verify' -disable-output %s - -; XFAIL: * +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: opt -passes='simplifycfg,verify' -S %s | FileCheck %s declare void @clobber1() declare void @clobber2() -; FIXME: currently simplifycfg tries to sink the stores to the exit block and -; introduces a select for the pointer operand. This is not allowed for -; swifterror pointers. -define swiftcc void @sink_store(ptr %arg, ptr swifterror %arg1, i1 %c) { +; Do not try to sink the stores to the exit block, as this requires introducing +; a select for the pointer operand. This is not allowed for swifterror pointers. +define swiftcc void @sink(ptr %arg, ptr swifterror %arg1, i1 %c) { +; CHECK-LABEL: define swiftcc void @sink +; CHECK-SAME: (ptr [[ARG:%.*]], ptr swifterror [[ARG1:%.*]], i1 [[C:%.*]]) { +; CHECK-NEXT: bb: +; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @clobber1() +; CHECK-NEXT: store ptr null, ptr [[ARG]], align 8 +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: call void @clobber2() +; CHECK-NEXT: store ptr null, ptr [[ARG1]], align 8 +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret void +; bb: br i1 %c, label %then, label %else @@ -27,6 +40,21 @@ } define swiftcc void @hoist_store(ptr %arg, ptr swifterror %arg1, i1 %c) { +; CHECK-LABEL: define swiftcc void @hoist_store +; CHECK-SAME: (ptr [[ARG:%.*]], ptr swifterror [[ARG1:%.*]], i1 [[C:%.*]]) { +; CHECK-NEXT: bb: +; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: store ptr null, ptr [[ARG]], align 8 +; CHECK-NEXT: call void @clobber1() +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: store ptr null, ptr [[ARG1]], align 8 +; CHECK-NEXT: call void @clobber2() +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret void +; bb: br i1 %c, label %then, label %else @@ -66,6 +94,22 @@ ret ptr %p } define swiftcc ptr @hoist_load(ptr %arg, ptr swifterror %arg1, i1 %c) { +; CHECK-LABEL: define swiftcc ptr @hoist_load +; CHECK-SAME: (ptr [[ARG:%.*]], ptr swifterror [[ARG1:%.*]], i1 [[C:%.*]]) { +; CHECK-NEXT: bb: +; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: [[L1:%.*]] = load ptr, ptr [[ARG]], align 8 +; CHECK-NEXT: call void @clobber1() +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: [[L2:%.*]] = load ptr, ptr [[ARG1]], align 8 +; CHECK-NEXT: call void @clobber2() +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[L1]], [[THEN]] ], [ [[L2]], [[ELSE]] ] +; CHECK-NEXT: ret ptr [[P]] +; bb: br i1 %c, label %then, label %else