Skip to content

[SimplifyCFG][swifterror] Don't sink calls with swifterror params #139015

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions llvm/lib/Transforms/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Constant, InlineAsm>(I->getOperand(OpIdx)))
if (!isa<Constant, InlineAsm>(Op))
return true;

switch (I->getOpcode()) {
Expand Down
8 changes: 0 additions & 8 deletions llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<StoreInst>(I) && I->getOperand(1)->isSwiftError())
return false;
if (isa<LoadInst>(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)
Expand Down
92 changes: 92 additions & 0 deletions llvm/test/Transforms/SimplifyCFG/hoist-sink-swifterror-store.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
}
Loading