Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2079,6 +2079,47 @@ GEP.getName()); } + // Combine opaque pointer GEPs having source array type with + // GEP having single index. + if (PtrTy->isOpaquePointerTy() && Src->getResultElementType()->isArrayTy() && + Src->getResultElementType() != GEP.getSourceElementType() && + GEP.getNumIndices() == 1) { + Type *SrcElemTy = GEP.getSourceElementType(); + Type *ResElemTy = Src->getResultElementType(); + Type *ElemTy = ResElemTy; + SmallVector NewIndices; + NewIndices.reserve(Src->getNumIndices() + GEP.getNumIndices()); + NewIndices.append(Src->idx_begin(), Src->idx_end()); + Type *IntIdxTy = DL.getIndexType(PtrTy); + unsigned BitWidth = DL.getTypeSizeInBits(IntIdxTy); + auto *Zero = + ConstantInt::get(Type::getIntNTy(Src->getContext(), BitWidth), 0); + + // Try to add additional zero indices to Src to make the + // Src ResultElementType match with GEP SourceElementType + while (ElemTy != SrcElemTy) { + Type *NextTy = GetElementPtrInst::getTypeAtIndex(ElemTy, (uint64_t)0); + if (!NextTy) + break; + NewIndices.push_back(Zero); + ElemTy = NextTy; + } + + // Combine the two Geps if Src ResultElementType now + // matches with GEP SourceElementType. + if (ElemTy == SrcElemTy) { + NewIndices.clear(); + NewIndices.append(Src->idx_begin(), Src->idx_end()); + NewIndices.append(GEP.idx_begin(), GEP.idx_end()); + bool IsInBounds = isMergedGEPInBounds(*Src, *cast(&GEP)); + GetElementPtrInst *NewGEP = GetElementPtrInst::Create( + Src->getSourceElementType(), Src->getOperand(0), NewIndices, + GEP.getName()); + NewGEP->setIsInBounds(IsInBounds); + return NewGEP; + } + } + if (Src->getResultElementType() != GEP.getSourceElementType()) return nullptr; Index: llvm/test/Transforms/InstCombine/opaque-ptr-gep-of-gep.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/opaque-ptr-gep-of-gep.ll @@ -0,0 +1,63 @@ +; RUN: opt -S -instcombine %s | FileCheck %s + +@ext1 = external hidden global [2 x [1 x float]] +@ext2 = external hidden global [2 x [2 x [1 x float]]] + +; Test to check if instcombine pass combines opaque pointer gepofgep with src array type +; and current gep having single index. +define void @gepofgep1(i64 %in1, i64 %in2, ptr %out) { +; CHECK-LABEL: @gepofgep1( +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [2 x [1 x float]], ptr [[EXT1:@.*]], i64 0, i64 [[IN1:%.*]], i64 [[IN2:%.*]] +; CHECK-NEXT: store ptr [[B]], ptr [[OUT:%.*]], align 8 +; CHECK-NEXT: ret void + + %a = getelementptr inbounds [2 x [1 x float]], ptr @ext1, i64 0, i64 %in1 + %b = getelementptr inbounds float, ptr %a, i64 %in2 + store ptr %b, ptr %out + ret void +} + +; Test to check if instcombine pass doesn't combine opaque pointer gepofgep with src array type +; and current gep having more than one index. +define void @gepofgep2(i64 %in1, i64 %in2, ptr %out) { +; CHECK-LABEL: @gepofgep2( +; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [2 x [2 x [1 x float]]], ptr [[EXT2:@.*]], i64 0, i64 [[IN1:%.*]] +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [1 x float], ptr [[A]], i64 0, i64 [[IN2:%.*]] +; CHECK-NEXT: store ptr [[B]], ptr [[OUT:%.*]], align 8 +; CHECK-NEXT: ret void + %a = getelementptr inbounds [2 x [2 x [1 x float]]], ptr @ext2, i64 0, i64 %in1 + %b = getelementptr inbounds [1 x float], ptr %a, i64 0, i64 %in2 + store ptr %b, ptr %out + ret void +} + +; Test to check if instcombine pass combines opaque pointer gepofgep with src of higher dimension array type +; and current gep having single index. +define void @gepofgep3(i64 %in1, i64 %in2, ptr %out) { +; CHECK-LABEL: @gepofgep3( +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [2 x [2 x [1 x float]]], ptr [[EXT2:@.*]], i64 [[IN1:%.*]], i64 [[IN2:%.*]] +; CHECK-NEXT: store ptr [[B]], ptr [[OUT:%.*]], align 8 +; CHECK-NEXT: ret void + %a = getelementptr inbounds [2 x [2 x [1 x float]]], ptr @ext2, i64 %in1 + %b = getelementptr inbounds float, ptr %a, i64 %in2 + store ptr %b, ptr %out + ret void +} + +; Test to check if instcombine pass combines opaque pointer gepofgep with src of array type having more than one user +; and current gep having single index. +define void @gepofgep4(i64 %in1, i64 %in2, ptr %out1, ptr %out2) { +; CHECK-LABEL: @gepofgep4( +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [2 x [1 x float]], ptr [[EXT1:@.*]], i64 0, i64 [[IN1:%.*]], i64 [[IN1]] +; CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [2 x [1 x float]], ptr [[EXT1:@.*]], i64 0, i64 [[IN1]], i64 [[IN2:%.*]] +; CHECK-NEXT: store ptr [[B]], ptr [[OUT1:%.*]], align 8 +; CHECK-NEXT: store ptr [[C]], ptr [[OUT2:%.*]], align 8 +; CHECK-NEXT: ret void + + %a = getelementptr inbounds [2 x [1 x float]], ptr @ext1, i64 0, i64 %in1 + %b = getelementptr inbounds float, ptr %a, i64 %in1 + %c = getelementptr inbounds float, ptr %a, i64 %in2 + store ptr %b, ptr %out1 + store ptr %c, ptr %out2 + ret void +}