ArrayRecycler<Value *> ArgRecycler;
// Congruence class info.
+
+ // This class is called INITIAL in the paper. It is the class everything
+ // startsout in, and represents any value. Being an optimistic analysis,
+ // anything in the INITIAL class has the value TOP, which is indeterminate and
+ // equivalent to everything.
CongruenceClass *InitialClass;
std::vector<CongruenceClass *> CongruenceClasses;
unsigned NextCongruenceNum;
// return it. Otherwise, return the operand itself.
Value *NewGVN::lookupOperandLeader(Value *V) const {
CongruenceClass *CC = ValueToClass.lookup(V);
- if (CC && (CC != InitialClass))
+ if (CC) {
+ // Everything in INITIAL is represneted by undef, as it can be any value.
+ // We do have to make sure we get the type right though, so we can't set the
+ // RepLeader to undef.
+ if (CC == InitialClass)
+ return UndefValue::get(V->getType());
return CC->RepStoredValue ? CC->RepStoredValue : CC->RepLeader;
+ }
+
return V;
}
// expression.
assert(II->getNumArgOperands() == 2 &&
"Expect two args for recognised intrinsics.");
- return createBinaryExpression(Opcode, EI->getType(),
- II->getArgOperand(0),
- II->getArgOperand(1));
+ return createBinaryExpression(
+ Opcode, EI->getType(), II->getArgOperand(0), II->getArgOperand(1));
}
}
}
}
// We don't need to sort members if there is only 1, and we don't care about
- // sorting the initial class because everything either gets out of it or is
+ // sorting the INITIAL class because everything either gets out of it or is
// unreachable.
if (OldClass->Members.size() == 1 || OldClass == InitialClass) {
OldClass->RepLeader = *(OldClass->Members.begin());
void NewGVN::performCongruenceFinding(Instruction *I, const Expression *E) {
ValueToExpression[I] = E;
// This is guaranteed to return something, since it will at least find
- // INITIAL.
+ // TOP.
CongruenceClass *IClass = ValueToClass[I];
assert(IClass && "Should have found a IClass");
}
// The algorithm initially places the values of the routine in the INITIAL
-// congruence
-// class. The leader of INITIAL is the undetermined value `TOP`.
+// congruence class. The leader of INITIAL is the undetermined value `TOP`.
// When the algorithm has finished, values still in INITIAL are unreachable.
void NewGVN::initializeCongruenceClasses(Function &F) {
// FIXME now i can't remember why this is 2
MemoryAccessToClass[MP] = InitialClass;
for (auto &I : B) {
- InitialValues.insert(&I);
- ValueToClass[&I] = InitialClass;
+ // Don't insert void terminators into the class
+ if (!isa<TerminatorInst>(I) || !I.getType()->isVoidTy()) {
+ InitialValues.insert(&I);
+ ValueToClass[&I] = InitialClass;
+ }
// All memory accesses are equivalent to live on entry to start. They must
// be initialized to something so that initial changes are noticed. For
// the maximal answer, we initialize them all to be the same as
performCongruenceFinding(I, Symbolized);
} else {
// Handle terminators that return values. All of them produce values we
- // don't currently understand.
+ // don't currently understand. We don't place non-value producing
+ // terminators in a class.
if (!I->getType()->isVoidTy()) {
auto *Symbolized = createUnknownExpression(I);
performCongruenceFinding(I, Symbolized);
// dead store elimination.
SmallVector<ValueDFS, 8> PossibleDeadStores;
- // FIXME: We should eventually be able to replace everything still
- // in the initial class with undef, as they should be unreachable.
- // Right now, initial still contains some things we skip value
- // numbering of (UNREACHABLE's, for example).
- if (CC == InitialClass || CC->Dead)
+ if (CC->Dead)
continue;
+ // Everything still in the INITIAL class is unreachable or dead.
+ if (CC == InitialClass) {
+#ifndef NDEBUG
+ for (auto M : CC->Members)
+ assert((!ReachableBlocks.count(cast<Instruction>(M)->getParent()) ||
+ InstructionsToErase.count(cast<Instruction>(M))) &&
+ "Everything in INITIAL should be unreachable or dead at this "
+ "point");
+#endif
+ continue;
+ }
+
assert(CC->RepLeader && "We should have had a leader");
// If this is a leader that is always available, and it's a
}
;; This is an irreducible test case that will cause a memoryphi node loop
-;; in the two block.
-;; it's equivalent to something like
+;; in the two blocks.
+;; It's equivalent to something like
;; *a = 0
;; if (<....>) goto loopmiddle
;; loopstart:
;; Both loads should equal 0, but it requires being
;; completely optimistic about MemoryPhis, otherwise
;; we will not be able to see through the cycle.
-define i8 @quux(i8* noalias %arg, i8* noalias %arg2) {
-; CHECK-LABEL: @quux(
+define i8 @irreducible_memoryphi(i8* noalias %arg, i8* noalias %arg2) {
+; CHECK-LABEL: @irreducible_memoryphi(
; CHECK-NEXT: bb:
; CHECK-NEXT: store i8 0, i8* [[ARG:%.*]]
; CHECK-NEXT: br i1 undef, label [[BB2:%.*]], label [[BB1:%.*]]
%tmp3 = add i8 %tmp, %tmp2
ret i8 %tmp3
}
+;; This is an irreducible test case that will cause a phi node loop
+;; in the two blocks
+;;
+;; It should return 0, but it requires being
+;; completely optimistic about phis, otherwise
+;; we will not be able to see through the cycle.
+define i32 @irreducible_phi(i32 %arg) {
+; CHECK-LABEL: @irreducible_phi(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: br i1 undef, label [[BB2:%.*]], label [[BB1:%.*]]
+; CHECK: bb1:
+; CHECK-NEXT: br label [[BB2]]
+; CHECK: bb2:
+; CHECK-NEXT: br i1 undef, label [[BB1]], label [[BB3:%.*]]
+; CHECK: bb3:
+; CHECK-NEXT: ret i32 0
+;
+bb:
+ %tmp = add i32 0, %arg
+ br i1 undef, label %bb2, label %bb1
+
+bb1: ; preds = %bb2, %bb
+ %phi1 = phi i32 [%tmp, %bb], [%phi2, %bb2]
+ br label %bb2
+
+bb2: ; preds = %bb1, %bb
+ %phi2 = phi i32 [%tmp, %bb], [%phi1, %bb1]
+ br i1 undef, label %bb1, label %bb3
+
+bb3: ; preds = %bb2
+ ; This should be zero
+ %tmp3 = sub i32 %tmp, %phi2
+ ret i32 %tmp3
+}
attributes #0 = { nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.ident = !{!0, !0, !0}