diff options
Diffstat (limited to 'lib/Transforms/Scalar/RewriteStatepointsForGC.cpp')
-rw-r--r-- | lib/Transforms/Scalar/RewriteStatepointsForGC.cpp | 1035 |
1 files changed, 359 insertions, 676 deletions
diff --git a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index d77d5745e60c..bab39a32677f 100644 --- a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -14,7 +14,6 @@ #include "llvm/Pass.h" #include "llvm/Analysis/CFG.h" -#include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/Statistic.h" @@ -63,7 +62,7 @@ static cl::opt<unsigned> RematerializationThreshold("spp-rematerialization-threshold", cl::Hidden, cl::init(6)); -#ifdef XDEBUG +#ifdef EXPENSIVE_CHECKS static bool ClobberNonLive = true; #else static bool ClobberNonLive = false; @@ -72,19 +71,10 @@ static cl::opt<bool, true> ClobberNonLiveOverride("rs4gc-clobber-non-live", cl::location(ClobberNonLive), cl::Hidden); -static cl::opt<bool> UseDeoptBundles("rs4gc-use-deopt-bundles", cl::Hidden, - cl::init(false)); static cl::opt<bool> AllowStatepointWithNoDeoptInfo("rs4gc-allow-statepoint-with-no-deopt-info", cl::Hidden, cl::init(true)); -/// Should we split vectors of pointers into their individual elements? This -/// is known to be buggy, but the alternate implementation isn't yet ready. -/// This is purely to provide a debugging and dianostic hook until the vector -/// split is replaced with vector relocations. -static cl::opt<bool> UseVectorSplit("rs4gc-split-vector-values", cl::Hidden, - cl::init(true)); - namespace { struct RewriteStatepointsForGC : public ModulePass { static char ID; // Pass identification, replacement for typeid @@ -141,24 +131,25 @@ ModulePass *llvm::createRewriteStatepointsForGCPass() { INITIALIZE_PASS_BEGIN(RewriteStatepointsForGC, "rewrite-statepoints-for-gc", "Make relocations explicit at statepoints", false, false) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_END(RewriteStatepointsForGC, "rewrite-statepoints-for-gc", "Make relocations explicit at statepoints", false, false) namespace { struct GCPtrLivenessData { /// Values defined in this block. - DenseMap<BasicBlock *, DenseSet<Value *>> KillSet; + MapVector<BasicBlock *, SetVector<Value *>> KillSet; /// Values used in this block (and thus live); does not included values /// killed within this block. - DenseMap<BasicBlock *, DenseSet<Value *>> LiveSet; + MapVector<BasicBlock *, SetVector<Value *>> LiveSet; /// Values live into this basic block (i.e. used by any /// instruction in this basic block or ones reachable from here) - DenseMap<BasicBlock *, DenseSet<Value *>> LiveIn; + MapVector<BasicBlock *, SetVector<Value *>> LiveIn; /// Values live out of this basic block (i.e. live into /// any successor block) - DenseMap<BasicBlock *, DenseSet<Value *>> LiveOut; + MapVector<BasicBlock *, SetVector<Value *>> LiveOut; }; // The type of the internal cache used inside the findBasePointers family @@ -171,9 +162,9 @@ struct GCPtrLivenessData { // Generally, after the execution of a full findBasePointer call, only the // base relation will remain. Internally, we add a mixture of the two // types, then update all the second type to the first type -typedef DenseMap<Value *, Value *> DefiningValueMapTy; -typedef DenseSet<Value *> StatepointLiveSetTy; -typedef DenseMap<AssertingVH<Instruction>, AssertingVH<Value>> +typedef MapVector<Value *, Value *> DefiningValueMapTy; +typedef SetVector<Value *> StatepointLiveSetTy; +typedef MapVector<AssertingVH<Instruction>, AssertingVH<Value>> RematerializedValueMapTy; struct PartiallyConstructedSafepointRecord { @@ -181,7 +172,7 @@ struct PartiallyConstructedSafepointRecord { StatepointLiveSetTy LiveSet; /// Mapping from live pointers to a base-defining-value - DenseMap<Value *, Value *> PointerToBase; + MapVector<Value *, Value *> PointerToBase; /// The *new* gc.statepoint instruction itself. This produces the token /// that normal path gc.relocates and the gc.result are tied to. @@ -199,9 +190,8 @@ struct PartiallyConstructedSafepointRecord { } static ArrayRef<Use> GetDeoptBundleOperands(ImmutableCallSite CS) { - assert(UseDeoptBundles && "Should not be called otherwise!"); - - Optional<OperandBundleUse> DeoptBundle = CS.getOperandBundle("deopt"); + Optional<OperandBundleUse> DeoptBundle = + CS.getOperandBundle(LLVMContext::OB_deopt); if (!DeoptBundle.hasValue()) { assert(AllowStatepointWithNoDeoptInfo && @@ -229,7 +219,7 @@ static bool isGCPointerType(Type *T) { // For the sake of this example GC, we arbitrarily pick addrspace(1) as our // GC managed heap. We know that a pointer into this heap needs to be // updated and that no other pointer does. - return (1 == PT->getAddressSpace()); + return PT->getAddressSpace() == 1; return false; } @@ -260,8 +250,7 @@ static bool containsGCPtrType(Type *Ty) { if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) return containsGCPtrType(AT->getElementType()); if (StructType *ST = dyn_cast<StructType>(Ty)) - return std::any_of(ST->subtypes().begin(), ST->subtypes().end(), - containsGCPtrType); + return any_of(ST->subtypes(), containsGCPtrType); return false; } @@ -273,19 +262,6 @@ static bool isUnhandledGCPointerType(Type *Ty) { } #endif -static bool order_by_name(Value *a, Value *b) { - if (a->hasName() && b->hasName()) { - return -1 == a->getName().compare(b->getName()); - } else if (a->hasName() && !b->hasName()) { - return true; - } else if (!a->hasName() && b->hasName()) { - return false; - } else { - // Better than nothing, but not stable - return a < b; - } -} - // Return the name of the value suffixed with the provided value, or if the // value didn't have a name, the default value specified. static std::string suffixed_name_or(Value *V, StringRef Suffix, @@ -297,30 +273,25 @@ static std::string suffixed_name_or(Value *V, StringRef Suffix, // given instruction. The analysis is performed immediately before the // given instruction. Values defined by that instruction are not considered // live. Values used by that instruction are considered live. -static void analyzeParsePointLiveness( - DominatorTree &DT, GCPtrLivenessData &OriginalLivenessData, - const CallSite &CS, PartiallyConstructedSafepointRecord &result) { - Instruction *inst = CS.getInstruction(); +static void +analyzeParsePointLiveness(DominatorTree &DT, + GCPtrLivenessData &OriginalLivenessData, CallSite CS, + PartiallyConstructedSafepointRecord &Result) { + Instruction *Inst = CS.getInstruction(); StatepointLiveSetTy LiveSet; - findLiveSetAtInst(inst, OriginalLivenessData, LiveSet); + findLiveSetAtInst(Inst, OriginalLivenessData, LiveSet); if (PrintLiveSet) { - // Note: This output is used by several of the test cases - // The order of elements in a set is not stable, put them in a vec and sort - // by name - SmallVector<Value *, 64> Temp; - Temp.insert(Temp.end(), LiveSet.begin(), LiveSet.end()); - std::sort(Temp.begin(), Temp.end(), order_by_name); - errs() << "Live Variables:\n"; - for (Value *V : Temp) + dbgs() << "Live Variables:\n"; + for (Value *V : LiveSet) dbgs() << " " << V->getName() << " " << *V << "\n"; } if (PrintLiveSetSize) { - errs() << "Safepoint For: " << CS.getCalledValue()->getName() << "\n"; - errs() << "Number live values: " << LiveSet.size() << "\n"; + dbgs() << "Safepoint For: " << CS.getCalledValue()->getName() << "\n"; + dbgs() << "Number live values: " << LiveSet.size() << "\n"; } - result.LiveSet = LiveSet; + Result.LiveSet = LiveSet; } static bool isKnownBaseResult(Value *V); @@ -372,8 +343,10 @@ findBaseDefiningValueOfVector(Value *I) { return BaseDefiningValueResult(I, true); if (isa<Constant>(I)) - // Constant vectors consist only of constant pointers. - return BaseDefiningValueResult(I, true); + // Base of constant vector consists only of constant null pointers. + // For reasoning see similar case inside 'findBaseDefiningValue' function. + return BaseDefiningValueResult(ConstantAggregateZero::get(I->getType()), + true); if (isa<LoadInst>(I)) return BaseDefiningValueResult(I, true); @@ -415,14 +388,20 @@ static BaseDefiningValueResult findBaseDefiningValue(Value *I) { // We should have never reached here if this argument isn't an gc value return BaseDefiningValueResult(I, true); - if (isa<Constant>(I)) + if (isa<Constant>(I)) { // We assume that objects with a constant base (e.g. a global) can't move // and don't need to be reported to the collector because they are always - // live. All constants have constant bases. Besides global references, all - // kinds of constants (e.g. undef, constant expressions, null pointers) can - // be introduced by the inliner or the optimizer, especially on dynamically - // dead paths. See e.g. test4 in constants.ll. - return BaseDefiningValueResult(I, true); + // live. Besides global references, all kinds of constants (e.g. undef, + // constant expressions, null pointers) can be introduced by the inliner or + // the optimizer, especially on dynamically dead paths. + // Here we treat all of them as having single null base. By doing this we + // trying to avoid problems reporting various conflicts in a form of + // "phi (const1, const2)" or "phi (const, regular gc ptr)". + // See constant.ll file for relevant test cases. + + return BaseDefiningValueResult( + ConstantPointerNull::get(cast<PointerType>(I->getType())), true); + } if (CastInst *CI = dyn_cast<CastInst>(I)) { Value *Def = CI->stripPointerCasts(); @@ -570,30 +549,36 @@ class BDVState { public: enum Status { Unknown, Base, Conflict }; - BDVState(Status s, Value *b = nullptr) : status(s), base(b) { - assert(status != Base || b); + BDVState() : Status(Unknown), BaseValue(nullptr) {} + + explicit BDVState(Status Status, Value *BaseValue = nullptr) + : Status(Status), BaseValue(BaseValue) { + assert(Status != Base || BaseValue); } - explicit BDVState(Value *b) : status(Base), base(b) {} - BDVState() : status(Unknown), base(nullptr) {} - Status getStatus() const { return status; } - Value *getBase() const { return base; } + explicit BDVState(Value *BaseValue) : Status(Base), BaseValue(BaseValue) {} + + Status getStatus() const { return Status; } + Value *getBaseValue() const { return BaseValue; } bool isBase() const { return getStatus() == Base; } bool isUnknown() const { return getStatus() == Unknown; } bool isConflict() const { return getStatus() == Conflict; } - bool operator==(const BDVState &other) const { - return base == other.base && status == other.status; + bool operator==(const BDVState &Other) const { + return BaseValue == Other.BaseValue && Status == Other.Status; } bool operator!=(const BDVState &other) const { return !(*this == other); } LLVM_DUMP_METHOD - void dump() const { print(dbgs()); dbgs() << '\n'; } - + void dump() const { + print(dbgs()); + dbgs() << '\n'; + } + void print(raw_ostream &OS) const { - switch (status) { + switch (getStatus()) { case Unknown: OS << "U"; break; @@ -604,13 +589,13 @@ public: OS << "C"; break; }; - OS << " (" << base << " - " - << (base ? base->getName() : "nullptr") << "): "; + OS << " (" << getBaseValue() << " - " + << (getBaseValue() ? getBaseValue()->getName() : "nullptr") << "): "; } private: - Status status; - AssertingVH<Value> base; // non null only if status == base + Status Status; + AssertingVH<Value> BaseValue; // Non-null only if Status == Base. }; } @@ -621,75 +606,50 @@ static raw_ostream &operator<<(raw_ostream &OS, const BDVState &State) { } #endif -namespace { -// Values of type BDVState form a lattice, and this is a helper -// class that implementes the meet operation. The meat of the meet -// operation is implemented in MeetBDVStates::pureMeet -class MeetBDVStates { -public: - /// Initializes the currentResult to the TOP state so that if can be met with - /// any other state to produce that state. - MeetBDVStates() {} - - // Destructively meet the current result with the given BDVState - void meetWith(BDVState otherState) { - currentResult = meet(otherState, currentResult); - } +static BDVState meetBDVStateImpl(const BDVState &LHS, const BDVState &RHS) { + switch (LHS.getStatus()) { + case BDVState::Unknown: + return RHS; - BDVState getResult() const { return currentResult; } + case BDVState::Base: + assert(LHS.getBaseValue() && "can't be null"); + if (RHS.isUnknown()) + return LHS; -private: - BDVState currentResult; - - /// Perform a meet operation on two elements of the BDVState lattice. - static BDVState meet(BDVState LHS, BDVState RHS) { - assert((pureMeet(LHS, RHS) == pureMeet(RHS, LHS)) && - "math is wrong: meet does not commute!"); - BDVState Result = pureMeet(LHS, RHS); - DEBUG(dbgs() << "meet of " << LHS << " with " << RHS - << " produced " << Result << "\n"); - return Result; - } - - static BDVState pureMeet(const BDVState &stateA, const BDVState &stateB) { - switch (stateA.getStatus()) { - case BDVState::Unknown: - return stateB; - - case BDVState::Base: - assert(stateA.getBase() && "can't be null"); - if (stateB.isUnknown()) - return stateA; - - if (stateB.isBase()) { - if (stateA.getBase() == stateB.getBase()) { - assert(stateA == stateB && "equality broken!"); - return stateA; - } - return BDVState(BDVState::Conflict); + if (RHS.isBase()) { + if (LHS.getBaseValue() == RHS.getBaseValue()) { + assert(LHS == RHS && "equality broken!"); + return LHS; } - assert(stateB.isConflict() && "only three states!"); return BDVState(BDVState::Conflict); - - case BDVState::Conflict: - return stateA; } - llvm_unreachable("only three states!"); + assert(RHS.isConflict() && "only three states!"); + return BDVState(BDVState::Conflict); + + case BDVState::Conflict: + return LHS; } -}; + llvm_unreachable("only three states!"); } +// Values of type BDVState form a lattice, and this function implements the meet +// operation. +static BDVState meetBDVState(BDVState LHS, BDVState RHS) { + BDVState Result = meetBDVStateImpl(LHS, RHS); + assert(Result == meetBDVStateImpl(RHS, LHS) && + "Math is wrong: meet does not commute!"); + return Result; +} -/// For a given value or instruction, figure out what base ptr it's derived -/// from. For gc objects, this is simply itself. On success, returns a value -/// which is the base pointer. (This is reliable and can be used for -/// relocation.) On failure, returns nullptr. -static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { - Value *def = findBaseOrBDV(I, cache); +/// For a given value or instruction, figure out what base ptr its derived from. +/// For gc objects, this is simply itself. On success, returns a value which is +/// the base pointer. (This is reliable and can be used for relocation.) On +/// failure, returns nullptr. +static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) { + Value *Def = findBaseOrBDV(I, Cache); - if (isKnownBaseResult(def)) { - return def; - } + if (isKnownBaseResult(Def)) + return Def; // Here's the rough algorithm: // - For every SSA value, construct a mapping to either an actual base @@ -731,14 +691,14 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // one for which we don't already know a definite base value for /* scope */ { SmallVector<Value*, 16> Worklist; - Worklist.push_back(def); - States.insert(std::make_pair(def, BDVState())); + Worklist.push_back(Def); + States.insert({Def, BDVState()}); while (!Worklist.empty()) { Value *Current = Worklist.pop_back_val(); assert(!isKnownBaseResult(Current) && "why did it get added?"); auto visitIncomingValue = [&](Value *InVal) { - Value *Base = findBaseOrBDV(InVal, cache); + Value *Base = findBaseOrBDV(InVal, Cache); if (isKnownBaseResult(Base)) // Known bases won't need new instructions introduced and can be // ignored safely @@ -748,12 +708,12 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { if (States.insert(std::make_pair(Base, BDVState())).second) Worklist.push_back(Base); }; - if (PHINode *Phi = dyn_cast<PHINode>(Current)) { - for (Value *InVal : Phi->incoming_values()) + if (PHINode *PN = dyn_cast<PHINode>(Current)) { + for (Value *InVal : PN->incoming_values()) visitIncomingValue(InVal); - } else if (SelectInst *Sel = dyn_cast<SelectInst>(Current)) { - visitIncomingValue(Sel->getTrueValue()); - visitIncomingValue(Sel->getFalseValue()); + } else if (SelectInst *SI = dyn_cast<SelectInst>(Current)) { + visitIncomingValue(SI->getTrueValue()); + visitIncomingValue(SI->getFalseValue()); } else if (auto *EE = dyn_cast<ExtractElementInst>(Current)) { visitIncomingValue(EE->getVectorOperand()); } else if (auto *IE = dyn_cast<InsertElementInst>(Current)) { @@ -762,7 +722,7 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { } else { // There is one known class of instructions we know we don't handle. assert(isa<ShuffleVectorInst>(Current)); - llvm_unreachable("unimplemented instruction case"); + llvm_unreachable("Unimplemented instruction case"); } } } @@ -784,12 +744,12 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { return I->second; }; - bool progress = true; - while (progress) { + bool Progress = true; + while (Progress) { #ifndef NDEBUG - const size_t oldSize = States.size(); + const size_t OldSize = States.size(); #endif - progress = false; + Progress = false; // We're only changing values in this loop, thus safe to keep iterators. // Since this is computing a fixed point, the order of visit does not // effect the result. TODO: We could use a worklist here and make this run @@ -801,38 +761,39 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // Given an input value for the current instruction, return a BDVState // instance which represents the BDV of that value. auto getStateForInput = [&](Value *V) mutable { - Value *BDV = findBaseOrBDV(V, cache); + Value *BDV = findBaseOrBDV(V, Cache); return getStateForBDV(BDV); }; - MeetBDVStates calculateMeet; - if (SelectInst *select = dyn_cast<SelectInst>(BDV)) { - calculateMeet.meetWith(getStateForInput(select->getTrueValue())); - calculateMeet.meetWith(getStateForInput(select->getFalseValue())); - } else if (PHINode *Phi = dyn_cast<PHINode>(BDV)) { - for (Value *Val : Phi->incoming_values()) - calculateMeet.meetWith(getStateForInput(Val)); + BDVState NewState; + if (SelectInst *SI = dyn_cast<SelectInst>(BDV)) { + NewState = meetBDVState(NewState, getStateForInput(SI->getTrueValue())); + NewState = + meetBDVState(NewState, getStateForInput(SI->getFalseValue())); + } else if (PHINode *PN = dyn_cast<PHINode>(BDV)) { + for (Value *Val : PN->incoming_values()) + NewState = meetBDVState(NewState, getStateForInput(Val)); } else if (auto *EE = dyn_cast<ExtractElementInst>(BDV)) { // The 'meet' for an extractelement is slightly trivial, but it's still // useful in that it drives us to conflict if our input is. - calculateMeet.meetWith(getStateForInput(EE->getVectorOperand())); + NewState = + meetBDVState(NewState, getStateForInput(EE->getVectorOperand())); } else { // Given there's a inherent type mismatch between the operands, will // *always* produce Conflict. auto *IE = cast<InsertElementInst>(BDV); - calculateMeet.meetWith(getStateForInput(IE->getOperand(0))); - calculateMeet.meetWith(getStateForInput(IE->getOperand(1))); + NewState = meetBDVState(NewState, getStateForInput(IE->getOperand(0))); + NewState = meetBDVState(NewState, getStateForInput(IE->getOperand(1))); } - BDVState oldState = States[BDV]; - BDVState newState = calculateMeet.getResult(); - if (oldState != newState) { - progress = true; - States[BDV] = newState; + BDVState OldState = States[BDV]; + if (OldState != NewState) { + Progress = true; + States[BDV] = NewState; } } - assert(oldSize == States.size() && + assert(OldSize == States.size() && "fixed point shouldn't be adding any new nodes to state"); } @@ -842,7 +803,7 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { DEBUG(dbgs() << " " << Pair.second << " for " << *Pair.first << "\n"); } #endif - + // Insert Phis for all conflicts // TODO: adjust naming patterns to avoid this order of iteration dependency for (auto Pair : States) { @@ -856,14 +817,13 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // The problem is that we need to convert from a vector base to a scalar // base for the particular indice we're interested in. if (State.isBase() && isa<ExtractElementInst>(I) && - isa<VectorType>(State.getBase()->getType())) { + isa<VectorType>(State.getBaseValue()->getType())) { auto *EE = cast<ExtractElementInst>(I); // TODO: In many cases, the new instruction is just EE itself. We should // exploit this, but can't do it here since it would break the invariant // about the BDV not being known to be a base. - auto *BaseInst = ExtractElementInst::Create(State.getBase(), - EE->getIndexOperand(), - "base_ee", EE); + auto *BaseInst = ExtractElementInst::Create( + State.getBaseValue(), EE->getIndexOperand(), "base_ee", EE); BaseInst->setMetadata("is_base_value", MDNode::get(I->getContext(), {})); States[I] = BDVState(BDVState::Base, BaseInst); } @@ -871,10 +831,8 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // Since we're joining a vector and scalar base, they can never be the // same. As a result, we should always see insert element having reached // the conflict state. - if (isa<InsertElementInst>(I)) { - assert(State.isConflict()); - } - + assert(!isa<InsertElementInst>(I) || State.isConflict()); + if (!State.isConflict()) continue; @@ -887,12 +845,11 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { assert(NumPreds > 0 && "how did we reach here"); std::string Name = suffixed_name_or(I, ".base", "base_phi"); return PHINode::Create(I->getType(), NumPreds, Name, I); - } else if (SelectInst *Sel = dyn_cast<SelectInst>(I)) { + } else if (SelectInst *SI = dyn_cast<SelectInst>(I)) { // The undef will be replaced later - UndefValue *Undef = UndefValue::get(Sel->getType()); + UndefValue *Undef = UndefValue::get(SI->getType()); std::string Name = suffixed_name_or(I, ".base", "base_select"); - return SelectInst::Create(Sel->getCondition(), Undef, - Undef, Name, Sel); + return SelectInst::Create(SI->getCondition(), Undef, Undef, Name, SI); } else if (auto *EE = dyn_cast<ExtractElementInst>(I)) { UndefValue *Undef = UndefValue::get(EE->getVectorOperand()->getType()); std::string Name = suffixed_name_or(I, ".base", "base_ee"); @@ -906,7 +863,6 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { return InsertElementInst::Create(VecUndef, ScalarUndef, IE->getOperand(2), Name, IE); } - }; Instruction *BaseInst = MakeBaseInstPlaceholder(I); // Add metadata marking this as a base value @@ -921,24 +877,21 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // instruction to propagate the base of it's BDV and have entered that newly // introduced instruction into the state table. In either case, we are // assured to be able to determine an instruction which produces it's base - // pointer. + // pointer. auto getBaseForInput = [&](Value *Input, Instruction *InsertPt) { - Value *BDV = findBaseOrBDV(Input, cache); + Value *BDV = findBaseOrBDV(Input, Cache); Value *Base = nullptr; if (isKnownBaseResult(BDV)) { Base = BDV; } else { // Either conflict or base. assert(States.count(BDV)); - Base = States[BDV].getBase(); + Base = States[BDV].getBaseValue(); } - assert(Base && "can't be null"); + assert(Base && "Can't be null"); // The cast is needed since base traversal may strip away bitcasts - if (Base->getType() != Input->getType() && - InsertPt) { - Base = new BitCastInst(Base, Input->getType(), "cast", - InsertPt); - } + if (Base->getType() != Input->getType() && InsertPt) + Base = new BitCastInst(Base, Input->getType(), "cast", InsertPt); return Base; }; @@ -954,12 +907,12 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { if (!State.isConflict()) continue; - if (PHINode *basephi = dyn_cast<PHINode>(State.getBase())) { - PHINode *phi = cast<PHINode>(BDV); - unsigned NumPHIValues = phi->getNumIncomingValues(); + if (PHINode *BasePHI = dyn_cast<PHINode>(State.getBaseValue())) { + PHINode *PN = cast<PHINode>(BDV); + unsigned NumPHIValues = PN->getNumIncomingValues(); for (unsigned i = 0; i < NumPHIValues; i++) { - Value *InVal = phi->getIncomingValue(i); - BasicBlock *InBB = phi->getIncomingBlock(i); + Value *InVal = PN->getIncomingValue(i); + BasicBlock *InBB = PN->getIncomingBlock(i); // If we've already seen InBB, add the same incoming value // we added for it earlier. The IR verifier requires phi @@ -970,22 +923,21 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // bitcasts (and hence two distinct values) as incoming // values for the same basic block. - int blockIndex = basephi->getBasicBlockIndex(InBB); - if (blockIndex != -1) { - Value *oldBase = basephi->getIncomingValue(blockIndex); - basephi->addIncoming(oldBase, InBB); - + int BlockIndex = BasePHI->getBasicBlockIndex(InBB); + if (BlockIndex != -1) { + Value *OldBase = BasePHI->getIncomingValue(BlockIndex); + BasePHI->addIncoming(OldBase, InBB); + #ifndef NDEBUG Value *Base = getBaseForInput(InVal, nullptr); - // In essence this assert states: the only way two - // values incoming from the same basic block may be - // different is by being different bitcasts of the same - // value. A cleanup that remains TODO is changing - // findBaseOrBDV to return an llvm::Value of the correct - // type (and still remain pure). This will remove the - // need to add bitcasts. - assert(Base->stripPointerCasts() == oldBase->stripPointerCasts() && - "sanity -- findBaseOrBDV should be pure!"); + // In essence this assert states: the only way two values + // incoming from the same basic block may be different is by + // being different bitcasts of the same value. A cleanup + // that remains TODO is changing findBaseOrBDV to return an + // llvm::Value of the correct type (and still remain pure). + // This will remove the need to add bitcasts. + assert(Base->stripPointerCasts() == OldBase->stripPointerCasts() && + "Sanity -- findBaseOrBDV should be pure!"); #endif continue; } @@ -994,28 +946,25 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // need to insert a bitcast in the incoming block. // TODO: Need to split critical edges if insertion is needed Value *Base = getBaseForInput(InVal, InBB->getTerminator()); - basephi->addIncoming(Base, InBB); + BasePHI->addIncoming(Base, InBB); } - assert(basephi->getNumIncomingValues() == NumPHIValues); - } else if (SelectInst *BaseSel = dyn_cast<SelectInst>(State.getBase())) { - SelectInst *Sel = cast<SelectInst>(BDV); - // Operand 1 & 2 are true, false path respectively. TODO: refactor to - // something more safe and less hacky. - for (int i = 1; i <= 2; i++) { - Value *InVal = Sel->getOperand(i); - // Find the instruction which produces the base for each input. We may - // need to insert a bitcast. - Value *Base = getBaseForInput(InVal, BaseSel); - BaseSel->setOperand(i, Base); - } - } else if (auto *BaseEE = dyn_cast<ExtractElementInst>(State.getBase())) { + assert(BasePHI->getNumIncomingValues() == NumPHIValues); + } else if (SelectInst *BaseSI = + dyn_cast<SelectInst>(State.getBaseValue())) { + SelectInst *SI = cast<SelectInst>(BDV); + + // Find the instruction which produces the base for each input. + // We may need to insert a bitcast. + BaseSI->setTrueValue(getBaseForInput(SI->getTrueValue(), BaseSI)); + BaseSI->setFalseValue(getBaseForInput(SI->getFalseValue(), BaseSI)); + } else if (auto *BaseEE = + dyn_cast<ExtractElementInst>(State.getBaseValue())) { Value *InVal = cast<ExtractElementInst>(BDV)->getVectorOperand(); // Find the instruction which produces the base for each input. We may // need to insert a bitcast. - Value *Base = getBaseForInput(InVal, BaseEE); - BaseEE->setOperand(0, Base); + BaseEE->setOperand(0, getBaseForInput(InVal, BaseEE)); } else { - auto *BaseIE = cast<InsertElementInst>(State.getBase()); + auto *BaseIE = cast<InsertElementInst>(State.getBaseValue()); auto *BdvIE = cast<InsertElementInst>(BDV); auto UpdateOperand = [&](int OperandIdx) { Value *InVal = BdvIE->getOperand(OperandIdx); @@ -1025,69 +974,6 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { UpdateOperand(0); // vector operand UpdateOperand(1); // scalar operand } - - } - - // Now that we're done with the algorithm, see if we can optimize the - // results slightly by reducing the number of new instructions needed. - // Arguably, this should be integrated into the algorithm above, but - // doing as a post process step is easier to reason about for the moment. - DenseMap<Value *, Value *> ReverseMap; - SmallPtrSet<Instruction *, 16> NewInsts; - SmallSetVector<AssertingVH<Instruction>, 16> Worklist; - // Note: We need to visit the states in a deterministic order. We uses the - // Keys we sorted above for this purpose. Note that we are papering over a - // bigger problem with the algorithm above - it's visit order is not - // deterministic. A larger change is needed to fix this. - for (auto Pair : States) { - auto *BDV = Pair.first; - auto State = Pair.second; - Value *Base = State.getBase(); - assert(BDV && Base); - assert(!isKnownBaseResult(BDV) && "why did it get added?"); - assert(isKnownBaseResult(Base) && - "must be something we 'know' is a base pointer"); - if (!State.isConflict()) - continue; - - ReverseMap[Base] = BDV; - if (auto *BaseI = dyn_cast<Instruction>(Base)) { - NewInsts.insert(BaseI); - Worklist.insert(BaseI); - } - } - auto ReplaceBaseInstWith = [&](Value *BDV, Instruction *BaseI, - Value *Replacement) { - // Add users which are new instructions (excluding self references) - for (User *U : BaseI->users()) - if (auto *UI = dyn_cast<Instruction>(U)) - if (NewInsts.count(UI) && UI != BaseI) - Worklist.insert(UI); - // Then do the actual replacement - NewInsts.erase(BaseI); - ReverseMap.erase(BaseI); - BaseI->replaceAllUsesWith(Replacement); - assert(States.count(BDV)); - assert(States[BDV].isConflict() && States[BDV].getBase() == BaseI); - States[BDV] = BDVState(BDVState::Conflict, Replacement); - BaseI->eraseFromParent(); - }; - const DataLayout &DL = cast<Instruction>(def)->getModule()->getDataLayout(); - while (!Worklist.empty()) { - Instruction *BaseI = Worklist.pop_back_val(); - assert(NewInsts.count(BaseI)); - Value *Bdv = ReverseMap[BaseI]; - if (auto *BdvI = dyn_cast<Instruction>(Bdv)) - if (BaseI->isIdenticalTo(BdvI)) { - DEBUG(dbgs() << "Identical Base: " << *BaseI << "\n"); - ReplaceBaseInstWith(Bdv, BaseI, Bdv); - continue; - } - if (Value *V = SimplifyInstruction(BaseI, DL)) { - DEBUG(dbgs() << "Base " << *BaseI << " simplified to " << *V << "\n"); - ReplaceBaseInstWith(Bdv, BaseI, V); - continue; - } } // Cache all of our results so we can cheaply reuse them @@ -1095,25 +981,27 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // relation and one of the base pointer relation! FIXME for (auto Pair : States) { auto *BDV = Pair.first; - Value *base = Pair.second.getBase(); - assert(BDV && base); + Value *Base = Pair.second.getBaseValue(); + assert(BDV && Base); + assert(!isKnownBaseResult(BDV) && "why did it get added?"); - std::string fromstr = cache.count(BDV) ? cache[BDV]->getName() : "none"; DEBUG(dbgs() << "Updating base value cache" - << " for: " << BDV->getName() - << " from: " << fromstr - << " to: " << base->getName() << "\n"); - - if (cache.count(BDV)) { - // Once we transition from the BDV relation being store in the cache to + << " for: " << BDV->getName() << " from: " + << (Cache.count(BDV) ? Cache[BDV]->getName().str() : "none") + << " to: " << Base->getName() << "\n"); + + if (Cache.count(BDV)) { + assert(isKnownBaseResult(Base) && + "must be something we 'know' is a base pointer"); + // Once we transition from the BDV relation being store in the Cache to // the base relation being stored, it must be stable - assert((!isKnownBaseResult(cache[BDV]) || cache[BDV] == base) && + assert((!isKnownBaseResult(Cache[BDV]) || Cache[BDV] == Base) && "base relation should be stable"); } - cache[BDV] = base; + Cache[BDV] = Base; } - assert(cache.count(def)); - return cache[def]; + assert(Cache.count(Def)); + return Cache[Def]; } // For a set of live pointers (base and/or derived), identify the base @@ -1133,15 +1021,9 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &cache) { // pointer was a base pointer. static void findBasePointers(const StatepointLiveSetTy &live, - DenseMap<Value *, Value *> &PointerToBase, + MapVector<Value *, Value *> &PointerToBase, DominatorTree *DT, DefiningValueMapTy &DVCache) { - // For the naming of values inserted to be deterministic - which makes for - // much cleaner and more stable tests - we need to assign an order to the - // live values. DenseSets do not provide a deterministic order across runs. - SmallVector<Value *, 64> Temp; - Temp.insert(Temp.end(), live.begin(), live.end()); - std::sort(Temp.begin(), Temp.end(), order_by_name); - for (Value *ptr : Temp) { + for (Value *ptr : live) { Value *base = findBasePointer(ptr, DVCache); assert(base && "failed to find base pointer"); PointerToBase[ptr] = base; @@ -1149,41 +1031,24 @@ findBasePointers(const StatepointLiveSetTy &live, DT->dominates(cast<Instruction>(base)->getParent(), cast<Instruction>(ptr)->getParent())) && "The base we found better dominate the derived pointer"); - - // If you see this trip and like to live really dangerously, the code should - // be correct, just with idioms the verifier can't handle. You can try - // disabling the verifier at your own substantial risk. - assert(!isa<ConstantPointerNull>(base) && - "the relocation code needs adjustment to handle the relocation of " - "a null pointer constant without causing false positives in the " - "safepoint ir verifier."); } } /// Find the required based pointers (and adjust the live set) for the given /// parse point. static void findBasePointers(DominatorTree &DT, DefiningValueMapTy &DVCache, - const CallSite &CS, + CallSite CS, PartiallyConstructedSafepointRecord &result) { - DenseMap<Value *, Value *> PointerToBase; + MapVector<Value *, Value *> PointerToBase; findBasePointers(result.LiveSet, PointerToBase, &DT, DVCache); if (PrintBasePointers) { - // Note: Need to print these in a stable order since this is checked in - // some tests. errs() << "Base Pairs (w/o Relocation):\n"; - SmallVector<Value *, 64> Temp; - Temp.reserve(PointerToBase.size()); - for (auto Pair : PointerToBase) { - Temp.push_back(Pair.first); - } - std::sort(Temp.begin(), Temp.end(), order_by_name); - for (Value *Ptr : Temp) { - Value *Base = PointerToBase[Ptr]; + for (auto &Pair : PointerToBase) { errs() << " derived "; - Ptr->printAsOperand(errs(), false); + Pair.first->printAsOperand(errs(), false); errs() << " base "; - Base->printAsOperand(errs(), false); + Pair.second->printAsOperand(errs(), false); errs() << "\n";; } } @@ -1194,7 +1059,7 @@ static void findBasePointers(DominatorTree &DT, DefiningValueMapTy &DVCache, /// Given an updated version of the dataflow liveness results, update the /// liveset and base pointer maps for the call site CS. static void recomputeLiveInValues(GCPtrLivenessData &RevisedLivenessData, - const CallSite &CS, + CallSite CS, PartiallyConstructedSafepointRecord &result); static void recomputeLiveInValues( @@ -1206,8 +1071,7 @@ static void recomputeLiveInValues( computeLiveInValues(DT, F, RevisedLivenessData); for (size_t i = 0; i < records.size(); i++) { struct PartiallyConstructedSafepointRecord &info = records[i]; - const CallSite &CS = toUpdate[i]; - recomputeLiveInValues(RevisedLivenessData, CS, info); + recomputeLiveInValues(RevisedLivenessData, toUpdate[i], info); } } @@ -1257,8 +1121,7 @@ static AttributeSet legalizeCallAttributes(AttributeSet AS) { // These attributes control the generation of the gc.statepoint call / // invoke itself; and once the gc.statepoint is in place, they're of no // use. - if (Attr.hasAttribute("statepoint-num-patch-bytes") || - Attr.hasAttribute("statepoint-id")) + if (isStatepointDirectiveAttr(Attr)) continue; Ret = Ret.addAttributes( @@ -1349,11 +1212,37 @@ namespace { class DeferredReplacement { AssertingVH<Instruction> Old; AssertingVH<Instruction> New; + bool IsDeoptimize = false; + + DeferredReplacement() {} public: - explicit DeferredReplacement(Instruction *Old, Instruction *New) : - Old(Old), New(New) { - assert(Old != New && "Not allowed!"); + static DeferredReplacement createRAUW(Instruction *Old, Instruction *New) { + assert(Old != New && Old && New && + "Cannot RAUW equal values or to / from null!"); + + DeferredReplacement D; + D.Old = Old; + D.New = New; + return D; + } + + static DeferredReplacement createDelete(Instruction *ToErase) { + DeferredReplacement D; + D.Old = ToErase; + return D; + } + + static DeferredReplacement createDeoptimizeReplacement(Instruction *Old) { +#ifndef NDEBUG + auto *F = cast<CallInst>(Old)->getCalledFunction(); + assert(F && F->getIntrinsicID() == Intrinsic::experimental_deoptimize && + "Only way to construct a deoptimize deferred replacement"); +#endif + DeferredReplacement D; + D.Old = Old; + D.IsDeoptimize = true; + return D; } /// Does the task represented by this instance. @@ -1362,12 +1251,23 @@ public: Instruction *NewI = New; assert(OldI != NewI && "Disallowed at construction?!"); + assert((!IsDeoptimize || !New) && + "Deoptimize instrinsics are not replaced!"); Old = nullptr; New = nullptr; if (NewI) OldI->replaceAllUsesWith(NewI); + + if (IsDeoptimize) { + // Note: we've inserted instructions, so the call to llvm.deoptimize may + // not necessarilly be followed by the matching return. + auto *RI = cast<ReturnInst>(OldI->getParent()->getTerminator()); + new UnreachableInst(RI->getContext(), RI); + RI->eraseFromParent(); + } + OldI->eraseFromParent(); } }; @@ -1380,8 +1280,6 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ PartiallyConstructedSafepointRecord &Result, std::vector<DeferredReplacement> &Replacements) { assert(BasePtrs.size() == LiveVariables.size()); - assert((UseDeoptBundles || isStatepoint(CS)) && - "This method expects to be rewriting a statepoint"); // Then go ahead and use the builder do actually do the inserts. We insert // immediately before the previous instruction under the assumption that all @@ -1391,47 +1289,53 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ IRBuilder<> Builder(InsertBefore); ArrayRef<Value *> GCArgs(LiveVariables); - uint64_t StatepointID = 0xABCDEF00; + uint64_t StatepointID = StatepointDirectives::DefaultStatepointID; uint32_t NumPatchBytes = 0; uint32_t Flags = uint32_t(StatepointFlags::None); - ArrayRef<Use> CallArgs; - ArrayRef<Use> DeoptArgs; + ArrayRef<Use> CallArgs(CS.arg_begin(), CS.arg_end()); + ArrayRef<Use> DeoptArgs = GetDeoptBundleOperands(CS); ArrayRef<Use> TransitionArgs; - - Value *CallTarget = nullptr; - - if (UseDeoptBundles) { - CallArgs = {CS.arg_begin(), CS.arg_end()}; - DeoptArgs = GetDeoptBundleOperands(CS); - // TODO: we don't fill in TransitionArgs or Flags in this branch, but we - // could have an operand bundle for that too. - AttributeSet OriginalAttrs = CS.getAttributes(); - - Attribute AttrID = OriginalAttrs.getAttribute(AttributeSet::FunctionIndex, - "statepoint-id"); - if (AttrID.isStringAttribute()) - AttrID.getValueAsString().getAsInteger(10, StatepointID); - - Attribute AttrNumPatchBytes = OriginalAttrs.getAttribute( - AttributeSet::FunctionIndex, "statepoint-num-patch-bytes"); - if (AttrNumPatchBytes.isStringAttribute()) - AttrNumPatchBytes.getValueAsString().getAsInteger(10, NumPatchBytes); - - CallTarget = CS.getCalledValue(); - } else { - // This branch will be gone soon, and we will soon only support the - // UseDeoptBundles == true configuration. - Statepoint OldSP(CS); - StatepointID = OldSP.getID(); - NumPatchBytes = OldSP.getNumPatchBytes(); - Flags = OldSP.getFlags(); - - CallArgs = {OldSP.arg_begin(), OldSP.arg_end()}; - DeoptArgs = {OldSP.vm_state_begin(), OldSP.vm_state_end()}; - TransitionArgs = {OldSP.gc_transition_args_begin(), - OldSP.gc_transition_args_end()}; - CallTarget = OldSP.getCalledValue(); + if (auto TransitionBundle = + CS.getOperandBundle(LLVMContext::OB_gc_transition)) { + Flags |= uint32_t(StatepointFlags::GCTransition); + TransitionArgs = TransitionBundle->Inputs; + } + + // Instead of lowering calls to @llvm.experimental.deoptimize as normal calls + // with a return value, we lower then as never returning calls to + // __llvm_deoptimize that are followed by unreachable to get better codegen. + bool IsDeoptimize = false; + + StatepointDirectives SD = + parseStatepointDirectivesFromAttrs(CS.getAttributes()); + if (SD.NumPatchBytes) + NumPatchBytes = *SD.NumPatchBytes; + if (SD.StatepointID) + StatepointID = *SD.StatepointID; + + Value *CallTarget = CS.getCalledValue(); + if (Function *F = dyn_cast<Function>(CallTarget)) { + if (F->getIntrinsicID() == Intrinsic::experimental_deoptimize) { + // Calls to llvm.experimental.deoptimize are lowered to calls to the + // __llvm_deoptimize symbol. We want to resolve this now, since the + // verifier does not allow taking the address of an intrinsic function. + + SmallVector<Type *, 8> DomainTy; + for (Value *Arg : CallArgs) + DomainTy.push_back(Arg->getType()); + auto *FTy = FunctionType::get(Type::getVoidTy(F->getContext()), DomainTy, + /* isVarArg = */ false); + + // Note: CallTarget can be a bitcast instruction of a symbol if there are + // calls to @llvm.experimental.deoptimize with different argument types in + // the same module. This is fine -- we assume the frontend knew what it + // was doing when generating this kind of IR. + CallTarget = + F->getParent()->getOrInsertFunction("__llvm_deoptimize", FTy); + + IsDeoptimize = true; + } } // Create the statepoint given all the arguments @@ -1514,7 +1418,13 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ } assert(Token && "Should be set in one of the above branches!"); - if (UseDeoptBundles) { + if (IsDeoptimize) { + // If we're wrapping an @llvm.experimental.deoptimize in a statepoint, we + // transform the tail-call like structure to a call to a void function + // followed by unreachable to get better codegen. + Replacements.push_back( + DeferredReplacement::createDeoptimizeReplacement(CS.getInstruction())); + } else { Token->setName("statepoint_token"); if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) { StringRef Name = @@ -1528,24 +1438,12 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ // llvm::Instruction. Instead, we defer the replacement and deletion to // after the live sets have been made explicit in the IR, and we no longer // have raw pointers to worry about. - Replacements.emplace_back(CS.getInstruction(), GCResult); + Replacements.emplace_back( + DeferredReplacement::createRAUW(CS.getInstruction(), GCResult)); } else { - Replacements.emplace_back(CS.getInstruction(), nullptr); + Replacements.emplace_back( + DeferredReplacement::createDelete(CS.getInstruction())); } - } else { - assert(!CS.getInstruction()->hasNUsesOrMore(2) && - "only valid use before rewrite is gc.result"); - assert(!CS.getInstruction()->hasOneUse() || - isGCResult(cast<Instruction>(*CS.getInstruction()->user_begin()))); - - // Take the name of the original statepoint token if there was one. - Token->takeName(CS.getInstruction()); - - // Update the gc.result of the original statepoint (if any) to use the newly - // inserted statepoint. This is safe to do here since the token can't be - // considered a live reference. - CS.getInstruction()->replaceAllUsesWith(Token); - CS.getInstruction()->eraseFromParent(); } Result.StatepointToken = Token; @@ -1555,43 +1453,13 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ CreateGCRelocates(LiveVariables, LiveStartIdx, BasePtrs, Token, Builder); } -namespace { -struct NameOrdering { - Value *Base; - Value *Derived; - - bool operator()(NameOrdering const &a, NameOrdering const &b) { - return -1 == a.Derived->getName().compare(b.Derived->getName()); - } -}; -} - -static void StabilizeOrder(SmallVectorImpl<Value *> &BaseVec, - SmallVectorImpl<Value *> &LiveVec) { - assert(BaseVec.size() == LiveVec.size()); - - SmallVector<NameOrdering, 64> Temp; - for (size_t i = 0; i < BaseVec.size(); i++) { - NameOrdering v; - v.Base = BaseVec[i]; - v.Derived = LiveVec[i]; - Temp.push_back(v); - } - - std::sort(Temp.begin(), Temp.end(), NameOrdering()); - for (size_t i = 0; i < BaseVec.size(); i++) { - BaseVec[i] = Temp[i].Base; - LiveVec[i] = Temp[i].Derived; - } -} - // Replace an existing gc.statepoint with a new one and a set of gc.relocates // which make the relocations happening at this safepoint explicit. // // WARNING: Does not do any fixup to adjust users of the original live // values. That's the callers responsibility. static void -makeStatepointExplicit(DominatorTree &DT, const CallSite &CS, +makeStatepointExplicit(DominatorTree &DT, CallSite CS, PartiallyConstructedSafepointRecord &Result, std::vector<DeferredReplacement> &Replacements) { const auto &LiveSet = Result.LiveSet; @@ -1609,11 +1477,6 @@ makeStatepointExplicit(DominatorTree &DT, const CallSite &CS, } assert(LiveVec.size() == BaseVec.size()); - // To make the output IR slightly more stable (for use in diffs), ensure a - // fixed order of the values in the safepoint (by sorting the value name). - // The order is otherwise meaningless. - StabilizeOrder(BaseVec, LiveVec); - // Do the actual rewriting and delete the old statepoint makeStatepointExplicitImpl(CS, BaseVec, LiveVec, Result, Replacements); } @@ -1634,7 +1497,7 @@ insertRelocationStores(iterator_range<Value::user_iterator> GCRelocs, if (!Relocate) continue; - Value *OriginalValue = const_cast<Value *>(Relocate->getDerivedPtr()); + Value *OriginalValue = Relocate->getDerivedPtr(); assert(AllocaMap.count(OriginalValue)); Value *Alloca = AllocaMap[OriginalValue]; @@ -1660,11 +1523,10 @@ insertRelocationStores(iterator_range<Value::user_iterator> GCRelocs, // Helper function for the "relocationViaAlloca". Similar to the // "insertRelocationStores" but works for rematerialized values. -static void -insertRematerializationStores( - RematerializedValueMapTy RematerializedValues, - DenseMap<Value *, Value *> &AllocaMap, - DenseSet<Value *> &VisitedLiveValues) { +static void insertRematerializationStores( + const RematerializedValueMapTy &RematerializedValues, + DenseMap<Value *, Value *> &AllocaMap, + DenseSet<Value *> &VisitedLiveValues) { for (auto RematerializedValuePair: RematerializedValues) { Instruction *RematerializedValue = RematerializedValuePair.first; @@ -1691,9 +1553,8 @@ static void relocationViaAlloca( // record initial number of (static) allocas; we'll check we have the same // number when we get done. int InitialAllocaNum = 0; - for (auto I = F.getEntryBlock().begin(), E = F.getEntryBlock().end(); I != E; - I++) - if (isa<AllocaInst>(*I)) + for (Instruction &I : F.getEntryBlock()) + if (isa<AllocaInst>(I)) InitialAllocaNum++; #endif @@ -1777,8 +1638,7 @@ static void relocationViaAlloca( auto InsertClobbersAt = [&](Instruction *IP) { for (auto *AI : ToClobber) { - auto AIType = cast<PointerType>(AI->getType()); - auto PT = cast<PointerType>(AIType->getElementType()); + auto PT = cast<PointerType>(AI->getAllocatedType()); Constant *CPN = ConstantPointerNull::get(PT); StoreInst *Store = new StoreInst(CPN, AI); Store->insertBefore(IP); @@ -1919,141 +1779,7 @@ static void findLiveReferences( computeLiveInValues(DT, F, OriginalLivenessData); for (size_t i = 0; i < records.size(); i++) { struct PartiallyConstructedSafepointRecord &info = records[i]; - const CallSite &CS = toUpdate[i]; - analyzeParsePointLiveness(DT, OriginalLivenessData, CS, info); - } -} - -/// Remove any vector of pointers from the live set by scalarizing them over the -/// statepoint instruction. Adds the scalarized pieces to the live set. It -/// would be preferable to include the vector in the statepoint itself, but -/// the lowering code currently does not handle that. Extending it would be -/// slightly non-trivial since it requires a format change. Given how rare -/// such cases are (for the moment?) scalarizing is an acceptable compromise. -static void splitVectorValues(Instruction *StatepointInst, - StatepointLiveSetTy &LiveSet, - DenseMap<Value *, Value *>& PointerToBase, - DominatorTree &DT) { - SmallVector<Value *, 16> ToSplit; - for (Value *V : LiveSet) - if (isa<VectorType>(V->getType())) - ToSplit.push_back(V); - - if (ToSplit.empty()) - return; - - DenseMap<Value *, SmallVector<Value *, 16>> ElementMapping; - - Function &F = *(StatepointInst->getParent()->getParent()); - - DenseMap<Value *, AllocaInst *> AllocaMap; - // First is normal return, second is exceptional return (invoke only) - DenseMap<Value *, std::pair<Value *, Value *>> Replacements; - for (Value *V : ToSplit) { - AllocaInst *Alloca = - new AllocaInst(V->getType(), "", F.getEntryBlock().getFirstNonPHI()); - AllocaMap[V] = Alloca; - - VectorType *VT = cast<VectorType>(V->getType()); - IRBuilder<> Builder(StatepointInst); - SmallVector<Value *, 16> Elements; - for (unsigned i = 0; i < VT->getNumElements(); i++) - Elements.push_back(Builder.CreateExtractElement(V, Builder.getInt32(i))); - ElementMapping[V] = Elements; - - auto InsertVectorReform = [&](Instruction *IP) { - Builder.SetInsertPoint(IP); - Builder.SetCurrentDebugLocation(IP->getDebugLoc()); - Value *ResultVec = UndefValue::get(VT); - for (unsigned i = 0; i < VT->getNumElements(); i++) - ResultVec = Builder.CreateInsertElement(ResultVec, Elements[i], - Builder.getInt32(i)); - return ResultVec; - }; - - if (isa<CallInst>(StatepointInst)) { - BasicBlock::iterator Next(StatepointInst); - Next++; - Instruction *IP = &*(Next); - Replacements[V].first = InsertVectorReform(IP); - Replacements[V].second = nullptr; - } else { - InvokeInst *Invoke = cast<InvokeInst>(StatepointInst); - // We've already normalized - check that we don't have shared destination - // blocks - BasicBlock *NormalDest = Invoke->getNormalDest(); - assert(!isa<PHINode>(NormalDest->begin())); - BasicBlock *UnwindDest = Invoke->getUnwindDest(); - assert(!isa<PHINode>(UnwindDest->begin())); - // Insert insert element sequences in both successors - Instruction *IP = &*(NormalDest->getFirstInsertionPt()); - Replacements[V].first = InsertVectorReform(IP); - IP = &*(UnwindDest->getFirstInsertionPt()); - Replacements[V].second = InsertVectorReform(IP); - } - } - - for (Value *V : ToSplit) { - AllocaInst *Alloca = AllocaMap[V]; - - // Capture all users before we start mutating use lists - SmallVector<Instruction *, 16> Users; - for (User *U : V->users()) - Users.push_back(cast<Instruction>(U)); - - for (Instruction *I : Users) { - if (auto Phi = dyn_cast<PHINode>(I)) { - for (unsigned i = 0; i < Phi->getNumIncomingValues(); i++) - if (V == Phi->getIncomingValue(i)) { - LoadInst *Load = new LoadInst( - Alloca, "", Phi->getIncomingBlock(i)->getTerminator()); - Phi->setIncomingValue(i, Load); - } - } else { - LoadInst *Load = new LoadInst(Alloca, "", I); - I->replaceUsesOfWith(V, Load); - } - } - - // Store the original value and the replacement value into the alloca - StoreInst *Store = new StoreInst(V, Alloca); - if (auto I = dyn_cast<Instruction>(V)) - Store->insertAfter(I); - else - Store->insertAfter(Alloca); - - // Normal return for invoke, or call return - Instruction *Replacement = cast<Instruction>(Replacements[V].first); - (new StoreInst(Replacement, Alloca))->insertAfter(Replacement); - // Unwind return for invoke only - Replacement = cast_or_null<Instruction>(Replacements[V].second); - if (Replacement) - (new StoreInst(Replacement, Alloca))->insertAfter(Replacement); - } - - // apply mem2reg to promote alloca to SSA - SmallVector<AllocaInst *, 16> Allocas; - for (Value *V : ToSplit) - Allocas.push_back(AllocaMap[V]); - PromoteMemToReg(Allocas, DT); - - // Update our tracking of live pointers and base mappings to account for the - // changes we just made. - for (Value *V : ToSplit) { - auto &Elements = ElementMapping[V]; - - LiveSet.erase(V); - LiveSet.insert(Elements.begin(), Elements.end()); - // We need to update the base mapping as well. - assert(PointerToBase.count(V)); - Value *OldBase = PointerToBase[V]; - auto &BaseElements = ElementMapping[OldBase]; - PointerToBase.erase(V); - assert(Elements.size() == BaseElements.size()); - for (unsigned i = 0; i < Elements.size(); i++) { - Value *Elem = Elements[i]; - PointerToBase[Elem] = BaseElements[i]; - } + analyzeParsePointLiveness(DT, OriginalLivenessData, toUpdate[i], info); } } @@ -2109,7 +1835,7 @@ chainToBasePointerCost(SmallVectorImpl<Instruction*> &Chain, } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Instr)) { // Cost of the address calculation - Type *ValTy = GEP->getPointerOperandType()->getPointerElementType(); + Type *ValTy = GEP->getSourceElementType(); Cost += TTI.getAddressComputationCost(ValTy); // And cost of the GEP itself @@ -2244,7 +1970,7 @@ static void rematerializeLiveValues(CallSite CS, // Remove rematerializaed values from the live set for (auto LiveValue: LiveValuesToBeDeleted) { - Info.LiveSet.erase(LiveValue); + Info.LiveSet.remove(LiveValue); } } @@ -2257,11 +1983,8 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, Uniqued.insert(ToUpdate.begin(), ToUpdate.end()); assert(Uniqued.size() == ToUpdate.size() && "no duplicates please!"); - for (CallSite CS : ToUpdate) { - assert(CS.getInstruction()->getParent()->getParent() == &F); - assert((UseDeoptBundles || isStatepoint(CS)) && - "expected to already be a deopt statepoint"); - } + for (CallSite CS : ToUpdate) + assert(CS.getInstruction()->getFunction() == &F); #endif // When inserting gc.relocates for invokes, we need to be able to insert at @@ -2287,12 +2010,7 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, for (CallSite CS : ToUpdate) { SmallVector<Value *, 64> DeoptValues; - iterator_range<const Use *> DeoptStateRange = - UseDeoptBundles - ? iterator_range<const Use *>(GetDeoptBundleOperands(CS)) - : iterator_range<const Use *>(Statepoint(CS).vm_state_args()); - - for (Value *Arg : DeoptStateRange) { + for (Value *Arg : GetDeoptBundleOperands(CS)) { assert(!isUnhandledGCPointerType(Arg->getType()) && "support for FCA unimplemented"); if (isHandledGCPointerType(Arg->getType())) @@ -2374,29 +2092,13 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, for (auto &Info : Records) for (auto &BasePair : Info.PointerToBase) if (isa<Constant>(BasePair.second)) - Info.LiveSet.erase(BasePair.first); + Info.LiveSet.remove(BasePair.first); for (CallInst *CI : Holders) CI->eraseFromParent(); Holders.clear(); - // Do a limited scalarization of any live at safepoint vector values which - // contain pointers. This enables this pass to run after vectorization at - // the cost of some possible performance loss. Note: This is known to not - // handle updating of the side tables correctly which can lead to relocation - // bugs when the same vector is live at multiple statepoints. We're in the - // process of implementing the alternate lowering - relocating the - // vector-of-pointers as first class item and updating the backend to - // understand that - but that's not yet complete. - if (UseVectorSplit) - for (size_t i = 0; i < Records.size(); i++) { - PartiallyConstructedSafepointRecord &Info = Records[i]; - Instruction *Statepoint = ToUpdate[i].getInstruction(); - splitVectorValues(cast<Instruction>(Statepoint), Info.LiveSet, - Info.PointerToBase, DT); - } - // In order to reduce live set of statepoint we might choose to rematerialize // some values instead of relocating them. This is purely an optimization and // does not influence correctness. @@ -2592,13 +2294,9 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F) { getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); auto NeedsRewrite = [](Instruction &I) { - if (UseDeoptBundles) { - if (ImmutableCallSite CS = ImmutableCallSite(&I)) - return !callsGCLeafFunction(CS); - return false; - } - - return isStatepoint(I); + if (ImmutableCallSite CS = ImmutableCallSite(&I)) + return !callsGCLeafFunction(CS) && !isStatepoint(CS); + return false; }; // Gather all the statepoints which need rewritten. Be careful to only @@ -2682,15 +2380,12 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F) { /// Compute the live-in set for the location rbegin starting from /// the live-out set of the basic block -static void computeLiveInValues(BasicBlock::reverse_iterator rbegin, - BasicBlock::reverse_iterator rend, - DenseSet<Value *> &LiveTmp) { - - for (BasicBlock::reverse_iterator ritr = rbegin; ritr != rend; ritr++) { - Instruction *I = &*ritr; - +static void computeLiveInValues(BasicBlock::reverse_iterator Begin, + BasicBlock::reverse_iterator End, + SetVector<Value *> &LiveTmp) { + for (auto &I : make_range(Begin, End)) { // KILL/Def - Remove this definition from LiveIn - LiveTmp.erase(I); + LiveTmp.remove(&I); // Don't consider *uses* in PHI nodes, we handle their contribution to // predecessor blocks when we seed the LiveOut sets @@ -2698,7 +2393,7 @@ static void computeLiveInValues(BasicBlock::reverse_iterator rbegin, continue; // USE - Add to the LiveIn set for this instruction - for (Value *V : I->operands()) { + for (Value *V : I.operands()) { assert(!isUnhandledGCPointerType(V->getType()) && "support for FCA unimplemented"); if (isHandledGCPointerType(V->getType()) && !isa<Constant>(V)) { @@ -2718,24 +2413,24 @@ static void computeLiveInValues(BasicBlock::reverse_iterator rbegin, } } -static void computeLiveOutSeed(BasicBlock *BB, DenseSet<Value *> &LiveTmp) { - +static void computeLiveOutSeed(BasicBlock *BB, SetVector<Value *> &LiveTmp) { for (BasicBlock *Succ : successors(BB)) { - const BasicBlock::iterator E(Succ->getFirstNonPHI()); - for (BasicBlock::iterator I = Succ->begin(); I != E; I++) { - PHINode *Phi = cast<PHINode>(&*I); - Value *V = Phi->getIncomingValueForBlock(BB); + for (auto &I : *Succ) { + PHINode *PN = dyn_cast<PHINode>(&I); + if (!PN) + break; + + Value *V = PN->getIncomingValueForBlock(BB); assert(!isUnhandledGCPointerType(V->getType()) && "support for FCA unimplemented"); - if (isHandledGCPointerType(V->getType()) && !isa<Constant>(V)) { + if (isHandledGCPointerType(V->getType()) && !isa<Constant>(V)) LiveTmp.insert(V); - } } } } -static DenseSet<Value *> computeKillSet(BasicBlock *BB) { - DenseSet<Value *> KillSet; +static SetVector<Value *> computeKillSet(BasicBlock *BB) { + SetVector<Value *> KillSet; for (Instruction &I : *BB) if (isHandledGCPointerType(I.getType())) KillSet.insert(&I); @@ -2745,7 +2440,7 @@ static DenseSet<Value *> computeKillSet(BasicBlock *BB) { #ifndef NDEBUG /// Check that the items in 'Live' dominate 'TI'. This is used as a basic /// sanity check for the liveness computation. -static void checkBasicSSA(DominatorTree &DT, DenseSet<Value *> &Live, +static void checkBasicSSA(DominatorTree &DT, SetVector<Value *> &Live, TerminatorInst *TI, bool TermOkay = false) { for (Value *V : Live) { if (auto *I = dyn_cast<Instruction>(V)) { @@ -2773,17 +2468,7 @@ static void checkBasicSSA(DominatorTree &DT, GCPtrLivenessData &Data, static void computeLiveInValues(DominatorTree &DT, Function &F, GCPtrLivenessData &Data) { - - SmallSetVector<BasicBlock *, 200> Worklist; - auto AddPredsToWorklist = [&](BasicBlock *BB) { - // We use a SetVector so that we don't have duplicates in the worklist. - Worklist.insert(pred_begin(BB), pred_end(BB)); - }; - auto NextItem = [&]() { - BasicBlock *BB = Worklist.back(); - Worklist.pop_back(); - return BB; - }; + SmallSetVector<BasicBlock *, 32> Worklist; // Seed the liveness for each individual block for (BasicBlock &BB : F) { @@ -2796,56 +2481,55 @@ static void computeLiveInValues(DominatorTree &DT, Function &F, assert(!Data.LiveSet[&BB].count(Kill) && "live set contains kill"); #endif - Data.LiveOut[&BB] = DenseSet<Value *>(); + Data.LiveOut[&BB] = SetVector<Value *>(); computeLiveOutSeed(&BB, Data.LiveOut[&BB]); Data.LiveIn[&BB] = Data.LiveSet[&BB]; - set_union(Data.LiveIn[&BB], Data.LiveOut[&BB]); - set_subtract(Data.LiveIn[&BB], Data.KillSet[&BB]); + Data.LiveIn[&BB].set_union(Data.LiveOut[&BB]); + Data.LiveIn[&BB].set_subtract(Data.KillSet[&BB]); if (!Data.LiveIn[&BB].empty()) - AddPredsToWorklist(&BB); + Worklist.insert(pred_begin(&BB), pred_end(&BB)); } // Propagate that liveness until stable while (!Worklist.empty()) { - BasicBlock *BB = NextItem(); + BasicBlock *BB = Worklist.pop_back_val(); - // Compute our new liveout set, then exit early if it hasn't changed - // despite the contribution of our successor. - DenseSet<Value *> LiveOut = Data.LiveOut[BB]; + // Compute our new liveout set, then exit early if it hasn't changed despite + // the contribution of our successor. + SetVector<Value *> LiveOut = Data.LiveOut[BB]; const auto OldLiveOutSize = LiveOut.size(); for (BasicBlock *Succ : successors(BB)) { assert(Data.LiveIn.count(Succ)); - set_union(LiveOut, Data.LiveIn[Succ]); + LiveOut.set_union(Data.LiveIn[Succ]); } // assert OutLiveOut is a subset of LiveOut if (OldLiveOutSize == LiveOut.size()) { // If the sets are the same size, then we didn't actually add anything - // when unioning our successors LiveIn Thus, the LiveIn of this block + // when unioning our successors LiveIn. Thus, the LiveIn of this block // hasn't changed. continue; } Data.LiveOut[BB] = LiveOut; // Apply the effects of this basic block - DenseSet<Value *> LiveTmp = LiveOut; - set_union(LiveTmp, Data.LiveSet[BB]); - set_subtract(LiveTmp, Data.KillSet[BB]); + SetVector<Value *> LiveTmp = LiveOut; + LiveTmp.set_union(Data.LiveSet[BB]); + LiveTmp.set_subtract(Data.KillSet[BB]); assert(Data.LiveIn.count(BB)); - const DenseSet<Value *> &OldLiveIn = Data.LiveIn[BB]; + const SetVector<Value *> &OldLiveIn = Data.LiveIn[BB]; // assert: OldLiveIn is a subset of LiveTmp if (OldLiveIn.size() != LiveTmp.size()) { Data.LiveIn[BB] = LiveTmp; - AddPredsToWorklist(BB); + Worklist.insert(pred_begin(BB), pred_end(BB)); } - } // while( !worklist.empty() ) + } // while (!Worklist.empty()) #ifndef NDEBUG // Sanity check our output against SSA properties. This helps catch any // missing kills during the above iteration. - for (BasicBlock &BB : F) { + for (BasicBlock &BB : F) checkBasicSSA(DT, Data, BB); - } #endif } @@ -2856,7 +2540,7 @@ static void findLiveSetAtInst(Instruction *Inst, GCPtrLivenessData &Data, // Note: The copy is intentional and required assert(Data.LiveOut.count(BB)); - DenseSet<Value *> LiveOut = Data.LiveOut[BB]; + SetVector<Value *> LiveOut = Data.LiveOut[BB]; // We want to handle the statepoint itself oddly. It's // call result is not live (normal), nor are it's arguments @@ -2864,12 +2548,12 @@ static void findLiveSetAtInst(Instruction *Inst, GCPtrLivenessData &Data, // specifically what we need to relocate BasicBlock::reverse_iterator rend(Inst->getIterator()); computeLiveInValues(BB->rbegin(), rend, LiveOut); - LiveOut.erase(Inst); + LiveOut.remove(Inst); Out.insert(LiveOut.begin(), LiveOut.end()); } static void recomputeLiveInValues(GCPtrLivenessData &RevisedLivenessData, - const CallSite &CS, + CallSite CS, PartiallyConstructedSafepointRecord &Info) { Instruction *Inst = CS.getInstruction(); StatepointLiveSetTy Updated; @@ -2877,33 +2561,32 @@ static void recomputeLiveInValues(GCPtrLivenessData &RevisedLivenessData, #ifndef NDEBUG DenseSet<Value *> Bases; - for (auto KVPair : Info.PointerToBase) { + for (auto KVPair : Info.PointerToBase) Bases.insert(KVPair.second); - } #endif + // We may have base pointers which are now live that weren't before. We need // to update the PointerToBase structure to reflect this. for (auto V : Updated) - if (!Info.PointerToBase.count(V)) { - assert(Bases.count(V) && "can't find base for unexpected live value"); - Info.PointerToBase[V] = V; + if (Info.PointerToBase.insert({V, V}).second) { + assert(Bases.count(V) && "Can't find base for unexpected live value!"); continue; } #ifndef NDEBUG - for (auto V : Updated) { + for (auto V : Updated) assert(Info.PointerToBase.count(V) && - "must be able to find base for live value"); - } + "Must be able to find base for live value!"); #endif // Remove any stale base mappings - this can happen since our liveness is - // more precise then the one inherent in the base pointer analysis + // more precise then the one inherent in the base pointer analysis. DenseSet<Value *> ToErase; for (auto KVPair : Info.PointerToBase) if (!Updated.count(KVPair.first)) ToErase.insert(KVPair.first); - for (auto V : ToErase) + + for (auto *V : ToErase) Info.PointerToBase.erase(V); #ifndef NDEBUG |