Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2109,6 +2109,48 @@ GEP.getName()); } + // Combine opaque pointer GEPs with GEP having single index and by matching + // the types. + if (PtrTy->isOpaquePointerTy() && + Src->getResultElementType() != GEP.getSourceElementType() && + GEP.getNumIndices() == 1) { + Type *SrcElemTy = GEP.getSourceElementType(); + Type *ResElemTy = Src->getResultElementType(); + Type *ElemTy = ResElemTy; + SmallVector NewIndices; + 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) { + // Erase the last zero from NewIndices if zeroes have been appended by + // previous step. + if (NewIndices.size() > Src->getNumIndices()) + NewIndices.erase(NewIndices.end() - 1); + 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,96 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -passes=instcombine %s | FileCheck %s + +@ext1 = external hidden global [2 x [1 x float]] +@ext2 = external hidden global [2 x [2 x [1 x float]]] +@ext3 = external hidden global { [2 x [1 x float]] } +@ext4 = external hidden global [3 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 0, 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 %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 +} + +; Test to check if instcombine pass combines opaque pointer gepofgep with src of struct type with array inside and +; current gep having single index. +define void @gepofgep5(i64 %in1, i64 %in2, ptr %out) { +; CHECK-LABEL: @gepofgep5( +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [2 x [1 x float]], ptr @ext3, 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 @ext3, 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 combines opaque pointer gepofgep with src array type +; and current gep having single index. Check if resulting gep has additional zero after src indices. +define void @gepofgep6(i64 %in1, i64 %in2, ptr %out) { +; CHECK-LABEL: @gepofgep6( +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [3 x [2 x [1 x float]]], ptr @ext4, i64 0, i64 [[IN1:%.*]], i64 0, i64 [[IN2:%.*]] +; CHECK-NEXT: store ptr [[B]], ptr [[OUT:%.*]], align 8 +; CHECK-NEXT: ret void +; + %a = getelementptr inbounds [3 x [2 x [1 x float]]], ptr @ext4, i64 0, i64 %in1 + %b = getelementptr inbounds float, ptr %a, i64 %in2 + store ptr %b, ptr %out + ret void +}