Skip to content

Commit a8a2610

Browse files
committed
[EVM] Support non-precise memory locations in VM AliasAnalysis
1 parent aec0233 commit a8a2610

File tree

3 files changed

+107
-1
lines changed

3 files changed

+107
-1
lines changed

llvm/lib/Analysis/VMAliasAnalysis.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ AliasResult VMAAResult::alias(const MemoryLocation &LocA,
112112
return AAResultBase::alias(LocA, LocB, AAQI, I);
113113

114114
// Don't check unknown memory locations.
115-
if (!LocA.Size.isPrecise() || !LocB.Size.isPrecise())
115+
if (!LocA.Size.isPrecise() && !LocB.Size.isPrecise())
116116
return AAResultBase::alias(LocA, LocB, AAQI, I);
117117

118118
// Only 256-bit keys are valid for storage.
@@ -166,6 +166,23 @@ AliasResult VMAAResult::alias(const MemoryLocation &LocA,
166166
return AliasResult::PartialAlias;
167167
}
168168

169+
// If one of the locations is imprecise, they don’t alias as long as
170+
// the other location is precise and ends before the first one begins.
171+
if (LocB.Size == LocationSize::afterPointer()) {
172+
if (StartBVal.sge(StartAVal + LocA.Size.getValue()))
173+
return AliasResult::NoAlias;
174+
return AliasResult::PartialAlias;
175+
}
176+
177+
if (LocA.Size == LocationSize::afterPointer()) {
178+
if (StartAVal.sge(StartBVal + LocB.Size.getValue()))
179+
return AliasResult::NoAlias;
180+
return AliasResult::PartialAlias;
181+
}
182+
183+
if (!LocA.Size.isPrecise() || !LocB.Size.isPrecise())
184+
return AAResultBase::alias(LocA, LocB, AAQI, I);
185+
169186
auto DoesOverlap = [](const APInt &X, const APInt &XEnd, const APInt &Y) {
170187
return Y.sge(X) && Y.slt(XEnd);
171188
};

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,20 @@ 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+
476+
; CHECK-LABEL: Function: test_as1_alias_return_nonprecise
477+
; CHECK: NoModRef: Ptr: i256* inttoptr (i256 32 to ptr addrspace(1)) <-> call void @llvm.evm.return
478+
define void @test_as1_alias_return_nonprecise(i256 %size) noreturn {
479+
store i256 1, ptr addrspace(1) inttoptr (i256 32 to ptr addrspace(1)), align 32
480+
call void @llvm.evm.return(ptr addrspace(1) inttoptr (i256 128 to ptr addrspace(1)), i256 %size)
481+
unreachable
482+
}
483+
484+
; CHECK-LABEL: Function: test_as1_part_alias_return_nonprecise
485+
; CHECK: Just Ref: Ptr: i256* inttoptr (i256 100 to ptr addrspace(1)) <-> call void @llvm.evm.return
486+
define void @test_as1_part_alias_return_nonprecise(i256 %size) noreturn {
487+
store i256 1, ptr addrspace(1) inttoptr (i256 100 to ptr addrspace(1)), align 32
488+
call void @llvm.evm.return(ptr addrspace(1) inttoptr (i256 128 to ptr addrspace(1)), i256 %size)
489+
unreachable
490+
}
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 -passes=dse -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 0)
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 0)
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)