-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
CallPromotionUtils: Correctly use IndexSize when determining the bit width of pointer offsets. #119138
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Owen Anderson (resistor) ChangesFull diff: https://github.com/llvm/llvm-project/pull/119138.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
index 17cba2e642a19a..5c8246c14b3882 100644
--- a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
+++ b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
@@ -692,14 +692,17 @@ bool llvm::tryPromoteCall(CallBase &CB) {
if (!VTableEntryLoad)
return false; // Not a vtable entry load.
Value *VTableEntryPtr = VTableEntryLoad->getPointerOperand();
- APInt VTableOffset(DL.getTypeSizeInBits(VTableEntryPtr->getType()), 0);
+ APInt VTableOffset(DL.getIndexSizeInBits(
+ VTableEntryPtr->getType()->getPointerAddressSpace()),
+ 0);
Value *VTableBasePtr = VTableEntryPtr->stripAndAccumulateConstantOffsets(
DL, VTableOffset, /* AllowNonInbounds */ true);
LoadInst *VTablePtrLoad = dyn_cast<LoadInst>(VTableBasePtr);
if (!VTablePtrLoad)
return false; // Not a vtable load.
Value *Object = VTablePtrLoad->getPointerOperand();
- APInt ObjectOffset(DL.getTypeSizeInBits(Object->getType()), 0);
+ APInt ObjectOffset(
+ DL.getIndexSizeInBits(Object->getType()->getPointerAddressSpace()), 0);
Value *ObjectBase = Object->stripAndAccumulateConstantOffsets(
DL, ObjectOffset, /* AllowNonInbounds */ true);
if (!(isa<AllocaInst>(ObjectBase) && ObjectOffset == 0))
@@ -712,7 +715,8 @@ bool llvm::tryPromoteCall(CallBase &CB) {
VTablePtrLoad, VTablePtrLoad->getParent(), BBI, 0, nullptr, nullptr);
if (!VTablePtr)
return false; // No vtable found.
- APInt VTableOffsetGVBase(DL.getTypeSizeInBits(VTablePtr->getType()), 0);
+ APInt VTableOffsetGVBase(
+ DL.getIndexSizeInBits(VTablePtr->getType()->getPointerAddressSpace()), 0);
Value *VTableGVBase = VTablePtr->stripAndAccumulateConstantOffsets(
DL, VTableOffsetGVBase, /* AllowNonInbounds */ true);
GlobalVariable *GV = dyn_cast<GlobalVariable>(VTableGVBase);
diff --git a/llvm/test/Transforms/Inline/promote-call-bitwidth.ll b/llvm/test/Transforms/Inline/promote-call-bitwidth.ll
new file mode 100644
index 00000000000000..f0e9f7aec00d6b
--- /dev/null
+++ b/llvm/test/Transforms/Inline/promote-call-bitwidth.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
+; RUN: opt -S -passes=inline < %s | FileCheck %s
+target datalayout = "e-m:e-p200:128:128:128:64-p:64:64-i64:64-i128:128-n64-S128-A200-P200-G200"
+target triple = "riscv64-unknown-freebsd13.0"
+
+define void @test(ptr addrspace(200) %arg1, ptr addrspace(200) %arg2) local_unnamed_addr addrspace(200) {
+; CHECK-LABEL: define {{[^@]+}}@test
+; CHECK-SAME: (ptr addrspace(200) [[ARG1:%.*]], ptr addrspace(200) [[ARG2:%.*]]) local_unnamed_addr addrspace(200) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = load ptr addrspace(200), ptr addrspace(200) [[ARG2]], align 16
+; CHECK-NEXT: call addrspace(200) void [[TMP0]](ptr addrspace(200) [[ARG1]])
+; CHECK-NEXT: ret void
+;
+entry:
+ call void @call_fnptr(ptr addrspace(200) %arg1, ptr addrspace(200) %arg2)
+ ret void
+}
+
+define internal void @call_fnptr(ptr addrspace(200) %this, ptr addrspace(200) %arg) unnamed_addr addrspace(200) align 2 {
+entry:
+ %0 = load ptr addrspace(200), ptr addrspace(200) %arg, align 16
+ call void %0(ptr addrspace(200) %this)
+ ret void
+}
+
+define void @test2(ptr addrspace(200) %this) local_unnamed_addr addrspace(200) {
+; CHECK-LABEL: define {{[^@]+}}@test2
+; CHECK-SAME: (ptr addrspace(200) [[THIS:%.*]]) local_unnamed_addr addrspace(200) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[VTABLE_I:%.*]] = load ptr addrspace(200), ptr addrspace(200) [[THIS]], align 16
+; CHECK-NEXT: [[FN_I:%.*]] = load ptr addrspace(200), ptr addrspace(200) [[VTABLE_I]], align 16
+; CHECK-NEXT: call addrspace(200) void [[FN_I]](ptr addrspace(200) [[THIS]])
+; CHECK-NEXT: ret void
+;
+entry:
+ call void @call_via_vtable(ptr addrspace(200) %this)
+ ret void
+}
+
+define internal void @call_via_vtable(ptr addrspace(200) %this) unnamed_addr addrspace(200) {
+entry:
+ %0 = bitcast ptr addrspace(200) %this to ptr addrspace(200)
+ %vtable = load ptr addrspace(200), ptr addrspace(200) %0, align 16
+ %fn = load ptr addrspace(200), ptr addrspace(200) %vtable, align 16
+ call void %fn(ptr addrspace(200) %this)
+ ret void
+}
|
Tagging @jrtc27 and @arichardson as this is a CHERI-derived change |
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.
Looks like this is my downstream commit CTSRD-CHERI/llvm-project@fb9fa37, would be nice if you could add Co-authored-by:
.
Thanks for working on upstreaming these changes!
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 with suggested changes.
Sure. Is that just written into the commit message, or do I need to do something special to make git recognize it? |
Just needs to be a separate line in the commit message for github to recognize it. I believe I was still at Cambridge Uni back then so adding |
Done |
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
…width of pointer offsets. Co-authored-by: Alexander Richardson <[email protected]>
I just reverted this due to ASAN bootstrap failures. https://lab.llvm.org/buildbot/#/builders/52/builds/4390 |
@@ -712,7 +712,7 @@ bool llvm::tryPromoteCall(CallBase &CB) { | |||
VTablePtrLoad, VTablePtrLoad->getParent(), BBI, 0, nullptr, nullptr); | |||
if (!VTablePtr) | |||
return false; // No vtable found. | |||
APInt VTableOffsetGVBase(DL.getTypeSizeInBits(VTablePtr->getType()), 0); |
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.
Presumably FindAvailableLoadedValue can return a pointer-sized integer (really, anything that CastInst::isBitOrNoopPointerCastable) if you end up storing a uintptr_t that you then load and call. If so, stripAndAccumulateConstantOffsets returns its input for non-pointers and then the dyn_cast will definitely give null.
(Obviously not true on CHERI for various reasons)
The other instances are fine because they're using the pointer operands of loads so by definition are pointers, whereas this one is some random other Value that is known to be the same bit pattern as the value loaded here.
So probably line 713 needs to gain a type check. Maybe you could cast back instead, though I'd worry about provenance due to peeking through inttoptr(ptrtoint(...)), and AFAICT the former would make the new code behave like the old code.
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.
Thanks. I'm doing a bootstrap build now to try to extract a test case. I'll put up a new PR with the test and the fix once I have that.
…width of pointer offsets. This reapplies llvm#119138 with a defensive fix for the assertion failure when building libcxx. Unfortunately the failure does not reproduce on my machine, so I am not able to extract a test case. The key insight for the fix comes from jrtc, who observes that `VTablePtr` may, in fact, not be a pointer on return from `FindAvailableLoadedValue`. This is easily worked around, because we are guaranteed that the vtable being manipulated is the same one accessed via `VTablePtrLoad` earlier, and thus can obtain the address space from there. Co-authored-by: Alexander Richardson <[email protected]>
…width of pointer offsets. This reapplies llvm#119138 with a defensive fix for the assertion failure when building libcxx. Unfortunately the failure does not reproduce on my machine, so I am not able to extract a test case. The key insight for the fix comes from jrtc, who observes that `VTablePtr` may, in fact, not be a pointer on return from `FindAvailableLoadedValue`. This is easily worked around, because we are guaranteed that the vtable being manipulated is the same one accessed via `VTablePtrLoad` earlier, and thus can obtain the address space from there. Co-authored-by: Alexander Richardson <[email protected]>
…width of pointer offsets. This reapplies llvm#119138 with a defensive fix for the assertion failure when building libcxx. Unfortunately the failure does not reproduce on my machine, so I am not able to extract a test case. The key insight for the fix comes from Jessica Clarke, who observes that `VTablePtr` may, in fact, not be a pointer on return from `FindAvailableLoadedValue`. Co-authored-by: Alexander Richardson <[email protected]>
…width of pointer offsets. (#119483) This reapplies #119138 with a defensive fix for the assertion failure when building libcxx. Unfortunately the failure does not reproduce on my machine, so I am not able to extract a test case. The key insight for the fix comes from Jessica Clarke, who observes that `VTablePtr` may, in fact, not be a pointer on return from `FindAvailableLoadedValue`. Co-authored-by: Alexander Richardson <[email protected]>
No description provided.