Skip to content

Commit a171f7e

Browse files
committed
Add non-strict aliasing support
1 parent e06acbf commit a171f7e

File tree

4 files changed

+120
-9
lines changed

4 files changed

+120
-9
lines changed

enzyme/Enzyme/TypeAnalysis/TypeAnalysis.cpp

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ llvm::cl::opt<bool> EnzymePrintType("enzyme-print-type", cl::init(false),
6363
llvm::cl::opt<bool> RustTypeRules("enzyme-rust-type", cl::init(false),
6464
cl::Hidden,
6565
cl::desc("Enable rust-specific type rules"));
66+
67+
llvm::cl::opt<bool> EnzymeStrictAliasing(
68+
"enzyme-strict-aliasing", cl::init(true), cl::Hidden,
69+
cl::desc("Assume strict aliasing of types / type stability"));
6670
}
6771

6872
const std::map<std::string, llvm::Intrinsic::ID> LIBM_FUNCTIONS = {
@@ -149,6 +153,7 @@ TypeAnalyzer::TypeAnalyzer(const FnTypeInfo &fn, TypeAnalysis &TA,
149153
: notForAnalysis(getGuaranteedUnreachable(fn.Function)), intseen(),
150154
fntypeinfo(fn), interprocedural(TA), direction(direction), Invalid(false),
151155
PHIRecur(false), DT(std::make_shared<DominatorTree>(*fn.Function)),
156+
PDT(std::make_shared<PostDominatorTree>(*fn.Function)),
152157
LI(std::make_shared<LoopInfo>(*DT)) {
153158

154159
assert(fntypeinfo.KnownValues.size() ==
@@ -176,11 +181,12 @@ TypeAnalyzer::TypeAnalyzer(const FnTypeInfo &fn, TypeAnalysis &TA,
176181
TypeAnalyzer::TypeAnalyzer(
177182
const FnTypeInfo &fn, TypeAnalysis &TA,
178183
const llvm::SmallPtrSetImpl<llvm::BasicBlock *> &notForAnalysis,
179-
std::shared_ptr<llvm::DominatorTree> DT, std::shared_ptr<llvm::LoopInfo> LI,
180-
uint8_t direction, bool PHIRecur)
184+
std::shared_ptr<llvm::DominatorTree> DT,
185+
std::shared_ptr<llvm::PostDominatorTree> PDT,
186+
std::shared_ptr<llvm::LoopInfo> LI, uint8_t direction, bool PHIRecur)
181187
: notForAnalysis(notForAnalysis.begin(), notForAnalysis.end()), intseen(),
182188
fntypeinfo(fn), interprocedural(TA), direction(direction), Invalid(false),
183-
PHIRecur(PHIRecur), DT(DT), LI(LI) {
189+
PHIRecur(PHIRecur), DT(DT), PDT(PDT), LI(LI) {
184190
assert(fntypeinfo.KnownValues.size() ==
185191
fntypeinfo.Function->getFunctionType()->getNumParams());
186192
}
@@ -402,7 +408,7 @@ void getConstantAnalysis(Constant *Val, TypeAnalyzer &TA,
402408
// Just analyze this new "instruction" and none of the others
403409
{
404410
TypeAnalyzer tmpAnalysis(TA.fntypeinfo, TA.interprocedural,
405-
TA.notForAnalysis, TA.DT, TA.LI);
411+
TA.notForAnalysis, TA.DT, TA.PDT, TA.LI);
406412
tmpAnalysis.visit(*I);
407413
analysis[Val] = tmpAnalysis.getAnalysis(I);
408414
}
@@ -548,8 +554,32 @@ void TypeAnalyzer::updateAnalysis(Value *Val, TypeTree Data, Value *Origin) {
548554
llvm::errs() << "inst: " << *I << "\n";
549555
}
550556
assert(fntypeinfo.Function == I->getParent()->getParent());
551-
} else if (auto Arg = dyn_cast<Argument>(Val))
557+
assert(Origin);
558+
if (!EnzymeStrictAliasing) {
559+
if (auto OI = dyn_cast<Instruction>(Origin)) {
560+
if (OI->getParent() != I->getParent() &&
561+
!PDT->dominates(OI->getParent(), I->getParent())) {
562+
if (EnzymePrintType)
563+
llvm::errs() << " skipping update into " << *I << " of "
564+
<< Data.str() << " from " << *OI << "\n";
565+
return;
566+
}
567+
}
568+
}
569+
} else if (auto Arg = dyn_cast<Argument>(Val)) {
552570
assert(fntypeinfo.Function == Arg->getParent());
571+
if (!EnzymeStrictAliasing)
572+
if (auto OI = dyn_cast<Instruction>(Origin)) {
573+
auto I = &*fntypeinfo.Function->getEntryBlock().begin();
574+
if (OI->getParent() != I->getParent() &&
575+
!PDT->dominates(OI->getParent(), I->getParent())) {
576+
if (EnzymePrintType)
577+
llvm::errs() << " skipping update into " << *Arg << " of "
578+
<< Data.str() << " from " << *OI << "\n";
579+
return;
580+
}
581+
}
582+
}
553583

554584
// Attempt to update the underlying analysis
555585
bool LegalOr = true;
@@ -641,7 +671,7 @@ void TypeAnalyzer::prepareArgs() {
641671
// Propagate input type information for arguments
642672
for (auto &pair : fntypeinfo.Arguments) {
643673
assert(pair.first->getParent() == fntypeinfo.Function);
644-
updateAnalysis(pair.first, pair.second, nullptr);
674+
updateAnalysis(pair.first, pair.second, pair.first);
645675
}
646676

647677
// Get type and other information about argument
@@ -656,7 +686,7 @@ void TypeAnalyzer::prepareArgs() {
656686
for (Instruction &I : BB) {
657687
if (ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
658688
if (Value *RV = RI->getReturnValue()) {
659-
updateAnalysis(RV, fntypeinfo.Return, nullptr);
689+
updateAnalysis(RV, fntypeinfo.Return, RV);
660690
updateAnalysis(RV, getAnalysis(RV), RV);
661691
}
662692
}
@@ -852,7 +882,7 @@ void TypeAnalyzer::runPHIHypotheses() {
852882
// the incoming operands are integral
853883

854884
TypeAnalyzer tmpAnalysis(fntypeinfo, interprocedural,
855-
notForAnalysis, DT, LI, DOWN,
885+
notForAnalysis, DT, PDT, LI, DOWN,
856886
/*PHIRecur*/ true);
857887
tmpAnalysis.intseen = intseen;
858888
tmpAnalysis.analysis = analysis;
@@ -884,7 +914,7 @@ void TypeAnalyzer::runPHIHypotheses() {
884914
// Assume that this is an integer, does that mean we can prove that
885915
// the incoming operands are integral
886916
TypeAnalyzer tmpAnalysis(fntypeinfo, interprocedural,
887-
notForAnalysis, DT, LI, DOWN,
917+
notForAnalysis, DT, PDT, LI, DOWN,
888918
/*PHIRecur*/ true);
889919
tmpAnalysis.intseen = intseen;
890920
tmpAnalysis.analysis = analysis;

enzyme/Enzyme/TypeAnalysis/TypeAnalysis.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "llvm/IR/Value.h"
4141

4242
#include "llvm/Analysis/LoopInfo.h"
43+
#include "llvm/Analysis/PostDominators.h"
4344
#include "llvm/IR/Dominators.h"
4445

4546
#include "TypeTree.h"
@@ -223,6 +224,7 @@ class TypeAnalyzer : public llvm::InstVisitor<TypeAnalyzer> {
223224
std::map<llvm::Value *, TypeTree> analysis;
224225

225226
std::shared_ptr<llvm::DominatorTree> DT;
227+
std::shared_ptr<llvm::PostDominatorTree> PDT;
226228

227229
std::shared_ptr<llvm::LoopInfo> LI;
228230

@@ -234,6 +236,7 @@ class TypeAnalyzer : public llvm::InstVisitor<TypeAnalyzer> {
234236
TypeAnalyzer(const FnTypeInfo &fn, TypeAnalysis &TA,
235237
const llvm::SmallPtrSetImpl<llvm::BasicBlock *> &notForAnalysis,
236238
std::shared_ptr<llvm::DominatorTree> DT,
239+
std::shared_ptr<llvm::PostDominatorTree> PDT,
237240
std::shared_ptr<llvm::LoopInfo> LI, uint8_t direction = BOTH,
238241
bool PHIRecur = false);
239242

enzyme/test/TypeAnalysis/nonstrict.ll

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
; RUN: %opt < %s %loadEnzyme -print-type-analysis -type-analysis-func=matvec -enzyme-strict-aliasing=0 -o /dev/null | FileCheck %s
2+
3+
define internal void @matvec(i32* %mptr, i1 %cmp) {
4+
entry:
5+
%ptr = bitcast i32* %mptr to i8*
6+
br i1 %cmp, label %doubleB, label %intB
7+
8+
doubleB:
9+
%dptr = bitcast i8* %ptr to double*
10+
store double 0.000000e+00, double* %dptr, align 8, !tbaa !8
11+
ret void
12+
13+
intB:
14+
%dint = bitcast i8* %ptr to i64*
15+
store i64 0, i64* %dint, align 8, !tbaa !10
16+
ret void
17+
}
18+
19+
!5 = !{!"omnipotent char", !6, i64 0}
20+
!6 = !{!"Simple C++ TBAA"}
21+
!7 = !{!"double", !5, i64 0}
22+
!8 = !{!7, !7, i64 0}
23+
24+
!9 = !{!"int", !5, i64 0}
25+
!10 = !{!9, !9, i64 0}
26+
27+
; CHECK: matvec - {} |{}:{} {[-1]:Integer}:{}
28+
; CHECK-NEXT: i32* %mptr: {}
29+
; CHECK-NEXT: i1 %cmp: {[-1]:Integer}
30+
; CHECK-NEXT: entry
31+
; CHECK-NEXT: %ptr = bitcast i32* %mptr to i8*: {}
32+
; CHECK-NEXT: br i1 %cmp, label %doubleB, label %intB: {}
33+
; CHECK-NEXT: doubleB
34+
; CHECK-NEXT: %dptr = bitcast i8* %ptr to double*: {[-1]:Pointer, [-1,0]:Float@double}
35+
; CHECK-NEXT: store double 0.000000e+00, double* %dptr, align 8, !tbaa !0: {}
36+
; CHECK-NEXT: ret void: {}
37+
; CHECK-NEXT: intB
38+
; CHECK-NEXT: %dint = bitcast i8* %ptr to i64*: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}
39+
; CHECK-NEXT: store i64 0, i64* %dint, align 8, !tbaa !4: {}
40+
; CHECK-NEXT: ret void: {}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: %opt < %s %loadEnzyme -print-type-analysis -type-analysis-func=matvec -enzyme-strict-aliasing=0 -o /dev/null | FileCheck %s
2+
3+
define internal void @matvec(i8* %ptr, i1 %cmp) {
4+
entry:
5+
br i1 %cmp, label %doubleB, label %intB
6+
7+
doubleB:
8+
%dptr = bitcast i8* %ptr to double*
9+
store double 0.000000e+00, double* %dptr, align 8, !tbaa !8
10+
ret void
11+
12+
intB:
13+
%dint = bitcast i8* %ptr to i64*
14+
store i64 0, i64* %dint, align 8, !tbaa !10
15+
ret void
16+
}
17+
18+
!5 = !{!"omnipotent char", !6, i64 0}
19+
!6 = !{!"Simple C++ TBAA"}
20+
!7 = !{!"double", !5, i64 0}
21+
!8 = !{!7, !7, i64 0}
22+
23+
!9 = !{!"int", !5, i64 0}
24+
!10 = !{!9, !9, i64 0}
25+
26+
; CHECK: matvec - {} |{}:{} {[-1]:Integer}:{}
27+
; CHECK-NEXT: i8* %ptr: {}
28+
; CHECK-NEXT: i1 %cmp: {[-1]:Integer}
29+
; CHECK-NEXT: entry
30+
; CHECK-NEXT: br i1 %cmp, label %doubleB, label %intB: {}
31+
; CHECK-NEXT: doubleB
32+
; CHECK-NEXT: %dptr = bitcast i8* %ptr to double*: {[-1]:Pointer, [-1,0]:Float@double}
33+
; CHECK-NEXT: store double 0.000000e+00, double* %dptr, align 8, !tbaa !0: {}
34+
; CHECK-NEXT: ret void: {}
35+
; CHECK-NEXT: intB
36+
; CHECK-NEXT: %dint = bitcast i8* %ptr to i64*: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}
37+
; CHECK-NEXT: store i64 0, i64* %dint, align 8, !tbaa !4: {}
38+
; CHECK-NEXT: ret void: {}

0 commit comments

Comments
 (0)