Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions docs/SPIR-V.rst
Original file line number Diff line number Diff line change
Expand Up @@ -518,12 +518,22 @@ generate valid SPIR-V for Vulkan.
Optimization
~~~~~~~~~~~~

Optimization is also delegated to SPIRV-Tools. Right now there are no difference
between optimization levels greater than zero; they will all invoke the same
optimization recipe. That is, the recipe behind ``spirv-opt -O``. If you want to
run a custom optimization recipe, you can do so using the command line option
``-Oconfig=`` and specifying a comma-separated list of your desired passes.
The passes are invoked in the specified order.
Optimization is also delegated to SPIRV-Tools. There are two built-in
optimization recipes for SPIR-V code generation:

* ``-O1experimental``: a development-oriented recipe that favors lower
optimizer wall time. This profile is opt-in, leaves the default ``-O0``,
``-O1``, ``-O2``, ``-O3`` and ``-Oconfig`` behavior unchanged, and may emit
``VariablePointers`` for modules that need the fast path. On Vulkan targets,
use at least ``-fspv-target-env=vulkan1.1`` and ensure the target device
supports the required variable-pointer features. Vulkan 1.4 guarantees that
support.
* ``-O1``, ``-O2``, and ``-O3``: the performance-oriented recipe behind
``spirv-opt -O``.

If you want to run a custom optimization recipe, you can do so using the
command line option ``-Oconfig=`` and specifying a comma-separated list of
your desired passes. The passes are invoked in the specified order.

For example, you can specify ``-Oconfig=--loop-unroll,--scalar-replacement=300,--eliminate-dead-code-aggressive``
to firstly invoke loop unrolling, then invoke scalar replacement of aggregates,
Expand Down
2 changes: 1 addition & 1 deletion external/SPIRV-Tools
Submodule SPIRV-Tools updated 124 files
3 changes: 3 additions & 0 deletions include/dxc/Support/HLSLOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ def O0 : Flag<["-", "/"], "O0">, Group<hlsloptz_Group>, Flags<[CoreOption]>,
HelpText<"Optimization Level 0">;
def O1 : Flag<["-", "/"], "O1">, Group<hlsloptz_Group>, Flags<[CoreOption]>,
HelpText<"Optimization Level 1">;
def O1experimental : Flag<["-"], "O1experimental">, Group<spirv_Group>,
Flags<[CoreOption, DriverOption]>,
HelpText<"Enable the experimental SPIR-V fast-compile profile; may emit VariablePointers and requires target support for them when used">;
def O2 : Flag<["-", "/"], "O2">, Group<hlsloptz_Group>, Flags<[CoreOption]>,
HelpText<"Optimization Level 2">;
def O3 : Flag<["-", "/"], "O3">, Group<hlsloptz_Group>, Flags<[CoreOption]>,
Expand Down
1 change: 1 addition & 0 deletions include/dxc/Support/SPIRVOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct SpirvCodeGenOptions {
bool noWarnIgnoredFeatures = false;
bool preserveBindings = false;
bool preserveInterface = false;
bool o1ExperimentalFastCompile = false;
bool useDxLayout = false;
bool useGlLayout = false;
bool useLegacyBufferMatrixOrder = false;
Expand Down
17 changes: 15 additions & 2 deletions lib/DxcSupport/HLSLOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,11 +792,15 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
}

opts.DisableOptimizations = false;
if (Arg *A = Args.getLastArg(OPT_O0, OPT_O1, OPT_O2, OPT_O3, OPT_Od)) {
if (Arg *A =
Args.getLastArg(OPT_O0, OPT_O1, OPT_O1experimental, OPT_O2, OPT_O3,
OPT_Od)) {
if (A->getOption().matches(OPT_O0))
opts.OptLevel = 0;
if (A->getOption().matches(OPT_O1))
opts.OptLevel = 1;
if (A->getOption().matches(OPT_O1experimental))
opts.OptLevel = 1;
if (A->getOption().matches(OPT_O2))
opts.OptLevel = 2;
if (A->getOption().matches(OPT_O3))
Expand Down Expand Up @@ -1096,6 +1100,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
// SPIRV Change Starts
#ifdef ENABLE_SPIRV_CODEGEN
opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
opts.SpirvOptions.o1ExperimentalFastCompile =
Args.hasFlag(OPT_O1experimental, OPT_INVALID, false);
opts.SpirvOptions.invertY =
Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
opts.SpirvOptions.invertW =
Expand Down Expand Up @@ -1261,7 +1267,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
errors << "-Oconfig should not be specified more than once";
return 1;
}
if (Args.getLastArg(OPT_O0, OPT_O1, OPT_O2, OPT_O3)) {
if (Args.getLastArg(OPT_O0, OPT_O1, OPT_O1experimental, OPT_O2,
OPT_O3)) {
errors << "-Oconfig should not be used together with -O";
return 1;
}
Expand All @@ -1273,6 +1280,11 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
opts.SpirvOptions.entrypointName =
Args.getLastArgValue(OPT_fspv_entrypoint_name_EQ);

if (opts.SpirvOptions.o1ExperimentalFastCompile && !opts.GenSPIRV) {
errors << "-O1experimental requires -spirv";
return 1;
}

// Check for use of options not implemented in the SPIR-V backend.
if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) &&
hasUnsupportedSpirvOption(Args, errors))
Expand All @@ -1295,6 +1307,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
Args.hasFlag(OPT_fspv_fix_func_call_arguments, OPT_INVALID, false) ||
Args.hasFlag(OPT_fspv_print_all, OPT_INVALID, false) ||
Args.hasFlag(OPT_O1experimental, OPT_INVALID, false) ||
Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false) ||
Args.hasFlag(OPT_Wno_vk_emulated_features, OPT_INVALID, false) ||
Args.hasFlag(OPT_fvk_auto_shift_bindings, OPT_INVALID, false) ||
Expand Down
2 changes: 1 addition & 1 deletion tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ namespace {
result = Context->getObjCIdType();
FunctionProtoType::ExtProtoInfo fpi;
fpi.Variadic = variadic;
return Context->getFunctionType(result, args, fpi);
return Context->getFunctionType(result, args, fpi, {});
}

// Helper function: create a CStyleCastExpr with trivial type source info.
Expand Down
55 changes: 50 additions & 5 deletions tools/clang/lib/SPIRV/SpirvEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,9 @@ SpirvEmitter::SpirvEmitter(CompilerInstance &ci)
constEvaluator(astContext, spvBuilder), entryFunction(nullptr),
curFunction(nullptr), curThis(nullptr), seenPushConstantAt(),
isSpecConstantMode(false), needsLegalization(false),
needsLegalizationLoopUnroll(false),
needsLegalizationSsaRewrite(false),
sawExplicitUnrollHint(false),
beforeHlslLegalization(false), mainSourceFile(nullptr) {

// Get ShaderModel from command line hlsl profile option.
Expand Down Expand Up @@ -918,6 +921,20 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) {
}
}

if (useSpirvFastCompileProfile() &&
(needsLegalizationLoopUnroll || sawExplicitUnrollHint)) {
if (featureManager.isTargetEnvVulkan() &&
!featureManager.isTargetEnvVulkan1p1OrAbove()) {
emitFatalError(
"-O1experimental requires -fspv-target-env=vulkan1.1 or above "
"when the generated module needs VariablePointers",
{});
return;
}

spvBuilder.requireCapability(spv::Capability::VariablePointers);
}

// Output the constructed module.
std::vector<uint32_t> m = spvBuilder.takeModule();
if (context.getDiagnostics().hasErrorOccurred())
Expand Down Expand Up @@ -954,6 +971,9 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) {
declIdMapper.requiresFlatteningCompositeResources() ||
!dsetbindingsToCombineImageSampler.empty() ||
spirvOptions.signaturePacking;
needsLegalizationSsaRewrite =
needsLegalizationSsaRewrite ||
!dsetbindingsToCombineImageSampler.empty();

// Run legalization passes
if (spirvOptions.codeGenHighLevel) {
Expand Down Expand Up @@ -2284,6 +2304,7 @@ spv::LoopControlMask SpirvEmitter::translateLoopAttribute(const Stmt *stmt,
case attr::HLSLFastOpt:
return spv::LoopControlMask::DontUnroll;
case attr::HLSLUnroll:
sawExplicitUnrollHint = true;
return spv::LoopControlMask::Unroll;
case attr::HLSLAllowUAVCondition:
if (!spirvOptions.noWarnIgnoredFeatures) {
Expand Down Expand Up @@ -5823,8 +5844,11 @@ SpirvInstruction *SpirvEmitter::createImageSample(
SpirvInstruction *minLod, SpirvInstruction *residencyCodeId,
SourceLocation loc, SourceRange range) {

if (varOffset)
if (varOffset) {
needsLegalization = true;
needsLegalizationLoopUnroll = true;
needsLegalizationSsaRewrite = true;
}

// SampleDref* instructions in SPIR-V always return a scalar.
// They also have the correct type in HLSL.
Expand Down Expand Up @@ -8045,7 +8069,7 @@ SpirvInstruction *SpirvEmitter::createVectorSplat(const Expr *scalarExpr,
// Should find a more meaningful one.
if (auto *constVal = dyn_cast<SpirvConstant>(scalarVal)) {
llvm::SmallVector<SpirvConstant *, 4> elements(size_t(size), constVal);
const bool isSpecConst = constVal->getopcode() == spv::Op::OpSpecConstant;
const bool isSpecConst = constVal->isSpecConstant();
auto *value =
spvBuilder.getConstantComposite(vecType, elements, isSpecConst);
if (!value)
Expand Down Expand Up @@ -16619,8 +16643,12 @@ bool SpirvEmitter::spirvToolsOptimize(std::vector<uint32_t> *mod,
options.set_max_id_bound(spirvOptions.maxId);

if (spirvOptions.optConfig.empty()) {
// Add performance passes.
optimizer.RegisterPerformancePasses(spirvOptions.preserveInterface);
if (useSpirvFastCompileProfile()) {
optimizer.RegisterPerformancePassesFastCompile(
spirvOptions.preserveInterface);
} else {
optimizer.RegisterPerformancePasses(spirvOptions.preserveInterface);
}

// Add propagation of volatile semantics passes.
optimizer.RegisterPass(spvtools::CreateSpreadVolatileSemanticsPass());
Expand All @@ -16640,6 +16668,11 @@ bool SpirvEmitter::spirvToolsOptimize(std::vector<uint32_t> *mod,
return optimizer.Run(mod->data(), mod->size(), mod, options);
}

bool SpirvEmitter::useSpirvFastCompileProfile() const {
return spirvOptions.o1ExperimentalFastCompile &&
spirvOptions.optConfig.empty();
}

bool SpirvEmitter::spirvToolsLegalize(std::vector<uint32_t> *mod,
std::string *messages,
const std::vector<DescriptorSetAndBinding>
Expand All @@ -16665,7 +16698,19 @@ bool SpirvEmitter::spirvToolsLegalize(std::vector<uint32_t> *mod,
optimizer.RegisterPass(
spvtools::CreateInterfaceVariableScalarReplacementPass());
}
optimizer.RegisterLegalizationPasses(spirvOptions.preserveInterface);
if (useSpirvFastCompileProfile()) {
auto legalizationSsaRewriteMode = spvtools::SSARewriteMode::None;
if (needsLegalizationLoopUnroll) {
legalizationSsaRewriteMode = spvtools::SSARewriteMode::All;
} else if (needsLegalizationSsaRewrite) {
legalizationSsaRewriteMode = spvtools::SSARewriteMode::OpaqueOnly;
}
optimizer.RegisterLegalizationPassesFastCompile(
spirvOptions.preserveInterface, needsLegalizationLoopUnroll,
legalizationSsaRewriteMode);
} else {
optimizer.RegisterLegalizationPasses(spirvOptions.preserveInterface);
}
// Add flattening of resources if needed.
if (spirvOptions.flattenResourceArrays) {
optimizer.RegisterPass(
Expand Down
4 changes: 4 additions & 0 deletions tools/clang/lib/SPIRV/SpirvEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,7 @@ class SpirvEmitter : public ASTConsumer {
/// gets the info/warning/error messages via |messages|.
/// Returns true on success and false otherwise.
bool spirvToolsOptimize(std::vector<uint32_t> *mod, std::string *messages);
bool useSpirvFastCompileProfile() const;

// \brief Runs the pass represented by the given pass token on the module.
// Returns true if the pass was successfully run. Any messages from the
Expand Down Expand Up @@ -1578,6 +1579,9 @@ class SpirvEmitter : public ASTConsumer {
///
/// Note: legalization specific code
bool needsLegalization;
bool needsLegalizationLoopUnroll;
bool needsLegalizationSsaRewrite;
bool sawExplicitUnrollHint;

/// Whether the translated SPIR-V binary passes --before-hlsl-legalization
/// option to spirv-val because of illegal function parameter scope.
Expand Down
27 changes: 14 additions & 13 deletions tools/clang/test/CodeGenSPIRV/cast.flat-conversion.matrix.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,18 @@ RWStructuredBuffer<T> t_output;
// COL: OpMemberDecorate %S 0 RowMajor
// ROW: OpMemberDecorate %S 0 ColMajor

// The DXIL generated for the two cases seem to produce the same results,
// and this matches that behaviour.
// CHECK: [[array_const:%[0-9]+]] = OpConstantComposite %_arr_float_uint_6 %float_0 %float_1 %float_2 %float_3 %float_4 %float_5
// CHECK: [[t:%[0-9]+]] = OpConstantComposite %T [[array_const]]

// The DXIL that is generates different order for the values depending on
// whether the matrix is column or row major. However, for SPIR-V, the value
// stored in both cases is the same because the decoration, which is checked
// above, is what determines the layout in memory for the value.

// CHECK: [[row0:%[0-9]+]] = OpConstantComposite %v3float %float_0 %float_1 %float_2
// CHECK: [[row1:%[0-9]+]] = OpConstantComposite %v3float %float_3 %float_4 %float_5
// CHECK: [[mat:%[0-9]+]] = OpConstantComposite %mat2v3float %33 %34
// CHECK: [[s:%[0-9]+]] = OpConstantComposite %S %35
// CHECK: [[mat:%[0-9]+]] = OpLoad %mat2v3float
// CHECK: [[e00:%[0-9]+]] = OpCompositeExtract %float [[mat]] 0 0
// CHECK: [[e01:%[0-9]+]] = OpCompositeExtract %float [[mat]] 0 1
// CHECK: [[e02:%[0-9]+]] = OpCompositeExtract %float [[mat]] 0 2
// CHECK: [[e10:%[0-9]+]] = OpCompositeExtract %float [[mat]] 1 0
// CHECK: [[e11:%[0-9]+]] = OpCompositeExtract %float [[mat]] 1 1
// CHECK: [[e12:%[0-9]+]] = OpCompositeExtract %float [[mat]] 1 2

void main() {
S s;
Expand All @@ -40,13 +38,16 @@ void main() {
s.a[i][j] = i*3+j;
}
}
// CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_T %t_output %int_0 %uint_0
// CHECK: OpStore [[ac]] [[t]]
// CHECK: [[tptr:%[0-9]+]] = OpAccessChain %_ptr_Uniform_T %t_output %int_0 %uint_0
// CHECK: [[tarr:%[0-9]+]] = OpCompositeConstruct %_arr_float_uint_6 [[e00]] [[e01]] [[e02]] [[e10]] [[e11]] [[e12]]
// CHECK: [[tval:%[0-9]+]] = OpCompositeConstruct %T [[tarr]]
// CHECK: OpStore [[tptr]] [[tval]]
T t = (T)(s);
t_output[0] = t;

// CHECK: [[ac:%[0-9]+]] = OpAccessChain %_ptr_Uniform_S %s_output %int_0 %uint_0
// CHECK: OpStore [[ac]] [[s]]
// CHECK: [[sptr:%[0-9]+]] = OpAccessChain %_ptr_Uniform_S %s_output %int_0 %uint_0
// CHECK: [[sval:%[0-9]+]] = OpCompositeConstruct %S [[mat]]
// CHECK: OpStore [[sptr]] [[sval]]
s = (S)t;
s_output[0] = s;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// RUN: %dxc -T cs_6_0 -E main -O3 -Vd %s -spirv | FileCheck %s
// RUN: %dxc -T cs_6_0 -E main -O3 -Vd -fspv-target-env=vulkan1.3 %s -spirv | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-O3
// RUN: %dxc -T cs_6_0 -E main -O1experimental -Vd -fspv-target-env=vulkan1.3 %s -spirv | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-O1EXP

// CHECK-O1EXP: OpCapability VariablePointers

// CHECK: [[ptr:%[0-9]+]] = OpAccessChain %_ptr_Uniform_S %gSBuffer2
// CHECK-NEXT: [[val:%[0-9]+]] = OpLoad %S [[ptr]]
Expand Down
4 changes: 2 additions & 2 deletions tools/clang/test/CodeGenSPIRV/max_id.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// CHECK-30: fatal error: failed to optimize SPIR-V: ID overflow. Try running compact-ids.

// With a larger limit, the test case can compile successfully.
// CHECK-400: Bound: 204
// CHECK-400: Bound:


RWStructuredBuffer<int> data;
Expand All @@ -20,4 +20,4 @@ void main(uint3 id : SV_DispatchThreadID)
for( int i = 0; i < 64; i++ ) {
data[i] = i;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ void func(RWStructuredBuffer<uint> local) {

float4 main(PSInput input) : SV_TARGET
{
// CHECK: [[ac2:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_g_rwbuffer {{%[0-9]+}} %uint_0
// CHECK: [[counter_struct:%[0-9]+]] = OpAccessChain %_ptr_Uniform_type_ACSBuffer_counter %counter_var_g_rwbuffer {{%[0-9]+}}
// CHECK: [[ac2:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int [[counter_struct]] %uint_0
// CHECK: OpAtomicIAdd %int [[ac2]] %uint_1 %uint_0 %int_1
func(g_rwbuffer[input.idx]);

// CHECK: [[ac2_0:%[0-9]+]] = OpAccessChain %_ptr_Uniform_uint %g_rwbuffer {{%[0-9]+}} %int_0 %uint_0
// CHECK: [[rwbuffer_struct:%[0-9]+]] = OpAccessChain %_ptr_Uniform_type_RWStructuredBuffer_uint %g_rwbuffer {{%[0-9]+}}
// CHECK: [[ac2_0:%[0-9]+]] = OpAccessChain %_ptr_Uniform_uint [[rwbuffer_struct]] %int_0 %uint_0
// CHECK: OpLoad %uint [[ac2_0]]
return g_rwbuffer[input.idx][0];
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ float4 main(PSInput input) : SV_TARGET
{
RWStructuredBuffer<uint> l_rwbuffer[5] = g_rwbuffer;

// CHECK: [[ac2:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int %counter_var_g_rwbuffer %int_0 %uint_0
// CHECK: [[counter_struct:%[0-9]+]] = OpAccessChain %_ptr_Uniform_type_ACSBuffer_counter %counter_var_g_rwbuffer %int_0
// CHECK: [[ac2:%[0-9]+]] = OpAccessChain %_ptr_Uniform_int [[counter_struct]] %uint_0
// CHECK: OpAtomicIAdd %int [[ac2]] %uint_1 %uint_0 %int_1
l_rwbuffer[0].IncrementCounter();

// CHECK: [[ac2_0:%[0-9]+]] = OpAccessChain %_ptr_Uniform_uint %g_rwbuffer {{%[0-9]+}} %int_0 %uint_0
// CHECK: [[rwbuffer_struct:%[0-9]+]] = OpAccessChain %_ptr_Uniform_type_RWStructuredBuffer_uint %g_rwbuffer {{%[0-9]+}}
// CHECK: [[ac2_0:%[0-9]+]] = OpAccessChain %_ptr_Uniform_uint [[rwbuffer_struct]] %int_0 %uint_0
// CHECK: OpLoad %uint [[ac2_0]]
return l_rwbuffer[input.idx][0];
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
// Check the names
//
// CHECK: OpName %secondGlobal_t "secondGlobal.t"
// CHECK: OpName %[[fg0:firstGlobal_[0-9]+__t]] "firstGlobal{{.*}}.t"
// CHECK: OpName %[[fg1:firstGlobal_[0-9]+__t]] "firstGlobal{{.*}}.t"
// CHECK: OpName %[[fg2:firstGlobal_[0-9]+__t]] "firstGlobal{{.*}}.t"
// CHECK: OpName %[[fg3:firstGlobal_[0-9]+__t]] "firstGlobal{{.*}}.t"
// CHECK: OpName %[[fg0:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.t"
// CHECK: OpName %[[fg1:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.t"
// CHECK: OpName %[[fg2:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.t"
// CHECK: OpName %[[fg3:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.t"
// CHECK: OpName %secondGlobal_tt_0__s "secondGlobal.tt[0].s"
// CHECK: OpName %secondGlobal_tt_1__s "secondGlobal.tt[1].s"
// CHECK: OpName %[[fgtt0_0:firstGlobal_[0-9]+__tt_0__s]] "firstGlobal{{.*}}.tt[0].s"
// CHECK: OpName %[[fgtt0_1:firstGlobal_[0-9]+__tt_1__s]] "firstGlobal{{.*}}.tt[1].s"
// CHECK: OpName %[[fgtt1_0:firstGlobal_[0-9]+__tt_0__s]] "firstGlobal{{.*}}.tt[0].s"
// CHECK: OpName %[[fgtt1_1:firstGlobal_[0-9]+__tt_1__s]] "firstGlobal{{.*}}.tt[1].s"
// CHECK: OpName %[[fgtt2_0:firstGlobal_[0-9]+__tt_0__s]] "firstGlobal{{.*}}.tt[0].s"
// CHECK: OpName %[[fgtt2_1:firstGlobal_[0-9]+__tt_1__s]] "firstGlobal{{.*}}.tt[1].s"
// CHECK: OpName %[[fgtt3_0:firstGlobal_[0-9]+__tt_0__s]] "firstGlobal{{.*}}.tt[0].s"
// CHECK: OpName %[[fgtt3_1:firstGlobal_[0-9]+__tt_1__s]] "firstGlobal{{.*}}.tt[1].s"
// CHECK: OpName %[[fgtt0_0:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.tt[0].s"
// CHECK: OpName %[[fgtt0_1:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.tt[1].s"
// CHECK: OpName %[[fgtt1_0:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.tt[0].s"
// CHECK: OpName %[[fgtt1_1:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.tt[1].s"
// CHECK: OpName %[[fgtt2_0:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.tt[0].s"
// CHECK: OpName %[[fgtt2_1:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.tt[1].s"
// CHECK: OpName %[[fgtt3_0:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.tt[0].s"
// CHECK: OpName %[[fgtt3_1:[0-9A-Za-z_]+]] "firstGlobal{{.*}}.tt[1].s"

// Check flattening of bindings
// Explanation: Only the resources that are used will have a binding assignment
Expand Down
Loading
Loading