Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2112,6 +2112,24 @@ GEP.getName()); } + // Combine opaque pointer GEPs having source array type with + // GEP having single index. + if (PtrTy->isOpaquePointerTy() && Src->getResultElementType()->isArrayTy() && + GEP.getNumIndices() == 1) { + SmallVector NewIndices; + NewIndices.reserve(Src->getNumIndices() + GEP.getNumIndices()); + NewIndices.append(Src->idx_begin(), Src->idx_end()); + NewIndices.append(GEP.idx_begin(), GEP.idx_end()); + bool IsInBounds = isMergedGEPInBounds(*Src, *cast(&GEP)); + return IsInBounds + ? GetElementPtrInst::CreateInBounds(Src->getSourceElementType(), + Src->getOperand(0), + NewIndices, GEP.getName()) + : GetElementPtrInst::Create(Src->getSourceElementType(), + Src->getOperand(0), NewIndices, + GEP.getName()); + } + 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,55 @@ +; RUN: opt -S -instcombine -opaque-pointers < %s | FileCheck %s + +@ext1 = external hidden global [2 x [1 x float]] +@ext2 = external hidden global [2 x [2 x [1 x float]]] + +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 +} + +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 +} + +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 +} + +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 +}