https://github.com/bob80905 created https://github.com/llvm/llvm-project/pull/190037
draft >From ea9445b3fa97f5fa0132985f39a41609ed51e6f5 Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Wed, 25 Mar 2026 16:40:16 -0700 Subject: [PATCH 1/4] first attempt --- .../Resources/local_resources_failures.hlsl | 175 +++++ .../Resources/local_resources_passes.hlsl | 643 ++++++++++++++++++ 2 files changed, 818 insertions(+) create mode 100644 clang/test/SemaHLSL/Resources/local_resources_failures.hlsl create mode 100644 clang/test/SemaHLSL/Resources/local_resources_passes.hlsl diff --git a/clang/test/SemaHLSL/Resources/local_resources_failures.hlsl b/clang/test/SemaHLSL/Resources/local_resources_failures.hlsl new file mode 100644 index 0000000000000..84637cf8ce99f --- /dev/null +++ b/clang/test/SemaHLSL/Resources/local_resources_failures.hlsl @@ -0,0 +1,175 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -verify + +Texture2D<float4> gTex0 : register(t0); +Texture2D<float4> gTex1 : register(t1); +SamplerState gSampler : register(s0); + +StructuredBuffer<float4> gSB : register(t2); +RWStructuredBuffer<float4> gRW : register(u0); + +Texture2D<float4> gTexArray[4] : register(t10); + +//-------------------------------------------------------------- +// FAIL 1: static local resource +//-------------------------------------------------------------- +// This causes an assert in DXC +float4 Fail_Static(float2 uv) +{ + static Texture2D<float4> tex = gTex0; + // expected-error@-1 {{static resource}} + return tex.Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// FAIL 2: arithmetic on resource +//-------------------------------------------------------------- + +float Fail_Arithmetic() +{ + Texture2D<float4> tex = gTex0; + tex = tex + 1; + // expected-error@-1 {{scalar, vector, or matrix expected}} + return tex; + // expected-error@-1 {{cannot initialize return object of type 'float' with an lvalue of type 'Texture2D<float4>'}} +} + +//-------------------------------------------------------------- +// FAIL 3: comparison of resources +//-------------------------------------------------------------- + +bool Fail_Compare() +{ + Texture2D<float4> a = gTex0; + Texture2D<float4> b = gTex1; + return a == b; + // expected-error@-1 {{operator cannot be used with built-in type 'Texture2D<vector<float, 4> >'}} +} + +//-------------------------------------------------------------- +// FAIL 4: conversion to bool +//-------------------------------------------------------------- + +bool Fail_Bool() +{ + Texture2D<float4> tex = gTex0; + return tex; + // expected-error@-1 {{cannot initialize return object of type 'bool' with an lvalue of type 'Texture2D<float4>'}} +} + +//-------------------------------------------------------------- +// FAIL 5: cast from resource +//-------------------------------------------------------------- + +uint Fail_Cast() +{ + Texture2D<float4> tex = gTex0; + return (uint)tex; + // expected-error@-1 {{cannot convert from 'Texture2D<float4>' to 'uint'}} +} + +//-------------------------------------------------------------- +// FAIL 6: addition of resources +//-------------------------------------------------------------- + +float Fail_Add() +{ + Texture2D<float4> tex = gTex0; + return tex + tex; + // expected-error@-1 {{scalar, vector, or matrix expected}} +} + + +//-------------------------------------------------------------- +// FAIL 7: default parameter on resource +//-------------------------------------------------------------- + +float4 Fail_DefaultParam(Texture2D<float4> tex = gTex0, float2 uv) + // expected-error@-1 {{missing default argument on parameter 'uv'}} + // expected-note@-2 {{candidate function not viable: requires 2 arguments, but 1 was provided}} + // note, this note above does not get emitted when -verify is passed as an option. +{ + return tex.Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// FAIL 8: reinterpret cast +//-------------------------------------------------------------- + +float4 Fail_Reinterpret(float2 uv) +{ + Texture2D<float4> tex = gTex0; + return ((Texture2D<float4>)gSampler).Sample(gSampler, uv); + // expected-error@-1 {{cannot convert from 'SamplerState' to 'Texture2D<float4>'}} +} + +//-------------------------------------------------------------- +// FAIL 9: RWStructuredBuffer with resource type +//-------------------------------------------------------------- + +void Fail_LocalBuffer() +{ + RWStructuredBuffer<Texture2D<float4> > badBuffer; + // expected-error@-1 {{object 'Texture2D<float4>' is not allowed in builtin template parameters}} +} + +//-------------------------------------------------------------- +// FAIL 10: wave uniformity violation +//-------------------------------------------------------------- + +float4 Fail_WaveUniform(float2 uv) +{ + Texture2D<float4> tex = gTex0; + // I presume the reason we don't see this expected error is that + // DxilCondenseResources is responsible for emitting this. + // So, it will not run when -verify is passed to the compiler since + // DXIL IR is not the intended output in that situation. + // However, in DXC, we do expect an error here. + if(WaveActiveAllTrue(true)) + // expected-error@-1 {{local resource not guaranteed to map to unique global resource}} + tex = gTex1; + return tex.Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// Entry point calling all fail functions to prevent DCE +//-------------------------------------------------------------- + +[numthreads(1,1,1)] +void main(uint3 tid : SV_DispatchThreadID) +{ + float2 uv = float2(0,0); + float4 r = 0; + gTex0 = tex; + // FAIL 1 + r += Fail_Static(uv); + + // FAIL 2 + Fail_Arithmetic(); + + // FAIL 3 + Fail_Compare(); + + // FAIL 4 + Fail_Bool(); + + // FAIL 5 + Fail_Cast(); + + // FAIL 6 + Fail_Add(); + + // FAIL 7 + // note, this error does not get emitted when -verify is passed as an option. + // expected-error@+1{{no matching function for call to 'Fail_DefaultParam'}} + Fail_DefaultParam(gTex0, uv); + + // FAIL 8 + Fail_Reinterpret(uv); + + // FAIL 9 + Fail_LocalBuffer(); + + // FAIL 10 + r += Fail_WaveUniform(uv); +} diff --git a/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl b/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl new file mode 100644 index 0000000000000..cc5fc2835033e --- /dev/null +++ b/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl @@ -0,0 +1,643 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -verify + +//============================================================== +// COMPREHENSIVE LOCAL RESOURCE VARIABLE TEST SUITE +// +// Structure +// PASS TESTS +// ENTRYPOINT +// +// Goal +// Exhaustively document legal and illegal uses of HLSL +// resource variables declared in local scope. +// +//============================================================== + +//-------------------------------------------------------------- +// Global resources +//-------------------------------------------------------------- + +Texture2D<float4> gTex0 : register(t0); +Texture2D<float4> gTex1 : register(t1); +Texture2D<float4> gTex2 : register(t2); + +SamplerState gSampler : register(s0); + +RWTexture2D<float4> gOut : register(u0); + +StructuredBuffer<float4> gSB : register(t3); +RWStructuredBuffer<float4> gRW : register(u1); + +Texture2D<float4> gTexArray[4] : register(t10); + + +//============================================================== +// PASS TESTS +//============================================================== + + +//-------------------------------------------------------------- +// PASS 0 +//-------------------------------------------------------------- + +groupshared Texture2D<float4> sharedTex; + +float4 Use_SharedTex(float2 uv) +{ + return gTex0.Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// PASS 1 +//-------------------------------------------------------------- + +float4 Fail_TernaryInit(bool cond, float2 uv) +{ + Texture2D<float4> tex = cond ? gTex0 : gTex1; + + return tex.Sample(gSampler, uv); +} +//-------------------------------------------------------------- +// PASS 2 +//-------------------------------------------------------------- + +void Fail_LoopVar() +{ + for(Texture2D<float4> tex = gTex0; false;) + { + } +} + +//-------------------------------------------------------------- +// PASS 3 +//-------------------------------------------------------------- + +float4 Fail_ExpressionInit(float2 uv) +{ + Texture2D<float4> tex = (true ? gTex0 : gTex1); + return tex.Sample(gSampler, uv); +} +//-------------------------------------------------------------- +// PASS 4 +//-------------------------------------------------------------- + +struct FailSharedStruct +{ + Texture2D<float4> tex; +}; + +groupshared FailSharedStruct sharedStruct; + +float4 Use_FailSharedStruct(float2 uv) +{ + return gTex0.Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// PASS 5 +//-------------------------------------------------------------- + +struct FailStruct +{ + Texture2D<float4> tex; +}; + +float4 Fail_StructArray(float2 uv) +{ + FailStruct s[2]; + + s[0].tex = gTex0; + return s[0].tex.Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// PASS 6 +//-------------------------------------------------------------- +groupshared Texture2D<float4> Fail_Shared; + +float4 Use_Fail_Shared(float2 uv) +{ + return gTex0.Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// PASS 7 +//-------------------------------------------------------------- +Texture2D<float4> Fail_ReturnLocal_Uninitialized() +{ + Texture2D<float4> tex; // uninitialized local resource + return tex; +} + +//-------------------------------------------------------------- +// PASS 8 +//-------------------------------------------------------------- +Texture2D<float4> Fail_ReturnLocal() +{ + Texture2D<float4> tex = gTex0; + return tex; +} + + +//-------------------------------------------------------------- +// PASS 9 +//-------------------------------------------------------------- +struct S { Texture2D<float4> arr[2]; }; +float4 Pass_StructArray(float2 uv) +{ + S s; + s.arr[0] = gTex0; + return s.arr[0].Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// PASS 10 +//-------------------------------------------------------------- + +float4 Pass_LocalArray(float2 uv) +{ + Texture2D<float4> arr[2]; + + arr[0] = gTex0; + return arr[0].Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// PASS 11 +// Uninitialized use +//-------------------------------------------------------------- + +float4 Pass_Uninitialized(float2 uv) +{ + Texture2D<float4> tex; + + + return tex.Sample(gSampler, uv); +} + +//-------------------------------------------------------------- +// PASS 12 +// Simple local alias +//-------------------------------------------------------------- + +float4 Pass_Alias(float2 uv) +{ + Texture2D<float4> tex = gTex0; + return tex.Sample(gSampler, uv); +} + + +//-------------------------------------------------------------- +// PASS 13 +// Reassignment +//-------------------------------------------------------------- + +float4 Pass_Reassign(float2 uv) +{ + Texture2D<float4> tex = gTex0; + tex = gTex1; + return tex.Sample(gSampler, uv); +} + + +//-------------------------------------------------------------- +// PASS 14 +// Control flow aliasing +//-------------------------------------------------------------- + +float4 Pass_IfAlias(bool cond, float2 uv) +{ + Texture2D<float4> tex; + + if (cond) + tex = gTex0; + else + tex = gTex1; + + return tex.Sample(gSampler, uv); +} + + +//-------------------------------------------------------------- +// PASS 15 +// Loop aliasing +//-------------------------------------------------------------- + +float4 Pass_Loop(float2 uv) +{ + float4 sum = 0; + + for(int i=0;i<4;i++) + { + Texture2D<float4> tex = gTexArray[i]; + sum += tex.Sample(gSampler, uv); + } + + return sum; +} + + + +//-------------------------------------------------------------- +// PASS 16 +// Struct containing resource +//-------------------------------------------------------------- + +struct PassStruct +{ + Texture2D<float4> tex; + SamplerState samp; +}; + +float4 Pass_Struct(float2 uv) +{ + PassStruct s; + s.tex = gTex0; + s.samp = gSampler; + + return s.tex.Sample(s.samp, uv); +} + + + +//-------------------------------------------------------------- +// PASS 17 +// Passing resource through multiple functions +//-------------------------------------------------------------- + +float4 Pass_Level2(Texture2D<float4> tex, float2 uv) +{ + return tex.Sample(gSampler, uv); +} + +float4 Pass_Level1(Texture2D<float4> tex, float2 uv) +{ + return Pass_Level2(tex, uv); +} + +float4 Pass_FunctionForward(float2 uv) +{ + Texture2D<float4> tex = gTex1; + return Pass_Level1(tex, uv); +} + + + +//-------------------------------------------------------------- +// PASS 18 +// Resource merge via conditional assignments +// (SSA-style PHI equivalent) +//-------------------------------------------------------------- + +float4 Pass_PhiMerge(bool cond, float2 uv) +{ + Texture2D<float4> tex; + + if(cond) + tex = gTex0; + else + tex = gTex2; + + return tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 19 +// Nested scope shadowing +//-------------------------------------------------------------- + +float4 Pass_Shadow(float2 uv) +{ + Texture2D<float4> tex = gTex0; + + { + Texture2D<float4> tex = gTex1; + return tex.Sample(gSampler, uv); + } +} + + + +//-------------------------------------------------------------- +// PASS 20 +// Resource in switch +//-------------------------------------------------------------- + +float4 Pass_Switch(int v, float2 uv) +{ + Texture2D<float4> tex = gTex0; + + switch(v) + { + case 1: tex = gTex1; break; + case 2: tex = gTex2; break; + } + + return tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 21 +// Bindless descriptor indexing +//-------------------------------------------------------------- + +float4 Pass_Bindless(uint idx, float2 uv) +{ + Texture2D<float4> tex = gTexArray[idx]; + return tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 22 +// Resource with wave operations +//-------------------------------------------------------------- + +float4 Pass_WaveUse(float2 uv) +{ + Texture2D<float4> tex = gTex0; + + float4 v = tex.Sample(gSampler, uv); + + uint active = WaveActiveCountBits(true); + + return v * active; +} + + + +//-------------------------------------------------------------- +// PASS 23 +// Resource alias used inside nested loops +//-------------------------------------------------------------- + +float4 Pass_NestedLoops(float2 uv) +{ + float4 sum = 0; + + for(int i=0;i<2;i++) + for(int j=0;j<2;j++) + { + Texture2D<float4> tex = gTexArray[i+j]; + sum += tex.Sample(gSampler, uv); + } + + return sum; +} + + + +//-------------------------------------------------------------- +// PASS 24 +// Resource lifetime across blocks +//-------------------------------------------------------------- + +float4 Pass_BlockLifetime(float2 uv) +{ + Texture2D<float4> tex; + + { + tex = gTex1; + } + + return tex.Sample(gSampler, uv); +} + + +//-------------------------------------------------------------- +// PASS 25 +// Deep nested PHI merges +//-------------------------------------------------------------- + +float4 Pass_DeepPhi(bool a, bool b, float2 uv) +{ + Texture2D<float4> tex; + + if(a) + { + if(b) + tex = gTex0; + else + tex = gTex1; + } + else + { + tex = gTex2; + } + + return tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 26 +// Loop-carried resource value +//-------------------------------------------------------------- + +float4 Pass_LoopCarried(int iterations, float2 uv) +{ + Texture2D<float4> tex = gTex0; + + for(int i=0;i<iterations;i++) + { + tex = gTexArray[i & 3]; + } + + return tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 27 +// Resource alias chain +//-------------------------------------------------------------- + +float4 Pass_AliasChain(float2 uv) +{ + Texture2D<float4> a = gTex0; + Texture2D<float4> b = a; + Texture2D<float4> c = b; + + return c.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 28 +// Resource inside nested structs +//-------------------------------------------------------------- + +struct PassNestedInner +{ + Texture2D<float4> tex; +}; + +struct PassNestedOuter +{ + PassNestedInner inner; +}; + +float4 Pass_NestedStruct(float2 uv) +{ + PassNestedOuter s; + + s.inner.tex = gTex1; + + return s.inner.tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 29 +// Resource forwarded through multiple struct layers +//-------------------------------------------------------------- + +struct PassForwardA { Texture2D<float4> tex; }; +struct PassForwardB { PassForwardA a; }; + +float4 Pass_ForwardStructLayers(float2 uv) +{ + PassForwardB b; + b.a.tex = gTex2; + + return b.a.tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 30 +// Resource alias inside switch fallthrough +//-------------------------------------------------------------- + +float4 Pass_SwitchFallthrough(int v, float2 uv) +{ + Texture2D<float4> tex = gTex0; + + switch(v) + { + case 0: + tex = gTex1; + case 1: + tex = gTex2; + break; + } + + return tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 31 +// Resource used after early-return path merge +//-------------------------------------------------------------- + +float4 Pass_EarlyReturn(bool cond, float2 uv) +{ + Texture2D<float4> tex = gTex0; + + if(cond) + return tex.Sample(gSampler, uv); + + tex = gTex1; + + return tex.Sample(gSampler, uv); +} + + +//-------------------------------------------------------------- +// PASS 32 +// Resource alias across nested blocks +//-------------------------------------------------------------- + +float4 Pass_NestedBlocks(float2 uv) +{ + Texture2D<float4> tex; + + { + tex = gTex1; + + { + tex = gTex2; + } + } + + return tex.Sample(gSampler, uv); +} + + + +//-------------------------------------------------------------- +// PASS 33 +// Resource assigned via bindless selection +//-------------------------------------------------------------- + +float4 Pass_BindlessSelection(uint a, uint b, float2 uv) +{ + Texture2D<float4> tex; + + tex = gTexArray[a]; + tex = gTexArray[b]; + + return tex.Sample(gSampler, uv); +} + + +//============================================================== +// ENTRY POINT +//============================================================== + + +[numthreads(8,8,1)] +void main(uint3 tid : SV_DispatchThreadID) +{ + float2 uv = float2(tid.xy)/256.0; + + float4 r = 0; + r += Pass_TernaryInit(true, uv); + Pass_LoopVar(); + r += Pass_ExpressionInit(uv); + r += Use_FailSharedStruct(uv); + r += Pass_StructArray(uv); + r += Use_Fail_Shared(uv); + Texture2D<float4> mytex = Fail_ReturnLocal_Uninitialized(); + Texture2D<float4> mytex2 = Fail_ReturnLocal(); + r += Pass_StructArray(uv); + r += Pass_LocalArray(uv); + r += Pass_Uninitialized(uv); + r += Pass_Alias(uv); + r += Pass_Reassign(uv); + r += Pass_IfAlias(true,uv); + r += Pass_Loop(uv); + r += Pass_Struct(uv); + r += Pass_FunctionForward(uv); + r += Pass_PhiMerge(true,uv); + r += Pass_Shadow(uv); + r += Pass_Switch(1,uv); + r += Pass_Bindless(0,uv); + r += Pass_WaveUse(uv); + r += Pass_NestedLoops(uv); + r += Pass_BlockLifetime(uv); + r += Pass_DeepPhi(true, false, uv); + r += Pass_LoopCarried(15, uv); + r += Pass_AliasChain(uv); + r += Pass_NestedStruct(uv); + r += Pass_ForwardStructLayers(uv); + r += Pass_SwitchFallthrough(0, uv); + r += Pass_EarlyReturn(true, uv); + r += Pass_NestedBlocks(uv); + r += Pass_BindlessSelection(2, 3, uv); + + gOut[tid.xy] = r; +} \ No newline at end of file >From bcc445e537ae44546db6ce4928d94039f5e4637e Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Mon, 30 Mar 2026 14:39:07 -0700 Subject: [PATCH 2/4] cleanup --- .../Resources/local_resources_failures.hlsl | 2 +- .../Resources/local_resources_passes.hlsl | 641 ++++++------------ 2 files changed, 218 insertions(+), 425 deletions(-) diff --git a/clang/test/SemaHLSL/Resources/local_resources_failures.hlsl b/clang/test/SemaHLSL/Resources/local_resources_failures.hlsl index 84637cf8ce99f..aee4d33815e51 100644 --- a/clang/test/SemaHLSL/Resources/local_resources_failures.hlsl +++ b/clang/test/SemaHLSL/Resources/local_resources_failures.hlsl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ // RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -verify Texture2D<float4> gTex0 : register(t0); diff --git a/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl b/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl index cc5fc2835033e..b44e9ff8896dc 100644 --- a/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl +++ b/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl @@ -1,596 +1,389 @@ -// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ -// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -verify +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-compute %s -emit-llvm -verify //============================================================== -// COMPREHENSIVE LOCAL RESOURCE VARIABLE TEST SUITE -// -// Structure -// PASS TESTS -// ENTRYPOINT -// -// Goal -// Exhaustively document legal and illegal uses of HLSL -// resource variables declared in local scope. -// +// GLOBAL RESOURCES //============================================================== -//-------------------------------------------------------------- -// Global resources -//-------------------------------------------------------------- +RWByteAddressBuffer gBuf0 : register(u0); +RWByteAddressBuffer gBuf1 : register(u1); +RWByteAddressBuffer gBuf2 : register(u2); -Texture2D<float4> gTex0 : register(t0); -Texture2D<float4> gTex1 : register(t1); -Texture2D<float4> gTex2 : register(t2); +RWByteAddressBuffer gOut : register(u3); -SamplerState gSampler : register(s0); +RWByteAddressBuffer gBufArray[4] : register(u10); -RWTexture2D<float4> gOut : register(u0); -StructuredBuffer<float4> gSB : register(t3); -RWStructuredBuffer<float4> gRW : register(u1); +//============================================================== +// HELPERS +//============================================================== -Texture2D<float4> gTexArray[4] : register(t10); +uint DoStore(RWByteAddressBuffer buf, uint offset, uint value) +{ + buf.Store(offset, value); + return value; +} //============================================================== // PASS TESTS //============================================================== - -//-------------------------------------------------------------- // PASS 0 -//-------------------------------------------------------------- - -groupshared Texture2D<float4> sharedTex; +groupshared RWByteAddressBuffer sharedBuf; -float4 Use_SharedTex(float2 uv) +uint Use_Shared(uint idx) { - return gTex0.Sample(gSampler, uv); + return DoStore(gBuf0, idx * 4, 1); } -//-------------------------------------------------------------- // PASS 1 -//-------------------------------------------------------------- - -float4 Fail_TernaryInit(bool cond, float2 uv) +uint Pass_TernaryInit(bool cond, uint idx) { - Texture2D<float4> tex = cond ? gTex0 : gTex1; - - return tex.Sample(gSampler, uv); + // expected-warning@+1{{assignment of 'cond ? gBuf0 : gBuf1' to local resource 'buf' is not to the same unique global resource}} + RWByteAddressBuffer buf = cond ? gBuf0 : gBuf1; + return DoStore(buf, idx * 4, 2); } -//-------------------------------------------------------------- -// PASS 2 -//-------------------------------------------------------------- -void Fail_LoopVar() +// PASS 2 +void Pass_LoopVar() { - for(Texture2D<float4> tex = gTex0; false;) + for(RWByteAddressBuffer buf = gBuf0; false;) { } } -//-------------------------------------------------------------- // PASS 3 -//-------------------------------------------------------------- - -float4 Fail_ExpressionInit(float2 uv) +uint Pass_ExpressionInit(uint idx) { - Texture2D<float4> tex = (true ? gTex0 : gTex1); - return tex.Sample(gSampler, uv); + RWByteAddressBuffer buf = (true ? gBuf0 : gBuf1); + return DoStore(buf, idx * 4, 3); } -//-------------------------------------------------------------- -// PASS 4 -//-------------------------------------------------------------- -struct FailSharedStruct -{ - Texture2D<float4> tex; -}; +// PASS 4 +struct PassBufStruct { RWByteAddressBuffer buf; }; -groupshared FailSharedStruct sharedStruct; +groupshared PassBufStruct sharedStruct; -float4 Use_FailSharedStruct(float2 uv) +uint Use_PassSharedStruct(uint idx) { - return gTex0.Sample(gSampler, uv); + return DoStore(gBuf0, idx * 4, 4); } -//-------------------------------------------------------------- // PASS 5 -//-------------------------------------------------------------- - -struct FailStruct +uint Pass_StructArray(uint idx) { - Texture2D<float4> tex; -}; - -float4 Fail_StructArray(float2 uv) -{ - FailStruct s[2]; - - s[0].tex = gTex0; - return s[0].tex.Sample(gSampler, uv); + PassBufStruct s[2]; + s[0].buf = gBuf0; + return DoStore(s[0].buf, idx * 4, 5); } -//-------------------------------------------------------------- // PASS 6 -//-------------------------------------------------------------- -groupshared Texture2D<float4> Fail_Shared; +groupshared RWByteAddressBuffer Pass_Shared; -float4 Use_Fail_Shared(float2 uv) +uint Use_Pass_Shared(uint idx) { - return gTex0.Sample(gSampler, uv); + return DoStore(gBuf0, idx * 4, 6); } -//-------------------------------------------------------------- // PASS 7 -//-------------------------------------------------------------- -Texture2D<float4> Fail_ReturnLocal_Uninitialized() +RWByteAddressBuffer Pass_ReturnLocal_Uninitialized() { - Texture2D<float4> tex; // uninitialized local resource - return tex; + RWByteAddressBuffer buf; + return buf; } -//-------------------------------------------------------------- // PASS 8 -//-------------------------------------------------------------- -Texture2D<float4> Fail_ReturnLocal() +RWByteAddressBuffer Pass_ReturnLocal() { - Texture2D<float4> tex = gTex0; - return tex; + RWByteAddressBuffer buf = gBuf0; + return buf; } - -//-------------------------------------------------------------- // PASS 9 -//-------------------------------------------------------------- -struct S { Texture2D<float4> arr[2]; }; -float4 Pass_StructArray(float2 uv) +struct S { RWByteAddressBuffer arr[2]; }; + +uint Pass_StructArrayAssignment(uint idx) { S s; - s.arr[0] = gTex0; - return s.arr[0].Sample(gSampler, uv); + s.arr[0] = gBuf0; + return DoStore(s.arr[0], idx * 4, 9); } -//-------------------------------------------------------------- // PASS 10 -//-------------------------------------------------------------- - -float4 Pass_LocalArray(float2 uv) +uint Pass_LocalArray(uint idx) { - Texture2D<float4> arr[2]; - - arr[0] = gTex0; - return arr[0].Sample(gSampler, uv); + RWByteAddressBuffer arr[2]; + arr[0] = gBuf0; + return DoStore(arr[0], idx * 4, 10); } -//-------------------------------------------------------------- // PASS 11 -// Uninitialized use -//-------------------------------------------------------------- - -float4 Pass_Uninitialized(float2 uv) +uint Pass_Uninitialized(uint idx) { - Texture2D<float4> tex; - - - return tex.Sample(gSampler, uv); + RWByteAddressBuffer buf; + return DoStore(buf, idx * 4, 11); } -//-------------------------------------------------------------- // PASS 12 -// Simple local alias -//-------------------------------------------------------------- - -float4 Pass_Alias(float2 uv) +uint Pass_Alias(uint idx) { - Texture2D<float4> tex = gTex0; - return tex.Sample(gSampler, uv); + RWByteAddressBuffer buf = gBuf0; + return DoStore(buf, idx * 4, 12); } - -//-------------------------------------------------------------- // PASS 13 -// Reassignment -//-------------------------------------------------------------- - -float4 Pass_Reassign(float2 uv) +uint Pass_Reassign(uint idx) { - Texture2D<float4> tex = gTex0; - tex = gTex1; - return tex.Sample(gSampler, uv); + // expected-note@+1{{variable 'buf' is declared here}} + RWByteAddressBuffer buf = gBuf0; + // expected-warning@+1{{assignment of 'gBuf1' to local resource 'buf' is not to the same unique global resource}} + buf = gBuf1; + return DoStore(buf, idx * 4, 13); } - -//-------------------------------------------------------------- // PASS 14 -// Control flow aliasing -//-------------------------------------------------------------- - -float4 Pass_IfAlias(bool cond, float2 uv) +uint Pass_IfAlias(bool cond, uint idx) { - Texture2D<float4> tex; - - if (cond) - tex = gTex0; - else - tex = gTex1; - - return tex.Sample(gSampler, uv); + RWByteAddressBuffer buf; + // expected-warning@+1{{assignment of 'cond ? gBuf0 : gBuf1' to local resource 'buf' is not to the same unique global resource}} + buf = cond ? gBuf0 : gBuf1; + return DoStore(buf, idx * 4, 14); } - -//-------------------------------------------------------------- // PASS 15 -// Loop aliasing -//-------------------------------------------------------------- - -float4 Pass_Loop(float2 uv) +uint Pass_Loop(uint idx) { - float4 sum = 0; - - for(int i=0;i<4;i++) - { - Texture2D<float4> tex = gTexArray[i]; - sum += tex.Sample(gSampler, uv); + uint sum = 0; + for(unsigned int i=0;i<4;i++) + { + RWByteAddressBuffer buf = gBufArray[i]; + sum += DoStore(buf, idx * 4 + i * 4, 15); } - return sum; } - - -//-------------------------------------------------------------- // PASS 16 -// Struct containing resource -//-------------------------------------------------------------- - struct PassStruct { - Texture2D<float4> tex; - SamplerState samp; + RWByteAddressBuffer buf; }; -float4 Pass_Struct(float2 uv) +uint Pass_Struct(uint idx) { PassStruct s; - s.tex = gTex0; - s.samp = gSampler; - - return s.tex.Sample(s.samp, uv); + s.buf = gBuf0; + return DoStore(s.buf, idx * 4, 16); } - - -//-------------------------------------------------------------- // PASS 17 -// Passing resource through multiple functions -//-------------------------------------------------------------- - -float4 Pass_Level2(Texture2D<float4> tex, float2 uv) +uint Pass_Level2(RWByteAddressBuffer buf, uint idx) { - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 17); } -float4 Pass_Level1(Texture2D<float4> tex, float2 uv) +uint Pass_Level1(RWByteAddressBuffer buf, uint idx) { - return Pass_Level2(tex, uv); + return Pass_Level2(buf, idx); } -float4 Pass_FunctionForward(float2 uv) +uint Pass_FunctionForward(uint idx) { - Texture2D<float4> tex = gTex1; - return Pass_Level1(tex, uv); + RWByteAddressBuffer buf = gBuf1; + return Pass_Level1(buf, idx); } - - -//-------------------------------------------------------------- // PASS 18 -// Resource merge via conditional assignments -// (SSA-style PHI equivalent) -//-------------------------------------------------------------- - -float4 Pass_PhiMerge(bool cond, float2 uv) +uint Pass_PhiMerge(bool cond, uint idx) { - Texture2D<float4> tex; - - if(cond) - tex = gTex0; - else - tex = gTex2; - - return tex.Sample(gSampler, uv); + RWByteAddressBuffer buf; + // expected-warning@+1{{assignment of 'cond ? gBuf0 : gBuf2' to local resource 'buf' is not to the same unique global resource}} + buf = cond ? gBuf0 : gBuf2; + return DoStore(buf, idx * 4, 18); } - - -//-------------------------------------------------------------- // PASS 19 -// Nested scope shadowing -//-------------------------------------------------------------- - -float4 Pass_Shadow(float2 uv) +uint Pass_Shadow(uint idx) { - Texture2D<float4> tex = gTex0; - + RWByteAddressBuffer buf = gBuf0; { - Texture2D<float4> tex = gTex1; - return tex.Sample(gSampler, uv); + RWByteAddressBuffer buf = gBuf1; + return DoStore(buf, idx * 4, 19); } } - - -//-------------------------------------------------------------- // PASS 20 -// Resource in switch -//-------------------------------------------------------------- - -float4 Pass_Switch(int v, float2 uv) +uint Pass_Switch(int v, uint idx) { - Texture2D<float4> tex = gTex0; + // expected-note@+2{{variable 'buf' is declared here}} + // expected-note@+1{{variable 'buf' is declared here}} + RWByteAddressBuffer buf = gBuf0; switch(v) { - case 1: tex = gTex1; break; - case 2: tex = gTex2; break; + // expected-warning@+1{{assignment of 'gBuf1' to local resource 'buf' is not to the same unique global resource}} + case 1: buf = gBuf1; break; + // expected-warning@+1{{assignment of 'gBuf2' to local resource 'buf' is not to the same unique global resource}} + case 2: buf = gBuf2; break; } - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 20); } - - -//-------------------------------------------------------------- // PASS 21 -// Bindless descriptor indexing -//-------------------------------------------------------------- - -float4 Pass_Bindless(uint idx, float2 uv) +uint Pass_Bindless(uint idx) { - Texture2D<float4> tex = gTexArray[idx]; - return tex.Sample(gSampler, uv); + RWByteAddressBuffer buf = gBufArray[idx & 3]; + return DoStore(buf, idx * 4, 21); } - - -//-------------------------------------------------------------- // PASS 22 -// Resource with wave operations -//-------------------------------------------------------------- - -float4 Pass_WaveUse(float2 uv) +uint Pass_WaveUse(uint idx) { - Texture2D<float4> tex = gTex0; - - float4 v = tex.Sample(gSampler, uv); - + RWByteAddressBuffer buf = gBuf0; uint active = WaveActiveCountBits(true); - - return v * active; + return DoStore(buf, idx * 4, active); } - - -//-------------------------------------------------------------- // PASS 23 -// Resource alias used inside nested loops -//-------------------------------------------------------------- - -float4 Pass_NestedLoops(float2 uv) -{ - float4 sum = 0; - - for(int i=0;i<2;i++) - for(int j=0;j<2;j++) - { - Texture2D<float4> tex = gTexArray[i+j]; - sum += tex.Sample(gSampler, uv); +uint Pass_NestedLoops(uint idx) +{ + uint sum = 0; + for(unsigned int i=0;i<2;i++) + for(unsigned int j=0;j<2;j++) + { + RWByteAddressBuffer buf = gBufArray[i+j]; + sum += DoStore(buf, idx * 4 + (i+j)*4, 23); } - return sum; } - - -//-------------------------------------------------------------- // PASS 24 -// Resource lifetime across blocks -//-------------------------------------------------------------- - -float4 Pass_BlockLifetime(float2 uv) +uint Pass_BlockLifetime(uint idx) { - Texture2D<float4> tex; - + RWByteAddressBuffer buf; { - tex = gTex1; + buf = gBuf1; } - - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 24); } - -//-------------------------------------------------------------- // PASS 25 -// Deep nested PHI merges -//-------------------------------------------------------------- - -float4 Pass_DeepPhi(bool a, bool b, float2 uv) +uint Pass_DeepPhi(bool a, bool b, uint idx) { - Texture2D<float4> tex; + RWByteAddressBuffer buf; if(a) - { - if(b) - tex = gTex0; - else - tex = gTex1; - } + // expected-warning@+1{{assignment of 'b ? gBuf0 : gBuf1' to local resource 'buf' is not to the same unique global resource}} + buf = b ? gBuf0 : gBuf1; else - { - tex = gTex2; - } + buf = gBuf2; - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 25); } - - -//-------------------------------------------------------------- // PASS 26 -// Loop-carried resource value -//-------------------------------------------------------------- - -float4 Pass_LoopCarried(int iterations, float2 uv) +uint Pass_LoopCarried(int iterations, uint idx) { - Texture2D<float4> tex = gTex0; + // expected-note@+1{{variable 'buf' is declared here}} + RWByteAddressBuffer buf = gBuf0; for(int i=0;i<iterations;i++) - { - tex = gTexArray[i & 3]; - } + // expected-warning@+1{{assignment of 'gBufArray[i & 3]' to local resource 'buf' is not to the same unique global resource}} + buf = gBufArray[i & 3]; - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 26); } - - -//-------------------------------------------------------------- // PASS 27 -// Resource alias chain -//-------------------------------------------------------------- - -float4 Pass_AliasChain(float2 uv) +uint Pass_AliasChain(uint idx) { - Texture2D<float4> a = gTex0; - Texture2D<float4> b = a; - Texture2D<float4> c = b; + RWByteAddressBuffer a = gBuf0; + RWByteAddressBuffer b = a; + RWByteAddressBuffer c = b; - return c.Sample(gSampler, uv); + return DoStore(c, idx * 4, 27); } - - -//-------------------------------------------------------------- // PASS 28 -// Resource inside nested structs -//-------------------------------------------------------------- - -struct PassNestedInner -{ - Texture2D<float4> tex; -}; - -struct PassNestedOuter -{ - PassNestedInner inner; -}; +struct PassNestedInner { RWByteAddressBuffer buf; }; +struct PassNestedOuter { PassNestedInner inner; }; -float4 Pass_NestedStruct(float2 uv) +uint Pass_NestedStruct(uint idx) { PassNestedOuter s; - - s.inner.tex = gTex1; - - return s.inner.tex.Sample(gSampler, uv); + s.inner.buf = gBuf1; + return DoStore(s.inner.buf, idx * 4, 28); } - - -//-------------------------------------------------------------- // PASS 29 -// Resource forwarded through multiple struct layers -//-------------------------------------------------------------- - -struct PassForwardA { Texture2D<float4> tex; }; +struct PassForwardA { RWByteAddressBuffer buf; }; struct PassForwardB { PassForwardA a; }; -float4 Pass_ForwardStructLayers(float2 uv) +uint Pass_ForwardStructLayers(uint idx) { PassForwardB b; - b.a.tex = gTex2; - - return b.a.tex.Sample(gSampler, uv); + b.a.buf = gBuf2; + return DoStore(b.a.buf, idx * 4, 29); } - - -//-------------------------------------------------------------- // PASS 30 -// Resource alias inside switch fallthrough -//-------------------------------------------------------------- - -float4 Pass_SwitchFallthrough(int v, float2 uv) +uint Pass_SwitchFallthrough(int v, uint idx) { - Texture2D<float4> tex = gTex0; + // expected-note@+2{{variable 'buf' is declared here}} + // expected-note@+1{{variable 'buf' is declared here}} + RWByteAddressBuffer buf = gBuf0; switch(v) { - case 0: - tex = gTex1; - case 1: - tex = gTex2; - break; + // expected-warning@+1{{assignment of 'gBuf1' to local resource 'buf' is not to the same unique global resource}} + case 0: buf = gBuf1; + // expected-warning@+1{{assignment of 'gBuf2' to local resource 'buf' is not to the same unique global resource}} + case 1: buf = gBuf2; break; } - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 30); } - - -//-------------------------------------------------------------- // PASS 31 -// Resource used after early-return path merge -//-------------------------------------------------------------- - -float4 Pass_EarlyReturn(bool cond, float2 uv) +uint Pass_EarlyReturn(bool cond, uint idx) { - Texture2D<float4> tex = gTex0; + // expected-note@+1{{variable 'buf' is declared here}} + RWByteAddressBuffer buf = gBuf0; if(cond) - return tex.Sample(gSampler, uv); - - tex = gTex1; - - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 31); + // expected-warning@+1{{assignment of 'gBuf1' to local resource 'buf' is not to the same unique global resource}} + buf = gBuf1; + return DoStore(buf, idx * 4, 31); } - -//-------------------------------------------------------------- // PASS 32 -// Resource alias across nested blocks -//-------------------------------------------------------------- - -float4 Pass_NestedBlocks(float2 uv) +uint Pass_NestedBlocks(uint idx) { - Texture2D<float4> tex; + // expected-note@+1{{variable 'buf' is declared here}} + RWByteAddressBuffer buf; { - tex = gTex1; - + buf = gBuf1; { - tex = gTex2; + // expected-warning@+1{{assignment of 'gBuf2' to local resource 'buf' is not to the same unique global resource}} + buf = gBuf2; } } - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 32); } - - -//-------------------------------------------------------------- // PASS 33 -// Resource assigned via bindless selection -//-------------------------------------------------------------- - -float4 Pass_BindlessSelection(uint a, uint b, float2 uv) +uint Pass_BindlessSelection(uint a, uint b, uint idx) { - Texture2D<float4> tex; + RWByteAddressBuffer buf; - tex = gTexArray[a]; - tex = gTexArray[b]; + buf = gBufArray[a & 3]; + buf = gBufArray[b & 3]; - return tex.Sample(gSampler, uv); + return DoStore(buf, idx * 4, 33); } @@ -598,46 +391,46 @@ float4 Pass_BindlessSelection(uint a, uint b, float2 uv) // ENTRY POINT //============================================================== - [numthreads(8,8,1)] void main(uint3 tid : SV_DispatchThreadID) { - float2 uv = float2(tid.xy)/256.0; + uint idx = tid.x + tid.y * 8; + + uint r = 0; - float4 r = 0; - r += Pass_TernaryInit(true, uv); + r += Pass_TernaryInit(true, idx); Pass_LoopVar(); - r += Pass_ExpressionInit(uv); - r += Use_FailSharedStruct(uv); - r += Pass_StructArray(uv); - r += Use_Fail_Shared(uv); - Texture2D<float4> mytex = Fail_ReturnLocal_Uninitialized(); - Texture2D<float4> mytex2 = Fail_ReturnLocal(); - r += Pass_StructArray(uv); - r += Pass_LocalArray(uv); - r += Pass_Uninitialized(uv); - r += Pass_Alias(uv); - r += Pass_Reassign(uv); - r += Pass_IfAlias(true,uv); - r += Pass_Loop(uv); - r += Pass_Struct(uv); - r += Pass_FunctionForward(uv); - r += Pass_PhiMerge(true,uv); - r += Pass_Shadow(uv); - r += Pass_Switch(1,uv); - r += Pass_Bindless(0,uv); - r += Pass_WaveUse(uv); - r += Pass_NestedLoops(uv); - r += Pass_BlockLifetime(uv); - r += Pass_DeepPhi(true, false, uv); - r += Pass_LoopCarried(15, uv); - r += Pass_AliasChain(uv); - r += Pass_NestedStruct(uv); - r += Pass_ForwardStructLayers(uv); - r += Pass_SwitchFallthrough(0, uv); - r += Pass_EarlyReturn(true, uv); - r += Pass_NestedBlocks(uv); - r += Pass_BindlessSelection(2, 3, uv); - - gOut[tid.xy] = r; + r += Pass_ExpressionInit(idx); + r += Use_PassSharedStruct(idx); + r += Pass_StructArray(idx); + r += Use_Pass_Shared(idx); + RWByteAddressBuffer tmp0 = Pass_ReturnLocal_Uninitialized(); + RWByteAddressBuffer tmp1 = Pass_ReturnLocal(); + r += Pass_StructArray(idx); + r += Pass_LocalArray(idx); + r += Pass_Uninitialized(idx); + r += Pass_Alias(idx); + r += Pass_Reassign(idx); + r += Pass_IfAlias(true, idx); + r += Pass_Loop(idx); + r += Pass_Struct(idx); + r += Pass_FunctionForward(idx); + r += Pass_PhiMerge(true, idx); + r += Pass_Shadow(idx); + r += Pass_Switch(1, idx); + r += Pass_Bindless(idx); + r += Pass_WaveUse(idx); + r += Pass_NestedLoops(idx); + r += Pass_BlockLifetime(idx); + r += Pass_DeepPhi(true, false, idx); + r += Pass_LoopCarried(15, idx); + r += Pass_AliasChain(idx); + r += Pass_NestedStruct(idx); + r += Pass_ForwardStructLayers(idx); + r += Pass_SwitchFallthrough(0, idx); + r += Pass_EarlyReturn(true, idx); + r += Pass_NestedBlocks(idx); + r += Pass_BindlessSelection(2, 3, idx); + + gOut.Store(idx * 4, r); } \ No newline at end of file >From 9146bb048c6712faeb8113ab2b22051156a7f036 Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Mon, 30 Mar 2026 15:00:21 -0700 Subject: [PATCH 3/4] first test, failing --- .../Local-Resources/use_groupshared.hlsl | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 clang/test/SemaHLSL/Resources/Local-Resources/use_groupshared.hlsl diff --git a/clang/test/SemaHLSL/Resources/Local-Resources/use_groupshared.hlsl b/clang/test/SemaHLSL/Resources/Local-Resources/use_groupshared.hlsl new file mode 100644 index 0000000000000..16747acbc19ff --- /dev/null +++ b/clang/test/SemaHLSL/Resources/Local-Resources/use_groupshared.hlsl @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-compute %s -emit-llvm -verify + +RWByteAddressBuffer gOut : register(u3); + +uint DoStore(RWByteAddressBuffer buf, uint offset, uint value) +{ + buf.Store(offset, value); + return value; +} + +groupshared RWByteAddressBuffer sharedBuf; +uint Use_Shared(uint idx) +{ + return DoStore(sharedBuf, idx * 4, 1); +} + +[numthreads(8,8,1)] +void main(uint3 tid : SV_DispatchThreadID) +{ + uint idx = tid.x + tid.y * 8; + Use_Shared(idx); +} \ No newline at end of file >From 20646667ced7fb1a343b793e6c3b23f4075f7e4d Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Tue, 31 Mar 2026 12:04:50 -0700 Subject: [PATCH 4/4] checkpoint --- .../ternary_initialization.hlsl | 30 ++ .../Local-Resources/expression_init.hlsl | 28 ++ .../Local-Resources/expression_init.ll | 318 ++++++++++++++++++ .../Resources/Local-Resources/loop_var.hlsl | 23 ++ .../Local-Resources/use_groupshared.hlsl | 12 +- .../use_struct_groupshared.hlsl | 37 ++ .../Local-Resources/use_struct_groupshared.ll | 255 ++++++++++++++ .../Resources/local_resources_passes.hlsl | 31 -- 8 files changed, 701 insertions(+), 33 deletions(-) create mode 100644 clang/test/CodeGenHLSL/resources/Local-Resources/ternary_initialization.hlsl create mode 100644 clang/test/SemaHLSL/Resources/Local-Resources/expression_init.hlsl create mode 100644 clang/test/SemaHLSL/Resources/Local-Resources/expression_init.ll create mode 100644 clang/test/SemaHLSL/Resources/Local-Resources/loop_var.hlsl create mode 100644 clang/test/SemaHLSL/Resources/Local-Resources/use_struct_groupshared.hlsl create mode 100644 clang/test/SemaHLSL/Resources/Local-Resources/use_struct_groupshared.ll diff --git a/clang/test/CodeGenHLSL/resources/Local-Resources/ternary_initialization.hlsl b/clang/test/CodeGenHLSL/resources/Local-Resources/ternary_initialization.hlsl new file mode 100644 index 0000000000000..71da9d8e1af5b --- /dev/null +++ b/clang/test/CodeGenHLSL/resources/Local-Resources/ternary_initialization.hlsl @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-compute -emit-llvm -disable-llvm-passes 2>&1 -o - %s | llvm-cxxfilt | FileCheck %s + +// This test fails after verify. + +RWByteAddressBuffer gOut : register(u3); +RWByteAddressBuffer gBuf0 : register(u0); +RWByteAddressBuffer gBuf1 : register(u1); + +uint DoStore(RWByteAddressBuffer buf, uint offset, uint value) +{ + buf.Store(offset, value); + return value; +} + +uint Pass_TernaryInit(bool cond, uint idx) +{ + // DXC emits this warning: local resource not guaranteed to map to unique global resource. + // Below is generated by -Whlsl-explicit-binding + // CHECK: warning: assignment of 'cond ? gBuf0 : gBuf1' to local resource 'buf' is not to the same unique global resource + RWByteAddressBuffer buf = cond ? gBuf0 : gBuf1; + return DoStore(buf, idx * 4, 2); +} + +[numthreads(8,8,1)] +void main(uint3 tid : SV_DispatchThreadID) +{ + uint idx = tid.x + tid.y * 8; + Pass_TernaryInit(idx < 32, idx); +} \ No newline at end of file diff --git a/clang/test/SemaHLSL/Resources/Local-Resources/expression_init.hlsl b/clang/test/SemaHLSL/Resources/Local-Resources/expression_init.hlsl new file mode 100644 index 0000000000000..3480b5f65a82e --- /dev/null +++ b/clang/test/SemaHLSL/Resources/Local-Resources/expression_init.hlsl @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-compute %s -emit-llvm -verify + +// expected-no-diagnostics + +RWByteAddressBuffer gBuf0 : register(u0); +RWByteAddressBuffer gBuf1 : register(u1); + +RWByteAddressBuffer gOut : register(u3); + +uint DoStore(RWByteAddressBuffer buf, uint offset, uint value) +{ + buf.Store(offset, value); + return value; +} + +uint Pass_ExpressionInit(uint idx) +{ + RWByteAddressBuffer buf = (true ? gBuf0 : gBuf1); + return DoStore(buf, idx * 4, 3); +} + +[numthreads(8,8,1)] +void main(uint3 tid : SV_DispatchThreadID) +{ + uint idx = tid.x + tid.y * 8; + Pass_ExpressionInit(idx); +} \ No newline at end of file diff --git a/clang/test/SemaHLSL/Resources/Local-Resources/expression_init.ll b/clang/test/SemaHLSL/Resources/Local-Resources/expression_init.ll new file mode 100644 index 0000000000000..0ff7f24d7fefe --- /dev/null +++ b/clang/test/SemaHLSL/Resources/Local-Resources/expression_init.ll @@ -0,0 +1,318 @@ +; ModuleID = 'D:\llvm-project\clang\test\SemaHLSL\Resources\Local-Resources\expression_init.hlsl' +source_filename = "D:\\llvm-project\\clang\\test\\SemaHLSL\\Resources\\Local-Resources\\expression_init.hlsl" +target datalayout = "e-m:e-ve-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64" +target triple = "dxilv1.6-pc-shadermodel6.6-compute" + +%"class.hlsl::RWByteAddressBuffer" = type { target("dx.RawBuffer", i8, 1, 0) } + +@_ZL5gBuf0 = internal global %"class.hlsl::RWByteAddressBuffer" poison, align 4 [email protected] = private unnamed_addr constant [6 x i8] c"gBuf0\00", align 1 +@_ZL5gBuf1 = internal global %"class.hlsl::RWByteAddressBuffer" poison, align 4 [email protected] = private unnamed_addr constant [6 x i8] c"gBuf1\00", align 1 +@_ZL4gOut = internal global %"class.hlsl::RWByteAddressBuffer" poison, align 4 [email protected] = private unnamed_addr constant [5 x i8] c"gOut\00", align 1 + +; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind +define hidden noundef i32 @_Z7DoStoreN4hlsl19RWByteAddressBufferEjj(ptr noundef byval(%"class.hlsl::RWByteAddressBuffer") align 4 %buf, i32 noundef %offset, i32 noundef %value) #0 { +entry: + %this.addr.i = alloca ptr, align 4 + %Index.addr.i = alloca i32, align 4 + %Value.addr.i = alloca i32, align 4 + %offset.addr = alloca i32, align 4 + %value.addr = alloca i32, align 4 + store i32 %offset, ptr %offset.addr, align 4 + store i32 %value, ptr %value.addr, align 4 + %0 = load i32, ptr %offset.addr, align 4 + %1 = load i32, ptr %value.addr, align 4 + store ptr %buf, ptr %this.addr.i, align 4 + store i32 %0, ptr %Index.addr.i, align 4 + store i32 %1, ptr %Value.addr.i, align 4 + %this1.i = load ptr, ptr %this.addr.i, align 4 + %2 = load i32, ptr %Value.addr.i, align 4 + %3 = load target("dx.RawBuffer", i8, 1, 0), ptr %this1.i, align 4 + %4 = load i32, ptr %Index.addr.i, align 4 + %5 = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %3, i32 %4) + store i32 %2, ptr %5, align 4 + %6 = load i32, ptr %value.addr, align 4 + ret i32 %6 +} + +; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind +define hidden noundef i32 @_Z19Pass_ExpressionInitj(i32 noundef %idx) #0 { +entry: + %this.addr.i10 = alloca ptr, align 4 + %other.addr.i11 = alloca ptr, align 4 + %this.addr.i7 = alloca ptr, align 4 + %other.addr.i8 = alloca ptr, align 4 + %this.addr.i4 = alloca ptr, align 4 + %other.addr.i5 = alloca ptr, align 4 + %this.addr.i2 = alloca ptr, align 4 + %other.addr.i = alloca ptr, align 4 + %this.addr.i = alloca ptr, align 4 + %Index.addr.i = alloca i32, align 4 + %Value.addr.i = alloca i32, align 4 + %offset.addr.i = alloca i32, align 4 + %value.addr.i = alloca i32, align 4 + %agg.tmp1 = alloca %"class.hlsl::RWByteAddressBuffer", align 8 + %idx.addr = alloca i32, align 4 + %buf = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %agg.tmp = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + store i32 %idx, ptr %idx.addr, align 4 + store ptr %buf, ptr %this.addr.i4, align 4 + store ptr @_ZL5gBuf0, ptr %other.addr.i5, align 4 + %this1.i6 = load ptr, ptr %this.addr.i4, align 4 + %0 = load ptr, ptr %other.addr.i5, align 4 + store ptr %this1.i6, ptr %this.addr.i7, align 4 + store ptr %0, ptr %other.addr.i8, align 4 + %this1.i9 = load ptr, ptr %this.addr.i7, align 4 + %1 = load ptr, ptr %other.addr.i8, align 4, !nonnull !3, !align !4 + %2 = load target("dx.RawBuffer", i8, 1, 0), ptr %1, align 4 + store target("dx.RawBuffer", i8, 1, 0) %2, ptr %this1.i9, align 4 + store ptr %agg.tmp, ptr %this.addr.i2, align 4 + store ptr %buf, ptr %other.addr.i, align 4 + %this1.i3 = load ptr, ptr %this.addr.i2, align 4 + %3 = load ptr, ptr %other.addr.i, align 4 + store ptr %this1.i3, ptr %this.addr.i10, align 4 + store ptr %3, ptr %other.addr.i11, align 4 + %this1.i12 = load ptr, ptr %this.addr.i10, align 4 + %4 = load ptr, ptr %other.addr.i11, align 4, !nonnull !3, !align !4 + %5 = load target("dx.RawBuffer", i8, 1, 0), ptr %4, align 4 + store target("dx.RawBuffer", i8, 1, 0) %5, ptr %this1.i12, align 4 + %6 = load i32, ptr %idx.addr, align 4 + %mul = mul i32 %6, 4 + call void @llvm.memcpy.p0.p0.i64(ptr align 8 %agg.tmp1, ptr align 4 %agg.tmp, i64 4, i1 false) + store i32 %mul, ptr %offset.addr.i, align 4 + store i32 3, ptr %value.addr.i, align 4 + %7 = load i32, ptr %offset.addr.i, align 4 + %8 = load i32, ptr %value.addr.i, align 4 + store ptr %agg.tmp1, ptr %this.addr.i, align 4 + store i32 %7, ptr %Index.addr.i, align 4 + store i32 %8, ptr %Value.addr.i, align 4 + %this1.i = load ptr, ptr %this.addr.i, align 4 + %9 = load i32, ptr %Value.addr.i, align 4 + %10 = load target("dx.RawBuffer", i8, 1, 0), ptr %this1.i, align 4 + %11 = load i32, ptr %Index.addr.i, align 4 + %12 = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %10, i32 %11) + store i32 %9, ptr %12, align 4 + %13 = load i32, ptr %value.addr.i, align 4 + ret i32 %13 +} + +; Function Attrs: convergent noinline norecurse +define void @main() #1 { +entry: + %this.addr.i19.i = alloca ptr, align 4 + %other.addr.i20.i = alloca ptr, align 4 + %this.addr.i16.i = alloca ptr, align 4 + %other.addr.i17.i = alloca ptr, align 4 + %this.addr.i13.i = alloca ptr, align 4 + %other.addr.i14.i = alloca ptr, align 4 + %this.addr.i10.i = alloca ptr, align 4 + %other.addr.i11.i = alloca ptr, align 4 + %this.addr.i7.i = alloca ptr, align 4 + %other.addr.i8.i = alloca ptr, align 4 + %this.addr.i.i4 = alloca ptr, align 4 + %other.addr.i.i5 = alloca ptr, align 4 + %registerNo.addr.i.i1.i = alloca i32, align 4 + %spaceNo.addr.i.i2.i = alloca i32, align 4 + %range.addr.i.i3.i = alloca i32, align 4 + %index.addr.i.i4.i = alloca i32, align 4 + %name.addr.i.i5.i = alloca ptr, align 4 + %tmp.i.i6.i = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %registerNo.addr.i.i.i = alloca i32, align 4 + %spaceNo.addr.i.i.i = alloca i32, align 4 + %range.addr.i.i.i = alloca i32, align 4 + %index.addr.i.i.i = alloca i32, align 4 + %name.addr.i.i.i = alloca ptr, align 4 + %tmp.i.i.i = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %registerNo.addr.i.i = alloca i32, align 4 + %spaceNo.addr.i.i = alloca i32, align 4 + %range.addr.i.i = alloca i32, align 4 + %index.addr.i.i = alloca i32, align 4 + %name.addr.i.i = alloca ptr, align 4 + %tmp.i.i = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %this.addr.i1 = alloca ptr, align 4 + %other.addr.i2 = alloca ptr, align 4 + %this.addr.i = alloca ptr, align 4 + %other.addr.i = alloca ptr, align 4 + %this.addr.i1.i = alloca ptr, align 4 + %other.addr.i2.i = alloca ptr, align 4 + %this.addr.i.i = alloca ptr, align 4 + %other.addr.i.i = alloca ptr, align 4 + %this.addr.i.i.i = alloca ptr, align 4 + %Index.addr.i.i.i = alloca i32, align 4 + %Value.addr.i.i.i = alloca i32, align 4 + %offset.addr.i.i.i = alloca i32, align 4 + %value.addr.i.i.i = alloca i32, align 4 + %agg.tmp1.i.i = alloca %"class.hlsl::RWByteAddressBuffer", align 8 + %idx.addr.i.i = alloca i32, align 4 + %buf.i.i = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %agg.tmp.i.i = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %tid.addr.i = alloca <3 x i32>, align 4 + %idx.i = alloca i32, align 4 + call void @llvm.experimental.noalias.scope.decl(metadata !5) + store i32 0, ptr %registerNo.addr.i.i, align 4, !noalias !5 + store i32 0, ptr %spaceNo.addr.i.i, align 4, !noalias !5 + store i32 1, ptr %range.addr.i.i, align 4, !noalias !5 + store i32 0, ptr %index.addr.i.i, align 4, !noalias !5 + store ptr @.str, ptr %name.addr.i.i, align 4, !noalias !5 + %0 = load i32, ptr %registerNo.addr.i.i, align 4, !noalias !5 + %1 = load i32, ptr %spaceNo.addr.i.i, align 4, !noalias !5 + %2 = load i32, ptr %range.addr.i.i, align 4, !noalias !5 + %3 = load i32, ptr %index.addr.i.i, align 4, !noalias !5 + %4 = load ptr, ptr %name.addr.i.i, align 4, !noalias !5 + %5 = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 %1, i32 %0, i32 %2, i32 %3, ptr %4) + store target("dx.RawBuffer", i8, 1, 0) %5, ptr %tmp.i.i, align 4, !noalias !5 + store ptr @_ZL5gBuf0, ptr %this.addr.i10.i, align 4 + store ptr %tmp.i.i, ptr %other.addr.i11.i, align 4 + %this1.i12.i = load ptr, ptr %this.addr.i10.i, align 4 + %6 = load ptr, ptr %other.addr.i11.i, align 4 + store ptr %this1.i12.i, ptr %this.addr.i13.i, align 4 + store ptr %6, ptr %other.addr.i14.i, align 4 + %this1.i15.i = load ptr, ptr %this.addr.i13.i, align 4 + %7 = load ptr, ptr %other.addr.i14.i, align 4, !nonnull !3, !align !4 + %8 = load target("dx.RawBuffer", i8, 1, 0), ptr %7, align 4 + store target("dx.RawBuffer", i8, 1, 0) %8, ptr %this1.i15.i, align 4 + call void @llvm.experimental.noalias.scope.decl(metadata !8) + store i32 1, ptr %registerNo.addr.i.i.i, align 4, !noalias !8 + store i32 0, ptr %spaceNo.addr.i.i.i, align 4, !noalias !8 + store i32 1, ptr %range.addr.i.i.i, align 4, !noalias !8 + store i32 0, ptr %index.addr.i.i.i, align 4, !noalias !8 + store ptr @.str.2, ptr %name.addr.i.i.i, align 4, !noalias !8 + %9 = load i32, ptr %registerNo.addr.i.i.i, align 4, !noalias !8 + %10 = load i32, ptr %spaceNo.addr.i.i.i, align 4, !noalias !8 + %11 = load i32, ptr %range.addr.i.i.i, align 4, !noalias !8 + %12 = load i32, ptr %index.addr.i.i.i, align 4, !noalias !8 + %13 = load ptr, ptr %name.addr.i.i.i, align 4, !noalias !8 + %14 = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 %10, i32 %9, i32 %11, i32 %12, ptr %13) + store target("dx.RawBuffer", i8, 1, 0) %14, ptr %tmp.i.i.i, align 4, !noalias !8 + store ptr @_ZL5gBuf1, ptr %this.addr.i7.i, align 4 + store ptr %tmp.i.i.i, ptr %other.addr.i8.i, align 4 + %this1.i9.i = load ptr, ptr %this.addr.i7.i, align 4 + %15 = load ptr, ptr %other.addr.i8.i, align 4 + store ptr %this1.i9.i, ptr %this.addr.i16.i, align 4 + store ptr %15, ptr %other.addr.i17.i, align 4 + %this1.i18.i = load ptr, ptr %this.addr.i16.i, align 4 + %16 = load ptr, ptr %other.addr.i17.i, align 4, !nonnull !3, !align !4 + %17 = load target("dx.RawBuffer", i8, 1, 0), ptr %16, align 4 + store target("dx.RawBuffer", i8, 1, 0) %17, ptr %this1.i18.i, align 4 + call void @llvm.experimental.noalias.scope.decl(metadata !11) + store i32 3, ptr %registerNo.addr.i.i1.i, align 4, !noalias !11 + store i32 0, ptr %spaceNo.addr.i.i2.i, align 4, !noalias !11 + store i32 1, ptr %range.addr.i.i3.i, align 4, !noalias !11 + store i32 0, ptr %index.addr.i.i4.i, align 4, !noalias !11 + store ptr @.str.4, ptr %name.addr.i.i5.i, align 4, !noalias !11 + %18 = load i32, ptr %registerNo.addr.i.i1.i, align 4, !noalias !11 + %19 = load i32, ptr %spaceNo.addr.i.i2.i, align 4, !noalias !11 + %20 = load i32, ptr %range.addr.i.i3.i, align 4, !noalias !11 + %21 = load i32, ptr %index.addr.i.i4.i, align 4, !noalias !11 + %22 = load ptr, ptr %name.addr.i.i5.i, align 4, !noalias !11 + %23 = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 %19, i32 %18, i32 %20, i32 %21, ptr %22) + store target("dx.RawBuffer", i8, 1, 0) %23, ptr %tmp.i.i6.i, align 4, !noalias !11 + store ptr @_ZL4gOut, ptr %this.addr.i.i4, align 4 + store ptr %tmp.i.i6.i, ptr %other.addr.i.i5, align 4 + %this1.i.i6 = load ptr, ptr %this.addr.i.i4, align 4 + %24 = load ptr, ptr %other.addr.i.i5, align 4 + store ptr %this1.i.i6, ptr %this.addr.i19.i, align 4 + store ptr %24, ptr %other.addr.i20.i, align 4 + %this1.i21.i = load ptr, ptr %this.addr.i19.i, align 4 + %25 = load ptr, ptr %other.addr.i20.i, align 4, !nonnull !3, !align !4 + %26 = load target("dx.RawBuffer", i8, 1, 0), ptr %25, align 4 + store target("dx.RawBuffer", i8, 1, 0) %26, ptr %this1.i21.i, align 4 + %27 = call i32 @llvm.dx.thread.id(i32 0) + %28 = insertelement <3 x i32> poison, i32 %27, i64 0 + %29 = call i32 @llvm.dx.thread.id(i32 1) + %30 = insertelement <3 x i32> %28, i32 %29, i64 1 + %31 = call i32 @llvm.dx.thread.id(i32 2) + %32 = insertelement <3 x i32> %30, i32 %31, i64 2 + store <3 x i32> %32, ptr %tid.addr.i, align 4 + %33 = load <3 x i32>, ptr %tid.addr.i, align 4 + %34 = extractelement <3 x i32> %33, i32 0 + %35 = load <3 x i32>, ptr %tid.addr.i, align 4 + %36 = extractelement <3 x i32> %35, i32 1 + %mul.i = mul i32 %36, 8 + %add.i = add i32 %34, %mul.i + store i32 %add.i, ptr %idx.i, align 4 + %37 = load i32, ptr %idx.i, align 4 + store i32 %37, ptr %idx.addr.i.i, align 4 + store ptr %buf.i.i, ptr %this.addr.i1.i, align 4 + store ptr @_ZL5gBuf0, ptr %other.addr.i2.i, align 4 + %this1.i3.i = load ptr, ptr %this.addr.i1.i, align 4 + %38 = load ptr, ptr %other.addr.i2.i, align 4 + store ptr %this1.i3.i, ptr %this.addr.i1, align 4 + store ptr %38, ptr %other.addr.i2, align 4 + %this1.i3 = load ptr, ptr %this.addr.i1, align 4 + %39 = load ptr, ptr %other.addr.i2, align 4, !nonnull !3, !align !4 + %40 = load target("dx.RawBuffer", i8, 1, 0), ptr %39, align 4 + store target("dx.RawBuffer", i8, 1, 0) %40, ptr %this1.i3, align 4 + store ptr %agg.tmp.i.i, ptr %this.addr.i.i, align 4 + store ptr %buf.i.i, ptr %other.addr.i.i, align 4 + %this1.i.i = load ptr, ptr %this.addr.i.i, align 4 + %41 = load ptr, ptr %other.addr.i.i, align 4 + store ptr %this1.i.i, ptr %this.addr.i, align 4 + store ptr %41, ptr %other.addr.i, align 4 + %this1.i = load ptr, ptr %this.addr.i, align 4 + %42 = load ptr, ptr %other.addr.i, align 4, !nonnull !3, !align !4 + %43 = load target("dx.RawBuffer", i8, 1, 0), ptr %42, align 4 + store target("dx.RawBuffer", i8, 1, 0) %43, ptr %this1.i, align 4 + %44 = load i32, ptr %idx.addr.i.i, align 4 + %mul.i.i = mul i32 %44, 4 + call void @llvm.memcpy.p0.p0.i64(ptr align 8 %agg.tmp1.i.i, ptr align 4 %agg.tmp.i.i, i64 4, i1 false) + store i32 %mul.i.i, ptr %offset.addr.i.i.i, align 4 + store i32 3, ptr %value.addr.i.i.i, align 4 + %45 = load i32, ptr %offset.addr.i.i.i, align 4 + %46 = load i32, ptr %value.addr.i.i.i, align 4 + store ptr %agg.tmp1.i.i, ptr %this.addr.i.i.i, align 4 + store i32 %45, ptr %Index.addr.i.i.i, align 4 + store i32 %46, ptr %Value.addr.i.i.i, align 4 + %this1.i.i.i = load ptr, ptr %this.addr.i.i.i, align 4 + %47 = load i32, ptr %Value.addr.i.i.i, align 4 + %48 = load target("dx.RawBuffer", i8, 1, 0), ptr %this1.i.i.i, align 4 + %49 = load i32, ptr %Index.addr.i.i.i, align 4 + %50 = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %48, i32 %49) + store i32 %47, ptr %50, align 4 + %51 = load i32, ptr %value.addr.i.i.i, align 4 + ret void +} + +; Function Attrs: nounwind willreturn memory(none) +declare i32 @llvm.dx.thread.id(i32) #2 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none) +declare target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32, i32, i32, i32, ptr) #3 + +; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none) +declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0), i32) #4 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) +declare void @llvm.experimental.noalias.scope.decl(metadata) #5 + +; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) +declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #6 + +attributes #0 = { alwaysinline convergent mustprogress norecurse nounwind "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { convergent noinline norecurse "hlsl.numthreads"="8,8,1" "hlsl.shader"="compute" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { nounwind willreturn memory(none) } +attributes #3 = { nocallback nofree nosync nounwind willreturn memory(none) } +attributes #4 = { convergent nocallback nofree nosync nounwind willreturn memory(none) } +attributes #5 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) } +attributes #6 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } + +!dx.valver = !{!0} +!llvm.module.flags = !{!1} +!llvm.ident = !{!2} + +!0 = !{i32 1, i32 8} +!1 = !{i32 4, !"dx.disable_optimizations", i32 1} +!2 = !{!"clang version 23.0.0git (https://github.com/llvm/llvm-project.git b084fa7a5172e2502324f9df2723e22dad071e3a)"} +!3 = !{} +!4 = !{i64 4} +!5 = !{!6} +!6 = distinct !{!6, !7, !"_ZN4hlsl19RWByteAddressBuffer19__createFromBindingEjjijPKc: %agg.result"} +!7 = distinct !{!7, !"_ZN4hlsl19RWByteAddressBuffer19__createFromBindingEjjijPKc"} +!8 = !{!9} +!9 = distinct !{!9, !10, !"_ZN4hlsl19RWByteAddressBuffer19__createFromBindingEjjijPKc: %agg.result"} +!10 = distinct !{!10, !"_ZN4hlsl19RWByteAddressBuffer19__createFromBindingEjjijPKc"} +!11 = !{!12} +!12 = distinct !{!12, !13, !"_ZN4hlsl19RWByteAddressBuffer19__createFromBindingEjjijPKc: %agg.result"} +!13 = distinct !{!13, !"_ZN4hlsl19RWByteAddressBuffer19__createFromBindingEjjijPKc"} diff --git a/clang/test/SemaHLSL/Resources/Local-Resources/loop_var.hlsl b/clang/test/SemaHLSL/Resources/Local-Resources/loop_var.hlsl new file mode 100644 index 0000000000000..71d1a1b4302b0 --- /dev/null +++ b/clang/test/SemaHLSL/Resources/Local-Resources/loop_var.hlsl @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-compute %s -emit-llvm -verify + +// expected-no-diagnostics + +RWByteAddressBuffer gBuf0 : register(u0); + +RWByteAddressBuffer gOut : register(u3); + +void Pass_LoopVar() +{ + for(RWByteAddressBuffer buf = gBuf0; false == false; ) + { + buf.Store(0, 0); + break; + } +} + +[numthreads(8,8,1)] +void main(uint3 tid : SV_DispatchThreadID) +{ + Pass_LoopVar(); +} \ No newline at end of file diff --git a/clang/test/SemaHLSL/Resources/Local-Resources/use_groupshared.hlsl b/clang/test/SemaHLSL/Resources/Local-Resources/use_groupshared.hlsl index 16747acbc19ff..1c6d0f9e35f0a 100644 --- a/clang/test/SemaHLSL/Resources/Local-Resources/use_groupshared.hlsl +++ b/clang/test/SemaHLSL/Resources/Local-Resources/use_groupshared.hlsl @@ -1,17 +1,25 @@ // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ // RUN: dxil-pc-shadermodel6.6-compute %s -emit-llvm -verify +// This test fails validation in DXC, but DXC's sema allows it. +// Meanwhile, groupshared is immediately detected and rejected in clang's sema. + RWByteAddressBuffer gOut : register(u3); +// expected-note@+1{{passing argument to parameter 'buf' here}} uint DoStore(RWByteAddressBuffer buf, uint offset, uint value) { buf.Store(offset, value); return value; } +// expected-note@*:*{{candidate constructor not viable: cannot bind reference in address space 'groupshared' to object in generic address space in 1st argument}} +// expected-note@*:*{{candidate constructor not viable: requires 0 arguments, but 1 was provided}} + groupshared RWByteAddressBuffer sharedBuf; uint Use_Shared(uint idx) { + // expected-error@+1{{no matching constructor for initialization of 'RWByteAddressBuffer'}} return DoStore(sharedBuf, idx * 4, 1); } @@ -19,5 +27,5 @@ uint Use_Shared(uint idx) void main(uint3 tid : SV_DispatchThreadID) { uint idx = tid.x + tid.y * 8; - Use_Shared(idx); -} \ No newline at end of file + Use_Shared(idx); +} diff --git a/clang/test/SemaHLSL/Resources/Local-Resources/use_struct_groupshared.hlsl b/clang/test/SemaHLSL/Resources/Local-Resources/use_struct_groupshared.hlsl new file mode 100644 index 0000000000000..3f47ae6db82c6 --- /dev/null +++ b/clang/test/SemaHLSL/Resources/Local-Resources/use_struct_groupshared.hlsl @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-compute %s -emit-llvm -verify + +// This test fails validation in DXC, but DXC's sema allows it. +// Meanwhile, it is for some reason accepted by clang's sema. +// TODO: Why does this pass clang's sema, but use_groupshared.hlsl fails clang's sema? +// Run a git bisect on https://github.com/llvm/llvm-project/issues/158107, and figure +// out which commit seemed to resolve this issue. + +RWByteAddressBuffer gOut : register(u3); + +// expected-note@+1{{passing argument to parameter 'buf' here}} +uint DoStore(RWByteAddressBuffer buf, uint offset, uint value) +{ + buf.Store(offset, value); + return value; +} + +// expected-note@*:*{{candidate constructor not viable: cannot bind reference in address space 'groupshared' to object in generic address space in 1st argument}} +// expected-note@*:*{{candidate constructor not viable: requires 0 arguments, but 1 was provided}} + +struct PassBufStruct { RWByteAddressBuffer buf; }; + +groupshared PassBufStruct sharedStruct; + +uint Use_PassSharedStruct(uint idx) +{ + // expected-error@+1{{no matching constructor for initialization of 'RWByteAddressBuffer'}} + return DoStore(sharedStruct.buf, idx * 4, 1); +} + +[numthreads(8,8,1)] +void main(uint3 tid : SV_DispatchThreadID) +{ + uint idx = tid.x + tid.y * 8; + Use_PassSharedStruct(idx); +} diff --git a/clang/test/SemaHLSL/Resources/Local-Resources/use_struct_groupshared.ll b/clang/test/SemaHLSL/Resources/Local-Resources/use_struct_groupshared.ll new file mode 100644 index 0000000000000..b84ac5379905c --- /dev/null +++ b/clang/test/SemaHLSL/Resources/Local-Resources/use_struct_groupshared.ll @@ -0,0 +1,255 @@ +; ModuleID = 'D:\llvm-project\clang\test\SemaHLSL\Resources\Local-Resources\use_struct_groupshared.hlsl' +source_filename = "D:\\llvm-project\\clang\\test\\SemaHLSL\\Resources\\Local-Resources\\use_struct_groupshared.hlsl" +target datalayout = "e-m:e-ve-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64" +target triple = "dxilv1.6-pc-shadermodel6.6-compute" + +%"class.hlsl::RWByteAddressBuffer" = type { target("dx.RawBuffer", i8, 1, 0) } +%struct.PassBufStruct = type { %"class.hlsl::RWByteAddressBuffer" } + +@_ZL4gOut = internal global %"class.hlsl::RWByteAddressBuffer" poison, align 4 [email protected] = private unnamed_addr constant [5 x i8] c"gOut\00", align 1 +@_ZL16sharedStruct.buf = internal global %"class.hlsl::RWByteAddressBuffer" poison, align 4 [email protected] = private unnamed_addr constant [17 x i8] c"sharedStruct.buf\00", align 1 +@sharedStruct = external hidden addrspace(3) global %struct.PassBufStruct, align 4 + +; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind +define hidden noundef i32 @_Z7DoStoreN4hlsl19RWByteAddressBufferEjj(ptr noundef byval(%"class.hlsl::RWByteAddressBuffer") align 4 %buf, i32 noundef %offset, i32 noundef %value) #0 { +entry: + %this.addr.i = alloca ptr, align 4 + %Index.addr.i = alloca i32, align 4 + %Value.addr.i = alloca i32, align 4 + %offset.addr = alloca i32, align 4 + %value.addr = alloca i32, align 4 + store i32 %offset, ptr %offset.addr, align 4 + store i32 %value, ptr %value.addr, align 4 + %0 = load i32, ptr %offset.addr, align 4 + %1 = load i32, ptr %value.addr, align 4 + store ptr %buf, ptr %this.addr.i, align 4 + store i32 %0, ptr %Index.addr.i, align 4 + store i32 %1, ptr %Value.addr.i, align 4 + %this1.i = load ptr, ptr %this.addr.i, align 4 + %2 = load i32, ptr %Value.addr.i, align 4 + %3 = load target("dx.RawBuffer", i8, 1, 0), ptr %this1.i, align 4 + %4 = load i32, ptr %Index.addr.i, align 4 + %5 = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %3, i32 %4) + store i32 %2, ptr %5, align 4 + %6 = load i32, ptr %value.addr, align 4 + ret i32 %6 +} + +; Function Attrs: alwaysinline convergent mustprogress norecurse nounwind +define hidden noundef i32 @_Z20Use_PassSharedStructj(i32 noundef %idx) #0 { +entry: + %this.addr.i4 = alloca ptr, align 4 + %other.addr.i5 = alloca ptr, align 4 + %this.addr.i2 = alloca ptr, align 4 + %other.addr.i = alloca ptr, align 4 + %this.addr.i = alloca ptr, align 4 + %Index.addr.i = alloca i32, align 4 + %Value.addr.i = alloca i32, align 4 + %offset.addr.i = alloca i32, align 4 + %value.addr.i = alloca i32, align 4 + %agg.tmp1 = alloca %"class.hlsl::RWByteAddressBuffer", align 8 + %idx.addr = alloca i32, align 4 + %agg.tmp = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + store i32 %idx, ptr %idx.addr, align 4 + store ptr %agg.tmp, ptr %this.addr.i2, align 4 + store ptr addrspacecast (ptr addrspace(3) @sharedStruct to ptr), ptr %other.addr.i, align 4 + %this1.i3 = load ptr, ptr %this.addr.i2, align 4 + %0 = load ptr, ptr %other.addr.i, align 4 + store ptr %this1.i3, ptr %this.addr.i4, align 4 + store ptr %0, ptr %other.addr.i5, align 4 + %this1.i6 = load ptr, ptr %this.addr.i4, align 4 + %1 = load ptr, ptr %other.addr.i5, align 4, !nonnull !3, !align !4 + %2 = load target("dx.RawBuffer", i8, 1, 0), ptr %1, align 4 + store target("dx.RawBuffer", i8, 1, 0) %2, ptr %this1.i6, align 4 + %3 = load i32, ptr %idx.addr, align 4 + %mul = mul i32 %3, 4 + call void @llvm.memcpy.p0.p0.i64(ptr align 8 %agg.tmp1, ptr align 4 %agg.tmp, i64 4, i1 false) + store i32 %mul, ptr %offset.addr.i, align 4 + store i32 1, ptr %value.addr.i, align 4 + %4 = load i32, ptr %offset.addr.i, align 4 + %5 = load i32, ptr %value.addr.i, align 4 + store ptr %agg.tmp1, ptr %this.addr.i, align 4 + store i32 %4, ptr %Index.addr.i, align 4 + store i32 %5, ptr %Value.addr.i, align 4 + %this1.i = load ptr, ptr %this.addr.i, align 4 + %6 = load i32, ptr %Value.addr.i, align 4 + %7 = load target("dx.RawBuffer", i8, 1, 0), ptr %this1.i, align 4 + %8 = load i32, ptr %Index.addr.i, align 4 + %9 = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %7, i32 %8) + store i32 %6, ptr %9, align 4 + %10 = load i32, ptr %value.addr.i, align 4 + ret i32 %10 +} + +; Function Attrs: convergent noinline norecurse +define void @main() #1 { +entry: + %this.addr.i12.i = alloca ptr, align 4 + %other.addr.i13.i = alloca ptr, align 4 + %this.addr.i9.i = alloca ptr, align 4 + %other.addr.i10.i = alloca ptr, align 4 + %this.addr.i6.i = alloca ptr, align 4 + %other.addr.i7.i = alloca ptr, align 4 + %this.addr.i.i1 = alloca ptr, align 4 + %other.addr.i.i2 = alloca ptr, align 4 + %orderId.addr.i.i = alloca i32, align 4 + %spaceNo.addr.i1.i = alloca i32, align 4 + %range.addr.i2.i = alloca i32, align 4 + %index.addr.i3.i = alloca i32, align 4 + %name.addr.i4.i = alloca ptr, align 4 + %tmp.i5.i = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %registerNo.addr.i.i = alloca i32, align 4 + %spaceNo.addr.i.i = alloca i32, align 4 + %range.addr.i.i = alloca i32, align 4 + %index.addr.i.i = alloca i32, align 4 + %name.addr.i.i = alloca ptr, align 4 + %tmp.i.i = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %this.addr.i = alloca ptr, align 4 + %other.addr.i = alloca ptr, align 4 + %this.addr.i.i = alloca ptr, align 4 + %other.addr.i.i = alloca ptr, align 4 + %this.addr.i.i.i = alloca ptr, align 4 + %Index.addr.i.i.i = alloca i32, align 4 + %Value.addr.i.i.i = alloca i32, align 4 + %offset.addr.i.i.i = alloca i32, align 4 + %value.addr.i.i.i = alloca i32, align 4 + %agg.tmp1.i.i = alloca %"class.hlsl::RWByteAddressBuffer", align 8 + %idx.addr.i.i = alloca i32, align 4 + %agg.tmp.i.i = alloca %"class.hlsl::RWByteAddressBuffer", align 4 + %tid.addr.i = alloca <3 x i32>, align 4 + %idx.i = alloca i32, align 4 + call void @llvm.experimental.noalias.scope.decl(metadata !5) + store i32 3, ptr %registerNo.addr.i.i, align 4, !noalias !5 + store i32 0, ptr %spaceNo.addr.i.i, align 4, !noalias !5 + store i32 1, ptr %range.addr.i.i, align 4, !noalias !5 + store i32 0, ptr %index.addr.i.i, align 4, !noalias !5 + store ptr @.str, ptr %name.addr.i.i, align 4, !noalias !5 + %0 = load i32, ptr %registerNo.addr.i.i, align 4, !noalias !5 + %1 = load i32, ptr %spaceNo.addr.i.i, align 4, !noalias !5 + %2 = load i32, ptr %range.addr.i.i, align 4, !noalias !5 + %3 = load i32, ptr %index.addr.i.i, align 4, !noalias !5 + %4 = load ptr, ptr %name.addr.i.i, align 4, !noalias !5 + %5 = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 %1, i32 %0, i32 %2, i32 %3, ptr %4) + store target("dx.RawBuffer", i8, 1, 0) %5, ptr %tmp.i.i, align 4, !noalias !5 + store ptr @_ZL4gOut, ptr %this.addr.i6.i, align 4 + store ptr %tmp.i.i, ptr %other.addr.i7.i, align 4 + %this1.i8.i = load ptr, ptr %this.addr.i6.i, align 4 + %6 = load ptr, ptr %other.addr.i7.i, align 4 + store ptr %this1.i8.i, ptr %this.addr.i9.i, align 4 + store ptr %6, ptr %other.addr.i10.i, align 4 + %this1.i11.i = load ptr, ptr %this.addr.i9.i, align 4 + %7 = load ptr, ptr %other.addr.i10.i, align 4, !nonnull !3, !align !4 + %8 = load target("dx.RawBuffer", i8, 1, 0), ptr %7, align 4 + store target("dx.RawBuffer", i8, 1, 0) %8, ptr %this1.i11.i, align 4 + call void @llvm.experimental.noalias.scope.decl(metadata !8) + store i32 0, ptr %orderId.addr.i.i, align 4, !noalias !8 + store i32 0, ptr %spaceNo.addr.i1.i, align 4, !noalias !8 + store i32 1, ptr %range.addr.i2.i, align 4, !noalias !8 + store i32 0, ptr %index.addr.i3.i, align 4, !noalias !8 + store ptr @.str.2, ptr %name.addr.i4.i, align 4, !noalias !8 + %9 = load i32, ptr %orderId.addr.i.i, align 4, !noalias !8 + %10 = load i32, ptr %spaceNo.addr.i1.i, align 4, !noalias !8 + %11 = load i32, ptr %range.addr.i2.i, align 4, !noalias !8 + %12 = load i32, ptr %index.addr.i3.i, align 4, !noalias !8 + %13 = load ptr, ptr %name.addr.i4.i, align 4, !noalias !8 + %14 = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i8_1_0t(i32 %9, i32 %10, i32 %11, i32 %12, ptr %13) + store target("dx.RawBuffer", i8, 1, 0) %14, ptr %tmp.i5.i, align 4, !noalias !8 + store ptr @_ZL16sharedStruct.buf, ptr %this.addr.i.i1, align 4 + store ptr %tmp.i5.i, ptr %other.addr.i.i2, align 4 + %this1.i.i3 = load ptr, ptr %this.addr.i.i1, align 4 + %15 = load ptr, ptr %other.addr.i.i2, align 4 + store ptr %this1.i.i3, ptr %this.addr.i12.i, align 4 + store ptr %15, ptr %other.addr.i13.i, align 4 + %this1.i14.i = load ptr, ptr %this.addr.i12.i, align 4 + %16 = load ptr, ptr %other.addr.i13.i, align 4, !nonnull !3, !align !4 + %17 = load target("dx.RawBuffer", i8, 1, 0), ptr %16, align 4 + store target("dx.RawBuffer", i8, 1, 0) %17, ptr %this1.i14.i, align 4 + %18 = call i32 @llvm.dx.thread.id(i32 0) + %19 = insertelement <3 x i32> poison, i32 %18, i64 0 + %20 = call i32 @llvm.dx.thread.id(i32 1) + %21 = insertelement <3 x i32> %19, i32 %20, i64 1 + %22 = call i32 @llvm.dx.thread.id(i32 2) + %23 = insertelement <3 x i32> %21, i32 %22, i64 2 + store <3 x i32> %23, ptr %tid.addr.i, align 4 + %24 = load <3 x i32>, ptr %tid.addr.i, align 4 + %25 = extractelement <3 x i32> %24, i32 0 + %26 = load <3 x i32>, ptr %tid.addr.i, align 4 + %27 = extractelement <3 x i32> %26, i32 1 + %mul.i = mul i32 %27, 8 + %add.i = add i32 %25, %mul.i + store i32 %add.i, ptr %idx.i, align 4 + %28 = load i32, ptr %idx.i, align 4 + store i32 %28, ptr %idx.addr.i.i, align 4 + store ptr %agg.tmp.i.i, ptr %this.addr.i.i, align 4 + store ptr addrspacecast (ptr addrspace(3) @sharedStruct to ptr), ptr %other.addr.i.i, align 4 + %this1.i.i = load ptr, ptr %this.addr.i.i, align 4 + %29 = load ptr, ptr %other.addr.i.i, align 4 + store ptr %this1.i.i, ptr %this.addr.i, align 4 + store ptr %29, ptr %other.addr.i, align 4 + %this1.i = load ptr, ptr %this.addr.i, align 4 + %30 = load ptr, ptr %other.addr.i, align 4, !nonnull !3, !align !4 + %31 = load target("dx.RawBuffer", i8, 1, 0), ptr %30, align 4 + store target("dx.RawBuffer", i8, 1, 0) %31, ptr %this1.i, align 4 + %32 = load i32, ptr %idx.addr.i.i, align 4 + %mul.i.i = mul i32 %32, 4 + call void @llvm.memcpy.p0.p0.i64(ptr align 8 %agg.tmp1.i.i, ptr align 4 %agg.tmp.i.i, i64 4, i1 false) + store i32 %mul.i.i, ptr %offset.addr.i.i.i, align 4 + store i32 1, ptr %value.addr.i.i.i, align 4 + %33 = load i32, ptr %offset.addr.i.i.i, align 4 + %34 = load i32, ptr %value.addr.i.i.i, align 4 + store ptr %agg.tmp1.i.i, ptr %this.addr.i.i.i, align 4 + store i32 %33, ptr %Index.addr.i.i.i, align 4 + store i32 %34, ptr %Value.addr.i.i.i, align 4 + %this1.i.i.i = load ptr, ptr %this.addr.i.i.i, align 4 + %35 = load i32, ptr %Value.addr.i.i.i, align 4 + %36 = load target("dx.RawBuffer", i8, 1, 0), ptr %this1.i.i.i, align 4 + %37 = load i32, ptr %Index.addr.i.i.i, align 4 + %38 = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %36, i32 %37) + store i32 %35, ptr %38, align 4 + %39 = load i32, ptr %value.addr.i.i.i, align 4 + ret void +} + +; Function Attrs: nounwind willreturn memory(none) +declare i32 @llvm.dx.thread.id(i32) #2 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none) +declare target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32, i32, i32, i32, ptr) #3 + +; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none) +declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0), i32) #4 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none) +declare target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_i8_1_0t(i32, i32, i32, i32, ptr) #3 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) +declare void @llvm.experimental.noalias.scope.decl(metadata) #5 + +; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) +declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #6 + +attributes #0 = { alwaysinline convergent mustprogress norecurse nounwind "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { convergent noinline norecurse "hlsl.numthreads"="8,8,1" "hlsl.shader"="compute" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { nounwind willreturn memory(none) } +attributes #3 = { nocallback nofree nosync nounwind willreturn memory(none) } +attributes #4 = { convergent nocallback nofree nosync nounwind willreturn memory(none) } +attributes #5 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) } +attributes #6 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } + +!dx.valver = !{!0} +!llvm.module.flags = !{!1} +!llvm.ident = !{!2} + +!0 = !{i32 1, i32 8} +!1 = !{i32 4, !"dx.disable_optimizations", i32 1} +!2 = !{!"clang version 23.0.0git (https://github.com/llvm/llvm-project.git b084fa7a5172e2502324f9df2723e22dad071e3a)"} +!3 = !{} +!4 = !{i64 4} +!5 = !{!6} +!6 = distinct !{!6, !7, !"_ZN4hlsl19RWByteAddressBuffer19__createFromBindingEjjijPKc: %agg.result"} +!7 = distinct !{!7, !"_ZN4hlsl19RWByteAddressBuffer19__createFromBindingEjjijPKc"} +!8 = !{!9} +!9 = distinct !{!9, !10, !"_ZN4hlsl19RWByteAddressBuffer27__createFromImplicitBindingEjjijPKc: %agg.result"} +!10 = distinct !{!10, !"_ZN4hlsl19RWByteAddressBuffer27__createFromImplicitBindingEjjijPKc"} diff --git a/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl b/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl index b44e9ff8896dc..d97a03580242c 100644 --- a/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl +++ b/clang/test/SemaHLSL/Resources/local_resources_passes.hlsl @@ -29,37 +29,6 @@ uint DoStore(RWByteAddressBuffer buf, uint offset, uint value) // PASS TESTS //============================================================== -// PASS 0 -groupshared RWByteAddressBuffer sharedBuf; - -uint Use_Shared(uint idx) -{ - return DoStore(gBuf0, idx * 4, 1); -} - -// PASS 1 -uint Pass_TernaryInit(bool cond, uint idx) -{ - // expected-warning@+1{{assignment of 'cond ? gBuf0 : gBuf1' to local resource 'buf' is not to the same unique global resource}} - RWByteAddressBuffer buf = cond ? gBuf0 : gBuf1; - return DoStore(buf, idx * 4, 2); -} - -// PASS 2 -void Pass_LoopVar() -{ - for(RWByteAddressBuffer buf = gBuf0; false;) - { - } -} - -// PASS 3 -uint Pass_ExpressionInit(uint idx) -{ - RWByteAddressBuffer buf = (true ? gBuf0 : gBuf1); - return DoStore(buf, idx * 4, 3); -} - // PASS 4 struct PassBufStruct { RWByteAddressBuffer buf; }; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
