[clang] [HLSL] Handle logical pointer for array assign (PR #193227)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 21 06:59:50 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Nathan Gauër (Keenuts)
<details>
<summary>Changes</summary>
This commits adds SPIR-V testing on an existing test (NFC on DXIL testing). It also copies it and invokes Clang using the experimental logical pointer flag.
Adding this flag shows a missing case in the frontend, handled with this commit.
Due to the difference in index handling between the structured.gep and legacy one, the Cbuffer load codegen had to be rewritten. It's a bit more naive, as we get one gep per level, but this will be handled by optimizations later on.
---
Patch is 85.16 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/193227.diff
6 Files Affected:
- (modified) clang/lib/CodeGen/CGBuilder.h (+22)
- (modified) clang/lib/CodeGen/CGExprAgg.cpp (+9-3)
- (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+89-84)
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+4)
- (modified) clang/test/CodeGenHLSL/ArrayAssignable.hlsl (+330-131)
- (added) clang/test/CodeGenHLSL/ArrayAssignable.logicalptr.hlsl (+443)
``````````diff
diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h
index 6d2a01ae33bd7..4a51f6be8578f 100644
--- a/clang/lib/CodeGen/CGBuilder.h
+++ b/clang/lib/CodeGen/CGBuilder.h
@@ -362,6 +362,28 @@ class CGBuilderTy : public CGBuilderBaseTy {
ElementType, Align, Addr.isKnownNonNull());
}
+ using CGBuilderBaseTy::CreateStructuredGEP;
+ llvm::Value *CreateAccessChain(bool Logical, llvm::Type *BaseType,
+ llvm::Value *PtrBase,
+ ArrayRef<llvm::Value *> IdxList,
+ const Twine &Name = "") {
+
+ if (Logical)
+ return CreateStructuredGEP(BaseType, PtrBase, IdxList, Name);
+ return CreateInBoundsGEP(BaseType, PtrBase, IdxList, Name);
+ }
+
+ Address CreateAccessChain(bool Logical, Address Addr,
+ ArrayRef<llvm::Value *> IdxList,
+ llvm::Type *ElementType, CharUnits Align,
+ const Twine &Name = "") {
+
+ return RawAddress(CreateAccessChain(Logical, Addr.getElementType(),
+ emitRawPointerFromAddress(Addr),
+ IdxList, Name),
+ ElementType, Align, Addr.isKnownNonNull());
+ }
+
using CGBuilderBaseTy::CreateIsNull;
llvm::Value *CreateIsNull(Address Addr, const Twine &Name = "") {
if (!Addr.hasOffset())
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 3a4291719da74..e5007f59e452c 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -647,9 +647,15 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
auto Emit = [&](Expr *Init, uint64_t ArrayIndex) {
llvm::Value *element = begin;
if (ArrayIndex > 0) {
- element = Builder.CreateInBoundsGEP(
- llvmElementType, begin,
- llvm::ConstantInt::get(CGF.SizeTy, ArrayIndex), "arrayinit.element");
+ if (CGF.getLangOpts().EmitLogicalPointer)
+ element = Builder.CreateStructuredGEP(
+ AType, begin, llvm::ConstantInt::get(CGF.SizeTy, ArrayIndex),
+ "arrayinit.element");
+ else
+ element = Builder.CreateInBoundsGEP(
+ llvmElementType, begin,
+ llvm::ConstantInt::get(CGF.SizeTy, ArrayIndex),
+ "arrayinit.element");
// Tell the cleanup that it needs to destroy up to this
// element. TODO: some of these stores can be trivially
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 1e25172d18890..a42b2c3b7b596 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1469,64 +1469,34 @@ namespace {
/// copying out of a cbuffer).
class HLSLBufferCopyEmitter {
CodeGenFunction &CGF;
- Address DestPtr;
+ Address DstPtr;
Address SrcPtr;
llvm::Type *LayoutTy = nullptr;
SmallVector<llvm::Value *> CurStoreIndices;
SmallVector<llvm::Value *> CurLoadIndices;
- void emitCopyAtIndices(llvm::Type *FieldTy, llvm::ConstantInt *StoreIndex,
- llvm::ConstantInt *LoadIndex) {
- CurStoreIndices.push_back(StoreIndex);
- CurLoadIndices.push_back(LoadIndex);
- llvm::scope_exit RestoreIndices([&]() {
- CurStoreIndices.pop_back();
- CurLoadIndices.pop_back();
- });
-
- // First, see if this is some kind of aggregate and recurse.
- if (processArray(FieldTy))
- return;
- if (processBufferLayoutArray(FieldTy))
- return;
- if (processStruct(FieldTy))
- return;
-
- // When we have a scalar or vector element we can emit the copy.
- CharUnits Align = CharUnits::fromQuantity(
- CGF.CGM.getDataLayout().getABITypeAlign(FieldTy));
- Address SrcGEP = RawAddress(
- CGF.Builder.CreateInBoundsGEP(LayoutTy, SrcPtr.getBasePointer(),
- CurLoadIndices, "cbuf.src"),
- FieldTy, Align, SrcPtr.isKnownNonNull());
- Address DestGEP = CGF.Builder.CreateInBoundsGEP(
- DestPtr, CurStoreIndices, FieldTy, Align, "cbuf.dest");
- llvm::Value *Load = CGF.Builder.CreateLoad(SrcGEP, "cbuf.load");
- CGF.Builder.CreateStore(Load, DestGEP);
+ // Creates & returns either a structured.gep or a ptradd/gep depending on
+ // langopts.
+ 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);
+
+ llvm::SmallVector<llvm::Value *> GEPIndices;
+ GEPIndices.reserve(Indices.size() + 1);
+ GEPIndices.push_back(llvm::ConstantInt::get(CGF.IntTy, 0));
+ GEPIndices.append(Indices.begin(), Indices.end());
+ return CGF.Builder.CreateAccessChain(EmitLogical, BaseTy, Base, GEPIndices);
}
- bool processArray(llvm::Type *FieldTy) {
- auto *AT = dyn_cast<llvm::ArrayType>(FieldTy);
- if (!AT)
- return false;
-
- // If we have an llvm::ArrayType this is just a regular array with no top
- // level padding, so all we need to do is copy each member.
- for (unsigned I = 0, E = AT->getNumElements(); I < E; ++I)
- emitCopyAtIndices(AT->getElementType(),
- llvm::ConstantInt::get(CGF.SizeTy, I),
- llvm::ConstantInt::get(CGF.SizeTy, I));
- return true;
- }
-
- bool processBufferLayoutArray(llvm::Type *FieldTy) {
+ bool isBufferLayoutArray(llvm::StructType *ST) {
// A buffer layout array is a struct with two elements: the padded array,
// and the last element. That is, is should look something like this:
//
// { [%n x { %type, %padding }], %type }
//
- auto *ST = dyn_cast<llvm::StructType>(FieldTy);
if (!ST || ST->getNumElements() != 2)
return false;
@@ -1545,51 +1515,86 @@ class HLSLBufferCopyEmitter {
llvm::Type *ElementTy = ST->getElementType(1);
if (PaddedTy->getElementType(0) != ElementTy)
return false;
+ return true;
+ }
- // All but the last of the logical array elements are in the padded array.
- unsigned NumElts = PaddedEltsTy->getNumElements() + 1;
-
- // Add an extra indirection to the load for the struct and walk the
- // array prefix.
- CurLoadIndices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
- for (unsigned I = 0; I < NumElts - 1; ++I) {
- // We need to copy the element itself, without the padding.
- CurLoadIndices.push_back(llvm::ConstantInt::get(CGF.SizeTy, I));
- emitCopyAtIndices(ElementTy, llvm::ConstantInt::get(CGF.SizeTy, I),
- llvm::ConstantInt::get(CGF.Int32Ty, 0));
- CurLoadIndices.pop_back();
+ void emitBufferLayoutCopy(Value *Src, llvm::StructType *SrcTy, Value *Dst,
+ llvm::ArrayType *DstTy) {
+ // Those assumptions are checked by isBufferLayoutArray.
+ auto *SrcPaddedArrayTy = cast<llvm::ArrayType>(SrcTy->getElementType(0));
+ auto *SrcPaddedEltTy =
+ cast<llvm::StructType>(SrcPaddedArrayTy->getElementType());
+ assert(SrcPaddedArrayTy->getNumElements() + 1 == DstTy->getNumElements());
+ assert(SrcPaddedEltTy->getElementType(0) == SrcTy->getElementType(1));
+
+ auto *SrcDataTy = SrcTy->getElementType(1);
+ auto Zero = llvm::ConstantInt::get(CGF.IntTy, 0);
+
+ for (unsigned I = 0; I < SrcPaddedArrayTy->getNumElements(); ++I) {
+ auto Index = llvm::ConstantInt::get(CGF.IntTy, I);
+ auto *SrcElt = emitAccessChain(SrcTy, Src, {Zero, Index, Zero});
+ auto *DstElt = emitAccessChain(DstTy, Dst, {Index});
+ emitElementCopy(SrcElt, SrcDataTy, DstElt, DstTy->getElementType());
}
- CurLoadIndices.pop_back();
-
- // Now copy the last element.
- emitCopyAtIndices(ElementTy,
- llvm::ConstantInt::get(CGF.SizeTy, NumElts - 1),
- llvm::ConstantInt::get(CGF.Int32Ty, 1));
- return true;
+ auto *SrcElt =
+ emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, 1)});
+ auto *DstElt = emitAccessChain(
+ DstTy, Dst,
+ {llvm::ConstantInt::get(CGF.IntTy, DstTy->getNumElements() - 1)});
+ emitElementCopy(SrcElt, SrcDataTy, DstElt, DstTy->getElementType());
}
- bool processStruct(llvm::Type *FieldTy) {
- auto *ST = dyn_cast<llvm::StructType>(FieldTy);
- if (!ST)
- return false;
+ void emitCopy(Value *Src, llvm::StructType *SrcTy, Value *Dst,
+ llvm::Type *DstTy) {
+ if (isBufferLayoutArray(SrcTy))
+ return emitBufferLayoutCopy(Src, SrcTy, Dst,
+ cast<llvm::ArrayType>(DstTy));
+
+ auto *DST = cast<llvm::StructType>(DstTy);
+ for (unsigned I = 0; I < SrcTy->getNumElements(); ++I) {
+ auto *SrcElt =
+ emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, I)});
+ auto *DstElt =
+ emitAccessChain(DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, I)});
+ emitElementCopy(SrcElt, SrcTy->getElementType(I), DstElt,
+ DST->getElementType(I));
+ }
+ }
- // Copy the struct field by field, but skip any explicit padding.
- unsigned Skipped = 0;
- for (unsigned I = 0, E = ST->getNumElements(); I < E; ++I) {
- llvm::Type *ElementTy = ST->getElementType(I);
- if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(ElementTy))
- ++Skipped;
- else
- emitCopyAtIndices(ElementTy, llvm::ConstantInt::get(CGF.Int32Ty, I),
- llvm::ConstantInt::get(CGF.Int32Ty, I + Skipped));
+ void emitCopy(Value *Src, llvm::ArrayType *SrcTy, Value *Dst,
+ llvm::Type *DstTy) {
+ for (unsigned I = 0, E = SrcTy->getNumElements(); I < E; ++I) {
+ auto *SrcElt =
+ emitAccessChain(SrcTy, Src, {llvm::ConstantInt::get(CGF.IntTy, I)});
+ auto *DstElt =
+ emitAccessChain(DstTy, Dst, {llvm::ConstantInt::get(CGF.IntTy, I)});
+ emitElementCopy(SrcElt, SrcTy->getElementType(), DstElt,
+ cast<llvm::ArrayType>(DstTy)->getElementType());
}
- return true;
+ }
+
+ void emitElementCopy(Value *Src, llvm::Type *SrcTy, Value *Dst,
+ llvm::Type *DstTy) {
+ if (auto *AT = dyn_cast<llvm::ArrayType>(SrcTy))
+ return emitCopy(Src, AT, Dst, DstTy);
+ if (auto *ST = dyn_cast<llvm::StructType>(SrcTy))
+ return emitCopy(Src, ST, Dst, DstTy);
+
+ // When we have a scalar or vector element we can emit the copy.
+ CharUnits SrcAlign =
+ CharUnits::fromQuantity(CGF.CGM.getDataLayout().getABITypeAlign(SrcTy));
+ CharUnits DstAlign =
+ CharUnits::fromQuantity(CGF.CGM.getDataLayout().getABITypeAlign(DstTy));
+ Address SrcAddr(Src, SrcTy, SrcAlign);
+ Address DstAddr(Dst, DstTy, DstAlign);
+ llvm::Value *Load = CGF.Builder.CreateLoad(SrcAddr, "cbuf.load");
+ CGF.Builder.CreateStore(Load, DstAddr);
}
public:
- HLSLBufferCopyEmitter(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr)
- : CGF(CGF), DestPtr(DestPtr), SrcPtr(SrcPtr) {}
+ HLSLBufferCopyEmitter(CodeGenFunction &CGF, Address DstPtr, Address SrcPtr)
+ : CGF(CGF), DstPtr(DstPtr), SrcPtr(SrcPtr) {}
bool emitCopy(QualType CType) {
LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(CType);
@@ -1599,16 +1604,16 @@ class HLSLBufferCopyEmitter {
// currently.
//
// See https://github.com/llvm/wg-hlsl/issues/351
- emitCopyAtIndices(LayoutTy, llvm::ConstantInt::get(CGF.SizeTy, 0),
- llvm::ConstantInt::get(CGF.SizeTy, 0));
+ emitElementCopy(SrcPtr.getBasePointer(), LayoutTy, DstPtr.getBasePointer(),
+ DstPtr.getElementType());
return true;
}
};
} // namespace
-bool CGHLSLRuntime::emitBufferCopy(CodeGenFunction &CGF, Address DestPtr,
+bool CGHLSLRuntime::emitBufferCopy(CodeGenFunction &CGF, Address DstPtr,
Address SrcPtr, QualType CType) {
- return HLSLBufferCopyEmitter(CGF, DestPtr, SrcPtr).emitCopy(CType);
+ return HLSLBufferCopyEmitter(CGF, DstPtr, SrcPtr).emitCopy(CType);
}
LValue CGHLSLRuntime::emitBufferMemberExpr(CodeGenFunction &CGF,
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index c635a6c175b25..28937f4a5382e 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -484,6 +484,10 @@ CodeGenModule::CodeGenModule(ASTContext &C,
TBAA.reset(new CodeGenTBAA(Context, getTypes(), TheModule, CodeGenOpts,
getLangOpts()));
+ if (LangOpts.EmitLogicalPointer)
+ getModule().addModuleFlag(llvm::Module::Error,
+ "ExperimentalEmitLogicalPointer", true);
+
// If debug info or coverage generation is enabled, create the CGDebugInfo
// object.
if (CodeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo ||
diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
index 9a568fe3371d0..acd1e1a3e0724 100644
--- a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
+++ b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
@@ -1,18 +1,12 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK-DXIL
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-library -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK-SPIR
struct S {
int x;
float f;
};
-// CHECK: [[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: @CBArrays.cb = global target("dx.CBuffer", [[CBLayout]])
-// CHECK: @c1 = external hidden addrspace(2) global <{ [1 x <{ float, target("dx.Padding", 12) }>], float }>, align 4
-// CHECK: @c2 = external hidden addrspace(2) global [2 x <4 x i32>], align 4
-// CHECK: @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: @c4 = external hidden addrspace(2) global <{ [1 x <{ %S, target("dx.Padding", 8) }>], %S }>, align 1
-
cbuffer CBArrays : register(b0) {
float c1[2];
int4 c2[2];
@@ -20,31 +14,75 @@ cbuffer CBArrays : register(b0) {
S c4[2];
}
-// CHECK-LABEL: define hidden void {{.*}}arr_assign1
-// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4
-// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4
-// CHECK-NOT: alloca
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false)
-// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false)
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false)
-// CHECK-NEXT: ret void
+// 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 = 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 = 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(
+// CHECK-DXIL-SAME: ) #[[ATTR2:[0-9]+]] {
+// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
+// CHECK-DXIL-NEXT: [[ARR:%.*]] = alloca [2 x i32], align 4
+// CHECK-DXIL-NEXT: [[ARR2:%.*]] = alloca [2 x i32], align 4
+// 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: 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: ret void
+//
+// CHECK-SPIR-LABEL: define hidden spir_func void @_Z11arr_assign1v(
+// CHECK-SPIR-SAME: ) #[[ATTR2:[0-9]+]] {
+// CHECK-SPIR-NEXT: [[ENTRY:.*:]]
+// CHECK-SPIR-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
+// CHECK-SPIR-NEXT: [[ARR:%.*]] = alloca [2 x i32], align 4
+// CHECK-SPIR-NEXT: [[ARR2:%.*]] = alloca [2 x i32], align 4
+// CHECK-SPIR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARR]], ptr align 4 @__const._Z11arr_assign1v.Arr, i64 8, i1 false)
+// 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: ret void
+//
void arr_assign1() {
int Arr[2] = {0, 1};
int Arr2[2] = {0, 0};
Arr = Arr2;
}
-// CHECK-LABEL: define hidden void {{.*}}arr_assign2
-// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4
-// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4
-// CHECK-NEXT: [[Arr3:%.*]] = alloca [2 x i32], align 4
-// CHECK-NOT: alloca
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false)
-// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false)
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 8, i1 false)
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr2]], ptr align 4 [[Arr3]], i32 8, i1 false)
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false)
-// CHECK-NEXT: ret void
+// CHECK-DXIL-LABEL: define hidden void @_Z11arr_assign2v(
+// CHECK-DXIL-SAME: ) #[[ATTR2]] {
+// CHECK-DXIL-NEXT: [[ENTRY:.*:]]
+// CHECK-DXIL-NEXT: [[ARR:%.*]] = alloca [2 x i32], align 4
+// CHECK-DXIL-NEXT: [[ARR2:%.*]] = alloca [2 x i32], align 4
+// CHECK-DXIL-NEXT: [[ARR3:%.*]] = alloca [2 x i32], align 4
+// 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: call void @llvm.memset.p0.i32(ptr align 4 [[ARR2]], i8 0, i32 8, i1 false)
+// CHECK-DXI...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/193227
More information about the cfe-commits
mailing list