[clang] [llvm] [IR] Add flags operand to structured.gep (PR #200093)
Krzysztof Drewniak via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 23 12:00:52 PDT 2026
https://github.com/krzysz00 updated https://github.com/llvm/llvm-project/pull/200093
>From 4a80b79ea94393f78c62a6236a77c4e9bdd20fc4 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Wed, 27 May 2026 23:23:12 +0000
Subject: [PATCH 1/8] [IR] Add flags operand to structured.gep
This commit extenrds the structured.gep intrinsic to take a constant
vector of flags allowing people to specify, per-index, whether:
1. The index is inbounds (removing the old [0 x T] system that could
lose static information about array sizes in cases where indices
weren't known to be in-bounds)
2. Whether an index is known to be non-negative
3. If the index should be treated as signed or unsigned. The SGEP
semantics prreviously specified that indices were unsigned, but this
was in conflict wit some source langauges. This wasn't a simple
semantics change because AMDGPU buffer descriptors use unsigned
indexing, so we wanted to preserve the old behavior.
These flags are edded to make SGEP more expressive, enable
optimizations/transformations (ex. for automatically
extending/truncating indices), and to enable upcoming usecases in the
AMDGPU backend where more flexible inbounds behaviors is desired.
Co-Authored-By: Codex <codex at openai.com>
---
clang/lib/CodeGen/CGBuilder.h | 24 +-
clang/lib/CodeGen/CGExpr.cpp | 97 ++++++-
clang/lib/CodeGen/CGExprAgg.cpp | 3 +
clang/lib/CodeGen/CGHLSLRuntime.cpp | 86 ++++++-
.../ArrayAssignable.logicalptr.hlsl | 238 +++++++++---------
.../cbuffer_struct_passing.logical.hlsl | 16 +-
clang/test/CodeGenHLSL/sgep/array_load.hlsl | 36 ++-
clang/test/CodeGenHLSL/sgep/array_store.hlsl | 18 +-
clang/test/CodeGenHLSL/sgep/load_global.hlsl | 8 +-
.../test/CodeGenHLSL/sgep/object_method.hlsl | 2 +-
llvm/docs/LangRef.rst | 131 +++++++---
llvm/include/llvm/IR/IRBuilder.h | 19 +-
llvm/include/llvm/IR/IntrinsicInst.h | 36 ++-
llvm/include/llvm/IR/Intrinsics.td | 3 +-
llvm/include/llvm/IR/StructuredGEPFlags.h | 73 ++++++
llvm/lib/Analysis/InstructionSimplify.cpp | 6 +-
llvm/lib/IR/AutoUpgrade.cpp | 93 +++++++
llvm/lib/IR/Verifier.cpp | 48 +++-
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 2 +-
.../test/Assembler/auto_upgrade_intrinsics.ll | 22 ++
.../test/CodeGen/SPIRV/pointers/sgep-array.ll | 36 +--
.../test/CodeGen/SPIRV/pointers/sgep-class.ll | 6 +-
.../SPIRV/pointers/sgep-dynamic-index.ll | 22 +-
.../pointers/sgep-nested-struct-array.ll | 4 +-
.../SPIRV/pointers/sgep-runtime-array.ll | 6 +-
.../CodeGen/SPIRV/pointers/sgep-struct.ll | 4 +-
.../CodeGen/SPIRV/pointers/sgep-vector.ll | 11 +-
.../Transforms/InstSimplify/structured-gep.ll | 31 +--
.../amdgpu-stridemark-structured-gep.ll | 4 +-
.../Verifier/logical-pointer-notrequired.ll | 2 +-
.../test/Verifier/logical-pointer-required.ll | 2 +-
.../Verifier/structured-gep-indices-bad.ll | 54 +++-
llvm/test/Verifier/structured-gep-indices.ll | 30 ++-
33 files changed, 890 insertions(+), 283 deletions(-)
create mode 100644 llvm/include/llvm/IR/StructuredGEPFlags.h
diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h
index 4a51f6be8578f..2678162baf96e 100644
--- a/clang/lib/CodeGen/CGBuilder.h
+++ b/clang/lib/CodeGen/CGBuilder.h
@@ -18,6 +18,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GEPNoWrapFlags.h"
#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/StructuredGEPFlags.h"
#include "llvm/IR/Type.h"
namespace clang {
@@ -366,13 +367,32 @@ class CGBuilderTy : public CGBuilderBaseTy {
llvm::Value *CreateAccessChain(bool Logical, llvm::Type *BaseType,
llvm::Value *PtrBase,
ArrayRef<llvm::Value *> IdxList,
+ ArrayRef<llvm::StructuredGEPFlags> Flags,
const Twine &Name = "") {
-
if (Logical)
- return CreateStructuredGEP(BaseType, PtrBase, IdxList, Name);
+ return CreateStructuredGEP(BaseType, PtrBase, IdxList, Flags, Name);
return CreateInBoundsGEP(BaseType, PtrBase, IdxList, Name);
}
+ llvm::Value *CreateAccessChain(bool Logical, llvm::Type *BaseType,
+ llvm::Value *PtrBase,
+ ArrayRef<llvm::Value *> IdxList,
+ const Twine &Name = "") {
+ assert(!Logical && "logical access chains require structured GEP flags");
+ return CreateInBoundsGEP(BaseType, PtrBase, IdxList, Name);
+ }
+
+ Address CreateAccessChain(bool Logical, Address Addr,
+ ArrayRef<llvm::Value *> IdxList,
+ ArrayRef<llvm::StructuredGEPFlags> Flags,
+ llvm::Type *ElementType, CharUnits Align,
+ const Twine &Name = "") {
+ return RawAddress(CreateAccessChain(Logical, Addr.getElementType(),
+ emitRawPointerFromAddress(Addr),
+ IdxList, Flags, Name),
+ ElementType, Align, Addr.isKnownNonNull());
+ }
+
Address CreateAccessChain(bool Logical, Address Addr,
ArrayRef<llvm::Value *> IdxList,
llvm::Type *ElementType, CharUnits Align,
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index f6cb636368598..90ae5cf3e4a00 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -48,6 +48,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/MatrixBuilder.h"
+#include "llvm/IR/StructuredGEPFlags.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/MathExtras.h"
@@ -4644,8 +4645,9 @@ Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E,
if (getLangOpts().EmitLogicalPointer) {
// Array-to-pointer decay for an SGEP is a no-op as we don't do any
// logical indexing. See #179951 for some additional context.
- auto *SGEP =
- Builder.CreateStructuredGEP(NewTy, Addr.emitRawPointer(*this), {});
+ auto *SGEP = Builder.CreateStructuredGEP(
+ NewTy, Addr.emitRawPointer(*this), ArrayRef<llvm::Value *>(),
+ ArrayRef<llvm::StructuredGEPFlags>());
Addr = Address(SGEP, NewTy, Addr.getAlignment(), Addr.isKnownNonNull());
} else {
Addr = Builder.CreateConstArrayGEP(Addr, 0, "arraydecay");
@@ -4680,6 +4682,60 @@ static const Expr *isSimpleArrayDecayOperand(const Expr *E) {
return SubExpr;
}
+static bool isStructuredGEPIndexableType(llvm::Type *T) {
+ return isa<llvm::ArrayType>(T) || isa<llvm::StructType>(T) ||
+ isa<llvm::VectorType>(T);
+}
+
+static llvm::StructuredGEPFlags
+getStructuredGEPArrayIndexFlags(llvm::Type *IndexedType, llvm::Value *Index,
+ bool InBounds, bool SignedIndex) {
+ llvm::StructuredGEPFlags Flags = llvm::StructuredGEPFlags::none();
+ if (InBounds) {
+ if (auto *AT = dyn_cast<llvm::ArrayType>(IndexedType)) {
+ if (AT->getNumElements() != 0)
+ Flags |= llvm::StructuredGEPFlags::inBounds();
+ } else {
+ Flags |= llvm::StructuredGEPFlags::inBounds();
+ }
+ }
+ if (!SignedIndex)
+ Flags |= llvm::StructuredGEPFlags::unsignedIndex();
+ if (auto *CI = dyn_cast<llvm::ConstantInt>(Index))
+ if (!CI->isNegative())
+ Flags |= llvm::StructuredGEPFlags::nneg();
+ return Flags;
+}
+
+static SmallVector<llvm::StructuredGEPFlags>
+getStructuredGEPFlagsForIndices(llvm::Type *BaseType,
+ ArrayRef<llvm::Value *> Indices,
+ bool InBounds, bool SignedIndices) {
+ SmallVector<llvm::StructuredGEPFlags> Flags;
+ Flags.reserve(Indices.size());
+ llvm::Type *CurrentType = BaseType;
+ for (llvm::Value *Index : Indices) {
+ if (auto *ST = dyn_cast<llvm::StructType>(CurrentType)) {
+ Flags.push_back(llvm::StructuredGEPFlags::inBounds() |
+ llvm::StructuredGEPFlags::nneg());
+ if (auto *CI = dyn_cast<llvm::ConstantInt>(Index))
+ if (CI->getZExtValue() < ST->getNumElements())
+ CurrentType = ST->getElementType(CI->getZExtValue());
+ continue;
+ }
+
+ Flags.push_back(getStructuredGEPArrayIndexFlags(
+ CurrentType, Index, InBounds, SignedIndices));
+ if (auto *AT = dyn_cast<llvm::ArrayType>(CurrentType))
+ CurrentType = AT->getElementType();
+ else if (auto *VT = dyn_cast<llvm::VectorType>(CurrentType))
+ CurrentType = VT->getElementType();
+ else
+ CurrentType = nullptr;
+ }
+ return Flags;
+}
+
static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF,
llvm::Type *elemType,
llvm::Value *ptr,
@@ -4688,8 +4744,13 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF,
bool signedIndices,
SourceLocation loc,
const llvm::Twine &name = "arrayidx") {
- if (inbounds && CGF.getLangOpts().EmitLogicalPointer)
- return CGF.Builder.CreateStructuredGEP(elemType, ptr, indices);
+ if (inbounds && CGF.getLangOpts().EmitLogicalPointer &&
+ isStructuredGEPIndexableType(elemType)) {
+ SmallVector<llvm::StructuredGEPFlags> Flags =
+ getStructuredGEPFlagsForIndices(elemType, indices, inbounds,
+ signedIndices);
+ return CGF.Builder.CreateStructuredGEP(elemType, ptr, indices, Flags, name);
+ }
if (inbounds) {
return CGF.EmitCheckedInBoundsGEP(elemType, ptr, indices, signedIndices,
@@ -4707,11 +4768,19 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
bool signedIndices, SourceLocation loc,
CharUnits align,
const llvm::Twine &name = "arrayidx") {
- if (inbounds && CGF.getLangOpts().EmitLogicalPointer)
- return RawAddress(CGF.Builder.CreateStructuredGEP(arrayType,
- addr.emitRawPointer(CGF),
- indices.drop_front()),
- elementType, align);
+ ArrayRef<llvm::Value *> LogicalIndices =
+ indices.empty() ? indices : indices.drop_front();
+ // arrayType is optional after array-to-pointer decay.
+ if (inbounds && CGF.getLangOpts().EmitLogicalPointer && arrayType &&
+ isStructuredGEPIndexableType(arrayType)) {
+ SmallVector<llvm::StructuredGEPFlags> Flags =
+ getStructuredGEPFlagsForIndices(arrayType, LogicalIndices, inbounds,
+ signedIndices);
+ return RawAddress(
+ CGF.Builder.CreateStructuredGEP(arrayType, addr.emitRawPointer(CGF),
+ LogicalIndices, Flags, name),
+ elementType, align);
+ }
if (inbounds) {
return CGF.EmitCheckedInBoundsGEP(addr, indices, elementType, signedIndices,
@@ -5709,10 +5778,12 @@ static Address emitRawAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
CGF.CGM.getTypes().getCGRecordLayout(rec).getLLVMType();
if (CGF.getLangOpts().EmitLogicalPointer)
- return RawAddress(
- CGF.Builder.CreateStructuredGEP(StructType, base.emitRawPointer(CGF),
- {CGF.Builder.getSize(idx)}),
- base.getElementType(), base.getAlignment());
+ return RawAddress(CGF.Builder.CreateStructuredGEP(
+ StructType, base.emitRawPointer(CGF),
+ {CGF.Builder.getSize(idx)},
+ {llvm::StructuredGEPFlags::inBounds() |
+ llvm::StructuredGEPFlags::nneg()}),
+ base.getElementType(), base.getAlignment());
if (!IsInBounds)
return CGF.Builder.CreateConstGEP2_32(base, 0, idx, field->getName());
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index befc2659b2f4c..fbe432a54a256 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -31,6 +31,7 @@
#include "llvm/IR/Instruction.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/StructuredGEPFlags.h"
using namespace clang;
using namespace CodeGen;
@@ -655,6 +656,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
if (CGF.getLangOpts().EmitLogicalPointer)
element = Builder.CreateStructuredGEP(
AType, begin, llvm::ConstantInt::get(CGF.SizeTy, ArrayIndex),
+ llvm::StructuredGEPFlags::inBounds() |
+ llvm::StructuredGEPFlags::nneg(),
"arrayinit.element");
else
element = Builder.CreateInBoundsGEP(
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 33d76cbda494a..49bf0178de72e 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -29,6 +29,7 @@
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -40,6 +41,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/StructuredGEPFlags.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Alignment.h"
@@ -57,6 +59,59 @@ using llvm::hlsl::CBufferRowSizeInBytes;
namespace {
+StructuredGEPFlags getHLSLStructuredGEPArrayIndexFlags(llvm::Type *IndexedType,
+ Value *Index,
+ bool InBounds,
+ bool SignedIndex) {
+ StructuredGEPFlags Flags = StructuredGEPFlags::none();
+ if (InBounds) {
+ if (auto *AT = dyn_cast<llvm::ArrayType>(IndexedType)) {
+ if (AT->getNumElements() != 0)
+ Flags |= StructuredGEPFlags::inBounds();
+ } else {
+ Flags |= StructuredGEPFlags::inBounds();
+ }
+ }
+ if (!SignedIndex)
+ Flags |= StructuredGEPFlags::unsignedIndex();
+ if (auto *CI = dyn_cast<ConstantInt>(Index))
+ if (!CI->isNegative())
+ Flags |= StructuredGEPFlags::nneg();
+ return Flags;
+}
+
+SmallVector<StructuredGEPFlags>
+getHLSLStructuredGEPFlags(llvm::Type *BaseType, ArrayRef<Value *> Indices,
+ bool InBounds,
+ std::optional<bool> FirstIndexSigned = std::nullopt) {
+ // FirstIndexSigned describes only the caller-provided source-language index.
+ // Generated layout indices after it are signed constants.
+ SmallVector<StructuredGEPFlags> Flags;
+ Flags.reserve(Indices.size());
+ llvm::Type *CurrentType = BaseType;
+ for (auto [IndexNo, Index] : llvm::enumerate(Indices)) {
+ if (auto *ST = dyn_cast<llvm::StructType>(CurrentType)) {
+ Flags.push_back(StructuredGEPFlags::inBounds() |
+ StructuredGEPFlags::nneg());
+ if (auto *CI = dyn_cast<ConstantInt>(Index))
+ if (CI->getZExtValue() < ST->getNumElements())
+ CurrentType = ST->getElementType(CI->getZExtValue());
+ continue;
+ }
+
+ bool SignedIndex = IndexNo == 0 ? FirstIndexSigned.value_or(true) : true;
+ Flags.push_back(getHLSLStructuredGEPArrayIndexFlags(
+ CurrentType, Index, InBounds, SignedIndex));
+ if (auto *AT = dyn_cast<llvm::ArrayType>(CurrentType))
+ CurrentType = AT->getElementType();
+ else if (auto *VT = dyn_cast<llvm::VectorType>(CurrentType))
+ CurrentType = VT->getElementType();
+ else
+ CurrentType = nullptr;
+ }
+ return Flags;
+}
+
void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
// The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
// Assume ValVersionStr is legal here.
@@ -1601,8 +1656,11 @@ std::optional<LValue> CGHLSLRuntime::emitBufferArraySubscriptExpr(
LayoutTy = llvm::ArrayType::get(
LayoutTy,
cast<llvm::ArrayType>(Addr.getElementType())->getNumElements());
+ SmallVector<StructuredGEPFlags> Flags = getHLSLStructuredGEPFlags(
+ LayoutTy, Indices, /*InBounds=*/true,
+ E->getIdx()->getType()->isSignedIntegerOrEnumerationType());
auto *GEP = cast<StructuredGEPInst>(CGF.Builder.CreateStructuredGEP(
- LayoutTy, Addr.emitRawPointer(CGF), Indices, "cbufferidx"));
+ LayoutTy, Addr.emitRawPointer(CGF), Indices, Flags, "cbufferidx"));
Addr =
Address(GEP, GEP->getResultElementType(), RowAlignedSize, KnownNonNull);
return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
@@ -1662,8 +1720,12 @@ class HLSLBufferCopyEmitter {
llvm::Value *emitAccessChain(llvm::Type *BaseTy, llvm::Value *Base,
ArrayRef<llvm::Value *> Indices) {
bool EmitLogical = CGF.getLangOpts().EmitLogicalPointer;
- if (EmitLogical)
- return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, Indices);
+ if (EmitLogical) {
+ SmallVector<StructuredGEPFlags> Flags =
+ getHLSLStructuredGEPFlags(BaseTy, Indices, /*InBounds=*/true);
+ return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, Indices,
+ Flags);
+ }
llvm::SmallVector<llvm::Value *> GEPIndices;
GEPIndices.reserve(Indices.size() + 1);
@@ -1856,12 +1918,18 @@ LValue CGHLSLRuntime::emitBufferMemberExpr(CodeGenFunction &CGF,
CharUnits Align = CharUnits::fromQuantity(
CGF.CGM.getDataLayout().getABITypeAlign(FieldLLVMTy));
- Value *Ptr = CGF.getLangOpts().EmitLogicalPointer
- ? CGF.Builder.CreateStructuredGEP(
- LayoutTy, Base.getPointer(CGF),
- llvm::ConstantInt::get(CGM.IntTy, FieldIdx))
- : CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF),
- FieldIdx, Field->getName());
+ Value *Ptr;
+ if (CGF.getLangOpts().EmitLogicalPointer) {
+ Value *FieldIndex = llvm::ConstantInt::get(CGM.IntTy, FieldIdx);
+ SmallVector<Value *> Indices = {FieldIndex};
+ SmallVector<StructuredGEPFlags> Flags =
+ getHLSLStructuredGEPFlags(LayoutTy, Indices, /*InBounds=*/true);
+ Ptr = CGF.Builder.CreateStructuredGEP(LayoutTy, Base.getPointer(CGF),
+ Indices, Flags);
+ } else {
+ Ptr = CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF), FieldIdx,
+ Field->getName());
+ }
Address Addr(Ptr, FieldLLVMTy, Align, KnownNonNull);
LValue LV = LValue::MakeAddr(Addr, FieldType, CGM.getContext(),
diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl
index e5fa7e62f739d..625be2fbfe819 100644
--- a/clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl
+++ b/clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl
@@ -32,7 +32,7 @@ cbuffer CBArrays : register(b0) {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign1v(
// CHECK-DXIL-SAME: ) #[[ATTR2:[0-9]+]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[ARR:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 @__const._Z11arr_assign1v.Arr, i32 8, i1 false)
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
@@ -60,7 +60,7 @@ void arr_assign1() {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign2v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[ARR:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 @__const._Z11arr_assign2v.Arr, i32 8, i1 false)
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
@@ -95,7 +95,7 @@ void arr_assign2() {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign3v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign3v.Arr2, i32 16, i1 false)
// CHECK-DXIL-NEXT: [[ARR3:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
@@ -123,14 +123,14 @@ void arr_assign3() {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign4v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[ARR:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 @__const._Z11arr_assign4v.Arr, i32 8, i1 false)
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[ARR2]], i8 0, i32 8, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i32 8, i1 false)
-// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[ARR]], i32 0)
-// CHECK-DXIL-NEXT: store i32 6, ptr [[TMP0]], align 4
+// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-DXIL-NEXT: ret void
//
// CHECK-SPIR-LABEL: define hidden spir_func void @_Z11arr_assign4v(
@@ -142,8 +142,8 @@ void arr_assign3() {
// CHECK-SPIR-NEXT: [[ARR2:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
// CHECK-SPIR-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[ARR2]], i8 0, i64 8, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i64 8, i1 false)
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[ARR]], i64 0)
-// CHECK-SPIR-NEXT: store i32 6, ptr [[TMP1]], align 4
+// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-SPIR-NEXT: ret void
//
void arr_assign4() {
@@ -155,7 +155,7 @@ void arr_assign4() {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign5v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[ARR:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 @__const._Z11arr_assign5v.Arr, i32 8, i1 false)
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
@@ -164,8 +164,8 @@ void arr_assign4() {
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR3]], ptr align 4 @__const._Z11arr_assign5v.Arr3, i32 8, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR2]], ptr align 4 [[ARR3]], i32 8, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i32 8, i1 false)
-// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[ARR]], i32 0)
-// CHECK-DXIL-NEXT: store i32 6, ptr [[TMP0]], align 4
+// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-DXIL-NEXT: ret void
//
// CHECK-SPIR-LABEL: define hidden spir_func void @_Z11arr_assign5v(
@@ -180,8 +180,8 @@ void arr_assign4() {
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR3]], ptr align 4 @__const._Z11arr_assign5v.Arr3, i64 8, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR2]], ptr align 4 [[ARR3]], i64 8, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i64 8, i1 false)
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[ARR]], i64 0)
-// CHECK-SPIR-NEXT: store i32 6, ptr [[TMP1]], align 4
+// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-SPIR-NEXT: ret void
//
void arr_assign5() {
@@ -194,15 +194,15 @@ void arr_assign5() {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign6v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[ARR:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 @__const._Z11arr_assign6v.Arr, i32 16, i1 false)
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign6v.Arr2, i32 16, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i32 16, i1 false)
-// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [2 x i32]]) [[ARR]], i32 0)
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP0]], i32 0)
-// CHECK-DXIL-NEXT: store i32 6, ptr [[TMP1]], align 4
+// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[ARRAYIDX1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYIDX1]], align 4
// CHECK-DXIL-NEXT: ret void
//
// CHECK-SPIR-LABEL: define hidden spir_func void @_Z11arr_assign6v(
@@ -214,9 +214,9 @@ void arr_assign5() {
// CHECK-SPIR-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign6v.Arr2, i64 16, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i64 16, i1 false)
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [2 x i32]]) [[ARR]], i64 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP1]], i64 0)
-// CHECK-SPIR-NEXT: store i32 6, ptr [[TMP2]], align 4
+// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: [[ARRAYIDX1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYIDX1]], align 4
// CHECK-SPIR-NEXT: ret void
//
void arr_assign6() {
@@ -228,15 +228,15 @@ void arr_assign6() {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign7v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[ARR:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 @__const._Z11arr_assign7v.Arr, i32 16, i1 false)
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign7v.Arr2, i32 16, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i32 16, i1 false)
-// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [2 x i32]]) [[ARR]], i32 0)
-// CHECK-DXIL-NEXT: store i32 6, ptr [[TMP0]], align 4
-// CHECK-DXIL-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP0]], i32 1)
+// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
+// CHECK-DXIL-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 3), i32 1)
// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYINIT_ELEMENT]], align 4
// CHECK-DXIL-NEXT: ret void
//
@@ -249,9 +249,9 @@ void arr_assign6() {
// CHECK-SPIR-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign7v.Arr2, i64 16, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i64 16, i1 false)
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [2 x i32]]) [[ARR]], i64 0)
-// CHECK-SPIR-NEXT: store i32 6, ptr [[TMP1]], align 4
-// CHECK-SPIR-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP1]], i64 1)
+// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
+// CHECK-SPIR-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 3), i64 1)
// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYINIT_ELEMENT]], align 4
// CHECK-SPIR-NEXT: ret void
//
@@ -265,16 +265,16 @@ void arr_assign7() {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign8v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[C:%.*]] = call elementtype([2 x float]) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>) @c1, i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x float]) [[C]], i32 0)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load float, ptr addrspace(2) [[TMP0]], align 4
-// CHECK-DXIL-NEXT: store float [[CBUF_LOAD]], ptr [[TMP1]], align 4
-// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>) @c1, i32 1)
-// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x float]) [[C]], i32 1)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(2) [[TMP2]], align 4
-// CHECK-DXIL-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP3]], align 4
+// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>) @c1, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load float, ptr addrspace(2) [[TMP1]], align 4
+// CHECK-DXIL-NEXT: store float [[CBUF_LOAD]], ptr [[TMP2]], align 4
+// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>) @c1, <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(2) [[TMP3]], align 4
+// CHECK-DXIL-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP4]], align 4
// CHECK-DXIL-NEXT: ret void
//
// CHECK-SPIR-LABEL: define hidden spir_func void @_Z11arr_assign8v(
@@ -282,12 +282,12 @@ void arr_assign7() {
// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIR-NEXT: [[C:%.*]] = call elementtype([2 x float]) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>) @c1, i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x float]) [[C]], i32 0)
+// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>) @c1, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 3), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD:%.*]] = load float, ptr addrspace(12) [[TMP1]], align 4
// CHECK-SPIR-NEXT: store float [[CBUF_LOAD]], ptr [[TMP2]], align 4
-// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>) @c1, i32 1)
-// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x float]) [[C]], i32 1)
+// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>) @c1, <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 3), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(12) [[TMP3]], align 4
// CHECK-SPIR-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP4]], align 4
// CHECK-SPIR-NEXT: ret void
@@ -300,16 +300,16 @@ void arr_assign8() {
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign9v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[C:%.*]] = call elementtype([2 x <4 x i32>]) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype([2 x <4 x i32>]) @c2, i32 0)
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x <4 x i32>]) [[C]], i32 0)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load <4 x i32>, ptr addrspace(2) [[TMP0]], align 4
-// CHECK-DXIL-NEXT: store <4 x i32> [[CBUF_LOAD]], ptr [[TMP1]], align 4
-// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype([2 x <4 x i32>]) @c2, i32 1)
-// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x <4 x i32>]) [[C]], i32 1)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load <4 x i32>, ptr addrspace(2) [[TMP2]], align 4
-// CHECK-DXIL-NEXT: store <4 x i32> [[CBUF_LOAD1]], ptr [[TMP3]], align 4
+// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load <4 x i32>, ptr addrspace(2) [[TMP1]], align 4
+// CHECK-DXIL-NEXT: store <4 x i32> [[CBUF_LOAD]], ptr [[TMP2]], align 4
+// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load <4 x i32>, ptr addrspace(2) [[TMP3]], align 4
+// CHECK-DXIL-NEXT: store <4 x i32> [[CBUF_LOAD1]], ptr [[TMP4]], align 4
// CHECK-DXIL-NEXT: ret void
//
// CHECK-SPIR-LABEL: define hidden spir_func void @_Z11arr_assign9v(
@@ -317,12 +317,12 @@ void arr_assign8() {
// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIR-NEXT: [[C:%.*]] = call elementtype([2 x <4 x i32>]) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype([2 x <4 x i32>]) @c2, i32 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x <4 x i32>]) [[C]], i32 0)
+// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 3), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD:%.*]] = load <4 x i32>, ptr addrspace(12) [[TMP1]], align 4
// CHECK-SPIR-NEXT: store <4 x i32> [[CBUF_LOAD]], ptr [[TMP2]], align 4
-// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype([2 x <4 x i32>]) @c2, i32 1)
-// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x <4 x i32>]) [[C]], i32 1)
+// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 3), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD1:%.*]] = load <4 x i32>, ptr addrspace(12) [[TMP3]], align 4
// CHECK-SPIR-NEXT: store <4 x i32> [[CBUF_LOAD1]], ptr [[TMP4]], align 4
// CHECK-SPIR-NEXT: ret void
@@ -338,28 +338,28 @@ void arr_assign9() {
// CHECK-DXIL-LABEL: define hidden void @_Z12arr_assign10v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[C:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>) @c3, i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [2 x i32]]) [[C]], i32 0)
-// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP0]], i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP1]], i32 0)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(2) [[TMP2]], align 4
-// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP3]], align 4
-// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP0]], i32 1)
-// CHECK-DXIL-NEXT: [[TMP5:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP1]], i32 1)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load i32, ptr addrspace(2) [[TMP4]], align 4
-// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD1]], ptr [[TMP5]], align 4
-// CHECK-DXIL-NEXT: [[TMP6:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>) @c3, i32 1)
-// CHECK-DXIL-NEXT: [[TMP7:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [2 x i32]]) [[C]], i32 1)
-// CHECK-DXIL-NEXT: [[TMP8:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP6]], i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP9:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP7]], i32 0)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(2) [[TMP8]], align 4
-// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP9]], align 4
-// CHECK-DXIL-NEXT: [[TMP10:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP6]], i32 1)
-// CHECK-DXIL-NEXT: [[TMP11:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP7]], i32 1)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD3:%.*]] = load i32, ptr addrspace(2) [[TMP10]], align 4
-// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD3]], ptr [[TMP11]], align 4
+// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>) @c3, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP1]], <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(2) [[TMP3]], align 4
+// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP4]], align 4
+// CHECK-DXIL-NEXT: [[TMP5:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP1]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load i32, ptr addrspace(2) [[TMP5]], align 4
+// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD1]], ptr [[TMP6]], align 4
+// CHECK-DXIL-NEXT: [[TMP7:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>) @c3, <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP9:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP7]], <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(2) [[TMP9]], align 4
+// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP10]], align 4
+// CHECK-DXIL-NEXT: [[TMP11:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP7]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD3:%.*]] = load i32, ptr addrspace(2) [[TMP11]], align 4
+// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD3]], ptr [[TMP12]], align 4
// CHECK-DXIL-NEXT: ret void
//
// CHECK-SPIR-LABEL: define hidden spir_func void @_Z12arr_assign10v(
@@ -367,24 +367,24 @@ void arr_assign9() {
// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIR-NEXT: [[C:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>) @c3, i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [2 x i32]]) [[C]], i32 0)
-// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP1]], i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP2]], i32 0)
+// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>) @c3, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP1]], <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 3), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(12) [[TMP3]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP4]], align 4
-// CHECK-SPIR-NEXT: [[TMP5:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP1]], i32 1)
-// CHECK-SPIR-NEXT: [[TMP6:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP2]], i32 1)
+// CHECK-SPIR-NEXT: [[TMP5:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP1]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 3), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD1:%.*]] = load i32, ptr addrspace(12) [[TMP5]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD1]], ptr [[TMP6]], align 4
-// CHECK-SPIR-NEXT: [[TMP7:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>) @c3, i32 1)
-// CHECK-SPIR-NEXT: [[TMP8:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [2 x i32]]) [[C]], i32 1)
-// CHECK-SPIR-NEXT: [[TMP9:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP7]], i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP10:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP8]], i32 0)
+// CHECK-SPIR-NEXT: [[TMP7:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>) @c3, <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP9:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP7]], <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 3), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(12) [[TMP9]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP10]], align 4
-// CHECK-SPIR-NEXT: [[TMP11:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP7]], i32 1)
-// CHECK-SPIR-NEXT: [[TMP12:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x i32]) [[TMP8]], i32 1)
+// CHECK-SPIR-NEXT: [[TMP11:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP7]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 3), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD3:%.*]] = load i32, ptr addrspace(12) [[TMP11]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD3]], ptr [[TMP12]], align 4
// CHECK-SPIR-NEXT: ret void
@@ -397,28 +397,28 @@ void arr_assign10() {
// CHECK-DXIL-LABEL: define hidden void @_Z12arr_assign11v(
// CHECK-DXIL-SAME: ) #[[ATTR2]] {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
-// CHECK-DXIL-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
+// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[C:%.*]] = call elementtype([2 x [[STRUCT_S:%.*]]]) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ [[S:%.*]], target("dx.Padding", 8) }>], [[S]] }>) @c4, i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], i32 0)
-// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype([[S]]) [[TMP0]], i32 0)
-// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([[STRUCT_S]]) [[TMP1]], i32 0)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(2) [[TMP2]], align 4
-// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP3]], align 4
-// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype([[S]]) [[TMP0]], i32 1)
-// CHECK-DXIL-NEXT: [[TMP5:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([[STRUCT_S]]) [[TMP1]], i32 1)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(2) [[TMP4]], align 4
-// CHECK-DXIL-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP5]], align 4
-// CHECK-DXIL-NEXT: [[TMP6:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(<{ [1 x <{ [[S]], target("dx.Padding", 8) }>], [[S]] }>) @c4, i32 1)
-// CHECK-DXIL-NEXT: [[TMP7:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], i32 1)
-// CHECK-DXIL-NEXT: [[TMP8:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype([[S]]) [[TMP6]], i32 0)
-// CHECK-DXIL-NEXT: [[TMP9:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([[STRUCT_S]]) [[TMP7]], i32 0)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(2) [[TMP8]], align 4
-// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP9]], align 4
-// CHECK-DXIL-NEXT: [[TMP10:%.*]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype([[S]]) [[TMP6]], i32 1)
-// CHECK-DXIL-NEXT: [[TMP11:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([[STRUCT_S]]) [[TMP7]], i32 1)
-// CHECK-DXIL-NEXT: [[CBUF_LOAD3:%.*]] = load float, ptr addrspace(2) [[TMP10]], align 4
-// CHECK-DXIL-NEXT: store float [[CBUF_LOAD3]], ptr [[TMP11]], align 4
+// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ [[S:%.*]], target("dx.Padding", 8) }>], [[S]] }>) @c4, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(2) [[TMP3]], align 4
+// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP4]], align 4
+// CHECK-DXIL-NEXT: [[TMP5:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(2) [[TMP5]], align 4
+// CHECK-DXIL-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP6]], align 4
+// CHECK-DXIL-NEXT: [[TMP7:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ [[S]], target("dx.Padding", 8) }>], [[S]] }>) @c4, <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP9:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(2) [[TMP9]], align 4
+// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP10]], align 4
+// CHECK-DXIL-NEXT: [[TMP11:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[CBUF_LOAD3:%.*]] = load float, ptr addrspace(2) [[TMP11]], align 4
+// CHECK-DXIL-NEXT: store float [[CBUF_LOAD3]], ptr [[TMP12]], align 4
// CHECK-DXIL-NEXT: ret void
//
// CHECK-SPIR-LABEL: define hidden spir_func void @_Z12arr_assign11v(
@@ -426,24 +426,24 @@ void arr_assign10() {
// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIR-NEXT: [[C:%.*]] = call elementtype([2 x [[STRUCT_S:%.*]]]) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ [[S:%.*]], target("spirv.Padding", 8) }>], [[S]] }>) @c4, i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], i32 0)
-// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype([[S]]) [[TMP1]], i32 0)
-// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([[STRUCT_S]]) [[TMP2]], i32 0)
+// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ [[S:%.*]], target("spirv.Padding", 8) }>], [[S]] }>) @c4, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 3), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(12) [[TMP3]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP4]], align 4
-// CHECK-SPIR-NEXT: [[TMP5:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype([[S]]) [[TMP1]], i32 1)
-// CHECK-SPIR-NEXT: [[TMP6:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([[STRUCT_S]]) [[TMP2]], i32 1)
+// CHECK-SPIR-NEXT: [[TMP5:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 3), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(12) [[TMP5]], align 4
// CHECK-SPIR-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP6]], align 4
-// CHECK-SPIR-NEXT: [[TMP7:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(<{ [1 x <{ [[S]], target("spirv.Padding", 8) }>], [[S]] }>) @c4, i32 1)
-// CHECK-SPIR-NEXT: [[TMP8:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], i32 1)
-// CHECK-SPIR-NEXT: [[TMP9:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype([[S]]) [[TMP7]], i32 0)
-// CHECK-SPIR-NEXT: [[TMP10:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([[STRUCT_S]]) [[TMP8]], i32 0)
+// CHECK-SPIR-NEXT: [[TMP7:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ [[S]], target("spirv.Padding", 8) }>], [[S]] }>) @c4, <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP9:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 3), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(12) [[TMP9]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP10]], align 4
-// CHECK-SPIR-NEXT: [[TMP11:%.*]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype([[S]]) [[TMP7]], i32 1)
-// CHECK-SPIR-NEXT: [[TMP12:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([[STRUCT_S]]) [[TMP8]], i32 1)
+// CHECK-SPIR-NEXT: [[TMP11:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 3), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD3:%.*]] = load float, ptr addrspace(12) [[TMP11]], align 4
// CHECK-SPIR-NEXT: store float [[CBUF_LOAD3]], ptr [[TMP12]], align 4
// CHECK-SPIR-NEXT: ret void
diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_struct_passing.logical.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_struct_passing.logical.hlsl
index 4f940880bbd8f..ffb23014f86cc 100644
--- a/clang/test/CodeGenHLSL/resources/cbuffer_struct_passing.logical.hlsl
+++ b/clang/test/CodeGenHLSL/resources/cbuffer_struct_passing.logical.hlsl
@@ -19,24 +19,24 @@ cbuffer CB {
void main() {
S tmp = (S)cbs;
// CHECK-DXIL: %agg-temp = call elementtype(%struct.S) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL: %[[#SRC:]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(%S) @cbs, i32 0)
-// CHECK-DXIL: %[[#DST:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %agg-temp, i32 0)
+// CHECK-DXIL: %[[#SRC:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @cbs, <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 3), i32 0)
// CHECK-DXIL: %cbuf.load = load <3 x float>, ptr addrspace(2) %[[#SRC]], align 4
// CHECK-DXIL: store <3 x float> %cbuf.load, ptr %[[#DST]], align 4
-// CHECK-DXIL: %[[#SRC:]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(%S) @cbs, i32 2)
-// CHECK-DXIL: %[[#DST:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %agg-temp, i32 1)
+// CHECK-DXIL: %[[#SRC:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @cbs, <1 x i32> splat (i32 3), i32 2)
+// CHECK-DXIL: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 3), i32 1)
// CHECK-DXIL: %cbuf.load1 = load <4 x float>, ptr addrspace(2) %[[#SRC]], align 4
// CHECK-DXIL: store <4 x float> %cbuf.load1, ptr %[[#DST]], align 4
// CHECK-SPIR: %agg-temp = call elementtype(%struct.S) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR: %[[#SRC:]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(%S) @cbs, i32 0)
-// CHECK-SPIR: %[[#DST:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %agg-temp, i32 0)
+// CHECK-SPIR: %[[#SRC:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @cbs, <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 3), i32 0)
// CHECK-SPIR: %cbuf.load = load <3 x float>, ptr addrspace(12) %[[#SRC]], align 4
// CHECK-SPIR: store <3 x float> %cbuf.load, ptr %[[#DST]], align 4
-// CHECK-SPIR: %[[#SRC:]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(%S) @cbs, i32 2)
-// CHECK-SPIR: %[[#DST:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %agg-temp, i32 1)
+// CHECK-SPIR: %[[#SRC:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @cbs, <1 x i32> splat (i32 3), i32 2)
+// CHECK-SPIR: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 3), i32 1)
// CHECK-SPIR: %cbuf.load1 = load <4 x float>, ptr addrspace(12) %[[#SRC]], align 4
// CHECK-SPIR: store <4 x float> %cbuf.load1, ptr %[[#DST]], align 4
}
diff --git a/clang/test/CodeGenHLSL/sgep/array_load.hlsl b/clang/test/CodeGenHLSL/sgep/array_load.hlsl
index db3d5a1580023..32ea373895bb9 100644
--- a/clang/test/CodeGenHLSL/sgep/array_load.hlsl
+++ b/clang/test/CodeGenHLSL/sgep/array_load.hlsl
@@ -5,11 +5,29 @@ void foo() {
// CHECK: %array = call elementtype([3 x i32]) ptr @llvm.structured.alloca.p0()
uint array[3] = { 0, 1, 2 };
-// CHECK: %[[#PTR:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x i32]) %array, {{i32|i64}} 2)
-// CHECK: load i32, ptr %[[#PTR]], align 4
+// CHECK: %[[FOO_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 2)
+// CHECK: load i32, ptr %[[FOO_PTR]], align 4
uint tmp = array[2];
}
+void signed_idx(int i) {
+// CHECK: %array = call elementtype([3 x i32]) ptr @llvm.structured.alloca.p0()
+ uint array[3] = { 0, 1, 2 };
+
+// CHECK: %[[SIGNED_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 1), {{i32|i64}} %{{.*}})
+// CHECK: load i32, ptr %[[SIGNED_PTR]], align 4
+ uint tmp = array[i];
+}
+
+void unsigned_idx(uint i) {
+// CHECK: %array = call elementtype([3 x i32]) ptr @llvm.structured.alloca.p0()
+ uint array[3] = { 0, 1, 2 };
+
+// CHECK: %[[UNSIGNED_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 5), {{i32|i64}} %{{.*}})
+// CHECK: load i32, ptr %[[UNSIGNED_PTR]], align 4
+ uint tmp = array[i];
+}
+
struct S {
uint a;
uint b;
@@ -19,9 +37,9 @@ void bar() {
// CHECK: %array = call elementtype([3 x %struct.S]) ptr @llvm.structured.alloca.p0()
S array[3] = { { 0, 1 }, { 2, 3 }, { 3, 4 } };
-// CHECK: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S]) %array, {{i32|i64}} 2)
-// CHECK: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#A]], {{i32|i64}} 1)
-// CHECK: load i32, ptr %[[#B]], align 1
+// CHECK: %[[BAR_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 2)
+// CHECK: %[[BAR_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAR_A]], <1 x i32> splat (i32 3), {{i32|i64}} 1)
+// CHECK: load i32, ptr %[[BAR_B]], align 1
uint tmp = array[2].b;
}
@@ -35,9 +53,9 @@ void baz() {
// CHECK: %array = call elementtype([2 x %struct.S2]) ptr @llvm.structured.alloca.p0()
S2 array[2] = { { 0, { 1, 2 }, 3 }, { 4, { 5, 6 }, 7 } };
-// CHECK: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x %struct.S2]) %array, {{i32|i64}} 1)
-// CHECK: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S2) %[[#A]], {{i32|i64}} 1)
-// CHECK: %[[#C:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#B]], {{i32|i64}} 0)
-// CHECK: load i32, ptr %[[#C]], align 1
+// CHECK: %[[BAZ_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x %struct.S2]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 1)
+// CHECK: %[[BAZ_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %[[BAZ_A]], <1 x i32> splat (i32 3), {{i32|i64}} 1)
+// CHECK: %[[BAZ_C:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAZ_B]], <1 x i32> splat (i32 3), {{i32|i64}} 0)
+// CHECK: load i32, ptr %[[BAZ_C]], align 1
uint tmp = array[1].b.a;
}
diff --git a/clang/test/CodeGenHLSL/sgep/array_store.hlsl b/clang/test/CodeGenHLSL/sgep/array_store.hlsl
index 886bc49c0019e..8c72743c02e43 100644
--- a/clang/test/CodeGenHLSL/sgep/array_store.hlsl
+++ b/clang/test/CodeGenHLSL/sgep/array_store.hlsl
@@ -7,8 +7,8 @@ void foo() {
// CHECK: %array = call elementtype([10 x i32]) ptr @llvm.structured.alloca.p0()
uint array[10];
-// CHECK: %[[#PTR:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %array, {{i32|i64}} 2)
-// CHECK: store i32 10, ptr %[[#PTR]], align 4
+// CHECK: %[[FOO_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 2)
+// CHECK: store i32 10, ptr %[[FOO_PTR]], align 4
array[2] = 10;
}
@@ -21,9 +21,9 @@ void bar() {
// CHECK: %array = call elementtype([3 x %struct.S]) ptr @llvm.structured.alloca.p0()
S array[3] = { { 0, 1 }, { 2, 3 }, { 3, 4 } };
-// CHECK: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S]) %array, {{i32|i64}} 2)
-// CHECK: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#A]], {{i32|i64}} 1)
-// CHECK: store i32 10, ptr %[[#B]], align 1
+// CHECK: %[[BAR_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 2)
+// CHECK: %[[BAR_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAR_A]], <1 x i32> splat (i32 3), {{i32|i64}} 1)
+// CHECK: store i32 10, ptr %[[BAR_B]], align 1
array[2].b = 10;
}
@@ -38,10 +38,10 @@ void baz() {
// CHECK: %array = call elementtype([2 x %struct.S2]) ptr @llvm.structured.alloca.p0()
S2 array[2] = { { 0, { 1, 2 }, 3 }, { 4, { 5, 6 }, 7 } };
-// CHECK: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x %struct.S2]) %array, {{i32|i64}} 1)
-// CHECK: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S2) %[[#A]], {{i32|i64}} 1)
-// CHECK: %[[#C:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#B]], {{i32|i64}} 0)
-// CHECK: store i32 10, ptr %[[#C]], align 1
+// CHECK: %[[BAZ_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x %struct.S2]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 1)
+// CHECK: %[[BAZ_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %[[BAZ_A]], <1 x i32> splat (i32 3), {{i32|i64}} 1)
+// CHECK: %[[BAZ_C:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAZ_B]], <1 x i32> splat (i32 3), {{i32|i64}} 0)
+// CHECK: store i32 10, ptr %[[BAZ_C]], align 1
array[1].b.a = 10;
}
diff --git a/clang/test/CodeGenHLSL/sgep/load_global.hlsl b/clang/test/CodeGenHLSL/sgep/load_global.hlsl
index b35583591fddf..932b0ac737690 100644
--- a/clang/test/CodeGenHLSL/sgep/load_global.hlsl
+++ b/clang/test/CodeGenHLSL/sgep/load_global.hlsl
@@ -21,19 +21,19 @@ const uint b;
void foo() {
-// CHECK-DXIL: %[[#PTR:]] = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype(%S) @_ZL1s, i32 1)
+// CHECK-DXIL: %[[#PTR:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @_ZL1s, <1 x i32> splat (i32 3), i32 1)
// CHECK-DXIL: %[[#]] = load i32, ptr addrspace(2) %[[#PTR]], align 4
-// CHECK-SPIR: %[[#PTR:]] = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype(%S) @_ZL1s, i32 1)
+// CHECK-SPIR: %[[#PTR:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @_ZL1s, <1 x i32> splat (i32 3), i32 1)
// CHECK-SPIR: %[[#]] = load i32, ptr addrspace(12) %[[#PTR]], align 4
uint tmp = s.b;
}
void bar() {
-// CHECK-DXIL: %cbufferidx = call ptr addrspace(2) (ptr addrspace(2), ...) @llvm.structured.gep.p2(ptr addrspace(2) elementtype([4 x <{ i32, target("dx.Padding", 12) }>]) @_ZL1a, i32 2, i32 0)
+// CHECK-DXIL: %cbufferidx = call ptr addrspace(2) (ptr addrspace(2), <2 x i32>, ...) @llvm.structured.gep.p2.v2i32(ptr addrspace(2) elementtype([4 x <{ i32, target("dx.Padding", 12) }>]) @_ZL1a, <2 x i32> splat (i32 3), i32 2, i32 0)
// CHECK-DXIL: %[[#]] = load i32, ptr addrspace(2) %cbufferidx, align 16
-// CHECK-SPIR: %cbufferidx = call ptr addrspace(12) (ptr addrspace(12), ...) @llvm.structured.gep.p12(ptr addrspace(12) elementtype([4 x <{ i32, target("spirv.Padding", 12) }>]) @_ZL1a, i64 2, i32 0)
+// CHECK-SPIR: %cbufferidx = call ptr addrspace(12) (ptr addrspace(12), <2 x i32>, ...) @llvm.structured.gep.p12.v2i32(ptr addrspace(12) elementtype([4 x <{ i32, target("spirv.Padding", 12) }>]) @_ZL1a, <2 x i32> splat (i32 3), i64 2, i32 0)
// CHECK-SPIR: %[[#]] = load i32, ptr addrspace(12) %cbufferidx, align 16
uint tmp = a[2];
}
diff --git a/clang/test/CodeGenHLSL/sgep/object_method.hlsl b/clang/test/CodeGenHLSL/sgep/object_method.hlsl
index 34b6c4a44ed65..869c9cb4089c6 100644
--- a/clang/test/CodeGenHLSL/sgep/object_method.hlsl
+++ b/clang/test/CodeGenHLSL/sgep/object_method.hlsl
@@ -25,6 +25,6 @@ void foo() {
// CHECK-DXIL: define linkonce_odr hidden noundef i32 @_ZN1O3getEv(ptr noundef nonnull align 1 dereferenceable(4) %this)
// CHECK-SPIR: define linkonce_odr hidden spir_func noundef i32 @_ZN1O3getEv(ptr noundef nonnull align 1 dereferenceable(4) %this)
-// CHECK: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.O) %this1, {{i32|i64}} 0)
+// CHECK: %[[#A:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.O) %this1, <1 x i32> splat (i32 3), {{i32|i64}} 0)
// CHECK: %[[#B:]] = load i32, ptr %[[#A]], align 1
// CHECK: ret i32 %[[#B]]
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index cf052513c5ef8..07a505f2bbdd0 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -15515,7 +15515,8 @@ Syntax:
::
declare <ret_type>
- @llvm.structured.gep(ptr elementtype(<basetype>) <source>
+ @llvm.structured.gep(ptr elementtype(<basetype>) <source>,
+ <[number of indices] x i32> flags,
{, [i32/i64] <index> }*)
Overview:
@@ -15538,7 +15539,7 @@ The ``source`` argument must be annotated with an :ref:`elementtype
type of the element pointed to by the pointer source. This type will be
used along with the provided indices and source operand to compute a new
pointer representing the result of a logical indexing into the basetype
-pointed by source.
+pointed to by ``source``.
The ``basetype`` is only associated with ``<source>`` for this particular
call. A frontend could possibly emit multiple structured
@@ -15546,11 +15547,27 @@ GEP with the same source pointer but a different ``basetype``.
``[i32/i64] index, ...``:
Indices used to traverse into the ``basetype`` and compute a pointer to the
-target element. Indices can be 32-bit or 64-bit unsigned integers. Indices being
-handled one by one, both sizes can be mixed in the same instruction. The
+target element. Indices can be 32-bit or 64-bit integers, which are
+treated as signed unless the ``unsigned`` bit is set in that index's flag. As
+indices are handled one by one, both sizes can be mixed in the same instruction. The
precision used to compute the resulting pointer is target-dependent.
When used to index into a struct, only integer constants are allowed.
+``<[number of indices] x i32> flags``:
+The semantic flags associated with each index application. The flags may differ
+for each index application. This operand must be a constant fixed vector of
+``i32`` values.
+
+Bits not given a meaning below are reserved and should be set to 0 for
+portability. The 0 value of such a bit preserves the most conservative default
+semantics. Bits 16-31 (``1 << 16`` and up) are reserved for target-specific
+flags. The verifier accepts reserved bits without assigning semantics to them.
+
+LLVM IR does not have zero-length vector types. If there are no indices, the
+flags operand must be ``<1 x i32> zeroinitializer`` and is ignored. This is
+the sole exception to the ``<[number of indices] x i32>`` notation above.
+Otherwise, the flags operand must have one element per index.
+
Semantics:
""""""""""
@@ -15565,33 +15582,43 @@ The first index determines which element/field of ``basetype`` is selected,
computes the pointer to access this element/field assuming ``source`` points
to the start of ``basetype``.
This pointer becomes the new ``source``, the current type the new
-``basetype``, and the next indices is consumed until a scalar type is
+``basetype``, and the next index is consumed until a scalar type is
reached or all indices are consumed.
-All indices must be consumed, and it is illegal to index into a scalar type.
-Meaning the maximum number of indices depends on the depth of the basetype.
-
-Because this instruction performs a logical addressing, all indices are
-assumed to be inbounds. This means it is not possible to access the next
-element in the logical layout by overflowing:
-
-- If the indexed type is a struct with N fields, the index must be an
- immediate/constant value in the range ``[0; N[``.
-- If indexing into an array or vector, the index can be a variable, but
- is assumed to be inbounds with regards to the current basetype logical layout.
-- If the traversed type is an array or vector of N elements with ``N > 0``,
- the index is assumed to belong to ``[0; N[``.
-- If the traversed type is an array of size ``0``, the array size is assumed
- to be known at runtime, and the instruction assumes the index is always
- inbounds.
-
-In all cases **except** when the accessed type is a 0-sized array, indexing
-out of bounds yields `poison`. When the index value is unknown, optimizations
-can use the type bounds to determine the range of values the index can have.
+All indices must be consumed, and it is illegal to index into a scalar type,
+meaning the maximum number of indices depends on the depth of the basetype.
+
+If the indexed type is a struct with N fields, the index must be an
+integer constant in the range ``[0, N)``.
+
+If the constraints implied by a flag bit are violated, the result is ``poison``.
If the source pointer is poison, the instruction returns poison.
The resulting pointer belongs to the same address space as ``source``.
This instruction does not dereference the pointer.
+Defined flag bits:
+""""""""""""""""""
+
+``inbounds``
+ Bit 0 (``1 << 0``) - specifies that this index is within the bounds of the type
+ being indexed at that level. In particular, when indexing an array or vector
+ ``[ N x T ]``, implies that the index is in the range ``[0, N)``. As an exception,
+ if ``N`` is 0, the bound is treated as an unknown, dynamic value, but the flag
+ still implies that the index is inside that runtime bound.
+ Structure accesses are always ``inbounds`` and must be marked as
+ such. A structured GEP is said to be inbounds if all of its indices are inbounds.
+
+``nneg``
+ Bit 1 (``1 << 1``) - specifies that the value of this index is non-negative.
+ This is not necessarily implied by ``inbounds``, as an object may have more
+ fields than the maximal signed value for the index type.
+
+``unsigned``
+ Bit 2 (``1 << 2``) - specifies that the index should be interpreted as an
+ unsigned number if extension or truncation is required.
+
+The ``inbounds`` and ``nneg`` flags must be set when indexing into structures.
+
Example:
""""""""
@@ -15607,7 +15634,7 @@ Could be translated to:
.. code-block:: llvm
%A = type { i32, i32, i32, i32 }
- %src = call ptr @llvm.structured.gep(ptr elementtype(%A) %my_struct, i32 1)
+ %src = call ptr @llvm.structured.gep(ptr elementtype(%A) %my_struct, <1 x i32> <i32 3>, i32 1)
%val = load i32, ptr %src
**A more complex case**
@@ -15634,24 +15661,68 @@ knows those logical layouts are lowered to the same physical layout:
- `{ i32, i32, i32, i32 }`
- `[ i32 x 4 ]`
-This means is is valid to lower the following code to either:
+This means it is valid to lower the following code to either:
.. code-block:: llvm
%S = type { i32, i32, i32, i32 }
- %src = call ptr @llvm.structured.gep(ptr elementtype(%S) %my_struct, i32 1)
+ %src = call ptr @llvm.structured.gep(ptr elementtype(%S) %my_struct, <1 x i32> <i32 3>, i32 1)
load i32, ptr %src
Or:
.. code-block:: llvm
- %src = call ptr @llvm.structured.gep(ptr elementtype([ 4 x i32 ]) %my_struct, i32 1)
+ %src = call ptr @llvm.structured.gep(ptr elementtype([4 x i32]) %my_struct, <1 x i32> <i32 3>, i32 1)
load i32, ptr %src
This is, however, dependent on context that codegen has an insight on. The
fact that `[ i32 x 4 ]` and `%S` are equivalent depends on the target.
+**Array bounds handling**
+
+.. code-block:: cpp
+
+ float array[M][N];
+ float val = array[i][j];
+
+Could be translated to:
+
+.. code-block:: llvm
+
+ ;; No knowledge about if 0 <= %i < M or 0 <= %j < N
+ %src = call ptr @llvm.structured.gep(ptr elementtype([M x [N x float]]) %array,
+ <2 x i32> <i32 0, i32 0>, i64 %i, i64 %j)
+ %val = load float, ptr %src
+
+or as something with more flags, such as
+
+.. code-block:: llvm
+
+ ;; 0 sle %i slt M follows from this, as does %j ult N.
+ %src = call ptr @llvm.structured.gep(ptr elementtype([M x [N x float]]) %array,
+ <2 x i32> <i32 3, i32 5>, i64 %i, i64 %j)
+ %val = load float, ptr %src
+
+depending on the semantics the frontend assigns to the program.
+
+When dealing with dynamic bounds, a "0-sized" array is used, so
+
+.. code-block:: cpp
+
+ float array[];
+ float val = array[i];
+
+could be translated to:
+
+.. code-block:: llvm
+
+ %src = call ptr @llvm.structured.gep(ptr elementtype([0 x float]) %array,
+ <1 x i32> <i32 3>, i64 %i)
+ %val = load float, ptr %src
+
+if the frontend knows that the dynamic index is non-negative and bounded by the
+size of ``array``.
.. _i_structured_alloca:
@@ -15716,7 +15787,7 @@ Example:
%ptr = call elementtype(%S) ptr @llvm.structured.alloca()
; Access the second field of the allocated struct
- %field_ptr = call ptr @llvm.structured.gep(ptr elementtype(%S) %ptr, i32 1)
+ %field_ptr = call ptr @llvm.structured.gep(ptr elementtype(%S) %ptr, <1 x i32> <i32 3>, i32 1)
%val = load i32, ptr %field_ptr
; Allocate an array of 10 i32s on the stack
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 99e4b748425c0..f38492962852d 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -35,6 +35,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Operator.h"
+#include "llvm/IR/StructuredGEPFlags.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/ValueHandle.h"
@@ -2005,13 +2006,27 @@ class IRBuilderBase {
CallInst *CreateStructuredGEP(Type *BaseType, Value *PtrBase,
ArrayRef<Value *> Indices,
+ ArrayRef<StructuredGEPFlags> Flags,
const Twine &Name = "") {
+ assert(Flags.size() == Indices.size() &&
+ "expected one flag value per structured GEP index");
+ Type *Int32Ty = getInt32Ty();
+ SmallVector<Constant *> FlagValues;
+ FlagValues.reserve(Flags.empty() ? 1 : Flags.size());
+ for (StructuredGEPFlags Flag : Flags)
+ FlagValues.push_back(ConstantInt::get(Int32Ty, Flag.getRaw()));
+ if (FlagValues.empty())
+ FlagValues.push_back(ConstantInt::get(Int32Ty, 0));
+ Value *FlagsVec = ConstantVector::get(FlagValues);
+
SmallVector<Value *> Args;
Args.push_back(PtrBase);
+ Args.push_back(FlagsVec);
llvm::append_range(Args, Indices);
- CallInst *Output = CreateIntrinsic(Intrinsic::structured_gep,
- {PtrBase->getType()}, Args, {}, Name);
+ CallInst *Output = CreateIntrinsic(
+ Intrinsic::structured_gep, {PtrBase->getType(), FlagsVec->getType()},
+ Args, {}, Name);
Output->addParamAttr(
0, Attribute::get(getContext(), Attribute::ElementType, BaseType));
return Output;
diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h
index 78a0cd569d5bd..ee86da2e17a57 100644
--- a/llvm/include/llvm/IR/IntrinsicInst.h
+++ b/llvm/include/llvm/IR/IntrinsicInst.h
@@ -23,6 +23,7 @@
#ifndef LLVM_IR_INTRINSICINST_H
#define LLVM_IR_INTRINSICINST_H
+#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
@@ -31,6 +32,7 @@
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/StructuredGEPFlags.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
@@ -1830,20 +1832,50 @@ class StructuredGEPInst : public IntrinsicInst {
}
static unsigned getPointerOperandIndex() { return 0; }
+ static unsigned getFlagsOperandIndex() { return 1; }
+ static unsigned getFirstIndexOperandIndex() { return 2; }
Value *getPointerOperand() const {
return getOperand(getPointerOperandIndex());
}
+ Constant *getFlagsOperand() const {
+ return cast<Constant>(getOperand(getFlagsOperandIndex()));
+ }
+
Type *getBaseType() const {
return getParamAttr(0, Attribute::ElementType).getValueAsType();
}
- unsigned getNumIndices() const { return arg_size() - 1; }
+ unsigned getNumIndices() const {
+ return arg_size() - getFirstIndexOperandIndex();
+ }
Value *getIndexOperand(size_t Index) const {
assert(Index < getNumIndices());
- return getOperand(Index + 1);
+ return getOperand(Index + getFirstIndexOperandIndex());
+ }
+
+ StructuredGEPFlags getIndexFlags(size_t Index) const {
+ assert(Index < getNumIndices());
+ Constant *Flags = getFlagsOperand();
+ auto *FlagValue = cast<ConstantInt>(Flags->getAggregateElement(Index));
+ return StructuredGEPFlags::fromRaw(FlagValue->getZExtValue());
+ }
+
+ bool isIndexInBounds(size_t Index) const {
+ return getIndexFlags(Index).isInBounds();
+ }
+
+ bool isIndexNNeg(size_t Index) const { return getIndexFlags(Index).isNNeg(); }
+
+ bool isIndexUnsigned(size_t Index) const {
+ return getIndexFlags(Index).isUnsignedIndex();
+ }
+
+ bool isInBounds() const {
+ return all_of(seq<unsigned>(0, getNumIndices()),
+ [this](unsigned Index) { return isIndexInBounds(Index); });
}
Type *getResultElementType() const {
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index b1b2bb2a72c65..1cc100bcc024f 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1059,7 +1059,8 @@ def int_callbr_landingpad : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>],
def int_structured_gep
: DefaultAttrsIntrinsic<[llvm_anyptr_ty],
- [LLVMMatchType<0>, llvm_vararg_ty],
+ [LLVMMatchType<0>, llvm_anyvector_ty,
+ llvm_vararg_ty],
[IntrNoMem, IntrSpeculatable]>;
def int_structured_alloca : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [],
diff --git a/llvm/include/llvm/IR/StructuredGEPFlags.h b/llvm/include/llvm/IR/StructuredGEPFlags.h
new file mode 100644
index 0000000000000..6ffc41b7dc5ce
--- /dev/null
+++ b/llvm/include/llvm/IR/StructuredGEPFlags.h
@@ -0,0 +1,73 @@
+//===- llvm/IR/StructuredGEPFlags.h - Structured GEP flags ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the per-index flags for llvm.structured.gep.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_STRUCTUREDGEPFLAGS_H
+#define LLVM_IR_STRUCTUREDGEPFLAGS_H
+
+namespace llvm {
+
+/// Represents the per-index flags for llvm.structured.gep.
+class StructuredGEPFlags {
+ enum Flag : unsigned {
+ InBoundsFlag = (1 << 0),
+ NNegFlag = (1 << 1),
+ UnsignedFlag = (1 << 2),
+ };
+
+ unsigned Flags;
+
+public:
+ StructuredGEPFlags() : Flags(0) {}
+ explicit StructuredGEPFlags(unsigned Flags) : Flags(Flags) {}
+
+ static StructuredGEPFlags none() { return StructuredGEPFlags(); }
+ static StructuredGEPFlags inBounds() {
+ return StructuredGEPFlags(InBoundsFlag);
+ }
+ static StructuredGEPFlags nneg() { return StructuredGEPFlags(NNegFlag); }
+ static StructuredGEPFlags unsignedIndex() {
+ return StructuredGEPFlags(UnsignedFlag);
+ }
+
+ static StructuredGEPFlags fromRaw(unsigned Flags) {
+ return StructuredGEPFlags(Flags);
+ }
+ unsigned getRaw() const { return Flags; }
+
+ bool isInBounds() const { return Flags & InBoundsFlag; }
+ bool isNNeg() const { return Flags & NNegFlag; }
+ bool isUnsignedIndex() const { return Flags & UnsignedFlag; }
+
+ bool operator==(StructuredGEPFlags Other) const {
+ return Flags == Other.Flags;
+ }
+ bool operator!=(StructuredGEPFlags Other) const { return !(*this == Other); }
+
+ StructuredGEPFlags operator&(StructuredGEPFlags Other) const {
+ return StructuredGEPFlags(Flags & Other.Flags);
+ }
+ StructuredGEPFlags operator|(StructuredGEPFlags Other) const {
+ return StructuredGEPFlags(Flags | Other.Flags);
+ }
+ StructuredGEPFlags &operator&=(StructuredGEPFlags Other) {
+ Flags &= Other.Flags;
+ return *this;
+ }
+ StructuredGEPFlags &operator|=(StructuredGEPFlags Other) {
+ Flags |= Other.Flags;
+ return *this;
+ }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_IR_STRUCTUREDGEPFLAGS_H
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 81debece796b1..7f63ea74f48e8 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6617,8 +6617,6 @@ Value *llvm::simplifyUnaryIntrinsic(Intrinsic::ID IID, Value *Op0,
if (isSplatValue(Op0))
return Op0;
break;
- case Intrinsic::structured_gep:
- return Op0;
default:
break;
}
@@ -7231,6 +7229,10 @@ static Value *simplifyIntrinsic(CallBase *Call, Value *Callee,
if (IID != Intrinsic::not_intrinsic && intrinsicPropagatesPoison(IID) &&
any_of(Args, IsaPred<PoisonValue>))
return PoisonValue::get(F->getReturnType());
+ if (IID == Intrinsic::structured_gep) {
+ auto *SGEP = cast<StructuredGEPInst>(Call);
+ return SGEP->getNumIndices() == 0 ? SGEP->getPointerOperand() : nullptr;
+ }
// Most of the intrinsics with no operands have some kind of side effect.
// Don't simplify.
if (!NumOperands) {
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 0770f0f0ff060..8054b2b201a0a 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -43,6 +43,7 @@
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/StructuredGEPFlags.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/AMDGPUAddrSpace.h"
@@ -1279,6 +1280,14 @@ static bool convertIntrinsicValidType(StringRef Name,
return false;
}
+static bool isOldStructuredGEPIntrinsic(Function *F, StringRef Name) {
+ if (Name != "structured.gep" && !Name.starts_with("structured.gep."))
+ return false;
+
+ FunctionType *FTy = F->getFunctionType();
+ return FTy->getNumParams() < 2 || !FTy->getParamType(1)->isVectorTy();
+}
+
static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
bool CanUpgradeDebugIntrinsicsToRecords) {
assert(F && "Illegal to upgrade a non-existent Function.");
@@ -1815,6 +1824,10 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
NewFn = nullptr;
return true;
}
+ if (isOldStructuredGEPIntrinsic(F, Name)) {
+ NewFn = nullptr;
+ return true;
+ }
break;
case 't':
@@ -5025,6 +5038,83 @@ static Value *upgradeConvertIntrinsicCall(StringRef Name, CallBase *CI,
return nullptr;
}
+static StructuredGEPFlags getLegacyStructuredGEPIndexFlags(Type *&CurrentType,
+ Value *Index) {
+ StructuredGEPFlags Flags = StructuredGEPFlags::unsignedIndex();
+ if (!CurrentType)
+ return Flags;
+
+ if (auto *AT = dyn_cast<ArrayType>(CurrentType)) {
+ if (AT->getNumElements() != 0)
+ Flags |= StructuredGEPFlags::inBounds();
+ CurrentType = AT->getElementType();
+ return Flags;
+ }
+
+ if (auto *VT = dyn_cast<VectorType>(CurrentType)) {
+ Flags |= StructuredGEPFlags::inBounds();
+ CurrentType = VT->getElementType();
+ return Flags;
+ }
+
+ if (auto *ST = dyn_cast<StructType>(CurrentType)) {
+ Flags |= StructuredGEPFlags::inBounds() | StructuredGEPFlags::nneg();
+ if (auto *CI = dyn_cast<ConstantInt>(Index))
+ if (CI->getZExtValue() < ST->getNumElements())
+ CurrentType = ST->getElementType(CI->getZExtValue());
+ return Flags;
+ }
+
+ CurrentType = nullptr;
+ return Flags;
+}
+
+static Constant *getLegacyStructuredGEPFlags(CallBase *CI) {
+ Type *CurrentType = nullptr;
+ if (CI->paramHasAttr(0, Attribute::ElementType))
+ CurrentType = CI->getParamAttr(0, Attribute::ElementType).getValueAsType();
+
+ Type *Int32Ty = Type::getInt32Ty(CI->getContext());
+ SmallVector<Constant *> FlagValues;
+ unsigned NumIndices = CI->arg_size() - 1;
+ FlagValues.reserve(NumIndices == 0 ? 1 : NumIndices);
+ for (unsigned I = 0; I < NumIndices; ++I) {
+ StructuredGEPFlags Flags =
+ getLegacyStructuredGEPIndexFlags(CurrentType, CI->getArgOperand(I + 1));
+ FlagValues.push_back(ConstantInt::get(Int32Ty, Flags.getRaw()));
+ }
+
+ if (FlagValues.empty())
+ FlagValues.push_back(ConstantInt::get(Int32Ty, 0));
+ return ConstantVector::get(FlagValues);
+}
+
+static Value *upgradeStructuredGEPIntrinsicCall(CallBase *CI, Function *F,
+ IRBuilder<> &Builder) {
+ Constant *Flags = getLegacyStructuredGEPFlags(CI);
+ SmallVector<Value *> Args;
+ Args.reserve(CI->arg_size() + 1);
+ Args.push_back(CI->getArgOperand(0));
+ Args.push_back(Flags);
+ for (unsigned I = 1; I < CI->arg_size(); ++I)
+ Args.push_back(CI->getArgOperand(I));
+
+ Function *NewFn = Intrinsic::getOrInsertDeclaration(
+ F->getParent(), Intrinsic::structured_gep,
+ {CI->getType(), Flags->getType()});
+ SmallVector<OperandBundleDef, 1> Bundles;
+ CI->getOperandBundlesAsDefs(Bundles);
+
+ CallInst *NewCall = Builder.CreateCall(NewFn, Args, Bundles);
+ NewCall->setCallingConv(CI->getCallingConv());
+ NewCall->setDebugLoc(CI->getDebugLoc());
+ NewCall->copyMetadata(*CI);
+ if (CI->paramHasAttr(0, Attribute::ElementType))
+ NewCall->addParamAttr(0, CI->getParamAttr(0, Attribute::ElementType));
+ NewCall->takeName(CI);
+ return NewCall;
+}
+
/// Upgrade a call to an old intrinsic. All argument and return casting must be
/// provided to seamlessly integrate with existing context.
void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) {
@@ -5077,6 +5167,9 @@ void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) {
Rep = upgradeVectorSplice(CI, Builder);
} else if (Name.consume_front("convert.")) {
Rep = upgradeConvertIntrinsicCall(Name, CI, F, Builder);
+ } else if (Name == "structured.gep" ||
+ Name.starts_with("structured.gep.")) {
+ Rep = upgradeStructuredGEPIntrinsicCall(CI, F, Builder);
} else {
llvm_unreachable("Unknown function for CallBase upgrade.");
}
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index f0363b6553440..3a83c2289f96a 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -107,6 +107,7 @@
#include "llvm/IR/PassManager.h"
#include "llvm/IR/ProfDataUtils.h"
#include "llvm/IR/Statepoint.h"
+#include "llvm/IR/StructuredGEPFlags.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/User.h"
@@ -7093,19 +7094,60 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
}
case Intrinsic::structured_gep: {
// Parser should refuse those 2 cases.
- assert(Call.arg_size() >= 1);
+ assert(Call.arg_size() >= 2);
assert(Call.getOperand(0)->getType()->isPointerTy());
Check(Call.paramHasAttr(0, Attribute::ElementType),
"Intrinsic first parameter is missing an ElementType attribute",
&Call);
+ Value *FlagsOp = Call.getOperand(1);
+ auto *FlagsTy = dyn_cast<FixedVectorType>(FlagsOp->getType());
+ bool FlagsElementTypeValid =
+ FlagsTy && FlagsTy->getElementType()->isIntegerTy(32);
+ Check(FlagsElementTypeValid,
+ "Flags operand type must be a fixed vector of i32", &Call);
+ unsigned NumIndices = Call.arg_size() - 2;
+ unsigned ExpectedFlags = NumIndices == 0 ? 1 : NumIndices;
+ bool FlagsElementCountValid =
+ FlagsTy && FlagsTy->getNumElements() == ExpectedFlags;
+ Check(FlagsElementCountValid,
+ "Flags operand must have one element per index", &Call);
+ auto *FlagsC = dyn_cast<Constant>(FlagsOp);
+ Check(FlagsC, "Flags operand must be a constant", &Call);
+
+ SmallVector<StructuredGEPFlags> FlagValues;
+ if (FlagsElementTypeValid && FlagsElementCountValid && FlagsC) {
+ FlagValues.reserve(ExpectedFlags);
+ for (unsigned I = 0; I < ExpectedFlags; ++I) {
+ auto *FlagValue =
+ dyn_cast_or_null<ConstantInt>(FlagsC->getAggregateElement(I));
+ Check(FlagValue, "Flags operand elements must be integer constants",
+ &Call);
+ if (!FlagValue)
+ continue;
+ FlagValues.push_back(
+ StructuredGEPFlags::fromRaw(FlagValue->getZExtValue()));
+ }
+
+ if (NumIndices == 0 && FlagValues.size() == 1)
+ Check(FlagValues[0] == StructuredGEPFlags::none(),
+ "Flags operand must be zero when there are no indices", &Call);
+ }
+
+ auto GetFlags = [&](unsigned Index) {
+ if (Index >= FlagValues.size())
+ return StructuredGEPFlags::none();
+ return FlagValues[Index];
+ };
+
Type *T = Call.getParamAttr(0, Attribute::ElementType).getValueAsType();
- for (unsigned I = 1; I < Call.arg_size(); ++I) {
+ for (unsigned I = 2; I < Call.arg_size(); ++I) {
Value *Index = Call.getOperand(I);
ConstantInt *CI = dyn_cast<ConstantInt>(Index);
Check(Index->getType()->isIntegerTy(),
"Index operand type must be an integer", &Call);
+ StructuredGEPFlags IndexFlags = GetFlags(I - 2);
if (ArrayType *AT = dyn_cast<ArrayType>(T)) {
T = AT->getElementType();
@@ -7113,6 +7155,8 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
Check(CI, "Indexing into a struct requires a constant int", &Call);
Check(CI->getZExtValue() < ST->getNumElements(),
"Indexing in a struct should be inbounds", &Call);
+ Check(IndexFlags.isInBounds() && IndexFlags.isNNeg(),
+ "Indexing into a struct requires inbounds and nneg flags", &Call);
T = ST->getElementType(CI->getZExtValue());
} else if (VectorType *VT = dyn_cast<VectorType>(T)) {
T = VT->getElementType();
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index f5c462bdc629b..af9428b4e1f41 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -1917,7 +1917,7 @@ Instruction *SPIRVEmitIntrinsics::visitIntrinsicInst(IntrinsicInst &I) {
B.SetInsertPoint(&I);
SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
SmallVector<Value *, 4> Args;
- Args.push_back(/* inBounds= */ B.getInt1(true));
+ Args.push_back(/* inBounds= */ B.getInt1(SGEP->isInBounds()));
Args.push_back(I.getOperand(0));
Args.push_back(/* zero index */ B.getInt32(0));
for (unsigned J = 0; J < SGEP->getNumIndices(); ++J)
diff --git a/llvm/test/Assembler/auto_upgrade_intrinsics.ll b/llvm/test/Assembler/auto_upgrade_intrinsics.ll
index a3719049c4419..2ac3edd02c786 100644
--- a/llvm/test/Assembler/auto_upgrade_intrinsics.ll
+++ b/llvm/test/Assembler/auto_upgrade_intrinsics.ll
@@ -3,6 +3,8 @@
; RUN: verify-uselistorder %s
%0 = type opaque;
+%struct.S = type { i32, i32 }
+%struct.RuntimeArray = type { [0 x i32] }
declare i8 @llvm.ctlz.i8(i8)
declare i16 @llvm.ctlz.i16(i16)
@@ -228,6 +230,23 @@ define void @test.vector.splice(<4 x i32> %a, <4 x i32> %b) {
ret void
}
+define void @test.structured.gep(ptr %ptr, i32 %index) {
+; CHECK-LABEL: @test.structured.gep(
+; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(i32) %ptr, <1 x i32> zeroinitializer)
+ %no_index = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(i32) %ptr)
+; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([4 x i32]) %ptr, <1 x i32> splat (i32 5), i32 %index)
+ %array = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([4 x i32]) %ptr, i32 %index)
+; CHECK: %array_with_md = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([4 x i32]) %ptr, <1 x i32> splat (i32 5), i32 %index), !annotation ![[SGEP_MD:[0-9]+]]
+ %array_with_md = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([4 x i32]) %ptr, i32 %index), !annotation !0
+; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([0 x i32]) %ptr, <1 x i32> splat (i32 4), i32 %index)
+ %runtime_array = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([0 x i32]) %ptr, i32 %index)
+; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %ptr, <1 x i32> splat (i32 7), i32 1)
+ %struct = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %ptr, i32 1)
+; CHECK: call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.RuntimeArray) %ptr, <2 x i32> <i32 7, i32 4>, i32 0, i32 %index)
+ %struct_runtime_array = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.RuntimeArray) %ptr, i32 0, i32 %index)
+ ret void
+}
+
define i32 @ctlz(i32 %A) {
; CHECK: %for.body.i = call i32 @llvm.ctlz.i32(i32 %A, i1 false)
%for.body.i = call i32 @llvm.ctlz.i32.p0(i32 %A)
@@ -266,3 +285,6 @@ define <8 x double> @preserve_fmf_on_x86_intrin(<8 x double> %x0, <8 x double> %
; CHECK: declare void @llvm.lifetime.start.p0(ptr captures(none))
; CHECK: declare void @llvm.lifetime.end.p0(ptr captures(none))
+; CHECK: ![[SGEP_MD]] = !{!"structured.gep.metadata"}
+
+!0 = !{!"structured.gep.metadata"}
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-array.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-array.ll
index d7a40dbc323b1..1b8571edad113 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-array.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-array.ll
@@ -31,12 +31,12 @@ entry:
%tmp = alloca [5 x i32], align 4
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_uint_5]] Function
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x i32]) %a, i64 2)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %a, <1 x i32> <i32 5>, i64 2)
%2 = load i32, ptr %1, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#]] %[[#ulong_2]]
; CHECK: %[[#B:]] = OpLoad %[[#uint]] %[[#A]]
- %3 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([5 x i32]) %tmp, i64 3)
+ %3 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([5 x i32]) %tmp, <1 x i32> <i32 5>, i64 3)
store i32 %2, ptr %3, align 4
; CHECK: %[[#C:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#tmp]] %[[#ulong_3]]
; CHECK: OpStore %[[#C]] %[[#B]]
@@ -50,15 +50,15 @@ entry:
%tmp = alloca [5 x %struct.S], align 4
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_S_5]] Function
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S]) %a, i64 2)
- %2 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %1, i64 1)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S]) %a, <1 x i32> <i32 5>, i64 2)
+ %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %1, <1 x i32> <i32 3>, i64 1)
%3 = load i32, ptr %2, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_S]] %[[#]] %[[#ulong_2]]
; CHECK: %[[#B:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#A]] %[[#ulong_1]]
; CHECK: %[[#C:]] = OpLoad %[[#uint]] %[[#B]]
- %4 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([5 x %struct.S]) %tmp, i64 3)
- %5 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %4, i32 0)
+ %4 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([5 x %struct.S]) %tmp, <1 x i32> <i32 5>, i64 3)
+ %5 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %4, <1 x i32> <i32 3>, i32 0)
store i32 %3, ptr %5, align 4
; CHECK: %[[#D:]] = OpInBoundsAccessChain %[[#ptr_S]] %[[#tmp]] %[[#ulong_3]]
; CHECK: %[[#E:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#D]] %[[#uint_0]]
@@ -73,12 +73,12 @@ entry:
%tmp = alloca [5 x %struct.S], align 4
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_S_5]] Function
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S]) %a, i64 2, i64 1)
+ %1 = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([3 x %struct.S]) %a, <2 x i32> <i32 5, i32 3>, i64 2, i64 1)
%2 = load i32, ptr %1, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#]] %[[#ulong_2]] %[[#ulong_1]]
; CHECK: %[[#B:]] = OpLoad %[[#uint]] %[[#A]]
- %3 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([5 x %struct.S]) %tmp, i64 3, i32 0)
+ %3 = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([5 x %struct.S]) %tmp, <2 x i32> <i32 5, i32 3>, i64 3, i32 0)
store i32 %2, ptr %3, align 4
; CHECK: %[[#C:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#tmp]] %[[#ulong_3]] %[[#uint_0]]
; CHECK: OpStore %[[#C]] %[[#B]]
@@ -92,18 +92,18 @@ entry:
%tmp = alloca [5 x %struct.S2], align 4
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_S2_5]] Function
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S2]) %a, i64 1)
- %2 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S2) %1, i64 1)
- %3 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %2, i64 0)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S2]) %a, <1 x i32> <i32 5>, i64 1)
+ %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %1, <1 x i32> <i32 3>, i64 1)
+ %3 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %2, <1 x i32> <i32 3>, i64 0)
%4 = load i32, ptr %3, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_S2]] %[[#]] %[[#ulong_1]]
; CHECK: %[[#B:]] = OpInBoundsAccessChain %[[#ptr_S]] %[[#A]] %[[#ulong_1]]
; CHECK: %[[#C:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#B]] %[[#ulong_0]]
; CHECK: %[[#D:]] = OpLoad %[[#uint]] %[[#C]]
- %5 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([5 x %struct.S2]) %tmp, i64 3)
- %6 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S2) %5, i32 1)
- %7 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %6, i32 0)
+ %5 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([5 x %struct.S2]) %tmp, <1 x i32> <i32 5>, i64 3)
+ %6 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %5, <1 x i32> <i32 3>, i32 1)
+ %7 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %6, <1 x i32> <i32 3>, i32 0)
store i32 %4, ptr %7, align 4
; CHECK: %[[#E:]] = OpInBoundsAccessChain %[[#ptr_S2]] %[[#tmp]] %[[#ulong_3]]
; CHECK: %[[#F:]] = OpInBoundsAccessChain %[[#ptr_S]] %[[#E]] %[[#uint_1]]
@@ -119,12 +119,12 @@ entry:
%tmp = alloca [5 x %struct.S2], align 4
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_S2_5]] Function
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S2]) %a, i64 1, i64 1, i64 0)
+ %1 = call ptr (ptr, <3 x i32>, ...) @llvm.structured.gep.p0.v3i32(ptr elementtype([3 x %struct.S2]) %a, <3 x i32> <i32 5, i32 3, i32 3>, i64 1, i64 1, i64 0)
%2 = load i32, ptr %1, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#]] %[[#ulong_1]] %[[#ulong_1]] %[[#ulong_0]]
; CHECK: %[[#B:]] = OpLoad %[[#uint]] %[[#A]]
- %3 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([5 x %struct.S2]) %tmp, i64 3, i32 1, i32 0)
+ %3 = call ptr (ptr, <3 x i32>, ...) @llvm.structured.gep.p0.v3i32(ptr elementtype([5 x %struct.S2]) %tmp, <3 x i32> <i32 5, i32 3, i32 3>, i64 3, i32 1, i32 0)
store i32 %2, ptr %3, align 4
; CHECK: %[[#C:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#tmp]] %[[#ulong_3]] %[[#uint_1]] %[[#uint_0]]
; CHECK: OpStore %[[#C]] %[[#B]]
@@ -134,7 +134,9 @@ entry:
declare token @llvm.experimental.convergence.entry() #1
-declare ptr @llvm.structured.gep.p0(ptr, ...) #3
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #3
+declare ptr @llvm.structured.gep.p0.v2i32(ptr, <2 x i32>, ...) #3
+declare ptr @llvm.structured.gep.p0.v3i32(ptr, <3 x i32>, ...) #3
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-class.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-class.ll
index 6f85bbd2e6bad..d0d5b9e825ef7 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-class.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-class.ll
@@ -19,11 +19,11 @@ entry:
; CHECK: %[[#d_var:]] = OpFunctionParameter %[[#ptr_Derived]]
; Access Base part
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%class.Derived) %d, i32 0)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%class.Derived) %d, <1 x i32> <i32 3>, i32 0)
; CHECK: %[[#ptr_base:]] = OpInBoundsAccessChain %[[#ptr_Base]] %[[#d_var]] %[[#idx_0]]
; Access field in Base
- %2 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%class.Base) %1, i32 0)
+ %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%class.Base) %1, <1 x i32> <i32 3>, i32 0)
; CHECK: %[[#ptr_field:]] = OpInBoundsAccessChain %[[#ptr_int]] %[[#ptr_base]] %[[#idx_0]]
store i32 42, ptr %2, align 4
@@ -33,7 +33,7 @@ entry:
}
declare token @llvm.experimental.convergence.entry() #1
-declare ptr @llvm.structured.gep.p0(ptr, ...) #3
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #3
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-dynamic-index.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-dynamic-index.ll
index 9c6d218592c7f..66d55d22e6493 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-dynamic-index.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-dynamic-index.ll
@@ -14,7 +14,7 @@ entry:
; CHECK: %[[#arr_var:]] = OpFunctionParameter %[[#ptr_array]]
; CHECK: %[[#idx_var:]] = OpFunctionParameter %[[#int]]
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %arr, i32 %idx)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %arr, <1 x i32> <i32 5>, i32 %idx)
; CHECK: %[[#ptr_elem:]] = OpInBoundsAccessChain %[[#ptr_int]] %[[#arr_var]] %[[#idx_var]]
%2 = load i32, ptr %1, align 4
@@ -30,7 +30,7 @@ entry:
; CHECK: %[[#arr_var2:]] = OpFunctionParameter %[[#ptr_array]]
; CHECK: %[[#idx_var2:]] = OpFunctionParameter %[[#long]]
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %arr, i64 %idx)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %arr, <1 x i32> <i32 5>, i64 %idx)
; CHECK: %[[#ptr_elem2:]] = OpInBoundsAccessChain %[[#ptr_int]] %[[#arr_var2]] %[[#idx_var2]]
%2 = load i32, ptr %1, align 4
@@ -40,8 +40,24 @@ entry:
; CHECK: OpReturnValue %[[#val2]]
}
+define spir_func i32 @dynamic_access_not_inbounds(ptr %arr, i32 %idx) convergent {
+entry:
+ %0 = call token @llvm.experimental.convergence.entry()
+ ; CHECK: %[[#arr_var3:]] = OpFunctionParameter %[[#ptr_array]]
+ ; CHECK: %[[#idx_var3:]] = OpFunctionParameter %[[#int]]
+
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %arr, <1 x i32> <i32 4>, i32 %idx)
+ ; CHECK: %[[#ptr_elem3:]] = OpAccessChain %[[#ptr_int]] %[[#arr_var3]] %[[#idx_var3]]
+
+ %2 = load i32, ptr %1, align 4
+ ; CHECK: %[[#val3:]] = OpLoad %[[#int]] %[[#ptr_elem3]]
+
+ ret i32 %2
+ ; CHECK: OpReturnValue %[[#val3]]
+}
+
declare token @llvm.experimental.convergence.entry() #1
-declare ptr @llvm.structured.gep.p0(ptr, ...) #3
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #3
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-nested-struct-array.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-nested-struct-array.ll
index f71a6400d726f..e012fb887fee7 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-nested-struct-array.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-nested-struct-array.ll
@@ -19,7 +19,7 @@ entry:
%0 = call token @llvm.experimental.convergence.entry()
; CHECK: %[[#obj_var:]] = OpFunctionParameter %[[#ptr_Outer]]
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.Outer) %obj, i32 0, i32 2, i32 1, i32 1)
+ %1 = call ptr (ptr, <4 x i32>, ...) @llvm.structured.gep.p0.v4i32(ptr elementtype(%struct.Outer) %obj, <4 x i32> <i32 3, i32 5, i32 3, i32 5>, i32 0, i32 2, i32 1, i32 1)
; CHECK: %[[#ptr_elem:]] = OpInBoundsAccessChain %[[#ptr_float]] %[[#obj_var]] %[[#]] %[[#]] %[[#]] %[[#]]
%2 = load float, ptr %1, align 4
@@ -29,7 +29,7 @@ entry:
}
declare token @llvm.experimental.convergence.entry() #1
-declare ptr @llvm.structured.gep.p0(ptr, ...) #3
+declare ptr @llvm.structured.gep.p0.v4i32(ptr, <4 x i32>, ...) #3
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-runtime-array.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-runtime-array.ll
index 333122236f63f..9a5583a9b41e8 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-runtime-array.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-runtime-array.ll
@@ -16,8 +16,8 @@ define spir_func i32 @runtime_array_access(i32 %idx) convergent {
entry:
%0 = call token @llvm.experimental.convergence.entry()
- %1 = call ptr addrspace(11) (ptr addrspace(11), ...) @llvm.structured.gep.p11(ptr addrspace(11) elementtype(%struct.RuntimeArray) @buffer, i32 0, i32 %idx)
- ; CHECK: %[[#ptr_elem:]] = OpInBoundsAccessChain %[[#ptr_sb_int]] %[[#buffer]] %[[#]] %[[#]]
+ %1 = call ptr addrspace(11) (ptr addrspace(11), <2 x i32>, ...) @llvm.structured.gep.p11.v2i32(ptr addrspace(11) elementtype(%struct.RuntimeArray) @buffer, <2 x i32> <i32 3, i32 4>, i32 0, i32 %idx)
+ ; CHECK: %[[#ptr_elem:]] = OpAccessChain %[[#ptr_sb_int]] %[[#buffer]] %[[#]] %[[#]]
%2 = load i32, ptr addrspace(11) %1, align 4
; CHECK: %[[#val:]] = OpLoad %[[#int]] %[[#ptr_elem]]
@@ -26,7 +26,7 @@ entry:
}
declare token @llvm.experimental.convergence.entry() #1
-declare ptr addrspace(11) @llvm.structured.gep.p11(ptr addrspace(11), ...) #3
+declare ptr addrspace(11) @llvm.structured.gep.p11.v2i32(ptr addrspace(11), <2 x i32>, ...) #3
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-struct.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-struct.ll
index f0ac1b158a975..347585147e609 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-struct.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-struct.ll
@@ -17,7 +17,7 @@ entry:
; CHECK: %[[#s_var:]] = OpFunctionParameter %[[#ptr_struct]]
; CHECK: %[[#out_var:]] = OpFunctionParameter %[[#ptr_float]]
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.Simple) %s, i32 1)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.Simple) %s, <1 x i32> <i32 3>, i32 1)
; CHECK: %[[#ptr_field:]] = OpInBoundsAccessChain %[[#ptr_float]] %[[#s_var]] %[[#idx_1]]
%2 = load float, ptr %1, align 4
@@ -30,7 +30,7 @@ entry:
}
declare token @llvm.experimental.convergence.entry() #1
-declare ptr @llvm.structured.gep.p0(ptr, ...) #3
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #3
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-vector.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-vector.ll
index 3a4bd4de731b5..0aeebb341ae0e 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-vector.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-vector.ll
@@ -22,7 +22,7 @@ entry:
; CHECK: %[[#vec_var:]] = OpFunctionParameter %[[#ptr_vec4]]
; CHECK: %[[#out_var:]] = OpFunctionParameter %[[#ptr_float]]
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(<4 x float>) %vec, i32 2)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(<4 x float>) %vec, <1 x i32> <i32 5>, i32 2)
; CHECK: %[[#ptr_elem:]] = OpInBoundsAccessChain %[[#ptr_float]] %[[#vec_var]] %[[#idx_2]]
%2 = load float, ptr %1, align 4
@@ -40,7 +40,7 @@ entry:
; CHECK: %[[#arr_var:]] = OpFunctionParameter %[[#ptr_array_vec4]]
; CHECK: %[[#out_var2:]] = OpFunctionParameter %[[#ptr_float]]
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x <4 x float>]) %arr, i32 1, i32 2)
+ %1 = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([2 x <4 x float>]) %arr, <2 x i32> <i32 5, i32 5>, i32 1, i32 2)
; CHECK: %[[#ptr_elem2:]] = OpInBoundsAccessChain %[[#ptr_float]] %[[#arr_var]] %[[#idx_1]] %[[#idx_2]]
%2 = load float, ptr %1, align 4
@@ -58,13 +58,13 @@ entry:
; CHECK: %[[#arr_var3:]] = OpFunctionParameter %[[#ptr_array_float]]
; CHECK: %[[#out_var3:]] = OpFunctionParameter %[[#ptr_float]]
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x float]) %arr, i32 0)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x float]) %arr, <1 x i32> <i32 5>, i32 0)
; CHECK: %[[#ptr_elem3_0:]] = OpInBoundsAccessChain %[[#ptr_float]] %[[#arr_var3]] %[[#idx_0]]
%2 = load float, ptr %1, align 4
; CHECK: %[[#val3_0:]] = OpLoad %[[#float]] %[[#ptr_elem3_0]]
- %3 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x float]) %arr, i32 5)
+ %3 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x float]) %arr, <1 x i32> <i32 5>, i32 5)
; CHECK: %[[#ptr_elem3_5:]] = OpInBoundsAccessChain %[[#ptr_float]] %[[#arr_var3]] %[[#idx_5]]
%4 = load float, ptr %3, align 4
@@ -80,7 +80,8 @@ entry:
}
declare token @llvm.experimental.convergence.entry() #1
-declare ptr @llvm.structured.gep.p0(ptr, ...) #3
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #3
+declare ptr @llvm.structured.gep.p0.v2i32(ptr, <2 x i32>, ...) #3
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/Transforms/InstSimplify/structured-gep.ll b/llvm/test/Transforms/InstSimplify/structured-gep.ll
index 6f3ebb98d86fd..f5d7b7ee88493 100644
--- a/llvm/test/Transforms/InstSimplify/structured-gep.ll
+++ b/llvm/test/Transforms/InstSimplify/structured-gep.ll
@@ -10,7 +10,7 @@ define ptr @zero_index_local(ptr %p) {
; CHECK-LABEL: @zero_index_local(ptr %p
; CHECK-NEXT: ret ptr %p
;
- %sgep = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(i32) %p)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(i32) %p, <1 x i32> zeroinitializer)
ret ptr %sgep
}
@@ -18,7 +18,7 @@ define ptr @zero_index_global() {
; CHECK-LABEL: @zero_index_global(
; CHECK-NEXT: ret ptr @g
;
- %sgep = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(i32) @g)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(i32) @g, <1 x i32> zeroinitializer)
ret ptr %sgep
}
@@ -26,7 +26,7 @@ define ptr @zero_index_array(ptr %p) {
; CHECK-LABEL: @zero_index_array(ptr %p
; CHECK-NEXT: ret ptr %p
;
- %sgep = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %p)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %p, <1 x i32> zeroinitializer)
ret ptr %sgep
}
@@ -34,7 +34,7 @@ define ptr addrspace(11) @zero_index_addrspace(ptr addrspace(11) %p) {
; CHECK-LABEL: @zero_index_addrspace(ptr addrspace(11) %p
; CHECK-NEXT: ret ptr addrspace(11) %p
;
- %sgep = call ptr addrspace(11) (ptr addrspace(11), ...) @llvm.structured.gep.p11(ptr addrspace(11) elementtype(i32) %p)
+ %sgep = call ptr addrspace(11) (ptr addrspace(11), <1 x i32>, ...) @llvm.structured.gep.p11.v1i32(ptr addrspace(11) elementtype(i32) %p, <1 x i32> zeroinitializer)
ret ptr addrspace(11) %sgep
}
@@ -43,7 +43,7 @@ define i32 @zero_index_with_load(ptr %p) {
; CHECK-NEXT: [[V:%.*]] = load i32, ptr %p, align 4
; CHECK-NEXT: ret i32 [[V]]
;
- %sgep = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(i32) %p)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(i32) %p, <1 x i32> zeroinitializer)
%v = load i32, ptr %sgep, align 4
ret i32 %v
}
@@ -51,41 +51,42 @@ define i32 @zero_index_with_load(ptr %p) {
; GEP with a zero index can be simplified, but SGEP cannot.
define ptr @zero_index_struct(ptr %p) {
; CHECK-LABEL: @zero_index_struct(ptr %p
-; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %p, i32 0)
+; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> splat (i32 3), i32 0)
; CHECK-NEXT: ret ptr [[SGEP]]
;
- %sgep = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %p, i32 0)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> <i32 3>, i32 0)
ret ptr %sgep
}
define ptr @one_index_struct(ptr %p) {
; CHECK-LABEL: @one_index_struct(ptr %p
-; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %p, i32 1)
+; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> splat (i32 3), i32 1)
; CHECK-NEXT: ret ptr [[SGEP]]
;
- %sgep = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %p, i32 1)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> <i32 3>, i32 1)
ret ptr %sgep
}
define ptr @multi_index_nested(ptr %p) {
; CHECK-LABEL: @multi_index_nested(
-; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.Nested) %p, i32 0, i32 0)
+; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.Nested) %p, <2 x i32> splat (i32 3), i32 0, i32 0)
; CHECK-NEXT: ret ptr [[SGEP]]
;
- %sgep = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.Nested) %p, i32 0, i32 0)
+ %sgep = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.Nested) %p, <2 x i32> <i32 3, i32 3>, i32 0, i32 0)
ret ptr %sgep
}
define ptr @dynamic_index(ptr %p, i32 %i) {
; CHECK-LABEL: @dynamic_index(
-; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %p, i32 %i)
+; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %p, <1 x i32> splat (i32 5), i32 %i)
; CHECK-NEXT: ret ptr [[SGEP]]
;
- %sgep = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %p, i32 %i)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %p, <1 x i32> <i32 5>, i32 %i)
ret ptr %sgep
}
-declare ptr @llvm.structured.gep.p0(ptr, ...) #0
-declare ptr addrspace(11) @llvm.structured.gep.p11(ptr addrspace(11), ...) #0
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #0
+declare ptr @llvm.structured.gep.p0.v2i32(ptr, <2 x i32>, ...) #0
+declare ptr addrspace(11) @llvm.structured.gep.p11.v1i32(ptr addrspace(11), <1 x i32>, ...) #0
attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/Verifier/amdgpu-stridemark-structured-gep.ll b/llvm/test/Verifier/amdgpu-stridemark-structured-gep.ll
index 5c822dcd8a2dd..707efbac765e6 100644
--- a/llvm/test/Verifier/amdgpu-stridemark-structured-gep.ll
+++ b/llvm/test/Verifier/amdgpu-stridemark-structured-gep.ll
@@ -3,7 +3,7 @@
define void @dynamic_index_then_gep_offset(ptr addrspace(9) %p, i32 %index,
i32 %offset) {
entry:
- %q1 = call ptr addrspace(9) (ptr addrspace(9), ...) @llvm.structured.gep.p9(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %p, i32 %index)
+ %q1 = call ptr addrspace(9) (ptr addrspace(9), <1 x i32>, ...) @llvm.structured.gep.p9.v1i32(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %p, <1 x i32> <i32 4>, i32 %index)
%q = getelementptr i8, ptr addrspace(9) %q1, i32 %offset
ret void
}
@@ -11,7 +11,7 @@ entry:
define void @known_bounds_and_stride(ptr addrspace(9) %p, i32 %index,
i32 %offset) {
entry:
- %q1 = call ptr addrspace(9) (ptr addrspace(9), ...) @llvm.structured.gep.p9(ptr addrspace(9) elementtype([256 x target("amdgpu.stridemark", 16)]) %p, i32 %index)
+ %q1 = call ptr addrspace(9) (ptr addrspace(9), <1 x i32>, ...) @llvm.structured.gep.p9.v1i32(ptr addrspace(9) elementtype([256 x target("amdgpu.stridemark", 16)]) %p, <1 x i32> <i32 5>, i32 %index)
%q = getelementptr i8, ptr addrspace(9) %q1, i32 %offset
ret void
}
diff --git a/llvm/test/Verifier/logical-pointer-notrequired.ll b/llvm/test/Verifier/logical-pointer-notrequired.ll
index 0f3c4950e355c..fa426cc0745e8 100644
--- a/llvm/test/Verifier/logical-pointer-notrequired.ll
+++ b/llvm/test/Verifier/logical-pointer-notrequired.ll
@@ -10,7 +10,7 @@ entry:
define void @structured_gep(ptr %src, i32 %index) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([0 x %S]) %src, i32 %index, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 3>, i32 %index, i32 1)
ret void
}
diff --git a/llvm/test/Verifier/logical-pointer-required.ll b/llvm/test/Verifier/logical-pointer-required.ll
index 6abdecc4a8576..b7fbda268cc9c 100644
--- a/llvm/test/Verifier/logical-pointer-required.ll
+++ b/llvm/test/Verifier/logical-pointer-required.ll
@@ -4,7 +4,7 @@
define void @structured_gep_allowed(ptr %src, i32 %index) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([0 x %S]) %src, i32 %index, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 3>, i32 %index, i32 1)
ret void
}
diff --git a/llvm/test/Verifier/structured-gep-indices-bad.ll b/llvm/test/Verifier/structured-gep-indices-bad.ll
index 994989029323d..6112e734b4782 100644
--- a/llvm/test/Verifier/structured-gep-indices-bad.ll
+++ b/llvm/test/Verifier/structured-gep-indices-bad.ll
@@ -5,41 +5,83 @@
define void @too_many_indices(ptr %src) {
entry:
; CHECK: Reached a non-composite type with more indices to process
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%S) %src, i32 0, i32 0)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%S) %src, <2 x i32> <i32 3, i32 4>, i32 0, i32 0)
ret void
}
define void @out_of_bounds_struct_access(ptr %src) {
entry:
; CHECK: Indexing in a struct should be inbounds
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%S) %src, i32 2)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> <i32 3>, i32 2)
ret void
}
define void @dynamic_index_struct(ptr %src, i32 %index) {
entry:
; CHECK: Indexing into a struct requires a constant int
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%S) %src, i32 %index)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> <i32 3>, i32 %index)
ret void
}
define void @non_integer_operand(ptr %src) {
entry:
; CHECK: Index operand type must be an integer
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([ 2 x i32 ]) %src, float 1.0)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([ 2 x i32 ]) %src, <1 x i32> <i32 5>, float 1.0)
ret void
}
define void @missing_attribute(ptr %src) {
entry:
; CHECK: Intrinsic first parameter is missing an ElementType attribute
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr %src, i32 0)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr %src, <1 x i32> <i32 4>, i32 0)
ret void
}
define void @amdgpu_stridemark_offset_in_structured_gep(ptr addrspace(9) %src) {
entry:
; CHECK: Reached a non-composite type with more indices to process
- %ptr = call ptr addrspace(9) (ptr addrspace(9), ...) @llvm.structured.gep.p9(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %src, i32 0, i32 0)
+ %ptr = call ptr addrspace(9) (ptr addrspace(9), <2 x i32>, ...) @llvm.structured.gep.p9.v2i32(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %src, <2 x i32> <i32 4, i32 4>, i32 0, i32 0)
+ ret void
+}
+
+define void @struct_access_missing_flags(ptr %src) {
+entry:
+; CHECK: Indexing into a struct requires inbounds and nneg flags
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> zeroinitializer, i32 0)
+ ret void
+}
+
+define void @flags_wrong_element_count(ptr %src) {
+entry:
+; CHECK: Flags operand must have one element per index
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([ 2 x i32 ]) %src, <2 x i32> <i32 5, i32 5>, i32 0)
+ ret void
+}
+
+define void @flags_wrong_element_type(ptr %src) {
+entry:
+; CHECK: Flags operand type must be a fixed vector of i32
+ %ptr = call ptr (ptr, <1 x i64>, ...) @llvm.structured.gep.p0.v1i64(ptr elementtype([ 2 x i32 ]) %src, <1 x i64> <i64 5>, i32 0)
+ ret void
+}
+
+define void @flags_poison(ptr %src) {
+entry:
+; CHECK: Flags operand elements must be integer constants
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([ 2 x i32 ]) %src, <1 x i32> poison, i32 0)
+ ret void
+}
+
+define void @flags_undef(ptr %src) {
+entry:
+; CHECK: Flags operand elements must be integer constants
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([ 2 x i32 ]) %src, <1 x i32> undef, i32 0)
+ ret void
+}
+
+define void @no_index_nonzero_flags(ptr %src) {
+entry:
+; CHECK: Flags operand must be zero when there are no indices
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(i32) %src, <1 x i32> <i32 1>)
ret void
}
diff --git a/llvm/test/Verifier/structured-gep-indices.ll b/llvm/test/Verifier/structured-gep-indices.ll
index 0e914f77a875a..cd1715003cc4b 100644
--- a/llvm/test/Verifier/structured-gep-indices.ll
+++ b/llvm/test/Verifier/structured-gep-indices.ll
@@ -4,54 +4,66 @@
define void @runtime_array_nested_access(ptr %src, i32 %index) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([0 x %S]) %src, i32 %index, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 3>, i32 %index, i32 1)
ret void
}
define void @normal_array_access(ptr %src, i32 %index) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x %S]) %src, i32 %index, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([2 x %S]) %src, <2 x i32> <i32 5, i32 3>, i32 %index, i32 1)
ret void
}
define void @normal_array_constant_index(ptr %src) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x %S]) %src, i32 1, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([2 x %S]) %src, <2 x i32> <i32 5, i32 3>, i32 1, i32 1)
ret void
}
define void @struct_access(ptr %src) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%S) %src, i32 0)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> <i32 3>, i32 0)
ret void
}
define void @nested_array_access(ptr %src) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([ 3 x [ 2 x i32 ] ]) %src, i32 2, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([ 3 x [ 2 x i32 ] ]) %src, <2 x i32> <i32 5, i32 5>, i32 2, i32 1)
ret void
}
define void @runtime_array_index(ptr %src) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([ 0 x i32 ]) %src, i32 1)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([ 0 x i32 ]) %src, <1 x i32> <i32 4>, i32 1)
ret void
}
define void @scalar_with_no_index(ptr %src) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(i32) %src)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(i32) %src, <1 x i32> zeroinitializer)
ret void
}
define void @access_64bit(ptr %src) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([ 0 x i32 ]) %src, i64 1)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([ 0 x i32 ]) %src, <1 x i32> <i32 4>, i64 1)
ret void
}
define void @access_8bit(ptr %src) {
entry:
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([ 0 x i32 ]) %src, i8 1)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([ 0 x i32 ]) %src, <1 x i32> <i32 4>, i8 1)
+ ret void
+}
+
+define void @array_index_with_unknown_bits(ptr %src, i64 %index) {
+entry:
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([ 0 x i32 ]) %src, <1 x i32> <i32 65540>, i64 %index)
+ ret void
+}
+
+define void @struct_index_with_unknown_bits(ptr %src) {
+entry:
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> <i32 65539>, i32 1)
ret void
}
>From 1bbc5da00b8fb4bfe226180d9693b07d082735d4 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Thu, 28 May 2026 15:36:42 +0000
Subject: [PATCH 2/8] Clang-format, update documentation
---
clang/lib/CodeGen/CGExpr.cpp | 20 +++++++++----------
clang/lib/CodeGen/CGHLSLRuntime.cpp | 4 ++--
llvm/docs/LangRef.rst | 14 +++++++------
.../Verifier/structured-gep-indices-bad.ll | 7 -------
4 files changed, 20 insertions(+), 25 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 90ae5cf3e4a00..3a82d89be686e 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4709,8 +4709,8 @@ getStructuredGEPArrayIndexFlags(llvm::Type *IndexedType, llvm::Value *Index,
static SmallVector<llvm::StructuredGEPFlags>
getStructuredGEPFlagsForIndices(llvm::Type *BaseType,
- ArrayRef<llvm::Value *> Indices,
- bool InBounds, bool SignedIndices) {
+ ArrayRef<llvm::Value *> Indices, bool InBounds,
+ bool SignedIndices) {
SmallVector<llvm::StructuredGEPFlags> Flags;
Flags.reserve(Indices.size());
llvm::Type *CurrentType = BaseType;
@@ -4724,8 +4724,8 @@ getStructuredGEPFlagsForIndices(llvm::Type *BaseType,
continue;
}
- Flags.push_back(getStructuredGEPArrayIndexFlags(
- CurrentType, Index, InBounds, SignedIndices));
+ Flags.push_back(getStructuredGEPArrayIndexFlags(CurrentType, Index,
+ InBounds, SignedIndices));
if (auto *AT = dyn_cast<llvm::ArrayType>(CurrentType))
CurrentType = AT->getElementType();
else if (auto *VT = dyn_cast<llvm::VectorType>(CurrentType))
@@ -5778,12 +5778,12 @@ static Address emitRawAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
CGF.CGM.getTypes().getCGRecordLayout(rec).getLLVMType();
if (CGF.getLangOpts().EmitLogicalPointer)
- return RawAddress(CGF.Builder.CreateStructuredGEP(
- StructType, base.emitRawPointer(CGF),
- {CGF.Builder.getSize(idx)},
- {llvm::StructuredGEPFlags::inBounds() |
- llvm::StructuredGEPFlags::nneg()}),
- base.getElementType(), base.getAlignment());
+ return RawAddress(
+ CGF.Builder.CreateStructuredGEP(StructType, base.emitRawPointer(CGF),
+ {CGF.Builder.getSize(idx)},
+ {llvm::StructuredGEPFlags::inBounds() |
+ llvm::StructuredGEPFlags::nneg()}),
+ base.getElementType(), base.getAlignment());
if (!IsInBounds)
return CGF.Builder.CreateConstGEP2_32(base, 0, idx, field->getName());
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 49bf0178de72e..cb1d034e79eb3 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -100,8 +100,8 @@ getHLSLStructuredGEPFlags(llvm::Type *BaseType, ArrayRef<Value *> Indices,
}
bool SignedIndex = IndexNo == 0 ? FirstIndexSigned.value_or(true) : true;
- Flags.push_back(getHLSLStructuredGEPArrayIndexFlags(
- CurrentType, Index, InBounds, SignedIndex));
+ Flags.push_back(getHLSLStructuredGEPArrayIndexFlags(CurrentType, Index,
+ InBounds, SignedIndex));
if (auto *AT = dyn_cast<llvm::ArrayType>(CurrentType))
CurrentType = AT->getElementType();
else if (auto *VT = dyn_cast<llvm::VectorType>(CurrentType))
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 07a505f2bbdd0..b1a9436e3fd54 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -15589,7 +15589,7 @@ All indices must be consumed, and it is illegal to index into a scalar type,
meaning the maximum number of indices depends on the depth of the basetype.
If the indexed type is a struct with N fields, the index must be an
-integer constant in the range ``[0, N)``.
+integer constant in the range ``[0, N[``.
If the constraints implied by a flag bit are violated, the result is ``poison``.
If the source pointer is poison, the instruction returns poison.
@@ -15602,7 +15602,7 @@ Defined flag bits:
``inbounds``
Bit 0 (``1 << 0``) - specifies that this index is within the bounds of the type
being indexed at that level. In particular, when indexing an array or vector
- ``[ N x T ]``, implies that the index is in the range ``[0, N)``. As an exception,
+ ``[ N x T ]``, implies that the index is in the range ``[0, N[``. As an exception,
if ``N`` is 0, the bound is treated as an unknown, dynamic value, but the flag
still implies that the index is inside that runtime bound.
Structure accesses are always ``inbounds`` and must be marked as
@@ -15679,12 +15679,14 @@ Or:
This is, however, dependent on context that codegen has an insight on. The
fact that `[ i32 x 4 ]` and `%S` are equivalent depends on the target.
-**Array bounds handling**
+**Bounds handling**
.. code-block:: cpp
- float array[M][N];
- float val = array[i][j];
+ // Type that treats indices separately, such as by allowing swizzling or
+ // per-dimension bounds checks.
+ tensor2d<float, M, N> array;
+ float val = array[i, j];
Could be translated to:
@@ -15710,7 +15712,7 @@ When dealing with dynamic bounds, a "0-sized" array is used, so
.. code-block:: cpp
- float array[];
+ tensor1d<float, kDynamic> array[];
float val = array[i];
could be translated to:
diff --git a/llvm/test/Verifier/structured-gep-indices-bad.ll b/llvm/test/Verifier/structured-gep-indices-bad.ll
index 6112e734b4782..b2c73c4ad6691 100644
--- a/llvm/test/Verifier/structured-gep-indices-bad.ll
+++ b/llvm/test/Verifier/structured-gep-indices-bad.ll
@@ -72,13 +72,6 @@ entry:
ret void
}
-define void @flags_undef(ptr %src) {
-entry:
-; CHECK: Flags operand elements must be integer constants
- %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([ 2 x i32 ]) %src, <1 x i32> undef, i32 0)
- ret void
-}
-
define void @no_index_nonzero_flags(ptr %src) {
entry:
; CHECK: Flags operand must be zero when there are no indices
>From 0104069e691af696df1f34e59240edaf779d072e Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Thu, 28 May 2026 18:39:13 +0000
Subject: [PATCH 3/8] Release note
---
llvm/docs/ReleaseNotes.md | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 61b0dd3220285..49949578b59b8 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -94,6 +94,13 @@ Makes programs 10x faster by doing Special New Thing.
* Fast math flags are now permitted on `uitofp` and `sitofp`.
+* The `llvm.structured.gep` intrinsic has gained an extra `flags` argument,
+ allowing the in-bounds nature of array indices, their signedness, and their
+ non-negativity to be provided on a per-index basis, removing the old
+ `[0 x T]` element type that conflated an array having unknown extent with
+ potentially in-bounds indexing. The default interpretation of indices has been
+ updated to be signed, matching GEP.
+
### Changes to LLVM infrastructure
* Removed ``Constant::isZeroValue``. It was functionally identical to
>From b649263ddd496a667981ff2d690eea6ac63a6289 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Tue, 9 Jun 2026 21:25:22 +0000
Subject: [PATCH 4/8] Make autoupgrade less paranoid, add examples
---
llvm/docs/LangRef.rst | 9 ++++--
llvm/lib/IR/AutoUpgrade.cpp | 61 +++++++++++++------------------------
2 files changed, 29 insertions(+), 41 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index b1a9436e3fd54..52b931f2a0a25 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -15610,8 +15610,13 @@ Defined flag bits:
``nneg``
Bit 1 (``1 << 1``) - specifies that the value of this index is non-negative.
- This is not necessarily implied by ``inbounds``, as an object may have more
- fields than the maximal signed value for the index type.
+ This is not necessarily implied by ``inbounds``. For exmaple, consider
+
+ .. code-black:: llvm
+ %q = sgep [8 x target("amdggpu.stridemark")], inbounds|nneg, ptr addrspace(9) %p, i32 4
+ %r = sgep [8 x target("amdgpu.stridemark")], inbounds, ptr addrspace(9) %q, i32 %x
+
+ where ``inbounds`` only implies that `-4 <= %p <= 4`.
``unsigned``
Bit 2 (``1 << 2``) - specifies that the index should be interpreted as an
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 8054b2b201a0a..27ed36cf850dd 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -5038,50 +5038,32 @@ static Value *upgradeConvertIntrinsicCall(StringRef Name, CallBase *CI,
return nullptr;
}
-static StructuredGEPFlags getLegacyStructuredGEPIndexFlags(Type *&CurrentType,
- Value *Index) {
- StructuredGEPFlags Flags = StructuredGEPFlags::unsignedIndex();
- if (!CurrentType)
- return Flags;
-
- if (auto *AT = dyn_cast<ArrayType>(CurrentType)) {
- if (AT->getNumElements() != 0)
- Flags |= StructuredGEPFlags::inBounds();
- CurrentType = AT->getElementType();
- return Flags;
- }
-
- if (auto *VT = dyn_cast<VectorType>(CurrentType)) {
- Flags |= StructuredGEPFlags::inBounds();
- CurrentType = VT->getElementType();
- return Flags;
- }
-
- if (auto *ST = dyn_cast<StructType>(CurrentType)) {
- Flags |= StructuredGEPFlags::inBounds() | StructuredGEPFlags::nneg();
- if (auto *CI = dyn_cast<ConstantInt>(Index))
- if (CI->getZExtValue() < ST->getNumElements())
- CurrentType = ST->getElementType(CI->getZExtValue());
- return Flags;
- }
-
- CurrentType = nullptr;
- return Flags;
-}
-
static Constant *getLegacyStructuredGEPFlags(CallBase *CI) {
- Type *CurrentType = nullptr;
- if (CI->paramHasAttr(0, Attribute::ElementType))
- CurrentType = CI->getParamAttr(0, Attribute::ElementType).getValueAsType();
+ Type *CurrentType =
+ CI->getParamAttr(0, Attribute::ElementType).getValueAsType();
Type *Int32Ty = Type::getInt32Ty(CI->getContext());
SmallVector<Constant *> FlagValues;
unsigned NumIndices = CI->arg_size() - 1;
FlagValues.reserve(NumIndices == 0 ? 1 : NumIndices);
for (unsigned I = 0; I < NumIndices; ++I) {
- StructuredGEPFlags Flags =
- getLegacyStructuredGEPIndexFlags(CurrentType, CI->getArgOperand(I + 1));
- FlagValues.push_back(ConstantInt::get(Int32Ty, Flags.getRaw()));
+ StructuredGEPFlags TheseFlags = StructuredGEPFlags::unsignedIndex();
+ if (auto *AT = dyn_cast<ArrayType>(CurrentType)) {
+ if (AT->getNumElements() != 0)
+ TheseFlags |= StructuredGEPFlags::inBounds();
+ CurrentType = AT->getElementType();
+ } else if (auto *VT = dyn_cast<VectorType>(CurrentType)) {
+ TheseFlags |= StructuredGEPFlags::inBounds();
+ CurrentType = VT->getElementType();
+ } else if (auto *ST = dyn_cast<StructType>(CurrentType)) {
+ TheseFlags |= StructuredGEPFlags::inBounds() | StructuredGEPFlags::nneg();
+ CurrentType = ST->getElementType(
+ cast<ConstantInt>(CI->getOperand(I + 1))->getZExtValue());
+ } else {
+ break;
+ }
+
+ FlagValues.push_back(ConstantInt::get(Int32Ty, TheseFlags.getRaw()));
}
if (FlagValues.empty())
@@ -5109,8 +5091,9 @@ static Value *upgradeStructuredGEPIntrinsicCall(CallBase *CI, Function *F,
NewCall->setCallingConv(CI->getCallingConv());
NewCall->setDebugLoc(CI->getDebugLoc());
NewCall->copyMetadata(*CI);
- if (CI->paramHasAttr(0, Attribute::ElementType))
- NewCall->addParamAttr(0, CI->getParamAttr(0, Attribute::ElementType));
+ NewCall->addParamAttrs(
+ 0, AttrBuilder(CI->getContext(), CI->getParamAttributes(0)));
+ NewCall->addRetAttrs(AttrBuilder(CI->getContext(), CI->getRetAttributes()));
NewCall->takeName(CI);
return NewCall;
}
>From 1773dbd3b3a6522fa3adf1ac14c54c20ab3f3005 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Wed, 10 Jun 2026 18:35:36 +0000
Subject: [PATCH 5/8] Put some of the paranoia back
---
llvm/docs/LangRef.rst | 2 +-
llvm/lib/IR/AutoUpgrade.cpp | 42 +++++++++++++++++++++++--------------
2 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 52b931f2a0a25..cb8e02fb9fb7a 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -15612,7 +15612,7 @@ Defined flag bits:
Bit 1 (``1 << 1``) - specifies that the value of this index is non-negative.
This is not necessarily implied by ``inbounds``. For exmaple, consider
- .. code-black:: llvm
+ .. code-block:: llvm
%q = sgep [8 x target("amdggpu.stridemark")], inbounds|nneg, ptr addrspace(9) %p, i32 4
%r = sgep [8 x target("amdgpu.stridemark")], inbounds, ptr addrspace(9) %q, i32 %x
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 27ed36cf850dd..e847d8c21cf34 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -14,6 +14,7 @@
#include "llvm/IR/AutoUpgrade.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVectorExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@@ -5038,37 +5039,46 @@ static Value *upgradeConvertIntrinsicCall(StringRef Name, CallBase *CI,
return nullptr;
}
+// Return the flags that represent the semantics of a structured GEP before
+// flags were added. Always sets `unsigned`. If the structered GEP is malformed,
+// will fill in one `unsigned` per index.
static Constant *getLegacyStructuredGEPFlags(CallBase *CI) {
- Type *CurrentType =
- CI->getParamAttr(0, Attribute::ElementType).getValueAsType();
+ Type *CurrentType = nullptr;
+ if (CI->paramHasAttr(0, Attribute::ElementType))
+ CurrentType = CI->getParamAttr(0, Attribute::ElementType).getValueAsType();
Type *Int32Ty = Type::getInt32Ty(CI->getContext());
- SmallVector<Constant *> FlagValues;
unsigned NumIndices = CI->arg_size() - 1;
- FlagValues.reserve(NumIndices == 0 ? 1 : NumIndices);
- for (unsigned I = 0; I < NumIndices; ++I) {
- StructuredGEPFlags TheseFlags = StructuredGEPFlags::unsignedIndex();
+ SmallVector<StructuredGEPFlags> FlagValues(
+ std::max({NumIndices, 1u}), StructuredGEPFlags::unsignedIndex());
+ for (auto [I, Flags] : llvm::enumerate(FlagValues)) {
+ // Safety valve for malformed SGEP.
+ if (!CurrentType)
+ break;
+
if (auto *AT = dyn_cast<ArrayType>(CurrentType)) {
if (AT->getNumElements() != 0)
- TheseFlags |= StructuredGEPFlags::inBounds();
+ Flags |= StructuredGEPFlags::inBounds();
CurrentType = AT->getElementType();
} else if (auto *VT = dyn_cast<VectorType>(CurrentType)) {
- TheseFlags |= StructuredGEPFlags::inBounds();
+ Flags |= StructuredGEPFlags::inBounds();
CurrentType = VT->getElementType();
} else if (auto *ST = dyn_cast<StructType>(CurrentType)) {
- TheseFlags |= StructuredGEPFlags::inBounds() | StructuredGEPFlags::nneg();
- CurrentType = ST->getElementType(
- cast<ConstantInt>(CI->getOperand(I + 1))->getZExtValue());
+ Flags |= StructuredGEPFlags::inBounds() | StructuredGEPFlags::nneg();
+ if (auto *ConstArg = dyn_cast<ConstantInt>(CI->getOperand(I + 1)))
+ CurrentType = ST->getElementType(ConstArg->getZExtValue());
+ else
+ break;
} else {
break;
}
-
- FlagValues.push_back(ConstantInt::get(Int32Ty, TheseFlags.getRaw()));
}
- if (FlagValues.empty())
- FlagValues.push_back(ConstantInt::get(Int32Ty, 0));
- return ConstantVector::get(FlagValues);
+ SmallVector<Constant *> FlagConsts =
+ llvm::map_to_vector(FlagValues, [&](auto V) {
+ return ConstantInt::get(Int32Ty, V.getRaw());
+ });
+ return ConstantVector::get(FlagConsts);
}
static Value *upgradeStructuredGEPIntrinsicCall(CallBase *CI, Function *F,
>From 17704017ce6eb75c6717f1ef1da97aada78c92d1 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Tue, 14 Jul 2026 19:10:24 +0000
Subject: [PATCH 6/8] Update semantics
---
llvm/docs/LangRef.md | 37 ++++++++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 11 deletions(-)
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 9d8fa8ee6cba0..d721a0299e680 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -13521,7 +13521,7 @@ This instruction requires several arguments:
```llvm
declare void @take_byval(ptr byval(i64))
declare void @take_ptr(ptr)
-
+
; Invalid (assuming @take_ptr dereferences the pointer), because %local
; may be de-allocated before the call to @take_ptr.
define void @invalid_alloca() {
@@ -13530,7 +13530,7 @@ This instruction requires several arguments:
tail call void @take_ptr(ptr %local)
ret void
}
-
+
; Valid, the byval attribute causes the memory allocated by %local to be
; copied into @take_byval's stack frame.
define void @byval_alloca() {
@@ -13539,7 +13539,7 @@ This instruction requires several arguments:
tail call void @take_byval(ptr byval(i64) %local)
ret void
}
-
+
; Invalid, because @use_global_va_list uses the variadic arguments from
; @invalid_va_list.
%struct.va_list = type { ptr }
@@ -13555,14 +13555,14 @@ This instruction requires several arguments:
tail call void @use_global_va_list()
ret void
}
-
+
; Valid, byval argument forwarded to tail call as another byval argument.
define void @forward_byval(ptr byval(i64) %x) {
entry:
tail call void @take_byval(ptr byval(i64) %x)
ret void
}
-
+
; Invalid (assuming @take_ptr dereferences the pointer), byval argument
; passed to tail callee as non-byval ptr.
define void @invalid_byval(ptr byval(i64) %x) {
@@ -14924,7 +14924,7 @@ at runtime.
A pointer to the memory location used as base for the address computation.
The `source` argument must be annotated with an {ref}`elementtype <attr_elementtype>` attribute at the call-site. This attribute specifies the
-type of the element pointed to by the pointer source. This type will be
+type of the value pointed into by the pointer `source`. This type will be
used along with the provided indices and source operand to compute a new
pointer representing the result of a logical indexing into the basetype
pointed to by `source`.
@@ -14960,18 +14960,33 @@ Otherwise, the flags operand must have one element per index.
The `llvm.structured.gep` performs a logical traversal of the type
`basetype` using the list of provided indices, computing the pointer
-addressing the targeted element/field assuming `source` points to a
-physically laid out `basetype`. The physical layout of the source depends
-on the target and does not necessarily match the one described by the
-datalayout.
+addressing the targeted element/field assuming `source` points to memory
+interpretable as a physically laid out `basetype` (with potentially differenig
+array lengths if permitted). The physical layout of the source depends on the
+target and does not necessarily match the one described by the datalayout.
The first index determines which element/field of `basetype` is selected,
computes the pointer to access this element/field assuming `source` points
-to the start of `basetype`.
+into memory interpretable as a `basetype`, optionally ignoring array element
+counts.
This pointer becomes the new `source`, the current type the new
`basetype`, and the next index is consumed until a scalar type is
reached or all indices are consumed.
+Note that the interpretability requirement prohibits `source` from pointing within
+a struct or a vector, but does permit pointers in the middle of arrays. In the case
+of such a mid-array pointer, the corresponding `index` moves logically within the
+array. Unlike with normal GEP, there is no requirement that indices "overflow" to
+the next dimension - that is, `sgep [8 x [8 x i8]], ptr %source, i32 0, i32 8`
+is not necessarily the same location as
+`sgep [8 x [8 x i8]], ptr %source, i32 1, i32 0`. The indices for each axis
+in a multidimtional array *may*, but are not *required to be*, tracked separately:
+the overflow flags apply to the ultimate, target-specific tracking mechanism.
+
+Targets, such as SPIR-V, may impose the additional requirement that `source`
+point to the **beginning** of a `basetype`, but LLVM will not optimize on this
+assumption.
+
All indices must be consumed, and it is illegal to index into a scalar type,
meaning the maximum number of indices depends on the depth of the basetype.
>From 4b369b1c33121bad48e36d61f9b0a31be97a44ff Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Tue, 14 Jul 2026 19:15:32 +0000
Subject: [PATCH 7/8] Clang-format
---
llvm/include/llvm/IR/IRBuilder.h | 3 +--
llvm/lib/IR/AutoUpgrade.cpp | 6 +++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 28ed60533fdad..3661537e2fc17 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2015,8 +2015,7 @@ class IRBuilderBase {
return CreateIntrinsic(
Intrinsic::structured_gep, {PtrBase->getType(), FlagsVec->getType()},
- Args, {}, Name, {},
- [&](CallInst *Output) {
+ Args, {}, Name, {}, [&](CallInst *Output) {
Output->addParamAttr(
0,
Attribute::get(getContext(), Attribute::ElementType, BaseType));
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 0a6bb5aefa416..5804e6f87516b 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -5144,9 +5144,9 @@ static Constant *getLegacyStructuredGEPFlags(CallBase *CI) {
Type *Int32Ty = Type::getInt32Ty(CI->getContext());
unsigned NumIndices = CI->arg_size() - 1;
SmallVector<StructuredGEPFlags> FlagValues(
- std::max({NumIndices, 1u}),
- NumIndices ? StructuredGEPFlags::unsignedIndex()
- : StructuredGEPFlags::none());
+ std::max({NumIndices, 1u}), NumIndices
+ ? StructuredGEPFlags::unsignedIndex()
+ : StructuredGEPFlags::none());
for (auto [I, Flags] : llvm::enumerate(FlagValues)) {
// Safety valve for malformed SGEP.
if (!CurrentType)
>From e183cbfdd97bd0f8de6a3daed8841dd45aff9e53 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Thu, 23 Jul 2026 19:00:28 +0000
Subject: [PATCH 8/8] Add fromstart flag, allow target extension types, update
docs
---
clang/lib/CodeGen/CGExpr.cpp | 27 ++-
clang/lib/CodeGen/CGExprAgg.cpp | 3 +-
clang/lib/CodeGen/CGHLSLRuntime.cpp | 8 +-
.../ArrayAssignable.logicalptr.hlsl | 164 ++++++++----------
.../cbuffer_struct_passing.logical.hlsl | 16 +-
clang/test/CodeGenHLSL/sgep/array_load.hlsl | 16 +-
clang/test/CodeGenHLSL/sgep/array_store.hlsl | 12 +-
clang/test/CodeGenHLSL/sgep/load_global.hlsl | 8 +-
.../test/CodeGenHLSL/sgep/object_method.hlsl | 2 +-
llvm/docs/AMDGPUUsage.rst | 30 ++--
llvm/docs/LangRef.md | 74 ++++----
llvm/docs/ReleaseNotes.md | 3 +-
llvm/include/llvm/IR/DerivedTypes.h | 2 +
llvm/include/llvm/IR/IntrinsicInst.h | 100 ++++++++---
llvm/include/llvm/IR/StructuredGEPFlags.h | 11 +-
llvm/lib/IR/AutoUpgrade.cpp | 7 +-
llvm/lib/IR/Instruction.cpp | 18 ++
llvm/lib/IR/Operator.cpp | 17 ++
llvm/lib/IR/Type.cpp | 3 +-
llvm/lib/IR/Verifier.cpp | 12 +-
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 9 +
llvm/lib/Transforms/Scalar/LogicalSROA.cpp | 6 +-
.../test/Assembler/auto_upgrade_intrinsics.ll | 10 +-
.../test/CodeGen/SPIRV/pointers/sgep-array.ll | 20 +--
.../test/CodeGen/SPIRV/pointers/sgep-class.ll | 4 +-
.../SPIRV/pointers/sgep-missing-fromstart.ll | 13 ++
.../pointers/sgep-nested-struct-array.ll | 2 +-
.../SPIRV/pointers/sgep-runtime-array.ll | 2 +-
.../CodeGen/SPIRV/pointers/sgep-struct.ll | 2 +-
.../Transforms/InstSimplify/structured-gep.ll | 12 +-
llvm/test/Transforms/LSROA/array.ll | 19 +-
llvm/test/Transforms/LSROA/basictest.ll | 16 +-
llvm/test/Transforms/LSROA/escaping.ll | 22 +--
llvm/test/Transforms/LSROA/nesting.ll | 9 +-
llvm/test/Transforms/LSROA/normal-gep.ll | 7 +-
llvm/test/Transforms/LSROA/phi.ll | 12 +-
llvm/test/Transforms/LSROA/select.ll | 11 +-
.../amdgpu-stridemark-structured-gep.ll | 11 +-
.../Verifier/logical-pointer-notrequired.ll | 2 +-
.../test/Verifier/logical-pointer-required.ll | 2 +-
.../Verifier/structured-gep-indices-bad.ll | 8 +-
llvm/test/Verifier/structured-gep-indices.ll | 10 +-
llvm/unittests/IR/InstructionsTest.cpp | 125 +++++++++++++
43 files changed, 587 insertions(+), 280 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/pointers/sgep-missing-fromstart.ll
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 64448c07870d5..f5cd21bcd657b 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -44,6 +44,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsWebAssembly.h"
#include "llvm/IR/LLVMContext.h"
@@ -4711,13 +4712,16 @@ static const Expr *isSimpleArrayDecayOperand(const Expr *E) {
static bool isStructuredGEPIndexableType(llvm::Type *T) {
return isa<llvm::ArrayType>(T) || isa<llvm::StructType>(T) ||
- isa<llvm::VectorType>(T);
+ isa<llvm::VectorType>(T) ||
+ (isa<llvm::TargetExtType>(T) &&
+ cast<llvm::TargetExtType>(T)->hasProperty(
+ llvm::TargetExtType::CanBeSGEPIndexed));
}
static llvm::StructuredGEPFlags
getStructuredGEPArrayIndexFlags(llvm::Type *IndexedType, llvm::Value *Index,
bool InBounds, bool SignedIndex) {
- llvm::StructuredGEPFlags Flags = llvm::StructuredGEPFlags::none();
+ llvm::StructuredGEPFlags Flags = llvm::StructuredGEPFlags::fromStart();
if (InBounds) {
if (auto *AT = dyn_cast<llvm::ArrayType>(IndexedType)) {
if (AT->getNumElements() != 0)
@@ -4744,7 +4748,8 @@ getStructuredGEPFlagsForIndices(llvm::Type *BaseType,
for (llvm::Value *Index : Indices) {
if (auto *ST = dyn_cast<llvm::StructType>(CurrentType)) {
Flags.push_back(llvm::StructuredGEPFlags::inBounds() |
- llvm::StructuredGEPFlags::nneg());
+ llvm::StructuredGEPFlags::nneg() |
+ llvm::StructuredGEPFlags::fromStart());
if (auto *CI = dyn_cast<llvm::ConstantInt>(Index))
if (CI->getZExtValue() < ST->getNumElements())
CurrentType = ST->getElementType(CI->getZExtValue());
@@ -4757,6 +4762,9 @@ getStructuredGEPFlagsForIndices(llvm::Type *BaseType,
CurrentType = AT->getElementType();
else if (auto *VT = dyn_cast<llvm::VectorType>(CurrentType))
CurrentType = VT->getElementType();
+ else if (auto *TET = dyn_cast<llvm::TargetExtType>(CurrentType);
+ TET && TET->hasProperty(llvm::TargetExtType::CanBeSGEPIndexed))
+ CurrentType = TET;
else
CurrentType = nullptr;
}
@@ -5804,12 +5812,13 @@ static Address emitRawAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
CGF.CGM.getTypes().getCGRecordLayout(rec).getLLVMType();
if (CGF.getLangOpts().EmitLogicalPointer)
- return RawAddress(
- CGF.Builder.CreateStructuredGEP(StructType, base.emitRawPointer(CGF),
- {CGF.Builder.getSize(idx)},
- {llvm::StructuredGEPFlags::inBounds() |
- llvm::StructuredGEPFlags::nneg()}),
- base.getElementType(), base.getAlignment());
+ return RawAddress(CGF.Builder.CreateStructuredGEP(
+ StructType, base.emitRawPointer(CGF),
+ {CGF.Builder.getSize(idx)},
+ {llvm::StructuredGEPFlags::inBounds() |
+ llvm::StructuredGEPFlags::nneg() |
+ llvm::StructuredGEPFlags::fromStart()}),
+ base.getElementType(), base.getAlignment());
if (!IsInBounds)
return CGF.Builder.CreateConstGEP2_32(base, 0, idx, field->getName());
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 312e398eb7653..170c0cb72c509 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -661,7 +661,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
element = Builder.CreateStructuredGEP(
AType, begin, llvm::ConstantInt::get(CGF.SizeTy, ArrayIndex),
llvm::StructuredGEPFlags::inBounds() |
- llvm::StructuredGEPFlags::nneg(),
+ llvm::StructuredGEPFlags::nneg() |
+ llvm::StructuredGEPFlags::fromStart(),
"arrayinit.element");
else
element = Builder.CreateInBoundsGEP(
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 94eb027304874..03106f7200cd3 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -67,7 +67,7 @@ StructuredGEPFlags getHLSLStructuredGEPArrayIndexFlags(llvm::Type *IndexedType,
Value *Index,
bool InBounds,
bool SignedIndex) {
- StructuredGEPFlags Flags = StructuredGEPFlags::none();
+ StructuredGEPFlags Flags = StructuredGEPFlags::fromStart();
if (InBounds) {
if (auto *AT = dyn_cast<llvm::ArrayType>(IndexedType)) {
if (AT->getNumElements() != 0)
@@ -96,7 +96,8 @@ getHLSLStructuredGEPFlags(llvm::Type *BaseType, ArrayRef<Value *> Indices,
for (auto [IndexNo, Index] : llvm::enumerate(Indices)) {
if (auto *ST = dyn_cast<llvm::StructType>(CurrentType)) {
Flags.push_back(StructuredGEPFlags::inBounds() |
- StructuredGEPFlags::nneg());
+ StructuredGEPFlags::nneg() |
+ StructuredGEPFlags::fromStart());
if (auto *CI = dyn_cast<ConstantInt>(Index))
if (CI->getZExtValue() < ST->getNumElements())
CurrentType = ST->getElementType(CI->getZExtValue());
@@ -110,6 +111,9 @@ getHLSLStructuredGEPFlags(llvm::Type *BaseType, ArrayRef<Value *> Indices,
CurrentType = AT->getElementType();
else if (auto *VT = dyn_cast<llvm::VectorType>(CurrentType))
CurrentType = VT->getElementType();
+ else if (auto *TET = dyn_cast<llvm::TargetExtType>(CurrentType);
+ TET && TET->hasProperty(llvm::TargetExtType::CanBeSGEPIndexed))
+ CurrentType = TET;
else
CurrentType = nullptr;
}
diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl
index 77d263d9ac0d3..de1ed684b980d 100644
--- a/clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl
+++ b/clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl
@@ -14,19 +14,7 @@ cbuffer CBArrays : register(b0) {
S c4[2];
}
-// CHECK-DXIL: [[CBLayout:%.*]] = type <{ <{ [1 x <{ float, target("dx.Padding", 12) }>], float }>, target("dx.Padding", 12), [2 x <4 x i32>], <{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>, target("dx.Padding", 12), <{ [1 x <{ %S, target("dx.Padding", 8) }>], %S }> }>
-// CHECK-DXIL: @CBArrays.cb = internal global target("dx.CBuffer", [[CBLayout]])
-// CHECK-DXIL: @c1 = external hidden addrspace(2) global <{ [1 x <{ float, target("dx.Padding", 12) }>], float }>, align 4
-// CHECK-DXIL: @c2 = external hidden addrspace(2) global [2 x <4 x i32>], align 4
-// CHECK-DXIL: @c3 = external hidden addrspace(2) global <{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>, align 4
-// CHECK-DXIL: @c4 = external hidden addrspace(2) global <{ [1 x <{ %S, target("dx.Padding", 8) }>], %S }>, align 1
-// CHECK-SPIR: [[CBLayout:%.*]] = type <{ <{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>, target("spirv.Padding", 12), [2 x <4 x i32>], <{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>, target("spirv.Padding", 12), <{ [1 x <{ %S, target("spirv.Padding", 8) }>], %S }> }>
-// CHECK-SPIR: @CBArrays.cb = internal global target("spirv.VulkanBuffer", %__cblayout_CBArrays, 2, 0) poison
-// CHECK-SPIR: @c1 = external hidden addrspace(12) global <{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>, align 4
-// CHECK-SPIR: @c2 = external hidden addrspace(12) global [2 x <4 x i32>], align 4
-// CHECK-SPIR: @c3 = external hidden addrspace(12) global <{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>, align 4
-// CHECK-SPIR: @c4 = external hidden addrspace(12) global <{ [1 x <{ %S, target("spirv.Padding", 8) }>], %S }>, align 1
// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign1v(
@@ -129,7 +117,7 @@ void arr_assign3() {
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[ARR2]], i8 0, i32 8, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i32 8, i1 false)
-// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-DXIL-NEXT: ret void
//
@@ -142,7 +130,7 @@ void arr_assign3() {
// CHECK-SPIR-NEXT: [[ARR2:%.*]] = call elementtype([2 x i32]) ptr @llvm.structured.alloca.p0()
// CHECK-SPIR-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[ARR2]], i8 0, i64 8, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i64 8, i1 false)
-// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 7), i64 0)
// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-SPIR-NEXT: ret void
//
@@ -164,7 +152,7 @@ void arr_assign4() {
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR3]], ptr align 4 @__const._Z11arr_assign5v.Arr3, i32 8, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR2]], ptr align 4 [[ARR3]], i32 8, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i32 8, i1 false)
-// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-DXIL-NEXT: ret void
//
@@ -180,7 +168,7 @@ void arr_assign4() {
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR3]], ptr align 4 @__const._Z11arr_assign5v.Arr3, i64 8, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR2]], ptr align 4 [[ARR3]], i64 8, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i64 8, i1 false)
-// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARR]], <1 x i32> splat (i32 7), i64 0)
// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
// CHECK-SPIR-NEXT: ret void
//
@@ -200,8 +188,8 @@ void arr_assign5() {
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign6v.Arr2, i32 16, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i32 16, i1 false)
-// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-DXIL-NEXT: [[ARRAYIDX1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-DXIL-NEXT: [[ARRAYIDX1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYIDX1]], align 4
// CHECK-DXIL-NEXT: ret void
//
@@ -214,8 +202,8 @@ void arr_assign5() {
// CHECK-SPIR-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign6v.Arr2, i64 16, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i64 16, i1 false)
-// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 3), i64 0)
-// CHECK-SPIR-NEXT: [[ARRAYIDX1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 7), i64 0)
+// CHECK-SPIR-NEXT: [[ARRAYIDX1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 7), i64 0)
// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYIDX1]], align 4
// CHECK-SPIR-NEXT: ret void
//
@@ -234,9 +222,9 @@ void arr_assign6() {
// CHECK-DXIL-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign7v.Arr2, i32 16, i1 false)
// CHECK-DXIL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i32 16, i1 false)
-// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
-// CHECK-DXIL-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL-NEXT: store i32 6, ptr [[ARRAYINIT_ELEMENT]], align 4
// CHECK-DXIL-NEXT: ret void
//
@@ -249,9 +237,9 @@ void arr_assign6() {
// CHECK-SPIR-NEXT: [[ARR2:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR2]], ptr align 4 @__const._Z11arr_assign7v.Arr2, i64 16, i1 false)
// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 [[ARR2]], i64 16, i1 false)
-// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 3), i64 0)
+// CHECK-SPIR-NEXT: [[ARRAYIDX:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[ARR]], <1 x i32> splat (i32 7), i64 0)
// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYIDX]], align 4
-// CHECK-SPIR-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 3), i64 1)
+// CHECK-SPIR-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[ARRAYIDX]], <1 x i32> splat (i32 7), i64 1)
// CHECK-SPIR-NEXT: store i32 6, ptr [[ARRAYINIT_ELEMENT]], align 4
// CHECK-SPIR-NEXT: ret void
//
@@ -267,12 +255,12 @@ void arr_assign7() {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[C:%.*]] = call elementtype([2 x float]) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>) @c1, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>) @c1, <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load float, ptr addrspace(2) [[TMP1]], align 4
// CHECK-DXIL-NEXT: store float [[CBUF_LOAD]], ptr [[TMP2]], align 4
-// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>) @c1, <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>) @c1, <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(2) [[TMP3]], align 4
// CHECK-DXIL-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP4]], align 4
// CHECK-DXIL-NEXT: ret void
@@ -282,12 +270,12 @@ void arr_assign7() {
// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIR-NEXT: [[C:%.*]] = call elementtype([2 x float]) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>) @c1, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>) @c1, <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 7), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD:%.*]] = load float, ptr addrspace(12) [[TMP1]], align 4
// CHECK-SPIR-NEXT: store float [[CBUF_LOAD]], ptr [[TMP2]], align 4
-// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>) @c1, <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ float, target("spirv.Padding", 12) }>], float }>) @c1, <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x float]) [[C]], <1 x i32> splat (i32 7), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(12) [[TMP3]], align 4
// CHECK-SPIR-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP4]], align 4
// CHECK-SPIR-NEXT: ret void
@@ -302,12 +290,12 @@ void arr_assign8() {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[C:%.*]] = call elementtype([2 x <4 x i32>]) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 3), i32 0)
-// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 7), i32 0)
+// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load <4 x i32>, ptr addrspace(2) [[TMP1]], align 4
// CHECK-DXIL-NEXT: store <4 x i32> [[CBUF_LOAD]], ptr [[TMP2]], align 4
-// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load <4 x i32>, ptr addrspace(2) [[TMP3]], align 4
// CHECK-DXIL-NEXT: store <4 x i32> [[CBUF_LOAD1]], ptr [[TMP4]], align 4
// CHECK-DXIL-NEXT: ret void
@@ -317,12 +305,12 @@ void arr_assign8() {
// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIR-NEXT: [[C:%.*]] = call elementtype([2 x <4 x i32>]) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 3), i32 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 7), i32 0)
+// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 7), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD:%.*]] = load <4 x i32>, ptr addrspace(12) [[TMP1]], align 4
// CHECK-SPIR-NEXT: store <4 x i32> [[CBUF_LOAD]], ptr [[TMP2]], align 4
-// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([2 x <4 x i32>]) @c2, <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x <4 x i32>]) [[C]], <1 x i32> splat (i32 7), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD1:%.*]] = load <4 x i32>, ptr addrspace(12) [[TMP3]], align 4
// CHECK-SPIR-NEXT: store <4 x i32> [[CBUF_LOAD1]], ptr [[TMP4]], align 4
// CHECK-SPIR-NEXT: ret void
@@ -340,24 +328,24 @@ void arr_assign9() {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[C:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>) @c3, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP1]], <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>) @c3, <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP1]], <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(2) [[TMP3]], align 4
// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP4]], align 4
-// CHECK-DXIL-NEXT: [[TMP5:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP1]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP5:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP1]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load i32, ptr addrspace(2) [[TMP5]], align 4
// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD1]], ptr [[TMP6]], align 4
-// CHECK-DXIL-NEXT: [[TMP7:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>) @c3, <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP9:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP7]], <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP7:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>) @c3, <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP9:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP7]], <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(2) [[TMP9]], align 4
// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP10]], align 4
-// CHECK-DXIL-NEXT: [[TMP11:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP7]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP11:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>) [[TMP7]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL-NEXT: [[CBUF_LOAD3:%.*]] = load i32, ptr addrspace(2) [[TMP11]], align 4
// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD3]], ptr [[TMP12]], align 4
// CHECK-DXIL-NEXT: ret void
@@ -367,24 +355,24 @@ void arr_assign9() {
// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIR-NEXT: [[C:%.*]] = call elementtype([2 x [2 x i32]]) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>) @c3, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP1]], <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>) @c3, <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP1]], <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 7), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(12) [[TMP3]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP4]], align 4
-// CHECK-SPIR-NEXT: [[TMP5:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP1]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP5:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP1]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP2]], <1 x i32> splat (i32 7), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD1:%.*]] = load i32, ptr addrspace(12) [[TMP5]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD1]], ptr [[TMP6]], align 4
-// CHECK-SPIR-NEXT: [[TMP7:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>) @c3, <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP9:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP7]], <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP7:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>, target("spirv.Padding", 12) }>], <{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }> }>) @c3, <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [2 x i32]]) [[C]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP9:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP7]], <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 7), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(12) [[TMP9]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP10]], align 4
-// CHECK-SPIR-NEXT: [[TMP11:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP7]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP11:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ i32, target("spirv.Padding", 12) }>], i32 }>) [[TMP7]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x i32]) [[TMP8]], <1 x i32> splat (i32 7), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD3:%.*]] = load i32, ptr addrspace(12) [[TMP11]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD3]], ptr [[TMP12]], align 4
// CHECK-SPIR-NEXT: ret void
@@ -399,24 +387,24 @@ void arr_assign10() {
// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
// CHECK-DXIL-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: [[C:%.*]] = call elementtype([2 x [[STRUCT_S:%.*]]]) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ [[S:%.*]], target("dx.Padding", 8) }>], [[S]] }>) @c4, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP1:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <3 x i32>, ...) @llvm.structured.gep.p2.v3i32(ptr addrspace(2) elementtype(<{ [1 x <{ [[S:%.*]], target("dx.Padding", 8) }>], [[S]] }>) @c4, <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-DXIL-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-DXIL-NEXT: [[TMP3:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-DXIL-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(2) [[TMP3]], align 4
// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP4]], align 4
-// CHECK-DXIL-NEXT: [[TMP5:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP5:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(2) [[TMP5]], align 4
// CHECK-DXIL-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP6]], align 4
-// CHECK-DXIL-NEXT: [[TMP7:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ [[S]], target("dx.Padding", 8) }>], [[S]] }>) @c4, <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP9:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-DXIL-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL-NEXT: [[TMP7:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(<{ [1 x <{ [[S]], target("dx.Padding", 8) }>], [[S]] }>) @c4, <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP9:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-DXIL-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(2) [[TMP9]], align 4
// CHECK-DXIL-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP10]], align 4
-// CHECK-DXIL-NEXT: [[TMP11:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-DXIL-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL-NEXT: [[TMP11:%.*]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-DXIL-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL-NEXT: [[CBUF_LOAD3:%.*]] = load float, ptr addrspace(2) [[TMP11]], align 4
// CHECK-DXIL-NEXT: store float [[CBUF_LOAD3]], ptr [[TMP12]], align 4
// CHECK-DXIL-NEXT: ret void
@@ -426,24 +414,24 @@ void arr_assign10() {
// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIR-NEXT: [[C:%.*]] = call elementtype([2 x [[STRUCT_S:%.*]]]) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ [[S:%.*]], target("spirv.Padding", 8) }>], [[S]] }>) @c4, <3 x i32> splat (i32 3), i32 0, i32 0, i32 0)
-// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP1:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <3 x i32>, ...) @llvm.structured.gep.p12.v3i32(ptr addrspace(12) elementtype(<{ [1 x <{ [[S:%.*]], target("spirv.Padding", 8) }>], [[S]] }>) @c4, <3 x i32> splat (i32 7), i32 0, i32 0, i32 0)
+// CHECK-SPIR-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-SPIR-NEXT: [[TMP3:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-SPIR-NEXT: [[TMP4:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 7), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD:%.*]] = load i32, ptr addrspace(12) [[TMP3]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD]], ptr [[TMP4]], align 4
-// CHECK-SPIR-NEXT: [[TMP5:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP5:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP1]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP6:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP2]], <1 x i32> splat (i32 7), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD1:%.*]] = load float, ptr addrspace(12) [[TMP5]], align 4
// CHECK-SPIR-NEXT: store float [[CBUF_LOAD1]], ptr [[TMP6]], align 4
-// CHECK-SPIR-NEXT: [[TMP7:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ [[S]], target("spirv.Padding", 8) }>], [[S]] }>) @c4, <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP9:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 3), i32 0)
-// CHECK-SPIR-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR-NEXT: [[TMP7:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(<{ [1 x <{ [[S]], target("spirv.Padding", 8) }>], [[S]] }>) @c4, <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP8:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x [[STRUCT_S]]]) [[C]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP9:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 7), i32 0)
+// CHECK-SPIR-NEXT: [[TMP10:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 7), i32 0)
// CHECK-SPIR-NEXT: [[CBUF_LOAD2:%.*]] = load i32, ptr addrspace(12) [[TMP9]], align 4
// CHECK-SPIR-NEXT: store i32 [[CBUF_LOAD2]], ptr [[TMP10]], align 4
-// CHECK-SPIR-NEXT: [[TMP11:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 3), i32 1)
-// CHECK-SPIR-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR-NEXT: [[TMP11:%.*]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype([[S]]) [[TMP7]], <1 x i32> splat (i32 7), i32 1)
+// CHECK-SPIR-NEXT: [[TMP12:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([[STRUCT_S]]) [[TMP8]], <1 x i32> splat (i32 7), i32 1)
// CHECK-SPIR-NEXT: [[CBUF_LOAD3:%.*]] = load float, ptr addrspace(12) [[TMP11]], align 4
// CHECK-SPIR-NEXT: store float [[CBUF_LOAD3]], ptr [[TMP12]], align 4
// CHECK-SPIR-NEXT: ret void
diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_struct_passing.logical.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_struct_passing.logical.hlsl
index ffb23014f86cc..af03caf9b6c43 100644
--- a/clang/test/CodeGenHLSL/resources/cbuffer_struct_passing.logical.hlsl
+++ b/clang/test/CodeGenHLSL/resources/cbuffer_struct_passing.logical.hlsl
@@ -19,24 +19,24 @@ cbuffer CB {
void main() {
S tmp = (S)cbs;
// CHECK-DXIL: %agg-temp = call elementtype(%struct.S) ptr @llvm.structured.alloca.p0()
-// CHECK-DXIL: %[[#SRC:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @cbs, <1 x i32> splat (i32 3), i32 0)
-// CHECK-DXIL: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 3), i32 0)
+// CHECK-DXIL: %[[#SRC:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @cbs, <1 x i32> splat (i32 7), i32 0)
+// CHECK-DXIL: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 7), i32 0)
// CHECK-DXIL: %cbuf.load = load <3 x float>, ptr addrspace(2) %[[#SRC]], align 4
// CHECK-DXIL: store <3 x float> %cbuf.load, ptr %[[#DST]], align 4
-// CHECK-DXIL: %[[#SRC:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @cbs, <1 x i32> splat (i32 3), i32 2)
-// CHECK-DXIL: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL: %[[#SRC:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @cbs, <1 x i32> splat (i32 7), i32 2)
+// CHECK-DXIL: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL: %cbuf.load1 = load <4 x float>, ptr addrspace(2) %[[#SRC]], align 4
// CHECK-DXIL: store <4 x float> %cbuf.load1, ptr %[[#DST]], align 4
// CHECK-SPIR: %agg-temp = call elementtype(%struct.S) ptr @llvm.structured.alloca.p0()
-// CHECK-SPIR: %[[#SRC:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @cbs, <1 x i32> splat (i32 3), i32 0)
-// CHECK-SPIR: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 3), i32 0)
+// CHECK-SPIR: %[[#SRC:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @cbs, <1 x i32> splat (i32 7), i32 0)
+// CHECK-SPIR: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 7), i32 0)
// CHECK-SPIR: %cbuf.load = load <3 x float>, ptr addrspace(12) %[[#SRC]], align 4
// CHECK-SPIR: store <3 x float> %cbuf.load, ptr %[[#DST]], align 4
-// CHECK-SPIR: %[[#SRC:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @cbs, <1 x i32> splat (i32 3), i32 2)
-// CHECK-SPIR: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR: %[[#SRC:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @cbs, <1 x i32> splat (i32 7), i32 2)
+// CHECK-SPIR: %[[#DST:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %agg-temp, <1 x i32> splat (i32 7), i32 1)
// CHECK-SPIR: %cbuf.load1 = load <4 x float>, ptr addrspace(12) %[[#SRC]], align 4
// CHECK-SPIR: store <4 x float> %cbuf.load1, ptr %[[#DST]], align 4
}
diff --git a/clang/test/CodeGenHLSL/sgep/array_load.hlsl b/clang/test/CodeGenHLSL/sgep/array_load.hlsl
index 32ea373895bb9..1936c333a2eca 100644
--- a/clang/test/CodeGenHLSL/sgep/array_load.hlsl
+++ b/clang/test/CodeGenHLSL/sgep/array_load.hlsl
@@ -5,7 +5,7 @@ void foo() {
// CHECK: %array = call elementtype([3 x i32]) ptr @llvm.structured.alloca.p0()
uint array[3] = { 0, 1, 2 };
-// CHECK: %[[FOO_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 2)
+// CHECK: %[[FOO_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 7), {{i32|i64}} 2)
// CHECK: load i32, ptr %[[FOO_PTR]], align 4
uint tmp = array[2];
}
@@ -14,7 +14,7 @@ void signed_idx(int i) {
// CHECK: %array = call elementtype([3 x i32]) ptr @llvm.structured.alloca.p0()
uint array[3] = { 0, 1, 2 };
-// CHECK: %[[SIGNED_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 1), {{i32|i64}} %{{.*}})
+// CHECK: %[[SIGNED_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 5), {{i32|i64}} %{{.*}})
// CHECK: load i32, ptr %[[SIGNED_PTR]], align 4
uint tmp = array[i];
}
@@ -23,7 +23,7 @@ void unsigned_idx(uint i) {
// CHECK: %array = call elementtype([3 x i32]) ptr @llvm.structured.alloca.p0()
uint array[3] = { 0, 1, 2 };
-// CHECK: %[[UNSIGNED_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 5), {{i32|i64}} %{{.*}})
+// CHECK: %[[UNSIGNED_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x i32]) %array, <1 x i32> splat (i32 13), {{i32|i64}} %{{.*}})
// CHECK: load i32, ptr %[[UNSIGNED_PTR]], align 4
uint tmp = array[i];
}
@@ -37,8 +37,8 @@ void bar() {
// CHECK: %array = call elementtype([3 x %struct.S]) ptr @llvm.structured.alloca.p0()
S array[3] = { { 0, 1 }, { 2, 3 }, { 3, 4 } };
-// CHECK: %[[BAR_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 2)
-// CHECK: %[[BAR_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAR_A]], <1 x i32> splat (i32 3), {{i32|i64}} 1)
+// CHECK: %[[BAR_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S]) %array, <1 x i32> splat (i32 7), {{i32|i64}} 2)
+// CHECK: %[[BAR_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAR_A]], <1 x i32> splat (i32 7), {{i32|i64}} 1)
// CHECK: load i32, ptr %[[BAR_B]], align 1
uint tmp = array[2].b;
}
@@ -53,9 +53,9 @@ void baz() {
// CHECK: %array = call elementtype([2 x %struct.S2]) ptr @llvm.structured.alloca.p0()
S2 array[2] = { { 0, { 1, 2 }, 3 }, { 4, { 5, 6 }, 7 } };
-// CHECK: %[[BAZ_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x %struct.S2]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 1)
-// CHECK: %[[BAZ_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %[[BAZ_A]], <1 x i32> splat (i32 3), {{i32|i64}} 1)
-// CHECK: %[[BAZ_C:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAZ_B]], <1 x i32> splat (i32 3), {{i32|i64}} 0)
+// CHECK: %[[BAZ_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x %struct.S2]) %array, <1 x i32> splat (i32 7), {{i32|i64}} 1)
+// CHECK: %[[BAZ_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %[[BAZ_A]], <1 x i32> splat (i32 7), {{i32|i64}} 1)
+// CHECK: %[[BAZ_C:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAZ_B]], <1 x i32> splat (i32 7), {{i32|i64}} 0)
// CHECK: load i32, ptr %[[BAZ_C]], align 1
uint tmp = array[1].b.a;
}
diff --git a/clang/test/CodeGenHLSL/sgep/array_store.hlsl b/clang/test/CodeGenHLSL/sgep/array_store.hlsl
index 8c72743c02e43..5dcaead2dd341 100644
--- a/clang/test/CodeGenHLSL/sgep/array_store.hlsl
+++ b/clang/test/CodeGenHLSL/sgep/array_store.hlsl
@@ -7,7 +7,7 @@ void foo() {
// CHECK: %array = call elementtype([10 x i32]) ptr @llvm.structured.alloca.p0()
uint array[10];
-// CHECK: %[[FOO_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 2)
+// CHECK: %[[FOO_PTR:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %array, <1 x i32> splat (i32 7), {{i32|i64}} 2)
// CHECK: store i32 10, ptr %[[FOO_PTR]], align 4
array[2] = 10;
}
@@ -21,8 +21,8 @@ void bar() {
// CHECK: %array = call elementtype([3 x %struct.S]) ptr @llvm.structured.alloca.p0()
S array[3] = { { 0, 1 }, { 2, 3 }, { 3, 4 } };
-// CHECK: %[[BAR_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 2)
-// CHECK: %[[BAR_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAR_A]], <1 x i32> splat (i32 3), {{i32|i64}} 1)
+// CHECK: %[[BAR_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S]) %array, <1 x i32> splat (i32 7), {{i32|i64}} 2)
+// CHECK: %[[BAR_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAR_A]], <1 x i32> splat (i32 7), {{i32|i64}} 1)
// CHECK: store i32 10, ptr %[[BAR_B]], align 1
array[2].b = 10;
@@ -38,9 +38,9 @@ void baz() {
// CHECK: %array = call elementtype([2 x %struct.S2]) ptr @llvm.structured.alloca.p0()
S2 array[2] = { { 0, { 1, 2 }, 3 }, { 4, { 5, 6 }, 7 } };
-// CHECK: %[[BAZ_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x %struct.S2]) %array, <1 x i32> splat (i32 3), {{i32|i64}} 1)
-// CHECK: %[[BAZ_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %[[BAZ_A]], <1 x i32> splat (i32 3), {{i32|i64}} 1)
-// CHECK: %[[BAZ_C:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAZ_B]], <1 x i32> splat (i32 3), {{i32|i64}} 0)
+// CHECK: %[[BAZ_A:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([2 x %struct.S2]) %array, <1 x i32> splat (i32 7), {{i32|i64}} 1)
+// CHECK: %[[BAZ_B:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %[[BAZ_A]], <1 x i32> splat (i32 7), {{i32|i64}} 1)
+// CHECK: %[[BAZ_C:.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %[[BAZ_B]], <1 x i32> splat (i32 7), {{i32|i64}} 0)
// CHECK: store i32 10, ptr %[[BAZ_C]], align 1
array[1].b.a = 10;
diff --git a/clang/test/CodeGenHLSL/sgep/load_global.hlsl b/clang/test/CodeGenHLSL/sgep/load_global.hlsl
index 932b0ac737690..108e871285e57 100644
--- a/clang/test/CodeGenHLSL/sgep/load_global.hlsl
+++ b/clang/test/CodeGenHLSL/sgep/load_global.hlsl
@@ -21,19 +21,19 @@ const uint b;
void foo() {
-// CHECK-DXIL: %[[#PTR:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @_ZL1s, <1 x i32> splat (i32 3), i32 1)
+// CHECK-DXIL: %[[#PTR:]] = call ptr addrspace(2) (ptr addrspace(2), <1 x i32>, ...) @llvm.structured.gep.p2.v1i32(ptr addrspace(2) elementtype(%S) @_ZL1s, <1 x i32> splat (i32 7), i32 1)
// CHECK-DXIL: %[[#]] = load i32, ptr addrspace(2) %[[#PTR]], align 4
-// CHECK-SPIR: %[[#PTR:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @_ZL1s, <1 x i32> splat (i32 3), i32 1)
+// CHECK-SPIR: %[[#PTR:]] = call ptr addrspace(12) (ptr addrspace(12), <1 x i32>, ...) @llvm.structured.gep.p12.v1i32(ptr addrspace(12) elementtype(%S) @_ZL1s, <1 x i32> splat (i32 7), i32 1)
// CHECK-SPIR: %[[#]] = load i32, ptr addrspace(12) %[[#PTR]], align 4
uint tmp = s.b;
}
void bar() {
-// CHECK-DXIL: %cbufferidx = call ptr addrspace(2) (ptr addrspace(2), <2 x i32>, ...) @llvm.structured.gep.p2.v2i32(ptr addrspace(2) elementtype([4 x <{ i32, target("dx.Padding", 12) }>]) @_ZL1a, <2 x i32> splat (i32 3), i32 2, i32 0)
+// CHECK-DXIL: %cbufferidx = call ptr addrspace(2) (ptr addrspace(2), <2 x i32>, ...) @llvm.structured.gep.p2.v2i32(ptr addrspace(2) elementtype([4 x <{ i32, target("dx.Padding", 12) }>]) @_ZL1a, <2 x i32> splat (i32 7), i32 2, i32 0)
// CHECK-DXIL: %[[#]] = load i32, ptr addrspace(2) %cbufferidx, align 16
-// CHECK-SPIR: %cbufferidx = call ptr addrspace(12) (ptr addrspace(12), <2 x i32>, ...) @llvm.structured.gep.p12.v2i32(ptr addrspace(12) elementtype([4 x <{ i32, target("spirv.Padding", 12) }>]) @_ZL1a, <2 x i32> splat (i32 3), i64 2, i32 0)
+// CHECK-SPIR: %cbufferidx = call ptr addrspace(12) (ptr addrspace(12), <2 x i32>, ...) @llvm.structured.gep.p12.v2i32(ptr addrspace(12) elementtype([4 x <{ i32, target("spirv.Padding", 12) }>]) @_ZL1a, <2 x i32> splat (i32 7), i64 2, i32 0)
// CHECK-SPIR: %[[#]] = load i32, ptr addrspace(12) %cbufferidx, align 16
uint tmp = a[2];
}
diff --git a/clang/test/CodeGenHLSL/sgep/object_method.hlsl b/clang/test/CodeGenHLSL/sgep/object_method.hlsl
index 869c9cb4089c6..171c020859a58 100644
--- a/clang/test/CodeGenHLSL/sgep/object_method.hlsl
+++ b/clang/test/CodeGenHLSL/sgep/object_method.hlsl
@@ -25,6 +25,6 @@ void foo() {
// CHECK-DXIL: define linkonce_odr hidden noundef i32 @_ZN1O3getEv(ptr noundef nonnull align 1 dereferenceable(4) %this)
// CHECK-SPIR: define linkonce_odr hidden spir_func noundef i32 @_ZN1O3getEv(ptr noundef nonnull align 1 dereferenceable(4) %this)
-// CHECK: %[[#A:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.O) %this1, <1 x i32> splat (i32 3), {{i32|i64}} 0)
+// CHECK: %[[#A:]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.O) %this1, <1 x i32> splat (i32 7), {{i32|i64}} 0)
// CHECK: %[[#B:]] = load i32, ptr %[[#A]], align 1
// CHECK: ret i32 %[[#B]]
diff --git a/llvm/docs/AMDGPUUsage.rst b/llvm/docs/AMDGPUUsage.rst
index b3b2a06005377..648dc672cb3e6 100644
--- a/llvm/docs/AMDGPUUsage.rst
+++ b/llvm/docs/AMDGPUUsage.rst
@@ -1620,29 +1620,33 @@ element type metadata. No value of this type can be created.
The marker type has one optional parameter - an integer indicating the constant
value of the stride of the buffer(s) being addressed if known. That integer, if
-given, must be non-negative (but can be 0, indicating the degenarate case where
+given, must be non-negative (but can be 0, indicating the degenerate case where
no stride is set but the index field should be used anyway).
When creating a structured GEP, arrays of ``amdgpu.stridemark``s are used to
-represent indexing into the *index* component of the structured/strided buffer,
-while a subsequent bare ``getelementptr`` - is used to manipulate the *offset*
-part.
+represent indexing into the components of the structured/strided buffer:
+the first index manipulates the *index* part, and the second index (or a subsequent
+bare ``getelementptr``) manipulates the *offset* part.
Example usage:
.. code-block:: llvm
- ;; A 2-D array of unknown length and stride.
- %q1 = call ptr addrspace(9) (ptr addrspace(9), ...)
+ ;; A 2-D array of unknown length and stride. Indices are specified as being
+ ;; interpreted as unsigned. No guarantee is made that the index or offset
+ ;; are 0.
+ call ptr addrspace(9) (ptr addrspace(9), ...)
(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark") ]) %p,
- i32 %index)
- %q = getelementptr i8, ptr addrspace(9) %q1, i32 %offset
-
- ;; Known bounds on index and offset.
- %y1 = call ptr addrspace(9) (ptr addrspace(9), ...)
+ <2 x i32> <i32 8, i32 8>,
+ i32 %index, i32 %offset)
+
+ ;; Known bounds on index and offset. Indices are known to be inbounds,
+ ;; non-negative, start from the logical beginning, and are treated as
+ ;; unsigned per the SGEP flags.
+ %y = call ptr addrspace(9) (ptr addrspace(9), ...),
+ <2 x i32> <i32 15, i32 15>
(ptr addrspace(9) elementtype([256 x target("amdgpu.stridemark", 16) ]) %p,
- i32 %index)
- %y = getelementptr ptr addrspace(9) %y1, i32 %offset
+ i32 %index, i32 %offset)
Note that the lowering for these examples is not yet implemented and will
be added in future changes.
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 654158a1b5063..e5e789829e70a 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -14989,35 +14989,37 @@ Otherwise, the flags operand must have one element per index.
The `llvm.structured.gep` performs a logical traversal of the type
`basetype` using the list of provided indices, computing the pointer
addressing the targeted element/field assuming `source` points to memory
-interpretable as a physically laid out `basetype` (with potentially differenig
-array lengths if permitted). The physical layout of the source depends on the
-target and does not necessarily match the one described by the datalayout.
+interpretable as an object of type `basetype` (or to locations within that object
+if the corresponding indexing levels are not marked `fromstart`).
+The physical layout of the source depends on the target and does not necessarily
+match the one described by the datalayout.
The first index determines which element/field of `basetype` is selected,
computes the pointer to access this element/field assuming `source` points
-into memory interpretable as a `basetype`, optionally ignoring array element
-counts.
+into memory interpretable as a `basetype` or, if the `fromstart` flag is set,
+to the start of such memory.
This pointer becomes the new `source`, the current type the new
`basetype`, and the next index is consumed until a scalar type is
reached or all indices are consumed.
-Note that the interpretability requirement prohibits `source` from pointing within
-a struct or a vector, but does permit pointers in the middle of arrays. In the case
-of such a mid-array pointer, the corresponding `index` moves logically within the
-array. Unlike with normal GEP, there is no requirement that indices "overflow" to
-the next dimension - that is, `sgep [8 x [8 x i8]], ptr %source, i32 0, i32 8`
-is not necessarily the same location as
-`sgep [8 x [8 x i8]], ptr %source, i32 1, i32 0`. The indices for each axis
-in a multidimtional array *may*, but are not *required to be*, tracked separately:
+In the case of such non-`fromstart` array pointers, the corresponding `index`
+moves logically within the array. Unlike with normal GEP, there is no requirement
+that indices "overflow" to the next dimension - that is,
+`sgep [8 x [8 x i8]], ptr %source, i32 0, i32 8` is not necessarily the same
+location as `sgep [8 x [8 x i8]], ptr %source, i32 1, i32 0`. The indices for each axis
+in a multidimensional array *may*, but are not *required to be*, tracked separately:
the overflow flags apply to the ultimate, target-specific tracking mechanism.
-Targets, such as SPIR-V, may impose the additional requirement that `source`
-point to the **beginning** of a `basetype`, but LLVM will not optimize on this
-assumption.
-
All indices must be consumed, and it is illegal to index into a scalar type,
meaning the maximum number of indices depends on the depth of the basetype.
+Targets may mark target extension types as SGEP-indexable. Such types may appear
+as the innermost type of a `basetype`, where their presence permits (but does not
+require) additional indices.
+
+Targets, such as SPIR-V, may require that `fromstart` is present on some or all
+indices.
+
If the indexed type is a struct with N fields, the index must be an
integer constant in the range `[0, N)`.
@@ -15042,17 +15044,29 @@ This instruction does not dereference the pointer.
This is not necessarily implied by `inbounds`. For example, consider
```llvm
- %q = sgep [8 x target("amdgpu.stridemark")], inbounds|nneg, ptr addrspace(9) %p, i32 4
- %r = sgep [8 x target("amdgpu.stridemark")], inbounds, ptr addrspace(9) %q, i32 %x
+ %q = sgep [8 x target("amdgpu.stridemark")],
+ <inbounds|nneg, inbounds|nneg|fromstart>,
+ ptr addrspace(9) %p, i32 4, i32 0
+ %r = sgep [8 x target("amdgpu.stridemark")],
+ <inbounds, inbounds|nneg|fromstart>,
+ ptr addrspace(9) %q, i32 %x, i32 2
```
where `inbounds` only implies that `-4 <= %x <= 4`.
+`fromstart`
+: Bit 2 (`1 << 2`) - specifies that the pointer at this indexing level points to
+ the beginning of the array or vector being indexed. If a type is indexed with a
+ `fromstart` annotation, the lack of a `fromstart` annotation on a subsequent
+ indexing level is only permitted with target-specific knowledge that the index
+ accumulation "resets" at that level.
+
`unsigned`
-: Bit 2 (`1 << 2`) - specifies that the index should be interpreted as an
+: Bit 3 (`1 << 3`) - specifies that the index should be interpreted as an
unsigned number if extension or truncation is required.
-The `inbounds` and `nneg` flags must be set when indexing into structures.
+The `inbounds`, `nneg`, and `fromstart` flags must currently be set when indexing
+into structures.
##### Aliasing rules:
@@ -15073,7 +15087,7 @@ undefined.
```
This implies that two `llvm.structured.gep` calls with the same pointer
-and element type do not alias unless the index sequence of one if a prefix
+and element type do not alias unless the index sequence of one is a prefix
of the other.
##### Example:
@@ -15089,7 +15103,7 @@ Could be translated to:
```llvm
%A = type { i32, i32, i32, i32 }
-%src = call ptr @llvm.structured.gep(ptr elementtype(%A) %my_struct, <1 x i32> <i32 3>, i32 1)
+%src = call ptr @llvm.structured.gep(ptr elementtype(%A) %my_struct, <1 x i32> <i32 7>, i32 1)
%val = load i32, ptr %src
```
@@ -15120,14 +15134,14 @@ This means it is valid to lower the following code to either:
```llvm
%S = type { i32, i32, i32, i32 }
-%src = call ptr @llvm.structured.gep(ptr elementtype(%S) %my_struct, <1 x i32> <i32 3>, i32 1)
+%src = call ptr @llvm.structured.gep(ptr elementtype(%S) %my_struct, <1 x i32> <i32 7>, i32 1)
load i32, ptr %src
```
Or:
```llvm
-%src = call ptr @llvm.structured.gep(ptr elementtype([4 x i32]) %my_struct, <1 x i32> <i32 3>, i32 1)
+%src = call ptr @llvm.structured.gep(ptr elementtype([4 x i32]) %my_struct, <1 x i32> <i32 7>, i32 1)
load i32, ptr %src
```
@@ -15155,9 +15169,11 @@ Could be translated to:
or as something with more flags, such as
```llvm
-;; 0 sle %i slt M follows from this, as does %j ult N.
+;; 0 sle %i slt M follows from this, as does %j ult N, as does knowledge that
+;; %array points to the beginning of memory that can be interpreted as an
+;; M x N x float array.
%src = call ptr @llvm.structured.gep(ptr elementtype([M x [N x float]]) %array,
- <2 x i32> <i32 3, i32 5>, i64 %i, i64 %j)
+ <2 x i32> <i32 7, i32 13>, i64 %i, i64 %j)
%val = load float, ptr %src
```
@@ -15174,7 +15190,7 @@ could be translated to:
```llvm
%src = call ptr @llvm.structured.gep(ptr elementtype([0 x float]) %array,
- <1 x i32> <i32 3>, i64 %i)
+ <1 x i32> <i32 7>, i64 %i)
%val = load float, ptr %src
```
@@ -15237,7 +15253,7 @@ the backend's layout rules.
%ptr = call elementtype(%S) ptr @llvm.structured.alloca()
; Access the second field of the allocated struct
-%field_ptr = call ptr @llvm.structured.gep(ptr elementtype(%S) %ptr, <1 x i32> <i32 3>, i32 1)
+%field_ptr = call ptr @llvm.structured.gep(ptr elementtype(%S) %ptr, <1 x i32> <i32 7>, i32 1)
%val = load i32, ptr %field_ptr
; Allocate an array of 10 i32s on the stack
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 4eead88b7b8f8..616abf842278b 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -55,7 +55,8 @@ Makes programs 10x faster by doing Special New Thing.
### Changes to the LLVM IR
* The `llvm.structured.gep` intrinsic has gained an extra `flags` argument,
- allowing the in-bounds nature of array indices, their signedness, and their
+ allowing the in-bounds nature of array indices, whether indexing starts from
+ the logical beginning of the object, their signedness, and their
non-negativity to be provided on a per-index basis, removing the old
`[0 x T]` element type that conflated an array having unknown extent with
potentially in-bounds indexing. The default interpretation of indices has been
diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h
index 93ccd5944d432..9890800de0104 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -918,6 +918,8 @@ class TargetExtType : public Type {
// This type can only be used in intrinsic arguments and return values.
/// In particular, it cannot be used in select and phi instructions.
IsTokenLike = 1U << 4,
+ /// This type permits target-defined llvm.structured.gep indices.
+ CanBeSGEPIndexed = 1U << 5,
};
/// Returns true if the target extension type contains the given property.
diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h
index 14d6e4b4fc38b..fceebcc884d35 100644
--- a/llvm/include/llvm/IR/IntrinsicInst.h
+++ b/llvm/include/llvm/IR/IntrinsicInst.h
@@ -24,6 +24,7 @@
#define LLVM_IR_INTRINSICINST_H
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
@@ -1866,6 +1867,20 @@ class StructuredGEPInst : public IntrinsicInst {
return cast<Constant>(getOperand(getFlagsOperandIndex()));
}
+ SmallVector<StructuredGEPFlags, 4> getFlagValues() const {
+ Constant *Flags = getFlagsOperand();
+ unsigned NumFlagValues =
+ cast<FixedVectorType>(Flags->getType())->getNumElements();
+ SmallVector<StructuredGEPFlags, 4> FlagValues;
+ FlagValues.reserve(NumFlagValues);
+ for (unsigned I = 0; I < NumFlagValues; ++I) {
+ auto *FlagValue = cast<ConstantInt>(Flags->getAggregateElement(I));
+ FlagValues.push_back(
+ StructuredGEPFlags::fromRaw(FlagValue->getZExtValue()));
+ }
+ return FlagValues;
+ }
+
Type *getBaseType() const {
return getParamAttr(0, Attribute::ElementType).getValueAsType();
}
@@ -1881,9 +1896,54 @@ class StructuredGEPInst : public IntrinsicInst {
StructuredGEPFlags getIndexFlags(size_t Index) const {
assert(Index < getNumIndices());
- Constant *Flags = getFlagsOperand();
- auto *FlagValue = cast<ConstantInt>(Flags->getAggregateElement(Index));
- return StructuredGEPFlags::fromRaw(FlagValue->getZExtValue());
+ return getFlagValues()[Index];
+ }
+
+ Type *getTypeAtIndexDepth(size_t Depth) const {
+ if (Depth > getNumIndices())
+ return nullptr;
+
+ Type *CurrentType = getBaseType();
+ for (unsigned I = 0; I < Depth; ++I) {
+ if (ArrayType *AT = dyn_cast<ArrayType>(CurrentType)) {
+ CurrentType = AT->getElementType();
+ } else if (VectorType *VT = dyn_cast<VectorType>(CurrentType)) {
+ CurrentType = VT->getElementType();
+ } else if (StructType *ST = dyn_cast<StructType>(CurrentType)) {
+ auto *CI = dyn_cast<ConstantInt>(getIndexOperand(I));
+ if (!CI || CI->getZExtValue() >= ST->getNumElements())
+ return nullptr;
+ CurrentType = ST->getElementType(CI->getZExtValue());
+ } else if (auto *TET = dyn_cast<TargetExtType>(CurrentType);
+ TET && TET->hasProperty(TargetExtType::CanBeSGEPIndexed)) {
+ CurrentType = TET;
+ } else {
+ return nullptr;
+ }
+ }
+
+ return CurrentType;
+ }
+
+ StructuredGEPFlags getRequiredIndexFlags(size_t Index) const {
+ if (Index >= getNumIndices())
+ return StructuredGEPFlags::none();
+
+ if (isa_and_nonnull<StructType>(getTypeAtIndexDepth(Index)))
+ return StructuredGEPFlags::inBounds() | StructuredGEPFlags::nneg() |
+ StructuredGEPFlags::fromStart();
+
+ return StructuredGEPFlags::none();
+ }
+
+ SmallVector<StructuredGEPFlags, 4> getRequiredFlagValues() const {
+ unsigned NumFlagValues =
+ cast<FixedVectorType>(getFlagsOperand()->getType())->getNumElements();
+ SmallVector<StructuredGEPFlags, 4> RequiredFlagValues;
+ RequiredFlagValues.reserve(NumFlagValues);
+ for (unsigned I = 0; I < NumFlagValues; ++I)
+ RequiredFlagValues.push_back(getRequiredIndexFlags(I));
+ return RequiredFlagValues;
}
bool isIndexInBounds(size_t Index) const {
@@ -1892,6 +1952,10 @@ class StructuredGEPInst : public IntrinsicInst {
bool isIndexNNeg(size_t Index) const { return getIndexFlags(Index).isNNeg(); }
+ bool isIndexFromStart(size_t Index) const {
+ return getIndexFlags(Index).isFromStart();
+ }
+
bool isIndexUnsigned(size_t Index) const {
return getIndexFlags(Index).isUnsignedIndex();
}
@@ -1901,28 +1965,22 @@ class StructuredGEPInst : public IntrinsicInst {
[this](unsigned Index) { return isIndexInBounds(Index); });
}
+ bool isFromStart() const {
+ return all_of(seq<unsigned>(0, getNumIndices()),
+ [this](unsigned Index) { return isIndexFromStart(Index); });
+ }
+
inline iterator_range<op_iterator> indices() {
- return make_range(op_begin() + 1, op_begin() + 1 + getNumIndices());
+ return make_range(op_begin() + getFirstIndexOperandIndex(),
+ op_begin() + getFirstIndexOperandIndex() +
+ getNumIndices());
}
Type *getResultElementType() const {
- Type *CurrentType = getBaseType();
- for (unsigned I = 0; I < getNumIndices(); I++) {
- if (ArrayType *AT = dyn_cast<ArrayType>(CurrentType)) {
- CurrentType = AT->getElementType();
- } else if (VectorType *VT = dyn_cast<VectorType>(CurrentType)) {
- CurrentType = VT->getElementType();
- } else if (StructType *ST = dyn_cast<StructType>(CurrentType)) {
- ConstantInt *CI = cast<ConstantInt>(getIndexOperand(I));
- CurrentType = ST->getElementType(CI->getZExtValue());
- } else {
- // FIXME(Keenuts): add testing reaching those places once initial
- // implementation has landed.
- llvm_unreachable("unimplemented");
- }
- }
-
- return CurrentType;
+ Type *ResultType = getTypeAtIndexDepth(getNumIndices());
+ if (!ResultType)
+ llvm_unreachable("invalid structured gep type path");
+ return ResultType;
}
};
diff --git a/llvm/include/llvm/IR/StructuredGEPFlags.h b/llvm/include/llvm/IR/StructuredGEPFlags.h
index 6ffc41b7dc5ce..877bcbd946212 100644
--- a/llvm/include/llvm/IR/StructuredGEPFlags.h
+++ b/llvm/include/llvm/IR/StructuredGEPFlags.h
@@ -20,7 +20,8 @@ class StructuredGEPFlags {
enum Flag : unsigned {
InBoundsFlag = (1 << 0),
NNegFlag = (1 << 1),
- UnsignedFlag = (1 << 2),
+ FromStartFlag = (1 << 2),
+ UnsignedFlag = (1 << 3),
};
unsigned Flags;
@@ -34,6 +35,9 @@ class StructuredGEPFlags {
return StructuredGEPFlags(InBoundsFlag);
}
static StructuredGEPFlags nneg() { return StructuredGEPFlags(NNegFlag); }
+ static StructuredGEPFlags fromStart() {
+ return StructuredGEPFlags(FromStartFlag);
+ }
static StructuredGEPFlags unsignedIndex() {
return StructuredGEPFlags(UnsignedFlag);
}
@@ -45,7 +49,12 @@ class StructuredGEPFlags {
bool isInBounds() const { return Flags & InBoundsFlag; }
bool isNNeg() const { return Flags & NNegFlag; }
+ bool isFromStart() const { return Flags & FromStartFlag; }
bool isUnsignedIndex() const { return Flags & UnsignedFlag; }
+ bool hasPoisonGeneratingFlags() const { return Flags & ~UnsignedFlag; }
+ StructuredGEPFlags withoutPoisonGeneratingFlags() const {
+ return StructuredGEPFlags(Flags & UnsignedFlag);
+ }
bool operator==(StructuredGEPFlags Other) const {
return Flags == Other.Flags;
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 17f11c26f8e97..c4fef16fb8956 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -5134,8 +5134,8 @@ static Value *upgradeConvertIntrinsicCall(StringRef Name, CallBase *CI,
}
// Return the flags that represent the semantics of a structured GEP before
-// flags were added. Always sets `unsigned`. If the structered GEP is malformed,
-// will fill in one `unsigned` per index.
+// flags were added. Always sets `unsigned` and `fromstart`. If the structured
+// GEP is malformed, will fill in one `unsigned|fromstart` per index.
static Constant *getLegacyStructuredGEPFlags(CallBase *CI) {
Type *CurrentType = nullptr;
if (CI->paramHasAttr(0, Attribute::ElementType))
@@ -5145,7 +5145,8 @@ static Constant *getLegacyStructuredGEPFlags(CallBase *CI) {
unsigned NumIndices = CI->arg_size() - 1;
SmallVector<StructuredGEPFlags> FlagValues(
std::max({NumIndices, 1u}), NumIndices
- ? StructuredGEPFlags::unsignedIndex()
+ ? StructuredGEPFlags::unsignedIndex() |
+ StructuredGEPFlags::fromStart()
: StructuredGEPFlags::none());
for (auto [I, Flags] : llvm::enumerate(FlagValues)) {
// Safety valve for malformed SGEP.
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index cad612752c220..ab9b679188b4e 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -481,6 +481,24 @@ void Instruction::dropPoisonGeneratingFlags() {
case Instruction::Call: {
if (auto *II = dyn_cast<IntrinsicInst>(this)) {
switch (II->getIntrinsicID()) {
+ case Intrinsic::structured_gep: {
+ auto *SGEP = cast<StructuredGEPInst>(II);
+ Type *Int32Ty = Type::getInt32Ty(getContext());
+ SmallVector<StructuredGEPFlags, 4> IndexFlagValues =
+ SGEP->getFlagValues();
+ SmallVector<StructuredGEPFlags, 4> RequiredFlagValues =
+ SGEP->getRequiredFlagValues();
+ SmallVector<Constant *> FlagValues;
+ for (auto [IndexFlags, RequiredFlags] :
+ zip_equal(IndexFlagValues, RequiredFlagValues)) {
+ StructuredGEPFlags Flags = IndexFlags.withoutPoisonGeneratingFlags();
+ Flags |= IndexFlags & RequiredFlags;
+ FlagValues.push_back(ConstantInt::get(Int32Ty, Flags.getRaw()));
+ }
+ II->setOperand(StructuredGEPInst::getFlagsOperandIndex(),
+ ConstantVector::get(FlagValues));
+ break;
+ }
case Intrinsic::ctlz:
case Intrinsic::cttz:
case Intrinsic::abs:
diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index 6235ef7000c73..116aa1925a671 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/Operator.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/Instructions.h"
@@ -57,6 +58,22 @@ bool Operator::hasPoisonGeneratingFlags() const {
case Instruction::Call:
if (auto *II = dyn_cast<IntrinsicInst>(this)) {
switch (II->getIntrinsicID()) {
+ case Intrinsic::structured_gep: {
+ auto *SGEP = cast<StructuredGEPInst>(II);
+ SmallVector<StructuredGEPFlags, 4> IndexFlagValues =
+ SGEP->getFlagValues();
+ SmallVector<StructuredGEPFlags, 4> RequiredFlagValues =
+ SGEP->getRequiredFlagValues();
+ auto HasDroppablePoisonGeneratingFlags = [](auto Item) {
+ StructuredGEPFlags Flags = std::get<0>(Item);
+ StructuredGEPFlags RequiredFlags = std::get<1>(Item);
+ Flags = StructuredGEPFlags::fromRaw(Flags.getRaw() &
+ ~RequiredFlags.getRaw());
+ return Flags.hasPoisonGeneratingFlags();
+ };
+ return any_of(zip_equal(IndexFlagValues, RequiredFlagValues),
+ HasDroppablePoisonGeneratingFlags);
+ }
case Intrinsic::ctlz:
case Intrinsic::cttz:
case Intrinsic::abs:
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 8c108a4d1f275..e07ffd7c60dc9 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -1123,7 +1123,8 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
TargetExtType::CanBeGlobal);
}
if (Name == "amdgpu.stridemark")
- return TargetTypeInfo(Type::getVoidTy(C), TargetExtType::IsTokenLike);
+ return TargetTypeInfo(Type::getVoidTy(C), TargetExtType::IsTokenLike,
+ TargetExtType::CanBeSGEPIndexed);
// Type used to test vector element target extension property.
// Can be removed once a public target extension type uses CanBeVectorElement.
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 9912d65217418..d9711c517f6e5 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -6999,11 +6999,19 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
Check(CI, "Indexing into a struct requires a constant int", &Call);
Check(CI->getZExtValue() < ST->getNumElements(),
"Indexing in a struct should be inbounds", &Call);
- Check(IndexFlags.isInBounds() && IndexFlags.isNNeg(),
- "Indexing into a struct requires inbounds and nneg flags", &Call);
+ Check(IndexFlags.isInBounds() && IndexFlags.isNNeg() &&
+ IndexFlags.isFromStart(),
+ "Indexing into a struct requires inbounds, nneg, and fromstart "
+ "flags",
+ &Call);
T = ST->getElementType(CI->getZExtValue());
} else if (auto *VT = dyn_cast<VectorType>(T)) {
T = VT->getElementType();
+ } else if (auto *TET = dyn_cast<TargetExtType>(T);
+ TET && TET->hasProperty(TargetExtType::CanBeSGEPIndexed)) {
+ // SGEP-indexable target extension types consume target-defined indices
+ // while remaining at the same logical type.
+ T = TET;
} else {
CheckFailed("Reached a non-composite type with more indices to process",
&Call);
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index e75aea53061f0..1fe59165f7557 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -1972,6 +1972,15 @@ Instruction *SPIRVEmitIntrinsicsImpl::visitIntrinsicInst(IntrinsicInst &I) {
if (!SGEP)
return &I;
+ if (!SGEP->isFromStart()) {
+ I.getContext().emitError(
+ &I, "llvm.structured.gep requires fromstart on every index for "
+ "SPIR-V lowering");
+ I.replaceAllUsesWith(PoisonValue::get(I.getType()));
+ I.eraseFromParent();
+ return nullptr;
+ }
+
IRBuilder<> B(I.getParent());
B.SetInsertPoint(&I);
SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
diff --git a/llvm/lib/Transforms/Scalar/LogicalSROA.cpp b/llvm/lib/Transforms/Scalar/LogicalSROA.cpp
index a0ed5cd0681d7..ac956a5b40089 100644
--- a/llvm/lib/Transforms/Scalar/LogicalSROA.cpp
+++ b/llvm/lib/Transforms/Scalar/LogicalSROA.cpp
@@ -159,9 +159,13 @@ static void rewriteSGEPChain(IRBuilder<> &B, StructuredGEPInst *SGEP,
}
SmallVector<Value *, 4> Indices(llvm::drop_begin(SGEP->indices()));
+ SmallVector<StructuredGEPFlags, 4> Flags;
+ Flags.reserve(SGEP->getNumIndices() - 1);
+ for (unsigned I = 1; I < SGEP->getNumIndices(); ++I)
+ Flags.push_back(SGEP->getIndexFlags(I));
B.SetInsertPoint(SGEP);
auto *I = B.CreateStructuredGEP(FieldAlloca->getAllocationType(), FieldAlloca,
- Indices, SGEP->getName());
+ Indices, Flags, SGEP->getName());
SGEP->replaceAllUsesWith(I);
SGEP->eraseFromParent();
}
diff --git a/llvm/test/Assembler/auto_upgrade_intrinsics.ll b/llvm/test/Assembler/auto_upgrade_intrinsics.ll
index 1e4788d49c91d..d43f89eacaffc 100644
--- a/llvm/test/Assembler/auto_upgrade_intrinsics.ll
+++ b/llvm/test/Assembler/auto_upgrade_intrinsics.ll
@@ -234,15 +234,15 @@ define void @test.structured.gep(ptr %ptr, i32 %index) {
; CHECK-LABEL: @test.structured.gep(
; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(i32) %ptr, <1 x i32> zeroinitializer)
%no_index = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(i32) %ptr)
-; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([4 x i32]) %ptr, <1 x i32> splat (i32 5), i32 %index)
+; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([4 x i32]) %ptr, <1 x i32> splat (i32 13), i32 %index)
%array = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([4 x i32]) %ptr, i32 %index)
-; CHECK: %array_with_md = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([4 x i32]) %ptr, <1 x i32> splat (i32 5), i32 %index), !annotation ![[SGEP_MD:[0-9]+]]
+; CHECK: %array_with_md = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([4 x i32]) %ptr, <1 x i32> splat (i32 13), i32 %index), !annotation ![[SGEP_MD:[0-9]+]]
%array_with_md = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([4 x i32]) %ptr, i32 %index), !annotation !0
-; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([0 x i32]) %ptr, <1 x i32> splat (i32 4), i32 %index)
+; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([0 x i32]) %ptr, <1 x i32> splat (i32 12), i32 %index)
%runtime_array = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([0 x i32]) %ptr, i32 %index)
-; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %ptr, <1 x i32> splat (i32 7), i32 1)
+; CHECK: call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %ptr, <1 x i32> splat (i32 15), i32 1)
%struct = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %ptr, i32 1)
-; CHECK: call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.RuntimeArray) %ptr, <2 x i32> <i32 7, i32 4>, i32 0, i32 %index)
+; CHECK: call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.RuntimeArray) %ptr, <2 x i32> <i32 15, i32 12>, i32 0, i32 %index)
%struct_runtime_array = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.RuntimeArray) %ptr, i32 0, i32 %index)
ret void
}
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-array.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-array.ll
index 1b8571edad113..eb52b0c4b25e0 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-array.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-array.ll
@@ -51,14 +51,14 @@ entry:
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_S_5]] Function
%1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S]) %a, <1 x i32> <i32 5>, i64 2)
- %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %1, <1 x i32> <i32 3>, i64 1)
+ %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %1, <1 x i32> <i32 7>, i64 1)
%3 = load i32, ptr %2, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_S]] %[[#]] %[[#ulong_2]]
; CHECK: %[[#B:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#A]] %[[#ulong_1]]
; CHECK: %[[#C:]] = OpLoad %[[#uint]] %[[#B]]
%4 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([5 x %struct.S]) %tmp, <1 x i32> <i32 5>, i64 3)
- %5 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %4, <1 x i32> <i32 3>, i32 0)
+ %5 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %4, <1 x i32> <i32 7>, i32 0)
store i32 %3, ptr %5, align 4
; CHECK: %[[#D:]] = OpInBoundsAccessChain %[[#ptr_S]] %[[#tmp]] %[[#ulong_3]]
; CHECK: %[[#E:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#D]] %[[#uint_0]]
@@ -73,12 +73,12 @@ entry:
%tmp = alloca [5 x %struct.S], align 4
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_S_5]] Function
- %1 = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([3 x %struct.S]) %a, <2 x i32> <i32 5, i32 3>, i64 2, i64 1)
+ %1 = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([3 x %struct.S]) %a, <2 x i32> <i32 5, i32 7>, i64 2, i64 1)
%2 = load i32, ptr %1, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#]] %[[#ulong_2]] %[[#ulong_1]]
; CHECK: %[[#B:]] = OpLoad %[[#uint]] %[[#A]]
- %3 = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([5 x %struct.S]) %tmp, <2 x i32> <i32 5, i32 3>, i64 3, i32 0)
+ %3 = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([5 x %struct.S]) %tmp, <2 x i32> <i32 5, i32 7>, i64 3, i32 0)
store i32 %2, ptr %3, align 4
; CHECK: %[[#C:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#tmp]] %[[#ulong_3]] %[[#uint_0]]
; CHECK: OpStore %[[#C]] %[[#B]]
@@ -93,8 +93,8 @@ entry:
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_S2_5]] Function
%1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([3 x %struct.S2]) %a, <1 x i32> <i32 5>, i64 1)
- %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %1, <1 x i32> <i32 3>, i64 1)
- %3 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %2, <1 x i32> <i32 3>, i64 0)
+ %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %1, <1 x i32> <i32 7>, i64 1)
+ %3 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %2, <1 x i32> <i32 7>, i64 0)
%4 = load i32, ptr %3, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_S2]] %[[#]] %[[#ulong_1]]
; CHECK: %[[#B:]] = OpInBoundsAccessChain %[[#ptr_S]] %[[#A]] %[[#ulong_1]]
@@ -102,8 +102,8 @@ entry:
; CHECK: %[[#D:]] = OpLoad %[[#uint]] %[[#C]]
%5 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([5 x %struct.S2]) %tmp, <1 x i32> <i32 5>, i64 3)
- %6 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %5, <1 x i32> <i32 3>, i32 1)
- %7 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %6, <1 x i32> <i32 3>, i32 0)
+ %6 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S2) %5, <1 x i32> <i32 7>, i32 1)
+ %7 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %6, <1 x i32> <i32 7>, i32 0)
store i32 %4, ptr %7, align 4
; CHECK: %[[#E:]] = OpInBoundsAccessChain %[[#ptr_S2]] %[[#tmp]] %[[#ulong_3]]
; CHECK: %[[#F:]] = OpInBoundsAccessChain %[[#ptr_S]] %[[#E]] %[[#uint_1]]
@@ -119,12 +119,12 @@ entry:
%tmp = alloca [5 x %struct.S2], align 4
; CHECK: %[[#tmp:]] = OpVariable %[[#ptr_arr_S2_5]] Function
- %1 = call ptr (ptr, <3 x i32>, ...) @llvm.structured.gep.p0.v3i32(ptr elementtype([3 x %struct.S2]) %a, <3 x i32> <i32 5, i32 3, i32 3>, i64 1, i64 1, i64 0)
+ %1 = call ptr (ptr, <3 x i32>, ...) @llvm.structured.gep.p0.v3i32(ptr elementtype([3 x %struct.S2]) %a, <3 x i32> <i32 5, i32 7, i32 7>, i64 1, i64 1, i64 0)
%2 = load i32, ptr %1, align 4
; CHECK: %[[#A:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#]] %[[#ulong_1]] %[[#ulong_1]] %[[#ulong_0]]
; CHECK: %[[#B:]] = OpLoad %[[#uint]] %[[#A]]
- %3 = call ptr (ptr, <3 x i32>, ...) @llvm.structured.gep.p0.v3i32(ptr elementtype([5 x %struct.S2]) %tmp, <3 x i32> <i32 5, i32 3, i32 3>, i64 3, i32 1, i32 0)
+ %3 = call ptr (ptr, <3 x i32>, ...) @llvm.structured.gep.p0.v3i32(ptr elementtype([5 x %struct.S2]) %tmp, <3 x i32> <i32 5, i32 7, i32 7>, i64 3, i32 1, i32 0)
store i32 %2, ptr %3, align 4
; CHECK: %[[#C:]] = OpInBoundsAccessChain %[[#ptr_uint]] %[[#tmp]] %[[#ulong_3]] %[[#uint_1]] %[[#uint_0]]
; CHECK: OpStore %[[#C]] %[[#B]]
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-class.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-class.ll
index d0d5b9e825ef7..db0d6403fda22 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-class.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-class.ll
@@ -19,11 +19,11 @@ entry:
; CHECK: %[[#d_var:]] = OpFunctionParameter %[[#ptr_Derived]]
; Access Base part
- %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%class.Derived) %d, <1 x i32> <i32 3>, i32 0)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%class.Derived) %d, <1 x i32> <i32 7>, i32 0)
; CHECK: %[[#ptr_base:]] = OpInBoundsAccessChain %[[#ptr_Base]] %[[#d_var]] %[[#idx_0]]
; Access field in Base
- %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%class.Base) %1, <1 x i32> <i32 3>, i32 0)
+ %2 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%class.Base) %1, <1 x i32> <i32 7>, i32 0)
; CHECK: %[[#ptr_field:]] = OpInBoundsAccessChain %[[#ptr_int]] %[[#ptr_base]] %[[#idx_0]]
store i32 42, ptr %2, align 4
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-missing-fromstart.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-missing-fromstart.ll
new file mode 100644
index 0000000000000..95617ac6693d6
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-missing-fromstart.ll
@@ -0,0 +1,13 @@
+; RUN: not llc -mtriple=spirv64-unknown-unknown %s -o - 2>&1 | FileCheck %s
+
+; CHECK: llvm.structured.gep requires fromstart on every index for SPIR-V lowering
+
+define ptr @missing_fromstart(ptr %p, i32 %idx) {
+entry:
+ %q = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %p, <1 x i32> <i32 1>, i32 %idx)
+ ret ptr %q
+}
+
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #0
+
+attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-nested-struct-array.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-nested-struct-array.ll
index e012fb887fee7..b67d54c86a285 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-nested-struct-array.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-nested-struct-array.ll
@@ -19,7 +19,7 @@ entry:
%0 = call token @llvm.experimental.convergence.entry()
; CHECK: %[[#obj_var:]] = OpFunctionParameter %[[#ptr_Outer]]
- %1 = call ptr (ptr, <4 x i32>, ...) @llvm.structured.gep.p0.v4i32(ptr elementtype(%struct.Outer) %obj, <4 x i32> <i32 3, i32 5, i32 3, i32 5>, i32 0, i32 2, i32 1, i32 1)
+ %1 = call ptr (ptr, <4 x i32>, ...) @llvm.structured.gep.p0.v4i32(ptr elementtype(%struct.Outer) %obj, <4 x i32> <i32 7, i32 5, i32 7, i32 5>, i32 0, i32 2, i32 1, i32 1)
; CHECK: %[[#ptr_elem:]] = OpInBoundsAccessChain %[[#ptr_float]] %[[#obj_var]] %[[#]] %[[#]] %[[#]] %[[#]]
%2 = load float, ptr %1, align 4
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-runtime-array.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-runtime-array.ll
index 9a5583a9b41e8..0897caf19967c 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-runtime-array.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-runtime-array.ll
@@ -16,7 +16,7 @@ define spir_func i32 @runtime_array_access(i32 %idx) convergent {
entry:
%0 = call token @llvm.experimental.convergence.entry()
- %1 = call ptr addrspace(11) (ptr addrspace(11), <2 x i32>, ...) @llvm.structured.gep.p11.v2i32(ptr addrspace(11) elementtype(%struct.RuntimeArray) @buffer, <2 x i32> <i32 3, i32 4>, i32 0, i32 %idx)
+ %1 = call ptr addrspace(11) (ptr addrspace(11), <2 x i32>, ...) @llvm.structured.gep.p11.v2i32(ptr addrspace(11) elementtype(%struct.RuntimeArray) @buffer, <2 x i32> <i32 7, i32 4>, i32 0, i32 %idx)
; CHECK: %[[#ptr_elem:]] = OpAccessChain %[[#ptr_sb_int]] %[[#buffer]] %[[#]] %[[#]]
%2 = load i32, ptr addrspace(11) %1, align 4
diff --git a/llvm/test/CodeGen/SPIRV/pointers/sgep-struct.ll b/llvm/test/CodeGen/SPIRV/pointers/sgep-struct.ll
index 347585147e609..322c9fa5239bc 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/sgep-struct.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/sgep-struct.ll
@@ -17,7 +17,7 @@ entry:
; CHECK: %[[#s_var:]] = OpFunctionParameter %[[#ptr_struct]]
; CHECK: %[[#out_var:]] = OpFunctionParameter %[[#ptr_float]]
- %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.Simple) %s, <1 x i32> <i32 3>, i32 1)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.Simple) %s, <1 x i32> <i32 7>, i32 1)
; CHECK: %[[#ptr_field:]] = OpInBoundsAccessChain %[[#ptr_float]] %[[#s_var]] %[[#idx_1]]
%2 = load float, ptr %1, align 4
diff --git a/llvm/test/Transforms/InstSimplify/structured-gep.ll b/llvm/test/Transforms/InstSimplify/structured-gep.ll
index f5d7b7ee88493..3e0467f813689 100644
--- a/llvm/test/Transforms/InstSimplify/structured-gep.ll
+++ b/llvm/test/Transforms/InstSimplify/structured-gep.ll
@@ -51,28 +51,28 @@ define i32 @zero_index_with_load(ptr %p) {
; GEP with a zero index can be simplified, but SGEP cannot.
define ptr @zero_index_struct(ptr %p) {
; CHECK-LABEL: @zero_index_struct(ptr %p
-; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> splat (i32 3), i32 0)
+; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> splat (i32 7), i32 0)
; CHECK-NEXT: ret ptr [[SGEP]]
;
- %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> <i32 3>, i32 0)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> <i32 7>, i32 0)
ret ptr %sgep
}
define ptr @one_index_struct(ptr %p) {
; CHECK-LABEL: @one_index_struct(ptr %p
-; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> splat (i32 3), i32 1)
+; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> splat (i32 7), i32 1)
; CHECK-NEXT: ret ptr [[SGEP]]
;
- %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> <i32 3>, i32 1)
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%struct.S) %p, <1 x i32> <i32 7>, i32 1)
ret ptr %sgep
}
define ptr @multi_index_nested(ptr %p) {
; CHECK-LABEL: @multi_index_nested(
-; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.Nested) %p, <2 x i32> splat (i32 3), i32 0, i32 0)
+; CHECK-NEXT: [[SGEP:%.*]] = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.Nested) %p, <2 x i32> splat (i32 7), i32 0, i32 0)
; CHECK-NEXT: ret ptr [[SGEP]]
;
- %sgep = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.Nested) %p, <2 x i32> <i32 3, i32 3>, i32 0, i32 0)
+ %sgep = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%struct.Nested) %p, <2 x i32> <i32 7, i32 7>, i32 0, i32 0)
ret ptr %sgep
}
diff --git a/llvm/test/Transforms/LSROA/array.ll b/llvm/test/Transforms/LSROA/array.ll
index d488d90a38424..654353fd26524 100644
--- a/llvm/test/Transforms/LSROA/array.ll
+++ b/llvm/test/Transforms/LSROA/array.ll
@@ -4,20 +4,21 @@
declare void @llvm.lifetime.start.p0(ptr nocapture)
declare void @llvm.lifetime.end.p0(ptr nocapture)
declare ptr @llvm.structured.alloca.p0()
-declare ptr @llvm.structured.gep.p0(ptr, ...)
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...)
+declare ptr @llvm.structured.gep.p0.v2i32(ptr, <2 x i32>, ...)
define i32 @test_simple_array() {
; CHECK-LABEL: define i32 @test_simple_array() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP:%.*]] = call elementtype([10 x i32]) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[PTR:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) [[TMP]], i32 0)
+; CHECK-NEXT: [[PTR:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) [[TMP]], <1 x i32> splat (i32 5), i32 0)
; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[PTR]], align 4
; CHECK-NEXT: ret i32 [[RES]]
;
entry:
%tmp = call elementtype([10 x i32]) ptr @llvm.structured.alloca.p0()
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %tmp, i32 0)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %tmp, <1 x i32> splat (i32 5), i32 0)
store i32 0, ptr %ptr
%res = load i32, ptr %ptr
ret i32 %res
@@ -28,14 +29,14 @@ define i32 @test_simple_array_dynamic_index(i32 %i) {
; CHECK-SAME: i32 [[I:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP:%.*]] = call elementtype([10 x i32]) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[PTR:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) [[TMP]], i32 [[I]])
+; CHECK-NEXT: [[PTR:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) [[TMP]], <1 x i32> splat (i32 5), i32 [[I]])
; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[PTR]], align 4
; CHECK-NEXT: ret i32 [[RES]]
;
entry:
%tmp = call elementtype([10 x i32]) ptr @llvm.structured.alloca.p0()
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %tmp, i32 %i)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) %tmp, <1 x i32> splat (i32 5), i32 %i)
store i32 0, ptr %ptr
%res = load i32, ptr %ptr
ret i32 %res
@@ -46,14 +47,14 @@ define i32 @test_simple_array_dynamic_index_in_child(i32 %i) {
; CHECK-SAME: i32 [[I:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call elementtype([10 x i32]) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) [[TMP0]], i32 [[I]])
+; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) [[TMP0]], <1 x i32> splat (i32 5), i32 [[I]])
; CHECK-NEXT: store i32 0, ptr [[PTR1]], align 4
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[PTR1]], align 4
; CHECK-NEXT: ret i32 [[RES]]
;
entry:
%tmp = call elementtype({ i32, [10 x i32]}) ptr @llvm.structured.alloca.p0()
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, [10 x i32] }) %tmp, i32 1, i32 %i)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype({ i32, [10 x i32] }) %tmp, <2 x i32> <i32 7, i32 5>, i32 1, i32 %i)
store i32 0, ptr %ptr
%res = load i32, ptr %ptr
ret i32 %res
@@ -64,14 +65,14 @@ define i32 @test_simple_array_dynamic_index_only_child(i32 %i) {
; CHECK-SAME: i32 [[I:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call elementtype([10 x i32]) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) [[TMP0]], i32 [[I]])
+; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype([10 x i32]) [[TMP0]], <1 x i32> splat (i32 5), i32 [[I]])
; CHECK-NEXT: store i32 0, ptr [[PTR1]], align 4
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[PTR1]], align 4
; CHECK-NEXT: ret i32 [[RES]]
;
entry:
%tmp = call elementtype({[10 x i32]}) ptr @llvm.structured.alloca.p0()
- %ptr = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({[10 x i32]}) %tmp, i32 0, i32 %i)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype({[10 x i32]}) %tmp, <2 x i32> <i32 7, i32 5>, i32 0, i32 %i)
store i32 0, ptr %ptr
%res = load i32, ptr %ptr
ret i32 %res
diff --git a/llvm/test/Transforms/LSROA/basictest.ll b/llvm/test/Transforms/LSROA/basictest.ll
index 2042590b159a4..b5ca39bb3e431 100644
--- a/llvm/test/Transforms/LSROA/basictest.ll
+++ b/llvm/test/Transforms/LSROA/basictest.ll
@@ -4,7 +4,7 @@
declare void @llvm.lifetime.start.p0(ptr nocapture)
declare void @llvm.lifetime.end.p0(ptr nocapture)
declare ptr @llvm.structured.alloca.p0()
-declare ptr @llvm.structured.gep.p0(ptr, ...)
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...)
define i32 @test_simple_scalar() {
; CHECK-LABEL: define i32 @test_simple_scalar() {
@@ -43,8 +43,8 @@ define i32 @test_simple_struct_entire_write_read() {
;
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
- %ptr1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 1)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
+ %ptr1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 1)
call void @llvm.lifetime.start.p0(ptr %tmp)
store i32 0, ptr %ptr0
@@ -72,8 +72,8 @@ define i32 @test_simple_struct_aliasing() {
;
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
- %ptr1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
+ %ptr1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
call void @llvm.lifetime.start.p0(ptr %tmp)
store i32 0, ptr %ptr0
@@ -99,7 +99,7 @@ define i32 @test_simple_struct_partial_write_read() {
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
call void @llvm.lifetime.start.p0(ptr %tmp)
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
store i32 0, ptr %ptr0
%a = load i32, ptr %ptr0
call void @llvm.lifetime.end.p0(ptr %tmp)
@@ -129,8 +129,8 @@ define i32 @test_struct_use_across_lifetime() {
;
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
- %ptr1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 1)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
+ %ptr1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 1)
call void @llvm.lifetime.start.p0(ptr %tmp)
store i32 0, ptr %ptr0
diff --git a/llvm/test/Transforms/LSROA/escaping.ll b/llvm/test/Transforms/LSROA/escaping.ll
index 3f90004d3649f..788d7b4203a35 100644
--- a/llvm/test/Transforms/LSROA/escaping.ll
+++ b/llvm/test/Transforms/LSROA/escaping.ll
@@ -4,7 +4,7 @@
declare void @llvm.lifetime.start.p0(ptr nocapture)
declare void @llvm.lifetime.end.p0(ptr nocapture)
declare ptr @llvm.structured.alloca.p0()
-declare ptr @llvm.structured.gep.p0(ptr, ...)
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...)
declare void @foo(ptr)
; The alloca ptr is escaping, we cannot know if splitting is safe.
@@ -12,8 +12,8 @@ define i32 @test_simple_escape() {
; CHECK-LABEL: define i32 @test_simple_escape() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP:%.*]] = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[PTR0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP]], i32 0)
-; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP]], i32 1)
+; CHECK-NEXT: [[PTR0:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP]], <1 x i32> splat (i32 7), i32 0)
+; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP]], <1 x i32> splat (i32 7), i32 1)
; CHECK-NEXT: store i32 0, ptr [[PTR0]], align 4
; CHECK-NEXT: store i32 1, ptr [[PTR1]], align 4
; CHECK-NEXT: call void @foo(ptr [[TMP]])
@@ -25,8 +25,8 @@ define i32 @test_simple_escape() {
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
- %ptr1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 1)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
+ %ptr1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 1)
store i32 0, ptr %ptr0
store i32 1, ptr %ptr1
@@ -43,8 +43,8 @@ define i32 @test_derived_escape() {
; CHECK-LABEL: define i32 @test_derived_escape() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP:%.*]] = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[PTR0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP]], i32 0)
-; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP]], i32 1)
+; CHECK-NEXT: [[PTR0:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP]], <1 x i32> splat (i32 7), i32 0)
+; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP]], <1 x i32> splat (i32 7), i32 1)
; CHECK-NEXT: store i32 0, ptr [[PTR0]], align 4
; CHECK-NEXT: store i32 1, ptr [[PTR1]], align 4
; CHECK-NEXT: call void @foo(ptr [[PTR0]])
@@ -56,8 +56,8 @@ define i32 @test_derived_escape() {
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
- %ptr1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 1)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
+ %ptr1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 1)
store i32 0, ptr %ptr0
store i32 1, ptr %ptr1
@@ -75,7 +75,7 @@ define i32 @test_normal_gep() {
; CHECK-LABEL: define i32 @test_normal_gep() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP:%.*]] = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[PTR0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP]], i32 0)
+; CHECK-NEXT: [[PTR0:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP]], <1 x i32> splat (i32 7), i32 0)
; CHECK-NEXT: [[PTR1:%.*]] = getelementptr i8, ptr [[PTR0]], i32 4
; CHECK-NEXT: store i32 0, ptr [[PTR0]], align 4
; CHECK-NEXT: store i32 1, ptr [[PTR1]], align 4
@@ -87,7 +87,7 @@ define i32 @test_normal_gep() {
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
%ptr1 = getelementptr i8, ptr %ptr0, i32 4
store i32 0, ptr %ptr0
diff --git a/llvm/test/Transforms/LSROA/nesting.ll b/llvm/test/Transforms/LSROA/nesting.ll
index 5291cfe4ebee0..8063196325588 100644
--- a/llvm/test/Transforms/LSROA/nesting.ll
+++ b/llvm/test/Transforms/LSROA/nesting.ll
@@ -4,7 +4,8 @@
declare void @llvm.lifetime.start.p0(ptr nocapture)
declare void @llvm.lifetime.end.p0(ptr nocapture)
declare ptr @llvm.structured.alloca.p0()
-declare ptr @llvm.structured.gep.p0(ptr, ...)
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...)
+declare ptr @llvm.structured.gep.p0.v2i32(ptr, <2 x i32>, ...)
%S = type { i32, { i32, i32 } }
@@ -15,7 +16,7 @@ define i32 @test_nested_struct() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call elementtype(i32) ptr @llvm.structured.alloca.p0()
; CHECK-NEXT: [[TMP1:%.*]] = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[TMP2:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP1]], i32 0)
+; CHECK-NEXT: [[TMP2:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP1]], <1 x i32> splat (i32 7), i32 0)
; CHECK-NEXT: store i32 0, ptr [[TMP0]], align 4
; CHECK-NEXT: store i32 1, ptr [[TMP2]], align 4
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[TMP0]], align 4
@@ -25,8 +26,8 @@ define i32 @test_nested_struct() {
;
entry:
%tmp = call elementtype(%S) ptr @llvm.structured.alloca.p0()
- %0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%S) %tmp, i32 0)
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%S) %tmp, i32 1, i32 0)
+ %0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %tmp, <1 x i32> splat (i32 7), i32 0)
+ %1 = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%S) %tmp, <2 x i32> splat (i32 7), i32 1, i32 0)
store i32 0, ptr %0
diff --git a/llvm/test/Transforms/LSROA/normal-gep.ll b/llvm/test/Transforms/LSROA/normal-gep.ll
index 4358d9790c2bd..6b424afbb6a24 100644
--- a/llvm/test/Transforms/LSROA/normal-gep.ll
+++ b/llvm/test/Transforms/LSROA/normal-gep.ll
@@ -6,7 +6,7 @@ define i32 @test_normal_gep() {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP:%.*]] = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[TMP]], i32 0
-; CHECK-NEXT: [[TMP1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP]], i32 1)
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP]], <1 x i32> splat (i32 7), i32 1)
; CHECK-NEXT: store i32 0, ptr [[TMP0]], align 4
; CHECK-NEXT: store i32 1, ptr [[TMP1]], align 4
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[TMP0]], align 4
@@ -17,7 +17,7 @@ define i32 @test_normal_gep() {
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
%0 = getelementptr i8, ptr %tmp, i32 0
- %1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 1)
+ %1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 1)
store i32 0, ptr %0
store i32 1, ptr %1
@@ -27,3 +27,6 @@ entry:
%c = add i32 %a, %b
ret i32 %c
}
+
+declare ptr @llvm.structured.alloca.p0()
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...)
diff --git a/llvm/test/Transforms/LSROA/phi.ll b/llvm/test/Transforms/LSROA/phi.ll
index a6a89fbf54f97..6b47810600679 100644
--- a/llvm/test/Transforms/LSROA/phi.ll
+++ b/llvm/test/Transforms/LSROA/phi.ll
@@ -7,8 +7,8 @@ define i32 @test_partial_use_phi_node(i1 %cond) {
; CHECK-SAME: i1 [[COND:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP1:%.*]] = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[TMP0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP1]], i32 0)
-; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP1]], i32 1)
+; CHECK-NEXT: [[TMP0:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP1]], <1 x i32> splat (i32 7), i32 0)
+; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP1]], <1 x i32> splat (i32 7), i32 1)
; CHECK-NEXT: br i1 [[COND]], label %[[L1:.*]], label %[[L2:.*]]
; CHECK: [[L1]]:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[TMP1]])
@@ -28,8 +28,8 @@ define i32 @test_partial_use_phi_node(i1 %cond) {
;
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
- %ptr1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 1)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
+ %ptr1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 1)
br i1 %cond, label %l1, label %l2
l1:
@@ -52,3 +52,7 @@ exit:
ret i32 %a
}
+declare void @llvm.lifetime.start.p0(ptr nocapture)
+declare void @llvm.lifetime.end.p0(ptr nocapture)
+declare ptr @llvm.structured.alloca.p0()
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...)
diff --git a/llvm/test/Transforms/LSROA/select.ll b/llvm/test/Transforms/LSROA/select.ll
index 22503710463b5..e260d7b2bcad0 100644
--- a/llvm/test/Transforms/LSROA/select.ll
+++ b/llvm/test/Transforms/LSROA/select.ll
@@ -7,8 +7,8 @@ define i32 @test_select_basic(i1 %cond) {
; CHECK-SAME: i1 [[COND:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP:%.*]] = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
-; CHECK-NEXT: [[PTR0:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP]], i32 0)
-; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) [[TMP]], i32 1)
+; CHECK-NEXT: [[PTR0:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP]], <1 x i32> splat (i32 7), i32 0)
+; CHECK-NEXT: [[PTR1:%.*]] = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) [[TMP]], <1 x i32> splat (i32 7), i32 1)
; CHECK-NEXT: store i32 0, ptr [[PTR0]], align 4
; CHECK-NEXT: store i32 1, ptr [[PTR1]], align 4
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[COND]], ptr [[PTR0]], ptr [[PTR1]]
@@ -17,8 +17,8 @@ define i32 @test_select_basic(i1 %cond) {
;
entry:
%tmp = call elementtype({ i32, i32 }) ptr @llvm.structured.alloca.p0()
- %ptr0 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 0)
- %ptr1 = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype({ i32, i32 }) %tmp, i32 1)
+ %ptr0 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 0)
+ %ptr1 = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %tmp, <1 x i32> splat (i32 7), i32 1)
store i32 0, ptr %ptr0
store i32 1, ptr %ptr1
@@ -27,3 +27,6 @@ entry:
%a = load i32, ptr %ptr
ret i32 %a
}
+
+declare ptr @llvm.structured.alloca.p0()
+declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...)
diff --git a/llvm/test/Verifier/amdgpu-stridemark-structured-gep.ll b/llvm/test/Verifier/amdgpu-stridemark-structured-gep.ll
index 707efbac765e6..24968c9bf2da3 100644
--- a/llvm/test/Verifier/amdgpu-stridemark-structured-gep.ll
+++ b/llvm/test/Verifier/amdgpu-stridemark-structured-gep.ll
@@ -3,15 +3,22 @@
define void @dynamic_index_then_gep_offset(ptr addrspace(9) %p, i32 %index,
i32 %offset) {
entry:
- %q1 = call ptr addrspace(9) (ptr addrspace(9), <1 x i32>, ...) @llvm.structured.gep.p9.v1i32(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %p, <1 x i32> <i32 4>, i32 %index)
+ %q1 = call ptr addrspace(9) (ptr addrspace(9), <2 x i32>, ...) @llvm.structured.gep.p9.v2i32(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %p, <2 x i32> <i32 4, i32 4>, i32 %index, i32 0)
%q = getelementptr i8, ptr addrspace(9) %q1, i32 %offset
ret void
}
+define void @multiple_stridemark_indices(ptr addrspace(9) %p, i32 %index,
+ i32 %offset) {
+entry:
+ %q = call ptr addrspace(9) (ptr addrspace(9), <3 x i32>, ...) @llvm.structured.gep.p9.v3i32(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %p, <3 x i32> <i32 4, i32 4, i32 4>, i32 %index, i32 %offset, i32 0)
+ ret void
+}
+
define void @known_bounds_and_stride(ptr addrspace(9) %p, i32 %index,
i32 %offset) {
entry:
- %q1 = call ptr addrspace(9) (ptr addrspace(9), <1 x i32>, ...) @llvm.structured.gep.p9.v1i32(ptr addrspace(9) elementtype([256 x target("amdgpu.stridemark", 16)]) %p, <1 x i32> <i32 5>, i32 %index)
+ %q1 = call ptr addrspace(9) (ptr addrspace(9), <2 x i32>, ...) @llvm.structured.gep.p9.v2i32(ptr addrspace(9) elementtype([256 x target("amdgpu.stridemark", 16)]) %p, <2 x i32> <i32 5, i32 4>, i32 %index, i32 0)
%q = getelementptr i8, ptr addrspace(9) %q1, i32 %offset
ret void
}
diff --git a/llvm/test/Verifier/logical-pointer-notrequired.ll b/llvm/test/Verifier/logical-pointer-notrequired.ll
index fa426cc0745e8..3b3d365f2d8df 100644
--- a/llvm/test/Verifier/logical-pointer-notrequired.ll
+++ b/llvm/test/Verifier/logical-pointer-notrequired.ll
@@ -10,7 +10,7 @@ entry:
define void @structured_gep(ptr %src, i32 %index) {
entry:
- %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 3>, i32 %index, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 7>, i32 %index, i32 1)
ret void
}
diff --git a/llvm/test/Verifier/logical-pointer-required.ll b/llvm/test/Verifier/logical-pointer-required.ll
index b7fbda268cc9c..ca2d1a2ee09a1 100644
--- a/llvm/test/Verifier/logical-pointer-required.ll
+++ b/llvm/test/Verifier/logical-pointer-required.ll
@@ -4,7 +4,7 @@
define void @structured_gep_allowed(ptr %src, i32 %index) {
entry:
- %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 3>, i32 %index, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 7>, i32 %index, i32 1)
ret void
}
diff --git a/llvm/test/Verifier/structured-gep-indices-bad.ll b/llvm/test/Verifier/structured-gep-indices-bad.ll
index b2c73c4ad6691..ad32474955eec 100644
--- a/llvm/test/Verifier/structured-gep-indices-bad.ll
+++ b/llvm/test/Verifier/structured-gep-indices-bad.ll
@@ -5,7 +5,7 @@
define void @too_many_indices(ptr %src) {
entry:
; CHECK: Reached a non-composite type with more indices to process
- %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%S) %src, <2 x i32> <i32 3, i32 4>, i32 0, i32 0)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype(%S) %src, <2 x i32> <i32 7, i32 4>, i32 0, i32 0)
ret void
}
@@ -37,16 +37,16 @@ entry:
ret void
}
-define void @amdgpu_stridemark_offset_in_structured_gep(ptr addrspace(9) %src) {
+define void @non_sgep_indexable_target_ext_offset_in_structured_gep(ptr addrspace(9) %src) {
entry:
; CHECK: Reached a non-composite type with more indices to process
- %ptr = call ptr addrspace(9) (ptr addrspace(9), <2 x i32>, ...) @llvm.structured.gep.p9.v2i32(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %src, <2 x i32> <i32 4, i32 4>, i32 0, i32 0)
+ %ptr = call ptr addrspace(9) (ptr addrspace(9), <2 x i32>, ...) @llvm.structured.gep.p9.v2i32(ptr addrspace(9) elementtype([0 x target("spirv.Sampler")]) %src, <2 x i32> <i32 4, i32 4>, i32 0, i32 0)
ret void
}
define void @struct_access_missing_flags(ptr %src) {
entry:
-; CHECK: Indexing into a struct requires inbounds and nneg flags
+; CHECK: Indexing into a struct requires inbounds, nneg, and fromstart flags
%ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> zeroinitializer, i32 0)
ret void
}
diff --git a/llvm/test/Verifier/structured-gep-indices.ll b/llvm/test/Verifier/structured-gep-indices.ll
index cd1715003cc4b..b1c463aefdc52 100644
--- a/llvm/test/Verifier/structured-gep-indices.ll
+++ b/llvm/test/Verifier/structured-gep-indices.ll
@@ -4,25 +4,25 @@
define void @runtime_array_nested_access(ptr %src, i32 %index) {
entry:
- %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 3>, i32 %index, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([0 x %S]) %src, <2 x i32> <i32 4, i32 7>, i32 %index, i32 1)
ret void
}
define void @normal_array_access(ptr %src, i32 %index) {
entry:
- %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([2 x %S]) %src, <2 x i32> <i32 5, i32 3>, i32 %index, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([2 x %S]) %src, <2 x i32> <i32 5, i32 7>, i32 %index, i32 1)
ret void
}
define void @normal_array_constant_index(ptr %src) {
entry:
- %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([2 x %S]) %src, <2 x i32> <i32 5, i32 3>, i32 1, i32 1)
+ %ptr = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([2 x %S]) %src, <2 x i32> <i32 5, i32 7>, i32 1, i32 1)
ret void
}
define void @struct_access(ptr %src) {
entry:
- %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> <i32 3>, i32 0)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> <i32 7>, i32 0)
ret void
}
@@ -64,6 +64,6 @@ entry:
define void @struct_index_with_unknown_bits(ptr %src) {
entry:
- %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> <i32 65539>, i32 1)
+ %ptr = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype(%S) %src, <1 x i32> <i32 65543>, i32 1)
ret void
}
diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp
index a1f22bbac02a1..1aad0052d07a2 100644
--- a/llvm/unittests/IR/InstructionsTest.cpp
+++ b/llvm/unittests/IR/InstructionsTest.cpp
@@ -21,6 +21,7 @@
#include "llvm/IR/FPEnv.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
@@ -873,6 +874,130 @@ TEST_F(ModuleWithFunctionTest, DropPoisonGeneratingFlags) {
GI->dropPoisonGeneratingFlags();
ASSERT_FALSE(GI->isInBounds());
}
+
+ {
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ declare ptr @llvm.structured.gep.p0.v2i32(ptr, <2 x i32>, ...) #0
+
+ define ptr @sgep(ptr %p, i32 %i) {
+ entry:
+ %sgep = call ptr (ptr, <2 x i32>, ...) @llvm.structured.gep.p0.v2i32(ptr elementtype([10 x { i32, i32 }]) %p, <2 x i32> <i32 13, i32 7>, i32 %i, i32 1)
+ ret ptr %sgep
+ }
+
+ attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+ )");
+ ASSERT_TRUE(M);
+ auto &Inst = *M->getFunction("sgep")->getEntryBlock().begin();
+ auto *SGEP = dyn_cast<StructuredGEPInst>(&Inst);
+ ASSERT_NE(SGEP, nullptr);
+
+ EXPECT_TRUE(isa<ArrayType>(SGEP->getTypeAtIndexDepth(0)));
+ EXPECT_TRUE(isa<StructType>(SGEP->getTypeAtIndexDepth(1)));
+ EXPECT_TRUE(SGEP->getTypeAtIndexDepth(2)->isIntegerTy(32));
+ EXPECT_EQ(SGEP->getTypeAtIndexDepth(3), nullptr);
+
+ ASSERT_TRUE(SGEP->isIndexUnsigned(0));
+ ASSERT_TRUE(SGEP->isIndexInBounds(0));
+ ASSERT_TRUE(SGEP->isIndexFromStart(0));
+ ASSERT_TRUE(SGEP->isIndexInBounds(1));
+ ASSERT_TRUE(SGEP->isIndexNNeg(1));
+ ASSERT_TRUE(SGEP->isIndexFromStart(1));
+ ASSERT_TRUE(SGEP->hasPoisonGeneratingFlags());
+
+ SGEP->dropPoisonGeneratingFlags();
+
+ ASSERT_FALSE(SGEP->hasPoisonGeneratingFlags());
+ ASSERT_TRUE(SGEP->isIndexUnsigned(0));
+ ASSERT_FALSE(SGEP->isIndexInBounds(0));
+ ASSERT_FALSE(SGEP->isIndexFromStart(0));
+ ASSERT_FALSE(SGEP->isIndexUnsigned(1));
+ ASSERT_TRUE(SGEP->isIndexInBounds(1));
+ ASSERT_TRUE(SGEP->isIndexNNeg(1));
+ ASSERT_TRUE(SGEP->isIndexFromStart(1));
+ }
+
+ {
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #0
+
+ define ptr @sgep(ptr %p) {
+ entry:
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %p, <1 x i32> <i32 7>, i32 1)
+ ret ptr %sgep
+ }
+
+ attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+ )");
+ ASSERT_TRUE(M);
+ auto &Inst = *M->getFunction("sgep")->getEntryBlock().begin();
+ auto *SGEP = dyn_cast<StructuredGEPInst>(&Inst);
+ ASSERT_NE(SGEP, nullptr);
+
+ ASSERT_FALSE(SGEP->hasPoisonGeneratingFlags());
+
+ SGEP->dropPoisonGeneratingFlags();
+
+ ASSERT_FALSE(SGEP->hasPoisonGeneratingFlags());
+ ASSERT_TRUE(SGEP->isIndexInBounds(0));
+ ASSERT_TRUE(SGEP->isIndexNNeg(0));
+ ASSERT_TRUE(SGEP->isIndexFromStart(0));
+ }
+}
+
+TEST_F(ModuleWithFunctionTest, StructuredGEPTargetExtMultipleIndices) {
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ declare ptr addrspace(9) @llvm.structured.gep.p9.v4i32(ptr addrspace(9), <4 x i32>, ...) #0
+
+ define ptr addrspace(9) @sgep(ptr addrspace(9) %p, i32 %i, i32 %j) {
+ entry:
+ %sgep = call ptr addrspace(9) (ptr addrspace(9), <4 x i32>, ...) @llvm.structured.gep.p9.v4i32(ptr addrspace(9) elementtype([0 x target("amdgpu.stridemark")]) %p, <4 x i32> <i32 4, i32 4, i32 4, i32 4>, i32 %i, i32 %j, i32 0, i32 1)
+ ret ptr addrspace(9) %sgep
+ }
+
+ attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+ )");
+ ASSERT_TRUE(M);
+ auto &Inst = *M->getFunction("sgep")->getEntryBlock().begin();
+ auto *SGEP = dyn_cast<StructuredGEPInst>(&Inst);
+ ASSERT_NE(SGEP, nullptr);
+
+ EXPECT_TRUE(isa<ArrayType>(SGEP->getTypeAtIndexDepth(0)));
+ EXPECT_EQ(SGEP->getTypeAtIndexDepth(5), nullptr);
+
+ auto *TET = dyn_cast<TargetExtType>(SGEP->getResultElementType());
+ ASSERT_NE(TET, nullptr);
+ EXPECT_EQ(TET->getName(), "amdgpu.stridemark");
+ for (unsigned Depth = 1; Depth <= SGEP->getNumIndices(); ++Depth)
+ EXPECT_EQ(SGEP->getTypeAtIndexDepth(Depth), TET);
+}
+
+TEST_F(ModuleWithFunctionTest, StructuredGEPZeroIndexFlagValues) {
+ std::unique_ptr<Module> M = parseIR(Ctx, R"(
+ declare ptr @llvm.structured.gep.p0.v1i32(ptr, <1 x i32>, ...) #0
+
+ define ptr @sgep(ptr %p) {
+ entry:
+ %sgep = call ptr (ptr, <1 x i32>, ...) @llvm.structured.gep.p0.v1i32(ptr elementtype({ i32, i32 }) %p, <1 x i32> <i32 0>)
+ ret ptr %sgep
+ }
+
+ attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+ )");
+ ASSERT_TRUE(M);
+ auto &Inst = *M->getFunction("sgep")->getEntryBlock().begin();
+ auto *SGEP = dyn_cast<StructuredGEPInst>(&Inst);
+ ASSERT_NE(SGEP, nullptr);
+
+ EXPECT_EQ(SGEP->getNumIndices(), 0u);
+ SmallVector<StructuredGEPFlags, 4> FlagValues = SGEP->getFlagValues();
+ ASSERT_EQ(FlagValues.size(), 1u);
+ EXPECT_EQ(FlagValues[0].getRaw(), 0u);
+ SmallVector<StructuredGEPFlags, 4> RequiredFlagValues =
+ SGEP->getRequiredFlagValues();
+ ASSERT_EQ(RequiredFlagValues.size(), FlagValues.size());
+ EXPECT_EQ(RequiredFlagValues[0], StructuredGEPFlags::none());
+ EXPECT_EQ(SGEP->getRequiredIndexFlags(0), StructuredGEPFlags::none());
}
TEST(InstructionsTest, GEPIndices) {
More information about the cfe-commits
mailing list