diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 1db01b2716a09..3dbd605e19c3a 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -4220,12 +4220,19 @@ void llvm::maybeMarkSanitizerLibraryCallNoBuiltin( } bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { + const auto *Op = I->getOperand(OpIdx); // We can't have a PHI with a metadata type. - if (I->getOperand(OpIdx)->getType()->isMetadataTy()) + if (Op->getType()->isMetadataTy()) + return false; + + // swifterror pointers can only be used by a load, store, or as a swifterror + // argument; swifterror pointers are not allowed to be used in select or phi + // instructions. + if (Op->isSwiftError()) return false; // Early exit. - if (!isa(I->getOperand(OpIdx))) + if (!isa(Op)) return true; switch (I->getOpcode()) { diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 5cd244c9d43da..d94abea8b87df 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -2208,14 +2208,6 @@ static bool canSinkInstructions( if (!I->isSameOperationAs(I0, Instruction::CompareUsingIntersectedAttrs)) 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; - // Treat MMRAs conservatively. This pass can be quite aggressive and // could drop a lot of MMRAs otherwise. if (MMRAMetadata(*I) != I0MMRA) diff --git a/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll b/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll index 0c13f5703447a..5dff39c1f9a52 100644 --- a/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll +++ b/llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll @@ -3,6 +3,8 @@ declare void @clobber1() declare void @clobber2() +declare swiftcc void @foo(ptr swifterror) +declare swiftcc void @bar(ptr swifterror, ptr) ; 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. @@ -76,6 +78,22 @@ exit: ; introduces a select for the pointer operand. This is not allowed for ; swifterror pointers. define swiftcc ptr @sink_load(ptr %arg, ptr swifterror %arg1, i1 %c) { +; CHECK-LABEL: define swiftcc ptr @sink_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: call void @clobber1() +; CHECK-NEXT: [[L1:%.*]] = load ptr, ptr [[ARG]], align 8 +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: call void @clobber2() +; CHECK-NEXT: [[L2:%.*]] = load ptr, ptr [[ARG1]], align 8 +; 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 @@ -127,3 +145,77 @@ exit: %p = phi ptr [ %l1, %then ], [ %l2, %else ] ret ptr %p } + + +define swiftcc void @sink_call(i1 %c) { +; CHECK-LABEL: define swiftcc void @sink_call +; CHECK-SAME: (i1 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = alloca swifterror ptr, align 8 +; CHECK-NEXT: [[TMP2:%.*]] = alloca swifterror ptr, align 8 +; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @clobber1() +; CHECK-NEXT: call swiftcc void @foo(ptr [[TMP2]]) +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: call void @clobber2() +; CHECK-NEXT: call swiftcc void @foo(ptr [[TMP1]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret void +; + %2 = alloca swifterror ptr, align 8 + %3 = alloca swifterror ptr, align 8 + br i1 %c, label %then, label %else + +then: + call void @clobber1() + call swiftcc void @foo(ptr %3) + br label %exit + +else: + call void @clobber2() + call swiftcc void @foo(ptr %2) + br label %exit + +exit: + ret void +} + + +define swiftcc void @safe_sink_call(i1 %c) { +; CHECK-LABEL: define swiftcc void @safe_sink_call +; CHECK-SAME: (i1 [[C:%.*]]) { +; CHECK-NEXT: [[ERR:%.*]] = alloca swifterror ptr, align 8 +; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8 +; CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8 +; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @clobber1() +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: call void @clobber2() +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[B_SINK:%.*]] = phi ptr [ [[B]], [[ELSE]] ], [ [[A]], [[THEN]] ] +; CHECK-NEXT: call swiftcc void @bar(ptr [[ERR]], ptr [[B_SINK]]) +; CHECK-NEXT: ret void +; + %err = alloca swifterror ptr, align 8 + %a = alloca ptr, align 8 + %b = alloca ptr, align 8 + br i1 %c, label %then, label %else + +then: + call void @clobber1() + call swiftcc void @bar(ptr %err, ptr %a) + br label %exit + +else: + call void @clobber2() + call swiftcc void @bar(ptr %err, ptr %b) + br label %exit + +exit: + ret void +}