llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-hlsl Author: Nathan Gauër (Keenuts) <details> <summary>Changes</summary> StructuredGEP is a new LLVM intrinsic which will allow to emit proper logical SPIR-V or DXIL. To properly stage this change going across FE, BE and optimizations, this commits adds a new flag: - `-fexperimental-emit-sgep` When used, this flag will allow compatible frontends to emit the new instructions. This will also allow us to migrate tests bit by bit, adding the flag to each migrated test as we make progress on the implementation. Once the frontend migration complete, the flag will remain, and work on the backend will start. Compatible backends like SPIR-V will first allow both instructions, but then, depending on a target bit similar to `requiresStructuredCFG`, will declare that they require the SGEP instruction and will start enforcing it. Once the whole chain completed, the flag will be defaulted to true and removed, finishing the migration. --- Full diff: https://github.com/llvm/llvm-project/pull/177332.diff 8 Files Affected: - (modified) clang/include/clang/Basic/LangOptions.def (+1) - (modified) clang/include/clang/Options/Options.td (+7) - (modified) clang/lib/CodeGen/CGExpr.cpp (+31) - (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+29-7) - (added) clang/test/CodeGenHLSL/sgep/array_load.hlsl (+52) - (added) clang/test/CodeGenHLSL/sgep/array_store.hlsl (+55) - (added) clang/test/CodeGenHLSL/sgep/load_global.hlsl (+45) - (added) clang/test/CodeGenHLSL/sgep/object_method.hlsl (+30) ``````````diff diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 36fec24638363..7eb88dc693504 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -248,6 +248,7 @@ LANGOPT(HLSLStrictAvailability, 1, 0, NotCompatible, "Strict availability diagnostic mode for HLSL built-in functions.") LANGOPT(HLSLSpvUseUnknownImageFormat, 1, 0, NotCompatible, "For storage images and texel buffers, sets the default format to 'Unknown' when not specified via the `vk::image_format` attribute. If this option is not used, the format is inferred from the resource's data type.") LANGOPT(HLSLSpvEnableMaximalReconvergence, 1, 0, NotCompatible, "Enables the MaximallyReconvergesKHR execution mode for this module. This ensures that control flow reconverges at well-defined merge points as defined by the Vulkan spec.") +LANGOPT(EmitStructuredGEP, 1, 0, NotCompatible, "Emit structured_gep instructions instead of GEP") LANGOPT(CUDAIsDevice , 1, 0, NotCompatible, "compiling for CUDA device") LANGOPT(CUDAHostDeviceConstexpr, 1, 1, NotCompatible, "treating unattributed constexpr functions as __host__ __device__") diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 188739e72434a..2d2a61bcf2048 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -9806,6 +9806,13 @@ def fhlsl_spv_enable_maximal_reconvergence "well-defined merge points as defined by the Vulkan spec.">, MarshallingInfoFlag<LangOpts<"HLSLSpvEnableMaximalReconvergence">>; +def fexperimental_emit_sgep + : Flag<["-"], "fexperimental-emit-sgep">, + Visibility<[CC1Option, DXCOption]>, + HelpText<"Emit structured GEP intrinsic instead of GEP instructions " + "(experimental).">, + MarshallingInfoFlag<LangOpts<"EmitStructuredGEP">>; + def no_wasm_opt : Flag<["--"], "no-wasm-opt">, Group<m_Group>, HelpText<"Disable the wasm-opt optimizer">, diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 2a5ae8da72512..8a74da7eb9a2e 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4497,6 +4497,17 @@ Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E, if (!E->getType()->isVariableArrayType()) { assert(isa<llvm::ArrayType>(Addr.getElementType()) && "Expected pointer to array"); + + if (getLangOpts().HLSL && getLangOpts().EmitStructuredGEP) { + llvm::Value *Ptr = Addr.emitRawPointer(*this); + if (auto *C = dyn_cast<llvm::Constant>(Ptr)) + return Address(C, Addr.getElementType(), Addr.getAlignment(), + Addr.isKnownNonNull()); + return Address( + Builder.CreateStructuredGEP(NewTy, Addr.getBasePointer(), {}), + Addr.getElementType(), Addr.getAlignment(), Addr.isKnownNonNull()); + } + Addr = Builder.CreateConstArrayGEP(Addr, 0, "arraydecay"); } @@ -4536,6 +4547,9 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF, bool signedIndices, SourceLocation loc, const llvm::Twine &name = "arrayidx") { + if (CGF.getLangOpts().HLSL && inbounds && CGF.getLangOpts().EmitStructuredGEP) + return CGF.Builder.CreateStructuredGEP(elemType, ptr, indices); + if (inbounds) { return CGF.EmitCheckedInBoundsGEP(elemType, ptr, indices, signedIndices, CodeGenFunction::NotSubtraction, loc, @@ -4547,10 +4561,17 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF, static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, ArrayRef<llvm::Value *> indices, + llvm::Type *arrayType, llvm::Type *elementType, bool inbounds, bool signedIndices, SourceLocation loc, CharUnits align, const llvm::Twine &name = "arrayidx") { + if (CGF.getLangOpts().HLSL && arrayType && inbounds && CGF.getLangOpts().EmitStructuredGEP) + return RawAddress(CGF.Builder.CreateStructuredGEP(arrayType, + addr.emitRawPointer(CGF), + indices.drop_front()), + elementType, align); + if (inbounds) { return CGF.EmitCheckedInBoundsGEP(addr, indices, elementType, signedIndices, CodeGenFunction::NotSubtraction, loc, @@ -4667,6 +4688,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, if (!LastIndex || (!CGF.IsInPreservedAIRegion && !IsPreserveAIArrayBase(CGF, Base))) { addr = emitArraySubscriptGEP(CGF, addr, indices, + arrayType ? CGF.ConvertTypeForMem(*arrayType) + : nullptr, CGF.ConvertTypeForMem(eltType), inbounds, signedIndices, loc, eltAlign, name); return addr; @@ -5521,6 +5544,14 @@ static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base, unsigned idx = CGF.CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field); + llvm::Type *StructType = + CGF.CGM.getTypes().getCGRecordLayout(rec).getLLVMType(); + + if (CGF.getLangOpts().HLSL && CGF.getLangOpts().EmitStructuredGEP) + return RawAddress( + CGF.Builder.CreateStructuredGEP(StructType, base.emitRawPointer(CGF), + {CGF.Builder.getSize(idx)}), + 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 e796bbb5855c8..cc465fb5ab098 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -36,6 +36,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" @@ -1108,12 +1109,19 @@ static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV, // Make sure the global variable is buffer resource handle llvm::Type *HandleTy = GV->getValueType(); assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global"); + llvm::Type *UnderlyingType = + cast<TargetExtType>(HandleTy)->getTypeParameter(0); llvm::Value *CreateHandle = Builder.CreateIntrinsic( /*ReturnType=*/HandleTy, IntrID, Args, nullptr, Twine(GV->getName()).concat("_h")); - llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0); + llvm::Value *HandleRef = + CGM.getLangOpts().EmitStructuredGEP + ? Builder.CreateStructuredGEP(UnderlyingType, GV, + llvm::ConstantInt::get(CGM.IntTy, 0)) + : Builder.CreateStructGEP(GV->getValueType(), GV, 0); + Builder.CreateAlignedStore(CreateHandle, HandleRef, HandleRef->getPointerAlignment(DL)); Builder.CreateRetVoid(); @@ -1397,9 +1405,18 @@ std::optional<LValue> CGHLSLRuntime::emitBufferArraySubscriptExpr( Indices.push_back(Idx); Indices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0)); - llvm::Value *GEP = CGF.Builder.CreateGEP(LayoutTy, Addr.emitRawPointer(CGF), - Indices, "cbufferidx"); - Addr = Address(GEP, Addr.getElementType(), RowAlignedSize, KnownNonNull); + if (CGF.getLangOpts().EmitStructuredGEP) { + if (auto *AT = dyn_cast<llvm::ArrayType>(Addr.getElementType())) + LayoutTy = llvm::ArrayType::get(LayoutTy, AT->getNumElements()); + auto *GEP = cast<StructuredGEPInst>(CGF.Builder.CreateStructuredGEP( + LayoutTy, Addr.emitRawPointer(CGF), Indices, "cbufferidx")); + Addr = + Address(GEP, GEP->getResultElementType(), RowAlignedSize, KnownNonNull); + } else { + llvm::Value *GEP = CGF.Builder.CreateGEP(LayoutTy, Addr.emitRawPointer(CGF), + Indices, "cbufferidx"); + Addr = Address(GEP, Addr.getElementType(), RowAlignedSize, KnownNonNull); + } return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo); } @@ -1579,9 +1596,14 @@ LValue CGHLSLRuntime::emitBufferMemberExpr(CodeGenFunction &CGF, llvm::Type *FieldLLVMTy = CGM.getTypes().ConvertTypeForMem(FieldType); CharUnits Align = CharUnits::fromQuantity( CGF.CGM.getDataLayout().getABITypeAlign(FieldLLVMTy)); - Address Addr(CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF), - FieldIdx, Field->getName()), - FieldLLVMTy, Align, KnownNonNull); + + Value *Ptr = CGF.getLangOpts().EmitStructuredGEP + ? CGF.Builder.CreateStructuredGEP( + LayoutTy, Base.getPointer(CGF), + llvm::ConstantInt::get(CGM.IntTy, FieldIdx)) + : CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF), + FieldIdx, Field->getName()); + Address Addr(Ptr, FieldLLVMTy, Align, KnownNonNull); LValue LV = LValue::MakeAddr(Addr, FieldType, CGM.getContext(), LValueBaseInfo(AlignmentSource::Type), diff --git a/clang/test/CodeGenHLSL/sgep/array_load.hlsl b/clang/test/CodeGenHLSL/sgep/array_load.hlsl new file mode 100644 index 0000000000000..26efa7cef57dc --- /dev/null +++ b/clang/test/CodeGenHLSL/sgep/array_load.hlsl @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -fexperimental-emit-sgep -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -fexperimental-emit-sgep -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIR + +void foo() { +// CHECK: %array = alloca [3 x i32], align 4 + uint array[3] = { 0, 1, 2 }; + +// CHECK-DXIL: %[[#PTR:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x i32]) %array, i32 2) +// CHECK-SPIR: %[[#PTR:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x i32]) %array, i64 2) +// CHECK: load i32, ptr %[[#PTR]], align 4 + uint tmp = array[2]; +} + +struct S { + uint a; + uint b; +}; + +void bar() { +// CHECK: %array = alloca [3 x %struct.S], align 1 + S array[3] = { { 0, 1 }, { 2, 3 }, { 3, 4 } }; + +// CHECK-DXIL: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S]) %array, i32 2) +// CHECK-DXIL: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#A]], i32 1) +// CHECK-SPIR: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S]) %array, i64 2) +// CHECK-SPIR: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#A]], i64 1) + +// CHECK: load i32, ptr %[[#B]], align 1 + uint tmp = array[2].b; +} + +struct S2 { + uint a; + S b; + uint c; +}; + +void baz() { +// CHECK: %array = alloca [2 x %struct.S2], align 1 + S2 array[2] = { { 0, { 1, 2 }, 3 }, { 4, { 5, 6 }, 7 } }; + +// CHECK-DXIL: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x %struct.S2]) %array, i32 1) +// CHECK-DXIL: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S2) %[[#A]], i32 1) +// CHECK-DXIL: %[[#C:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#B]], i32 0) + +// CHECK-SPIR: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x %struct.S2]) %array, i64 1) +// CHECK-SPIR: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S2) %[[#A]], i64 1) +// CHECK-SPIR: %[[#C:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#B]], i64 0) + +// CHECK: load i32, ptr %[[#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 new file mode 100644 index 0000000000000..a798bc47da50c --- /dev/null +++ b/clang/test/CodeGenHLSL/sgep/array_store.hlsl @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -fexperimental-emit-sgep -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -fexperimental-emit-sgep -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIR + +[shader("compute")] +[numthreads(1,1,1)] +void foo() { +// CHECK: %array = alloca [10 x i32], align 4 + uint array[10]; + +// CHECK-DXIL: %[[#PTR:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %array, i32 2) +// CHECK-SPIR: %[[#PTR:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([10 x i32]) %array, i64 2) +// CHECK: store i32 10, ptr %[[#PTR]], align 4 + array[2] = 10; +} + +struct S { + uint a; + uint b; +}; + +void bar() { +// CHECK: %array = alloca [3 x %struct.S], align 1 + S array[3] = { { 0, 1 }, { 2, 3 }, { 3, 4 } }; + +// CHECK-DXIL: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S]) %array, i32 2) +// CHECK-DXIL: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#A]], i32 1) + +// CHECK-SPIR: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([3 x %struct.S]) %array, i64 2) +// CHECK-SPIR: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#A]], i64 1) + +// CHECK: store i32 10, ptr %[[#B]], align 1 + array[2].b = 10; +} + +struct S2 { + uint a; + S b; + uint c; +}; + +void baz() { +// CHECK: %array = alloca [2 x %struct.S2], align 1 + S2 array[2] = { { 0, { 1, 2 }, 3 }, { 4, { 5, 6 }, 7 } }; + +// CHECK-DXIL: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x %struct.S2]) %array, i32 1) +// CHECK-DXIL: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S2) %[[#A]], i32 1) +// CHECK-DXIL: %[[#C:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#B]], i32 0) + +// CHECK-SPIR: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype([2 x %struct.S2]) %array, i64 1) +// CHECK-SPIR: %[[#B:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S2) %[[#A]], i64 1) +// CHECK-SPIR: %[[#C:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.S) %[[#B]], i64 0) + +// CHECK: store i32 10, ptr %[[#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 new file mode 100644 index 0000000000000..18e57e04e64fc --- /dev/null +++ b/clang/test/CodeGenHLSL/sgep/load_global.hlsl @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -fexperimental-emit-sgep -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK-DXIL +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -fexperimental-emit-sgep -o - %s | FileCheck %s --check-prefixes=CHECK-SPIR + +struct S { + uint a; + uint b; + uint c; + uint d; +}; + +// CHECK-DXIL: @_ZL1s = external hidden addrspace(2) global %struct.S, align 1 +// CHECK-DXIL: @_ZL1a = external hidden addrspace(2) constant [4 x i32], align 4 +// CHECK-DXIL: @_ZL1b = external hidden addrspace(2) constant i32, align 4 + +// CHECK-SPIR: @_ZL1s = external hidden addrspace(12) global %struct.S, align 1 +// CHECK-SPIR: @_ZL1a = external hidden addrspace(12) constant [4 x i32], align 4 +// CHECK-SPIR: @_ZL1b = external hidden addrspace(12) constant i32, align 4 +const S s; +const uint a[4]; +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: %[[#]] = 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: %[[#]] = 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: %[[#]] = 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: %[[#]] = load i32, ptr addrspace(12) %cbufferidx, align 16 + uint tmp = a[2]; +} + +void baz() { +// CHECK-DXIL: %[[#]] = load i32, ptr addrspace(2) @_ZL1b, align 4 +// CHECK-SPIR: %[[#]] = load i32, ptr addrspace(12) @_ZL1b, align 4 + uint tmp = b; +} diff --git a/clang/test/CodeGenHLSL/sgep/object_method.hlsl b/clang/test/CodeGenHLSL/sgep/object_method.hlsl new file mode 100644 index 0000000000000..f54f0c064bb31 --- /dev/null +++ b/clang/test/CodeGenHLSL/sgep/object_method.hlsl @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -fexperimental-emit-sgep -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -fexperimental-emit-sgep -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIR + +struct O { + int value = 0; + + int get() { + return value; + } +}; + +[shader("compute")] +[numthreads(1,1,1)] +void foo() { + O o; + +// CHECK: %o = alloca %struct.O, align 1 +// CHECK-DXIL: call noundef i32 @_ZN1O3getEv(ptr noundef nonnull align 1 dereferenceable(4) %o) +// CHECK-SPIR: call spir_func noundef i32 @_ZN1O3getEv(ptr noundef nonnull align 1 dereferenceable(4) %o) + uint tmp = o.get(); +} + + + +// 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-DXIL: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.O) %this1, i32 0) +// CHECK-SPIR: %[[#A:]] = call ptr (ptr, ...) @llvm.structured.gep.p0(ptr elementtype(%struct.O) %this1, i64 0) +// CHECK: %[[#B:]] = load i32, ptr %[[#A]], align 1 +// CHECK: ret i32 %[[#B]] `````````` </details> https://github.com/llvm/llvm-project/pull/177332 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
