GetElementPtrInst * NaryReassociate::tryReassociateGEPAtIndex(GetElementPtrInst *GEP, unsigned I, Value *LHS, Value *RHS, Type *IndexedType) { // Look for GEP's closest dominator that has the same SCEV as GEP except that // the I-th index is replaced with LHS. SmallVector<const SCEV *, 4> IndexExprs; for (auto Index = GEP->idx_begin(); Index != GEP->idx_end(); ++Index) IndexExprs.push_back(SE->getSCEV(*Index)); // Replace the I-th index with LHS. IndexExprs[I] = SE->getSCEV(LHS); const SCEV *CandidateExpr = SE->getGEPExpr( GEP->getSourceElementType(), SE->getSCEV(GEP->getPointerOperand()), IndexExprs, GEP->isInBounds()); auto *Candidate = findClosestMatchingDominator(CandidateExpr, GEP); if (Candidate == nullptr) return nullptr; PointerType *TypeOfCandidate = dyn_cast<PointerType>(Candidate->getType()); // Pretty rare but theoretically possible when a numeric value happens to // share CandidateExpr. if (TypeOfCandidate == nullptr) return nullptr; // NewGEP = (char *)Candidate + RHS * sizeof(IndexedType) uint64_t IndexedSize = DL->getTypeAllocSize(IndexedType); Type *ElementType = TypeOfCandidate->getElementType(); uint64_t ElementSize = DL->getTypeAllocSize(ElementType); // Another less rare case: because I is not necessarily the last index of the // GEP, the size of the type at the I-th index (IndexedSize) is not // necessarily divisible by ElementSize. For example, // // #pragma pack(1) // struct S { // int a[3]; // int64 b[8]; // }; // #pragma pack() // // sizeof(S) = 100 is indivisible by sizeof(int64) = 8. // // TODO: bail out on this case for now. We could emit uglygep. if (IndexedSize % ElementSize != 0) return nullptr; // NewGEP = &Candidate[RHS * (sizeof(IndexedType) / sizeof(Candidate[0]))); IRBuilder<> Builder(GEP); Type *IntPtrTy = DL->getIntPtrType(TypeOfCandidate); if (RHS->getType() != IntPtrTy) RHS = Builder.CreateSExtOrTrunc(RHS, IntPtrTy); if (IndexedSize != ElementSize) { RHS = Builder.CreateMul( RHS, ConstantInt::get(IntPtrTy, IndexedSize / ElementSize)); } GetElementPtrInst *NewGEP = cast<GetElementPtrInst>(Builder.CreateGEP(Candidate, RHS)); NewGEP->setIsInBounds(GEP->isInBounds()); NewGEP->takeName(GEP); return NewGEP; }
GetElementPtrInst * NaryReassociatePass::tryReassociateGEPAtIndex(GetElementPtrInst *GEP, unsigned I, Value *LHS, Value *RHS, Type *IndexedType) { // Look for GEP's closest dominator that has the same SCEV as GEP except that // the I-th index is replaced with LHS. SmallVector<const SCEV *, 4> IndexExprs; for (auto Index = GEP->idx_begin(); Index != GEP->idx_end(); ++Index) IndexExprs.push_back(SE->getSCEV(*Index)); // Replace the I-th index with LHS. IndexExprs[I] = SE->getSCEV(LHS); if (isKnownNonNegative(LHS, *DL, 0, AC, GEP, DT) && DL->getTypeSizeInBits(LHS->getType()) < DL->getTypeSizeInBits(GEP->getOperand(I)->getType())) { // Zero-extend LHS if it is non-negative. InstCombine canonicalizes sext to // zext if the source operand is proved non-negative. We should do that // consistently so that CandidateExpr more likely appears before. See // @reassociate_gep_assume for an example of this canonicalization. IndexExprs[I] = SE->getZeroExtendExpr(IndexExprs[I], GEP->getOperand(I)->getType()); } const SCEV *CandidateExpr = SE->getGEPExpr(cast<GEPOperator>(GEP), IndexExprs); Value *Candidate = findClosestMatchingDominator(CandidateExpr, GEP); if (Candidate == nullptr) return nullptr; IRBuilder<> Builder(GEP); // Candidate does not necessarily have the same pointer type as GEP. Use // bitcast or pointer cast to make sure they have the same type, so that the // later RAUW doesn't complain. Candidate = Builder.CreateBitOrPointerCast(Candidate, GEP->getType()); assert(Candidate->getType() == GEP->getType()); // NewGEP = (char *)Candidate + RHS * sizeof(IndexedType) uint64_t IndexedSize = DL->getTypeAllocSize(IndexedType); Type *ElementType = GEP->getResultElementType(); uint64_t ElementSize = DL->getTypeAllocSize(ElementType); // Another less rare case: because I is not necessarily the last index of the // GEP, the size of the type at the I-th index (IndexedSize) is not // necessarily divisible by ElementSize. For example, // // #pragma pack(1) // struct S { // int a[3]; // int64 b[8]; // }; // #pragma pack() // // sizeof(S) = 100 is indivisible by sizeof(int64) = 8. // // TODO: bail out on this case for now. We could emit uglygep. if (IndexedSize % ElementSize != 0) return nullptr; // NewGEP = &Candidate[RHS * (sizeof(IndexedType) / sizeof(Candidate[0]))); Type *IntPtrTy = DL->getIntPtrType(GEP->getType()); if (RHS->getType() != IntPtrTy) RHS = Builder.CreateSExtOrTrunc(RHS, IntPtrTy); if (IndexedSize != ElementSize) { RHS = Builder.CreateMul( RHS, ConstantInt::get(IntPtrTy, IndexedSize / ElementSize)); } GetElementPtrInst *NewGEP = cast<GetElementPtrInst>(Builder.CreateGEP(Candidate, RHS)); NewGEP->setIsInBounds(GEP->isInBounds()); NewGEP->takeName(GEP); return NewGEP; }