Skip to content

Commit aefd009

Browse files
michalpaszkowskiigcbot
authored andcommitted
Handle single-index GEPs into flat aggregates in SimplifyConstant
In opaque pointer mode, GEPs that index into globals often have a different shape. SimplifyConstant pass assumed two-index GEPs (0, index) and directly used the second operand as an element index. However, it is possible to address flat aggregates using single-index GEPs. See the two examples below from SYCL_CTS-math_builtin_float_double_1_ocl run in typed and opaque pointer mode. Two-index GEP example: %130 = getelementptr inbounds [2 x i32], [2 x i32] addrspace(2)* @__stgamma_ep_nofp64__ones, i64 0, i64 %129 %131 = bitcast i32 addrspace(2)* %130 to float addrspace(2)* %132 = load float, float addrspace(2)* %131, align 4, !tbaa !5163, !noalias !5409 Single-index GEP example: %103 = getelementptr inbounds float, ptr addrspace(2) @__stgamma_ep_nofp64__ones, i64 %102 %104 = load float, ptr addrspace(2) %103, align 4, !tbaa !5163, !noalias !5409 This patch changes the pass to always use the last GEP index as the element selector. This works because the pass only transforms top-level arrays of scalars/vectors. In these cases, the element being loaded is always designated by the final GEP index (whether there are earlier indices selecting the actual aggregate or single index in opaque pointer mode).
1 parent 215e971 commit aefd009

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

IGC/Compiler/CISACodeGen/SimplifyConstant.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,14 @@ void ConstantLoader::analyze() {
146146
matchSplat(CDA) || matchOddEven(CDA) || matchLadder2(CDA);
147147
}
148148

149+
// Returns the dynamic element index of a GEP addressing a flat (unnested) aggregate. This is the last GEP index operand
150+
// which addresses array elements. Earlier index operands (if present) select the indexed array itself. However, the
151+
// number of index operands is variable and depends on the type.
152+
static Value *getGEPElementIndex(GetElementPtrInst *GEP) {
153+
IGC_ASSERT(GEP && GEP->getNumIndices() >= 1);
154+
return GEP->getOperand(1 + (GEP->getNumIndices() - 1));
155+
}
156+
149157
void ConstantLoader::simplify() {
150158
if (Kind == CK_Unknown)
151159
return;
@@ -174,8 +182,8 @@ void ConstantLoader::simplify() {
174182
LoadInst *LI = dyn_cast<LoadInst>(*I++);
175183
if (!LI)
176184
continue;
177-
IGC_ASSERT(GEP->getNumIndices() == 2);
178-
Value *Index = GEP->getOperand(2);
185+
186+
Value *Index = getGEPElementIndex(GEP);
179187
Value *Val = V0;
180188
IRBuilder<> Builder(LI);
181189
if (Kind == CK_Ladder2) {
@@ -500,10 +508,8 @@ static void promote(GlobalVariable *GV, IGCLLVM::FixedVectorType *AllocaType, bo
500508
// might be Constant user in llvm.used
501509
if (!GEP || GEP->getParent()->getParent() != F)
502510
continue;
503-
IGC_ASSERT(GEP->getNumIndices() == 2);
504-
// This is the index to address the array, and the first index is to address
505-
// the global variable itself.
506-
Value *Index = GEP->getOperand(2);
511+
512+
Value *Index = getGEPElementIndex(GEP);
507513
// Demote the index type to int32 to avoid 64 multiplications during vISA
508514
// emission, e.g. it is illegal to emit Q x W.
509515
if (Index->getType()->getPrimitiveSizeInBits() > 32) {
@@ -570,10 +576,7 @@ static bool rewriteAsCmpSel(GlobalVariable *GV, Function &F) {
570576
if (!GEP || GEP->getParent()->getParent() != &F)
571577
continue;
572578

573-
// This is the index to address the array, and the first index is to
574-
// address the global variable itself.
575-
IGC_ASSERT(GEP->getNumIndices() == 2);
576-
Value *Index = GEP->getOperand(2);
579+
Value *Index = getGEPElementIndex(GEP);
577580
if (Index->getType()->getPrimitiveSizeInBits() > 32) {
578581
IRBuilder<> Builder(GEP);
579582
Index = Builder.CreateTrunc(Index, Builder.getInt32Ty());
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2025 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
9+
; REQUIRES: llvm-14-plus
10+
; RUN: igc_opt --opaque-pointers -SimplifyConstant -S < %s 2>&1 | FileCheck %s
11+
12+
; This test ensures SimplifyConstant pass supports flat GEPs with a single index operand.
13+
14+
@g = dso_local unnamed_addr addrspace(2) constant [2 x i32] [i32 1065353216, i32 -1082130432], align 4
15+
16+
define spir_kernel void @test(i64 %index, ptr %output) {
17+
; CHECK-LABEL: @test(
18+
; CHECK: [[TRUNC:%.*]] = trunc i64 [[INDEX:%.*]] to i1
19+
; CHECK: [[SELECT_I32:%.*]] = select i1 [[TRUNC]], i32 -1082130432, i32 1065353216
20+
; CHECK: [[BITCAST:%.*]] = bitcast i32 [[SELECT_I32]] to float
21+
; CHECK: store float [[BITCAST]], ptr [[OUTPUT:%.*]], align 4
22+
; CHECK: ret void
23+
%a = getelementptr inbounds float, ptr addrspace(2) @g, i64 %index
24+
%b = load float, ptr addrspace(2) %a, align 4
25+
store float %b, ptr %output, align 4
26+
ret void
27+
}

0 commit comments

Comments
 (0)