bool Scalarizer::visitGetElementPtrInst(GetElementPtrInst &GEPI) { VectorType *VT = dyn_cast<VectorType>(GEPI.getType()); if (!VT) return false; IRBuilder<> Builder(&GEPI); unsigned NumElems = VT->getNumElements(); unsigned NumIndices = GEPI.getNumIndices(); Scatterer Base = scatter(&GEPI, GEPI.getOperand(0)); SmallVector<Scatterer, 8> Ops; Ops.resize(NumIndices); for (unsigned I = 0; I < NumIndices; ++I) Ops[I] = scatter(&GEPI, GEPI.getOperand(I + 1)); ValueVector Res; Res.resize(NumElems); for (unsigned I = 0; I < NumElems; ++I) { SmallVector<Value *, 8> Indices; Indices.resize(NumIndices); for (unsigned J = 0; J < NumIndices; ++J) Indices[J] = Ops[J][I]; Res[I] = Builder.CreateGEP(GEPI.getSourceElementType(), Base[I], Indices, GEPI.getName() + ".i" + Twine(I)); if (GEPI.isInBounds()) if (GetElementPtrInst *NewGEPI = dyn_cast<GetElementPtrInst>(Res[I])) NewGEPI->setIsInBounds(); } gather(&GEPI, Res); return true; }
// Returns a clone of `I` with its operands converted to those specified in // ValueWithNewAddrSpace. Due to potential cycles in the data flow graph, an // operand whose address space needs to be modified might not exist in // ValueWithNewAddrSpace. In that case, uses undef as a placeholder operand and // adds that operand use to UndefUsesToFix so that caller can fix them later. // // Note that we do not necessarily clone `I`, e.g., if it is an addrspacecast // from a pointer whose type already matches. Therefore, this function returns a // Value* instead of an Instruction*. static Value *cloneInstructionWithNewAddressSpace( Instruction *I, unsigned NewAddrSpace, const ValueToValueMapTy &ValueWithNewAddrSpace, SmallVectorImpl<const Use *> *UndefUsesToFix) { Type *NewPtrType = I->getType()->getPointerElementType()->getPointerTo(NewAddrSpace); if (I->getOpcode() == Instruction::AddrSpaceCast) { Value *Src = I->getOperand(0); // Because `I` is flat, the source address space must be specific. // Therefore, the inferred address space must be the source space, according // to our algorithm. assert(Src->getType()->getPointerAddressSpace() == NewAddrSpace); if (Src->getType() != NewPtrType) return new BitCastInst(Src, NewPtrType); return Src; } // Computes the converted pointer operands. SmallVector<Value *, 4> NewPointerOperands; for (const Use &OperandUse : I->operands()) { if (!OperandUse.get()->getType()->isPointerTy()) NewPointerOperands.push_back(nullptr); else NewPointerOperands.push_back(operandWithNewAddressSpaceOrCreateUndef( OperandUse, NewAddrSpace, ValueWithNewAddrSpace, UndefUsesToFix)); } switch (I->getOpcode()) { case Instruction::BitCast: return new BitCastInst(NewPointerOperands[0], NewPtrType); case Instruction::PHI: { assert(I->getType()->isPointerTy()); PHINode *PHI = cast<PHINode>(I); PHINode *NewPHI = PHINode::Create(NewPtrType, PHI->getNumIncomingValues()); for (unsigned Index = 0; Index < PHI->getNumIncomingValues(); ++Index) { unsigned OperandNo = PHINode::getOperandNumForIncomingValue(Index); NewPHI->addIncoming(NewPointerOperands[OperandNo], PHI->getIncomingBlock(Index)); } return NewPHI; } case Instruction::GetElementPtr: { GetElementPtrInst *GEP = cast<GetElementPtrInst>(I); GetElementPtrInst *NewGEP = GetElementPtrInst::Create( GEP->getSourceElementType(), NewPointerOperands[0], SmallVector<Value *, 4>(GEP->idx_begin(), GEP->idx_end())); NewGEP->setIsInBounds(GEP->isInBounds()); return NewGEP; } case Instruction::Select: { assert(I->getType()->isPointerTy()); return SelectInst::Create(I->getOperand(0), NewPointerOperands[1], NewPointerOperands[2], "", nullptr, I); } default: llvm_unreachable("Unexpected opcode"); } }
bool EfficiencySanitizer::instrumentGetElementPtr(Instruction *I, Module &M) { GetElementPtrInst *GepInst = dyn_cast<GetElementPtrInst>(I); bool Res = false; if (GepInst == nullptr || GepInst->getNumIndices() == 1) { ++NumIgnoredGEPs; return false; } Type *SourceTy = GepInst->getSourceElementType(); StructType *StructTy = nullptr; ConstantInt *Idx; // Check if GEP calculates address from a struct array. if (isa<StructType>(SourceTy)) { StructTy = cast<StructType>(SourceTy); Idx = dyn_cast<ConstantInt>(GepInst->getOperand(1)); if ((Idx == nullptr || Idx->getSExtValue() != 0) && !shouldIgnoreStructType(StructTy) && StructTyMap.count(StructTy) != 0) Res |= insertCounterUpdate(I, StructTy, getArrayCounterIdx(StructTy)); } // Iterate all (except the first and the last) idx within each GEP instruction // for possible nested struct field address calculation. for (unsigned i = 1; i < GepInst->getNumIndices(); ++i) { SmallVector<Value *, 8> IdxVec(GepInst->idx_begin(), GepInst->idx_begin() + i); Type *Ty = GetElementPtrInst::getIndexedType(SourceTy, IdxVec); unsigned CounterIdx = 0; if (isa<ArrayType>(Ty)) { ArrayType *ArrayTy = cast<ArrayType>(Ty); StructTy = dyn_cast<StructType>(ArrayTy->getElementType()); if (shouldIgnoreStructType(StructTy) || StructTyMap.count(StructTy) == 0) continue; // The last counter for struct array access. CounterIdx = getArrayCounterIdx(StructTy); } else if (isa<StructType>(Ty)) { StructTy = cast<StructType>(Ty); if (shouldIgnoreStructType(StructTy) || StructTyMap.count(StructTy) == 0) continue; // Get the StructTy's subfield index. Idx = cast<ConstantInt>(GepInst->getOperand(i+1)); assert(Idx->getSExtValue() >= 0 && Idx->getSExtValue() < StructTy->getNumElements()); CounterIdx = getFieldCounterIdx(StructTy) + Idx->getSExtValue(); } Res |= insertCounterUpdate(I, StructTy, CounterIdx); } if (Res) ++NumInstrumentedGEPs; else ++NumIgnoredGEPs; return Res; }
Value *PropagateJuliaAddrspaces::LiftPointer(Value *V, Type *LocTy, Instruction *InsertPt) { SmallVector<Value *, 4> Stack; Value *CurrentV = V; // Follow pointer casts back, see if we're based on a pointer in // an untracked address space, in which case we're allowed to drop // intermediate addrspace casts. while (true) { Stack.push_back(CurrentV); if (isa<BitCastInst>(CurrentV)) CurrentV = cast<BitCastInst>(CurrentV)->getOperand(0); else if (isa<AddrSpaceCastInst>(CurrentV)) { CurrentV = cast<AddrSpaceCastInst>(CurrentV)->getOperand(0); if (!isSpecialAS(getValueAddrSpace(CurrentV))) break; } else if (isa<GetElementPtrInst>(CurrentV)) { if (LiftingMap.count(CurrentV)) { CurrentV = LiftingMap[CurrentV]; break; } else if (Visited.count(CurrentV)) { return nullptr; } Visited.insert(CurrentV); CurrentV = cast<GetElementPtrInst>(CurrentV)->getOperand(0); } else break; } if (!CurrentV->getType()->isPointerTy()) return nullptr; if (isSpecialAS(getValueAddrSpace(CurrentV))) return nullptr; // Ok, we're allowed to change the address space of this load, go back and // reconstitute any GEPs in the new address space. for (Value *V : llvm::reverse(Stack)) { GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V); if (!GEP) continue; if (LiftingMap.count(GEP)) { CurrentV = LiftingMap[GEP]; continue; } GetElementPtrInst *NewGEP = cast<GetElementPtrInst>(GEP->clone()); ToInsert.push_back(std::make_pair(NewGEP, GEP)); Type *GEPTy = GEP->getSourceElementType(); Type *NewRetTy = cast<PointerType>(GEP->getType())->getElementType()->getPointerTo(getValueAddrSpace(CurrentV)); NewGEP->mutateType(NewRetTy); if (cast<PointerType>(CurrentV->getType())->getElementType() != GEPTy) { auto *BCI = new BitCastInst(CurrentV, GEPTy->getPointerTo()); ToInsert.push_back(std::make_pair(BCI, NewGEP)); CurrentV = BCI; } NewGEP->setOperand(GetElementPtrInst::getPointerOperandIndex(), CurrentV); LiftingMap[GEP] = NewGEP; CurrentV = NewGEP; } if (LocTy && cast<PointerType>(CurrentV->getType())->getElementType() != LocTy) { auto *BCI = new BitCastInst(CurrentV, LocTy->getPointerTo()); ToInsert.push_back(std::make_pair(BCI, InsertPt)); CurrentV = BCI; } return CurrentV; }