Skip to content

Commit 56132d1

Browse files
committed
[EVM] Support non-precise memory locations in VM AliasAnalysis
1 parent c0ae543 commit 56132d1

File tree

3 files changed

+101
-8
lines changed

3 files changed

+101
-8
lines changed

llvm/lib/Analysis/VMAliasAnalysis.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,17 @@ AliasResult VMAAResult::alias(const MemoryLocation &LocA,
111111
if (!StorageAS.count(ASA) && !HeapAS.count(ASA))
112112
return AAResultBase::alias(LocA, LocB, AAQI, I);
113113

114+
LocationSize SizeA = LocA.Size;
115+
LocationSize SizeB = LocB.Size;
114116
// Don't check unknown memory locations.
115-
if (!LocA.Size.isPrecise() || !LocB.Size.isPrecise())
117+
if ((!SizeA.isPrecise() && SizeA != LocationSize::afterPointer()) ||
118+
(!SizeB.isPrecise() && SizeB != LocationSize::afterPointer()))
116119
return AAResultBase::alias(LocA, LocB, AAQI, I);
117120

118121
// Only 256-bit keys are valid for storage.
119122
if (StorageAS.count(ASA)) {
120123
constexpr unsigned KeyByteWidth = 32;
121-
if (LocA.Size != KeyByteWidth || LocB.Size != KeyByteWidth)
124+
if (SizeA != KeyByteWidth || SizeB != KeyByteWidth)
122125
return AAResultBase::alias(LocA, LocB, AAQI, I);
123126
}
124127

@@ -158,21 +161,23 @@ AliasResult VMAAResult::alias(const MemoryLocation &LocA,
158161
if (StartAVal == StartBVal) {
159162
// If either of the memory references is empty, it doesn't matter what the
160163
// pointer values are.
161-
if (LocA.Size.isZero() || LocB.Size.isZero())
164+
if (SizeA.isZero() || SizeB.isZero())
162165
return AliasResult::NoAlias;
163166

164-
if (LocA.Size == LocB.Size)
167+
if (SizeA == SizeB)
165168
return AliasResult::MustAlias;
166169
return AliasResult::PartialAlias;
167170
}
168171

169-
auto DoesOverlap = [](const APInt &X, const APInt &XEnd, const APInt &Y) {
170-
return Y.sge(X) && Y.slt(XEnd);
172+
auto DoesOverlap = [](const APInt &XStart, const LocationSize &XSize,
173+
const APInt &YStart) {
174+
return YStart.sge(XStart) && ((XSize == LocationSize::afterPointer() ||
175+
YStart.slt(XStart + XSize.getValue())));
171176
};
172177

173178
// For heap accesses, if locations don't overlap, they are not aliasing.
174-
if (!DoesOverlap(StartAVal, StartAVal + LocA.Size.getValue(), StartBVal) &&
175-
!DoesOverlap(StartBVal, StartBVal + LocB.Size.getValue(), StartAVal))
179+
if (!DoesOverlap(StartAVal, SizeA, StartBVal) &&
180+
!DoesOverlap(StartBVal, SizeB, StartAVal))
176181
return AliasResult::NoAlias;
177182
return AliasResult::PartialAlias;
178183
}

llvm/test/CodeGen/EVM/aa-eval.ll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,19 @@ define void @test_as1_alias_extcodecopy() {
471471
call void @llvm.evm.extcodecopy(i256 0, ptr addrspace(1) null, ptr addrspace(4) null, i256 32)
472472
ret void
473473
}
474+
475+
; CHECK-LABEL: Function: test_as1_alias_return_nonprecise
476+
; CHECK: NoModRef: Ptr: i256* inttoptr (i256 32 to ptr addrspace(1)) <-> call void @llvm.evm.return
477+
define void @test_as1_alias_return_nonprecise(i256 %size) noreturn {
478+
store i256 1, ptr addrspace(1) inttoptr (i256 32 to ptr addrspace(1)), align 32
479+
call void @llvm.evm.return(ptr addrspace(1) inttoptr (i256 128 to ptr addrspace(1)), i256 %size)
480+
unreachable
481+
}
482+
483+
; CHECK-LABEL: Function: test_as1_part_alias_return_nonprecise
484+
; CHECK: Just Ref: Ptr: i256* inttoptr (i256 100 to ptr addrspace(1)) <-> call void @llvm.evm.return
485+
define void @test_as1_part_alias_return_nonprecise(i256 %size) noreturn {
486+
store i256 1, ptr addrspace(1) inttoptr (i256 100 to ptr addrspace(1)), align 32
487+
call void @llvm.evm.return(ptr addrspace(1) inttoptr (i256 128 to ptr addrspace(1)), i256 %size)
488+
unreachable
489+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -O3 -S < %s | FileCheck %s
3+
target datalayout = "E-p:256:256-i256:256:256-S256-a:256:256"
4+
target triple = "evm"
5+
6+
; This test verifies that the dead store to (i256 32 to ptr addrspace(1)) is eliminated.
7+
8+
declare i256 @llvm.evm.datasize(metadata) #0
9+
10+
declare i256 @llvm.evm.dataoffset(metadata) #0
11+
12+
declare i256 @llvm.evm.callvalue() #1
13+
14+
declare void @llvm.evm.return(ptr addrspace(1) readonly, i256) #2
15+
16+
declare void @llvm.evm.revert(ptr addrspace(1) readonly, i256) #3
17+
18+
declare void @llvm.memcpy.p1.p4.i256(ptr addrspace(1) noalias nocapture writeonly, ptr addrspace(4) noalias nocapture readonly, i256, i1 immarg) #4
19+
20+
define void @__entry() local_unnamed_addr #5 {
21+
; CHECK-LABEL: define void @__entry(
22+
; CHECK-SAME: ) local_unnamed_addr #[[ATTR5:[0-9]+]] {
23+
; CHECK-NEXT: [[ENTRY:.*:]]
24+
; CHECK-NEXT: store i256 129, ptr addrspace(1) inttoptr (i256 100 to ptr addrspace(1)), align 64
25+
; CHECK-NEXT: [[CALLVALUE:%.*]] = tail call i256 @llvm.evm.callvalue()
26+
; CHECK-NEXT: [[IF_CONDITION_COMPARED_NOT:%.*]] = icmp eq i256 [[CALLVALUE]], 0
27+
; CHECK-NEXT: br i1 [[IF_CONDITION_COMPARED_NOT]], label %[[IF_JOIN:.*]], label %[[IF_MAIN:.*]]
28+
; CHECK: [[IF_MAIN]]:
29+
; CHECK-NEXT: tail call void @llvm.evm.revert(ptr addrspace(1) noalias nocapture nofree noundef nonnull align 32 null, i256 32)
30+
; CHECK-NEXT: unreachable
31+
; CHECK: [[IF_JOIN]]:
32+
; CHECK-NEXT: store i256 42, ptr addrspace(5) null, align 4294967296
33+
; CHECK-NEXT: [[DATASIZE:%.*]] = tail call i256 @llvm.evm.datasize(metadata [[META0:![0-9]+]])
34+
; CHECK-NEXT: [[DATAOFFSET:%.*]] = tail call i256 @llvm.evm.dataoffset(metadata [[META0]])
35+
; CHECK-NEXT: [[CODECOPY_SOURCE_POINTER:%.*]] = inttoptr i256 [[DATAOFFSET]] to ptr addrspace(4)
36+
; CHECK-NEXT: tail call void @llvm.memcpy.p1.p4.i256(ptr addrspace(1) nonnull align 128 inttoptr (i256 128 to ptr addrspace(1)), ptr addrspace(4) align 1 [[CODECOPY_SOURCE_POINTER]], i256 [[DATASIZE]], i1 false)
37+
; CHECK-NEXT: tail call void @llvm.evm.return(ptr addrspace(1) noalias nocapture nofree noundef nonnull align 32 inttoptr (i256 128 to ptr addrspace(1)), i256 [[DATASIZE]])
38+
; CHECK-NEXT: unreachable
39+
;
40+
entry:
41+
; To be removed
42+
store i256 128, ptr addrspace(1) inttoptr (i256 32 to ptr addrspace(1)), align 64
43+
store i256 129, ptr addrspace(1) inttoptr (i256 100 to ptr addrspace(1)), align 64
44+
%callvalue = tail call i256 @llvm.evm.callvalue()
45+
%if_condition_compared.not = icmp eq i256 %callvalue, 0
46+
br i1 %if_condition_compared.not, label %if_join, label %if_main
47+
48+
if_main:
49+
tail call void @llvm.evm.revert(ptr addrspace(1) noalias nocapture nofree noundef nonnull align 32 null, i256 32)
50+
unreachable
51+
52+
if_join:
53+
store i256 42, ptr addrspace(5) null, align 4294967296
54+
%datasize = tail call i256 @llvm.evm.datasize(metadata !0)
55+
%dataoffset = tail call i256 @llvm.evm.dataoffset(metadata !0)
56+
%codecopy_source_pointer = inttoptr i256 %dataoffset to ptr addrspace(4)
57+
tail call void @llvm.memcpy.p1.p4.i256(ptr addrspace(1) nonnull align 128 inttoptr (i256 128 to ptr addrspace(1)), ptr addrspace(4) align 1 %codecopy_source_pointer, i256 %datasize, i1 false)
58+
tail call void @llvm.evm.return(ptr addrspace(1) noalias nocapture nofree noundef nonnull align 32 inttoptr (i256 128 to ptr addrspace(1)), i256 %datasize)
59+
unreachable
60+
}
61+
62+
attributes #0 = { mustprogress nocallback nofree nosync nounwind willreturn memory(none) }
63+
attributes #1 = { mustprogress nofree nosync nounwind willreturn memory(none) }
64+
attributes #2 = { nofree noreturn nounwind memory(read) }
65+
attributes #3 = { nofree noreturn nounwind memory(argmem: read) }
66+
attributes #4 = { mustprogress nocallback nofree nounwind willreturn memory(argmem: readwrite) }
67+
attributes #5 = { nofree noreturn nounwind null_pointer_is_valid memory(readwrite, inaccessiblemem: read) "evm-entry-function" }
68+
69+
!0 = !{!"Test_16_deployed"}
70+
;.
71+
; CHECK: [[META0]] = !{!"Test_16_deployed"}
72+
;.

0 commit comments

Comments
 (0)