-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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
[StackSafetyAnalysis] Don't call getTruncateOrZeroExtend for pointers of different sizes #79804
Conversation
…tly-sized pointers Otherwise SCEV asserts. Fixes SWDEV-442670
@llvm/pr-subscribers-llvm-analysis Author: Pierre van Houtryve (Pierre-vh) ChangesOtherwise SCEV asserts Fixes SWDEV-442670 Full diff: https://github.com/llvm/llvm-project/pull/79804.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
index 19991c1a7baee6..b06c31f1b1c331 100644
--- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp
+++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
@@ -273,6 +273,17 @@ ConstantRange StackSafetyLocalAnalysis::offsetFrom(Value *Addr, Value *Base) {
return UnknownRange;
auto *PtrTy = PointerType::getUnqual(SE.getContext());
+
+ // SCEV will crash if we try to extend/truncate between differently-sized
+ // pointer.
+ const auto CanExtend = [&](Type *Ty) {
+ return !Ty->isPointerTy() ||
+ DL.getTypeSizeInBits(Ty) == DL.getTypeSizeInBits(PtrTy);
+ };
+
+ if (!CanExtend(Addr->getType()) || !CanExtend(Base->getType()))
+ return UnknownRange;
+
const SCEV *AddrExp = SE.getTruncateOrZeroExtend(SE.getSCEV(Addr), PtrTy);
const SCEV *BaseExp = SE.getTruncateOrZeroExtend(SE.getSCEV(Base), PtrTy);
const SCEV *Diff = SE.getMinusSCEV(AddrExp, BaseExp);
diff --git a/llvm/test/Analysis/StackSafetyAnalysis/extend-ptr.ll b/llvm/test/Analysis/StackSafetyAnalysis/extend-ptr.ll
new file mode 100644
index 00000000000000..bb9ae92c24fdda
--- /dev/null
+++ b/llvm/test/Analysis/StackSafetyAnalysis/extend-ptr.ll
@@ -0,0 +1,18 @@
+; RUN: opt %s -disable-output -S -passes="print<stack-safety-local>" 2>&1 | FileCheck %s
+
+; Datalayout from AMDGPU, p5 is 32 bits and p is 64.
+; We used to call SCEV getTruncateOrZeroExtend on %x.ascast/%x which caused an assertion failure.
+
+; CHECK: @a dso_preemptable
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: x[]: full-set
+; CHECK-NEXT: allocas uses:
+
+target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
+
+define void @a(ptr addrspace(5) %x) {
+entry:
+ %x.ascast = addrspacecast ptr addrspace(5) %x to ptr
+ store i64 0, ptr %x.ascast, align 8
+ ret void
+}
|
@@ -273,6 +273,17 @@ ConstantRange StackSafetyLocalAnalysis::offsetFrom(Value *Addr, Value *Base) { | |||
return UnknownRange; | |||
|
|||
auto *PtrTy = PointerType::getUnqual(SE.getContext()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't follow the context, but PointerType::getUnqual should never be used. Can this just use Addr->getType()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also found another use of getUnqual
in this pass that still causes the assert to trip, so indeed seems like we should get rid of those instead. I'll try it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried it and the pass messes up somewhere else instead. It seems like the pass isn't written with handling address spaces with differently sized pointers at all. It even hardcodes the pointer size for AS 0 and uses it in a bunch of places.
The changes needed to the pass seems to be big, I don't mind looking at it sometime but this is really a blocker so we need a quick bandaid first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the context, I'm guessing another quick bandaid would be to replace the hardcoded PtrTy with the alloca address space pointer type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd expect any fix to this to at least remove all the getTruncateOrZeroExtend() calls on pointer SCEVS in this pass, as that fundamentally never makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the diff so getTruncateOrZeroExtend
is no longer called for pointers
|
||
// FIXME: Pass does not deal with pointers from different address spaces that | ||
// don't have the same size. | ||
if (DL.getTypeSizeInBits(Addr->getType()) != PointerSize || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking mismatched address space would also be better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pass works fine for same size AS I think, because getTruncateOrZeroExtend
will not try to do anything as it just checks the type size and not the types themselves.
I guess the easiest thing then is to just reject any AS != 0 explicitly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the easiest thing then is to just reject any AS != 0 explicitly
Yes. This pass is just a optimization.
Type *ValTy = Val->getType(); | ||
|
||
auto *PtrTy = PointerType::getUnqual(SE.getContext()); | ||
if (ValTy->isPointerTy()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this ever false? I don't think this code is working on anything but pointers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah it only works on pointers, I added an assert and it doesn't trip
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as a workaround. I looked over the pass a bit, and it's a real mess.
From the presubmit bot, seems the assertion is not valid:
|
; CHECK-NEXT: allocas uses: | ||
|
||
target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set target triple
and specify ; REQUIRES: amdgpu-registered-target
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? The datalayout string should work the same for all targets in this context (just running one IR analysis), no?
✅ With the latest revision this PR passed the C/C++ code formatter. |
I've added a regression test for the pointer assertion failure in 4c2422e. The pass is blindly following all instruction uses in llvm-project/llvm/lib/Analysis/StackSafetyAnalysis.cpp Lines 524 to 525 in 4c2422e
|
When trying to fix that it turns out that StackSafetyAnalysis assumes that all accesses it doesn't visit are "safe". For example, in define void @indirect(ptr %p) {
entry:
%a = alloca i8
store ptr %a, ptr %p
%a2 = load ptr, ptr %p
store i64 0, ptr %a2
ret void
} the last store is considered "safe" even though it obviously isn't. Apparently the reason why this doesn't miscompile everything is that asan will only use stackAccessIsSafe() if findAllocaForValue() also succeeds. |
Why is this surprising? |
… of different sizes (llvm#79804) Otherwise SCEV asserts `Can't extend pointer!` Fixes SWDEV-442670 Change-Id: If1db5661c26760462acb7b05a1cd333a4eb01b88
Otherwise SCEV asserts
Can't extend pointer!
I assume the proper fix would be to teach SCEV about addrspacecast but this is a blocking issue downstream so I'm making a quick fix.
Fixes SWDEV-442670