From f64d106c023e7bed59bfb441ffb258c127e500c1 Mon Sep 17 00:00:00 2001 From: qiaojbao Date: Wed, 26 Jun 2024 13:58:40 +0800 Subject: [PATCH] Update llpc from commit 879e8809 [CONTINUATIONS] Add metadata required by RGP [CONTINUATIONS] Run some optimization pass for gpurt module Add NoContraction decoration to have a test for fmul_legacy mapping Add readfirstlane on the result of subgroupClusterReduction on gfx11+ Add RobustGsEmits to GFX10 Add support for GS patch primitive type amdllpc: Add more helpful info with PipelineLib* dumps Avoid upgrade to seqcst ordering Debug Printf refactor Downgrade SequentiallyConsistent to AcquireRelease Expose getResourceMappingNodeTypeName() to the driver lgc: Improve TANH expansion to avoid overflow lgc: Refactor getShaderStageAbbreviation lgc: Use agent scope in more places llpcSpirvLowerGlobal: Fix originUpperLeft handling llpcSpirvLowerGlobal: Refactor input/output lowering llvmraytracing: Separate out header file for pointee type metadata Postpone descriptor load to ImageBuilder Promote llvm-dialects submodule Set last-use for load from the continuation stack Support for LogRayTracingPipelineSummary Update shader tests after LLVM update Fix a typo on paClVsOutCntl Fix primitive type for barycentric Fix the cooperativematrix issues(convert+muladd) on gfx1010 Fixes for lit tests on standalone amdllpc build --- .../include/compilerutils/CompilerUtils.h | 3 + compilerutils/lib/CompilerUtils.cpp | 8 + gfxruntime/src/shaders/AdvancedBlend.hlsl | 12 +- imported/llvm-dialects | 2 +- include/vkgcDefs.h | 99 ++- lgc/CMakeLists.txt | 1 + lgc/builder/ArithBuilder.cpp | 35 +- lgc/builder/BuilderImpl.cpp | 12 +- lgc/builder/DescBuilder.cpp | 76 +- lgc/builder/ImageBuilder.cpp | 231 ++++-- lgc/builder/InOutBuilder.cpp | 4 +- lgc/builder/SubgroupBuilder.cpp | 89 ++- lgc/include/lgc/builder/BuilderImpl.h | 30 +- lgc/include/lgc/builder/SubgroupBuilder.h | 7 +- .../lgc/patch/LowerCooperativeMatrix.h | 5 +- lgc/include/lgc/patch/LowerDebugPrintf.h | 1 + lgc/include/lgc/patch/SystemValues.h | 4 + lgc/include/lgc/state/AbiMetadata.h | 25 +- lgc/include/lgc/state/PipelineState.h | 7 +- lgc/interface/lgc/Builder.h | 30 +- lgc/interface/lgc/CommonDefs.h | 48 ++ lgc/interface/lgc/LgcDialect.td | 2 +- lgc/interface/lgc/Pipeline.h | 3 +- .../interface/lgc/RuntimeContext.h | 12 +- lgc/patch/ConfigBuilderBase.cpp | 9 +- lgc/patch/ConfigBuilderBase.h | 4 +- lgc/patch/LowerCooperativeMatrix.cpp | 75 +- lgc/patch/LowerDebugPrintf.cpp | 48 +- lgc/patch/MeshTaskShader.cpp | 12 +- lgc/patch/NggPrimShader.cpp | 15 +- lgc/patch/NggPrimShader.h | 3 +- lgc/patch/Patch.cpp | 2 +- lgc/patch/PatchEntryPointMutate.cpp | 6 +- lgc/patch/PatchInOutImportExport.cpp | 68 +- lgc/patch/PatchReadFirstLane.cpp | 7 +- lgc/patch/PatchResourceCollect.cpp | 55 +- lgc/patch/RegisterMetadataBuilder.cpp | 36 +- lgc/patch/ShaderMerger.cpp | 6 +- lgc/patch/SystemValues.cpp | 18 +- lgc/patch/VertexFetch.cpp | 51 +- lgc/state/PipelineState.cpp | 105 +-- .../state/RuntimeContext.cpp | 8 +- lgc/state/ShaderStage.cpp | 30 +- lgc/test/CsLowerDebugPrintf.lgc | 126 +-- lgc/test/CsReconfigWorkgroup.lgc | 6 +- lgc/test/ElfRelocationSize.lgc | 4 +- lgc/test/PartPipeline.lgc | 4 +- lgc/test/PatchInvalidImageDescriptor.lgc | 25 +- lgc/test/SubgroupClusteredReduction.lgc | 51 ++ lgc/test/TaskShaderOps.lgc | 2 +- lgc/test/TestWaterfallLoopForStruct.lgc | 37 +- lgc/test/TextureRange.lgc | 4 +- .../LowerCooperativeMatrix/gfx1010muladd.lgc | 32 + .../LowerCooperativeMatrix/gfx1011muladd.lgc | 33 + .../Transforms/LowerDebugPrintf/basic.lgc | 14 +- lgc/test/lgcdis.lgc | 4 +- .../scalarizationOfDescriptorLoadsTest1.lgc | 27 +- .../scalarizationOfDescriptorLoadsTest10.lgc | 15 +- .../scalarizationOfDescriptorLoadsTest11.lgc | 15 +- .../scalarizationOfDescriptorLoadsTest12.lgc | 15 +- .../scalarizationOfDescriptorLoadsTest13.lgc | 23 +- .../scalarizationOfDescriptorLoadsTest14.lgc | 24 +- .../scalarizationOfDescriptorLoadsTest15.lgc | 24 +- .../scalarizationOfDescriptorLoadsTest16.lgc | 20 +- .../scalarizationOfDescriptorLoadsTest2.lgc | 20 +- .../scalarizationOfDescriptorLoadsTest3.lgc | 14 +- .../scalarizationOfDescriptorLoadsTest4.lgc | 19 +- .../scalarizationOfDescriptorLoadsTest5.lgc | 27 +- .../scalarizationOfDescriptorLoadsTest6.lgc | 39 +- .../scalarizationOfDescriptorLoadsTest7.lgc | 22 +- .../scalarizationOfDescriptorLoadsTest8.lgc | 15 +- .../scalarizationOfDescriptorLoadsTest9.lgc | 11 +- lgc/test/tanh.lgc | 54 ++ llpc/CMakeLists.txt | 1 - llpc/context/llpcCompiler.cpp | 88 ++- llpc/context/llpcContext.cpp | 20 +- llpc/context/llpcPipelineContext.cpp | 8 +- llpc/docs/DdnBindlessTexture.md | 21 +- ...lessTexturePipelineDumpDeclSamplerType.PNG | Bin 139864 -> 0 bytes ...ndlessTexturePipelineDumpDeclUvec2Type.PNG | Bin 103757 -> 313823 bytes llpc/lower/LowerAdvancedBlend.cpp | 28 +- llpc/lower/LowerGLCompatibility.cpp | 14 +- llpc/lower/ProcessGfxRuntimeLibrary.cpp | 28 +- llpc/lower/llpcSpirvLowerGlobal.cpp | 738 +++++------------- llpc/lower/llpcSpirvLowerGlobal.h | 33 +- ...SpirvLowerInternalLibraryIntrinsicUtil.cpp | 6 +- llpc/lower/llpcSpirvLowerTranslator.cpp | 3 +- llpc/test/lit.cfg.py | 3 + llpc/test/lit.site.cfg.py.in | 1 + ...onUniform_TestTexutreLoadStoreInt64.spvasm | 39 +- ...ccessChain_TestBlockVectorExtract_lit.frag | 4 +- .../OpAtomicXXX_TestImageDimension_lit.comp | 176 ++--- ...tomicXXX_TestImageMemoryQualifier_lit.comp | 6 +- .../core/OpAtomicXXX_TestImage_lit.comp | 34 +- .../core/OpAtomicXXX_TestImage_lit.frag | 34 +- .../core/OpFMul_TestOperandIsZero.spvasm | 2 + .../core/OpFOrdEqual_TestVec3_lit.frag | 2 +- .../core/OpFOrdNotEqual_TestVec3_lit.frag | 2 +- .../shaderdb/core/OpIEqual_TestIvec2_lit.frag | 2 +- .../core/OpINotEqual_TestIvec2_lit.frag | 2 +- .../core/OpImageDrefGather_TestBasic_lit.frag | 4 +- ...refGather_TestTextureGatherOffset_lit.frag | 6 +- ...ImageDrefGather_TestTextureGather_lit.frag | 3 +- ...mageExplicitLod_TestDrefLodOffset_lit.frag | 2 +- .../core/OpImageFetch_TestBuffer_lit.comp | 2 +- .../core/OpImageFetch_TestTexelFetch_lit.frag | 2 +- .../OpImageGather_TestConstOffsets_lit.frag | 2 +- ...pImageGather_TestDrefConstOffsets_lit.frag | 2 +- .../OpImageGather_TestIntegerSampler.frag | 12 +- .../core/OpImageGather_TestOffset_lit.frag | 2 +- ...geGather_TestTextureGatherBiasLod_lit.frag | 32 +- ...ageGather_TestTextureGatherOffset_lit.frag | 6 +- .../OpImageGather_TestTextureGather_lit.frag | 6 +- ...ueryLevels_TestTextureQueryLevels_lit.frag | 8 +- .../core/OpImageQuerySize_TestBasic_lit.frag | 2 +- .../OpImageQuerySize_TestImageSize_lit.frag | 2 +- .../core/OpImageQuerySize_TestImage_lit.comp | 2 +- .../OpImageQuerySize_TestTextureSize_lit.frag | 2 +- .../core/OpImageRead_TestBuffer_lit.comp | 2 +- .../core/OpImageRead_TestImageLoad_lit.frag | 2 +- .../OpImageRead_TestMemoryQualifier_lit.comp | 8 +- ...eExplicitLod_TestTextureGradClamp_lit.frag | 6 +- ...ImplicitLod_TestArrayDirectAccess_lit.frag | 2 +- ...pImageSampleImplicitLod_TestBasic_lit.frag | 2 +- ...pleImplicitLod_TestIntegerSampler_lit.frag | 4 +- ...Lod_TestMultiDimArrayDirectAccess_lit.frag | 2 +- ...ageSampleImplicitLod_TestSeparate_lit.frag | 2 +- ...eImplicitLod_TestTextureBiasClamp_lit.frag | 16 +- ...ampleImplicitLod_TestTextureClamp_lit.frag | 14 +- ...eImplicitLod_TestTextureGradClamp_lit.frag | 16 +- ...citLod_TestTextureGradOffsetClamp_lit.frag | 12 +- ...mplicitLod_TestTextureOffsetClamp_lit.frag | 12 +- .../OpLogicalNotEqual_TestGeneral_lit.frag | 4 +- ...ssThanEqual_TestSignedAndUnsigned_lit.frag | 2 +- ...OpSLessThan_TestSignedAndUnsigned_lit.frag | 2 +- .../shaderdb/core/TestXfbStateMetadata.vert | 4 +- .../ExtMultiView_TestSubpassLoad_lit.pipe | 2 +- .../OpExtInst_TestFmaDouble_lit.frag | 10 +- .../OpExtInst_TestFmaFloat_lit.frag | 10 +- .../OpExtInst_TestMixSelectDouble_lit.frag | 10 +- .../OpExtInst_TestMixSelectFloat_lit.frag | 10 +- .../OpExtInst_TestMixSelectInt_lit.frag | 10 +- .../OpExtInst_TestMixSelectUint_lit.frag | 10 +- .../OpExtInst_TestTanhFloat_lit.frag | 12 +- .../extensions/OpExtInst_TestTanh_lit.frag | 24 +- llpc/test/shaderdb/general/ImgDescLoad.comp | 19 +- .../general/PipelineCs_DebugPrintf.pipe | 9 +- .../PipelineRays_TestLgcRtTraceRayOp.pipe | 1 + .../WorkaroundStorageImageFormats.pipe | 3 +- .../PipelineVsFs_TestVsOutMiscSideBusEna.pipe | 8 +- .../shaderdb/gfx11/AttributePrecedesPos.pipe | 2 +- .../cooperativeMatrix/array-of-matrices.comp | 6 +- .../PipelineVsFs_TestGraphicsLibrary.pipe | 8 +- .../object/ObjFragMask_TestFragFetch_lit.frag | 10 +- .../ObjImage_TestCubeAtomicAdd_lit.comp | 4 +- .../ObjImage_TestMemoryQualifier_lit.frag | 12 +- .../object/ObjResource_TestAlias_lit.frag | 13 +- .../object/ObjSampler_TestLargeId_lit.frag | 34 +- ...Sampler_TestSeparateSamplerShadow_lit.frag | 2 +- .../ObjSharedVariable_TestArrayCopy_lit.comp | 4 +- .../ObjSharedVariable_TestArray_lit.comp | 4 +- ...geBlock_TestMultiLevelAccessChain_lit.vert | 2 +- .../ObjUniformBlock_TestDirectIndex_lit.frag | 2 +- ...jUniformBlock_TestLoadMatrixArray_lit.vert | 16 +- llpc/test/shaderdb/ray_tracing/lit.local.cfg | 2 + .../PipelineVsFs_EnableColorExport.pipe | 117 ++- llpc/tool/amdllpc.cpp | 12 +- llpc/translator/lib/SPIRV/SPIRVReader.cpp | 256 +++--- llpc/translator/lib/SPIRV/SPIRVReader.h | 2 +- llpc/util/llpcDebug.h | 9 + llpc/util/llpcShaderModuleHelper.cpp | 78 +- .../include/llvmraytracing/Continuations.h | 5 +- .../llvmraytracing/ContinuationsUtil.h | 21 - .../include/llvmraytracing/TypesMetadata.h | 49 ++ llvmraytracing/lib/Continuations.cpp | 2 + llvmraytracing/lib/DXILContPostProcess.cpp | 2 +- .../cont-payload-registers-get-i32.ll | 4 +- .../cont-payload-registers-set-i32.ll | 4 +- tool/dumper/vkgcPipelineDumper.cpp | 65 +- tool/vfx/vfxVkSection.h | 2 + util/vkgcUtil.cpp | 8 + version/include/llpcVersion.h.in | 2 + 182 files changed, 2520 insertions(+), 1911 deletions(-) rename llpc/context/GfxRuntimeContext.h => lgc/interface/lgc/RuntimeContext.h (91%) rename llpc/context/GfxRuntimeContext.cpp => lgc/state/RuntimeContext.cpp (90%) create mode 100644 lgc/test/SubgroupClusteredReduction.lgc create mode 100644 lgc/test/Transforms/LowerCooperativeMatrix/gfx1010muladd.lgc create mode 100644 lgc/test/Transforms/LowerCooperativeMatrix/gfx1011muladd.lgc create mode 100644 lgc/test/tanh.lgc delete mode 100644 llpc/docs/DdnBindlessTexturePipelineDumpDeclSamplerType.PNG create mode 100644 llvmraytracing/include/llvmraytracing/TypesMetadata.h diff --git a/compilerutils/include/compilerutils/CompilerUtils.h b/compilerutils/include/compilerutils/CompilerUtils.h index 3669ebeb2b..506dcad925 100644 --- a/compilerutils/include/compilerutils/CompilerUtils.h +++ b/compilerutils/include/compilerutils/CompilerUtils.h @@ -70,6 +70,9 @@ llvm::Function *cloneFunctionHeader(llvm::Function &f, llvm::FunctionType *newTy // Add an unreachable at the current position and remove the rest of the basic block. void createUnreachable(llvm::IRBuilder<> &b); +// Specifies a memory that is loaded is the last use. +void setIsLastUseLoad(llvm::LoadInst &Load); + struct CrossModuleInlinerResult { llvm::Value *returnValue; llvm::iterator_range newBBs; diff --git a/compilerutils/lib/CompilerUtils.cpp b/compilerutils/lib/CompilerUtils.cpp index 40cc96bd83..8bf7ca653d 100644 --- a/compilerutils/lib/CompilerUtils.cpp +++ b/compilerutils/lib/CompilerUtils.cpp @@ -41,6 +41,10 @@ using namespace llvm; +// Whether this is a load instruction that should translate to a last_use +// load. +static constexpr const char *MDIsLastUseName = "amdgpu.last.use"; + // ===================================================================================================================== // Create an LLVM function call to the named function. The callee is built // automatically based on return type and its parameters. @@ -150,6 +154,10 @@ void CompilerUtils::createUnreachable(llvm::IRBuilder<> &b) { DeleteDeadBlock(oldCode); } +void CompilerUtils::setIsLastUseLoad(llvm::LoadInst &Load) { + Load.setMetadata(MDIsLastUseName, MDTuple::get(Load.getContext(), {})); +} + namespace { // Get the name of a global that is copied to a different module for inlining. diff --git a/gfxruntime/src/shaders/AdvancedBlend.hlsl b/gfxruntime/src/shaders/AdvancedBlend.hlsl index 872f01b360..5bff6c24cc 100644 --- a/gfxruntime/src/shaders/AdvancedBlend.hlsl +++ b/gfxruntime/src/shaders/AdvancedBlend.hlsl @@ -49,8 +49,8 @@ float4 AmdExtFragCoord() DUMMY_FLOAT4_FUNC int AmdExtSampleId() DUMMY_INT_FUNC -float4 AmdAdvancedBlendTexelLoad(int4 imageLow, int4 imageHigh, int2 iCoord, int lod) DUMMY_FLOAT4_FUNC -float4 AmdAdvancedBlendTexelLoadFmask(int4 imageMsLow, int4 imageMsHigh, int4 fmaskLow, int4 fmaskHigh, int2 iCoord, int lod) DUMMY_FLOAT4_FUNC +float4 AmdAdvancedBlendTexelLoad(int64_t imageDesc, int2 iCoord, int lod) DUMMY_FLOAT4_FUNC +float4 AmdAdvancedBlendTexelLoadFmask(int64_t imageDesc, int64_t fmaskDesc, int2 iCoord, int lod) DUMMY_FLOAT4_FUNC float4 AmdAdvancedBlendCoherentTexelLoad(float4 color, int2 iCoord, int sampleId) DUMMY_FLOAT4_FUNC void AmdAdvancedBlendCoherentTexelStore(float4 color, int2 iCoord, int sampleId) DUMMY_VOID_FUNC @@ -224,8 +224,8 @@ float AmdAdvancedBlendDivide(float dividend, float divisor) { } } -export float4 AmdAdvancedBlendInternal(float4 inColor, int4 imageMsLow, int4 imageMsHigh, int4 imageLow, int4 imageHigh, - int4 fmaskLow, int4 fmaskHigh, int mode, bool isMsaa) { +export float4 AmdAdvancedBlendInternal(float4 inColor, int64_t imageDescMs, int64_t imageDesc, int64_t fmaskDesc, + int mode, bool isMsaa) { float4 srcColor = inColor; if (mode == 0) { return srcColor; @@ -234,9 +234,9 @@ export float4 AmdAdvancedBlendInternal(float4 inColor, int4 imageMsLow, int4 ima int2 iCoord = int2(fragCoord.x, fragCoord.y); float4 dstColor; if (isMsaa) { - dstColor = AmdAdvancedBlendTexelLoadFmask(imageMsLow, imageMsHigh, fmaskLow, fmaskHigh, iCoord, 0); + dstColor = AmdAdvancedBlendTexelLoadFmask(imageDescMs, fmaskDesc, iCoord, 0); } else { - dstColor = AmdAdvancedBlendTexelLoad(imageLow, imageHigh, iCoord, 0); + dstColor = AmdAdvancedBlendTexelLoad(imageDesc, iCoord, 0); } // TODO: Uncomment them once ROV is support in LLPC // int sampleId = AmdExtSampleId(); diff --git a/imported/llvm-dialects b/imported/llvm-dialects index 55e176fb88..ed4b46e842 160000 --- a/imported/llvm-dialects +++ b/imported/llvm-dialects @@ -1 +1 @@ -Subproject commit 55e176fb88bcfc4fae45bafaa3ff209ec4c0d4ee +Subproject commit ed4b46e8425066a96a5e79afc29bce3d82eecf71 diff --git a/include/vkgcDefs.h b/include/vkgcDefs.h index 60b5621565..aed46de1b2 100644 --- a/include/vkgcDefs.h +++ b/include/vkgcDefs.h @@ -472,6 +472,7 @@ struct PipelineOptions { bool internalRtShaders; ///< Whether this pipeline has internal raytracing shaders unsigned forceNonUniformResourceIndexStageMask; ///< Mask of the stage to force using non-uniform resource index. bool reserved16; +#if LLPC_CLIENT_INTERFACE_MAJOR_VERSION < 73 bool replaceSetWithResourceType; ///< For OGL only, replace 'set' with resource type during spirv translate bool disableSampleMask; ///< For OGL only, disabled if framebuffer doesn't attach multisample texture bool buildResourcesDataForShaderModule; ///< For OGL only, build resources usage data while building shader module @@ -482,6 +483,25 @@ struct PipelineOptions { bool enableFragColor; ///< For OGL only, need to do frag color broadcast if it is enabled. bool disableBaseVertex; ///< For OGL only, force the BaseVertex builtin to 0 instead of /// loading it from userdata + bool bindlessTextureMode; ///< For OGL only, true if bindless textures are used + bool bindlessImageMode; ///< For OGL only, true if bindless images are used + const auto &getGlState() const { return *this; } +#else + struct GLState { + bool replaceSetWithResourceType; ///< For OGL only, replace 'set' with resource type during spirv translate + bool disableSampleMask; ///< For OGL only, disabled if framebuffer doesn't attach multisample texture + bool buildResourcesDataForShaderModule; ///< For OGL only, build resources usage data while building shader module + bool disableTruncCoordForGather; ///< If set, trunc_coord of sampler srd is disabled for gather4 + bool enableCombinedTexture; ///< For OGL only, use the 'set' for DescriptorCombinedTexture + ///< for sampled images and samplers + bool vertex64BitsAttribSingleLoc; ///< For OGL only, dvec3/dvec4 vertex attrib only consumes 1 location. + bool enableFragColor; ///< For OGL only, need to do frag color broadcast if it is enabled. + bool disableBaseVertex; ///< For OGL only, force the BaseVertex builtin to 0 instead of + bool bindlessTextureMode; ///< For OGL only, true if bindless textures are used + bool bindlessImageMode; ///< For OGL only, true if bindless images are used + } glState; + const auto &getGlState() const { return glState; } +#endif unsigned reserved20; bool enablePrimGeneratedQuery; ///< If set, primitive generated query is enabled bool disablePerCompFetch; ///< Disable per component fetch in uber fetch shader. @@ -512,6 +532,7 @@ struct ResourceNodeData { unsigned isTexelFetchUsed; ///< TRUE if texelFetch is used unsigned isDefaultUniformSampler; ///< TRUE if it's sampler image in default uniform struct unsigned columnCount; ///< Column count if this is a matrix variable. + unsigned componentCount; ///< Component count if this is a vector, row count if it is a matrix. BasicType basicType; ///< Type of the variable or element }; @@ -545,6 +566,43 @@ struct ResourcesNodes { unsigned defaultUniformInfoCount; }; +// raytracing system value usage flags +union RayTracingSystemValueUsage { + struct { + union { + struct { + uint16_t flags : 1; // Shader calls gl_IncomingRayFlagsEXT + uint16_t worldRayOrigin : 1; // Shader calls gl_WorldRayOriginEXT + uint16_t tMin : 1; // Shader calls gl_RayTminEXT + uint16_t worldRayDirection : 1; // Shader calls gl_WorldRayDirectionEXT + uint16_t tCurrent : 1; // Shader calls gl_HitTEXT + uint16_t launchId : 1; // Shader calls gl_LaunchIDEXT + uint16_t launchSize : 1; // Shader calls gl_LaunchSizeEXT + uint16_t reserved : 9; // Reserved + }; + uint16_t u16All; + } ray; + + union { + struct { + uint16_t hitKind : 1; // Shader calls gl_HitKindEXT + uint16_t instanceIndex : 1; // Shader calls gl_InstanceCustomIndexEXT + uint16_t instanceID : 1; // Shader calls gl_InstanceID + uint16_t primitiveIndex : 1; // Shader calls gl_PrimitiveID + uint16_t geometryIndex : 1; // Shader calls gl_GeometryIndexEXT + uint16_t objectToWorld : 1; // Shader calls gl_ObjectToWorldEXT + uint16_t objectRayOrigin : 1; // Shader calls gl_ObjectRayOriginEXT + uint16_t objectRayDirection : 1; // Shader calls gl_ObjectRayDirectionEXT + uint16_t worldToObject : 1; // Shader calls gl_WorldToObjectEXT + uint16_t hitTrianglePosition : 1; // Shader calls gl_HitTriangleVertexPositionsEXT + uint16_t reserved : 6; // Reserved + }; + uint16_t u16All; + } primitive; + }; + uint32_t u32All; +}; + /// Represents usage info of a shader module struct ShaderModuleUsage { bool enableVarPtrStorageBuf; ///< Whether to enable "VariablePointerStorageBuffer" capability @@ -573,12 +631,14 @@ struct ShaderModuleUsage { bool pixelCenterInteger; ///< Whether pixel coord is Integer bool useGenericBuiltIn; ///< Whether to use builtIn inputs that include gl_PointCoord, gl_PrimitiveId, /// gl_Layer, gl_ClipDistance or gl_CullDistance. + bool useBarycentric; ///< Whether to use gl_BarycentricXX or pervertexEXT decoration bool enableXfb; ///< Whether transform feedback is enabled unsigned localSizeX; ///< Compute shader work-group size in the X dimension unsigned localSizeY; ///< Compute shader work-group size in the Y dimension unsigned localSizeZ; ///< Compute shader work-group size in the Z dimension bool disableDualSource; ///< Whether disable dualSource blend uint32_t clipDistanceArraySize; ///< Count of output clip distance + RayTracingSystemValueUsage rtSystemValueUsage; ///< Usage flags for ray tracing builtins }; /// Represents common part of shader module data @@ -1001,43 +1061,6 @@ enum RayTracingRayFlag : unsigned { }; // ===================================================================================================================== -// raytracing system value usage flags -union RayTracingSystemValueUsage { - struct { - union { - struct { - uint16_t flags : 1; // Shader calls gl_IncomingRayFlagsEXT - uint16_t worldRayOrigin : 1; // Shader calls gl_WorldRayOriginEXT - uint16_t tMin : 1; // Shader calls gl_RayTminEXT - uint16_t worldRayDirection : 1; // Shader calls gl_WorldRayDirectionEXT - uint16_t tCurrent : 1; // Shader calls gl_HitTEXT - uint16_t launchId : 1; // Shader calls gl_LaunchIDEXT - uint16_t launchSize : 1; // Shader calls gl_LaunchSizeEXT - uint16_t reserved : 9; // Reserved - }; - uint16_t u16All; - } ray; - - union { - struct { - uint16_t hitKind : 1; // Shader calls gl_HitKindEXT - uint16_t instanceIndex : 1; // Shader calls gl_InstanceCustomIndexEXT - uint16_t instanceID : 1; // Shader calls gl_InstanceID - uint16_t primitiveIndex : 1; // Shader calls gl_PrimitiveID - uint16_t geometryIndex : 1; // Shader calls gl_GeometryIndexEXT - uint16_t objectToWorld : 1; // Shader calls gl_ObjectToWorldEXT - uint16_t objectRayOrigin : 1; // Shader calls gl_ObjectRayOriginEXT - uint16_t objectRayDirection : 1; // Shader calls gl_ObjectRayDirectionEXT - uint16_t worldToObject : 1; // Shader calls gl_WorldToObjectEXT - uint16_t hitTrianglePosition : 1; // Shader calls gl_HitTriangleVertexPositionsEXT - uint16_t reserved : 6; // Reserved - }; - uint16_t u16All; - } primitive; - }; - uint32_t u32All; -}; - /// Represents ray-tracing shader export configuration struct RayTracingShaderExportConfig { unsigned indirectCallingConvention; ///< Indirect calling convention @@ -1299,6 +1322,7 @@ struct GraphicsPipelineBuildInfo { float pixelTransferBias[4]; ///< Bias apply to render color target bool enableColorClampVs; ///< Enable clamp vertex output color bool enableColorClampFs; ///< Enable clamp fragment output color + bool enableFlatShade; ///< Whether enable flat shade. } glState; const auto &getGlState() const { return glState; } #endif @@ -1597,6 +1621,7 @@ class IUtil { /// /// @param [in] spvBin SPIR-V binary static const char *VKAPI_CALL GetEntryPointNameFromSpirvBinary(const BinaryData *spvBin); + static const char *VKAPI_CALL GetResourceMappingNodeTypeName(ResourceMappingNodeType type); }; /// 128-bit hash compatible structure diff --git a/lgc/CMakeLists.txt b/lgc/CMakeLists.txt index e7feab6d76..e49c3a34fc 100644 --- a/lgc/CMakeLists.txt +++ b/lgc/CMakeLists.txt @@ -191,6 +191,7 @@ target_sources(LLVMlgc PRIVATE state/ShaderModes.cpp state/ShaderStage.cpp state/TargetInfo.cpp + state/RuntimeContext.cpp ) # lgc/util diff --git a/lgc/builder/ArithBuilder.cpp b/lgc/builder/ArithBuilder.cpp index 57ba3e3f8c..fee6b1a564 100644 --- a/lgc/builder/ArithBuilder.cpp +++ b/lgc/builder/ArithBuilder.cpp @@ -507,29 +507,20 @@ Value *BuilderImpl::CreateCosh(Value *x, const Twine &instName) { // @param x : Input value X // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateTanh(Value *x, const Twine &instName) { - // sinh(x) / cosh(x) - // (e^x - e^(-x))/(e^x + e^(-x)) + // tanh(x) = copysign(1-2/(e^-|2x|+1),x) // 1/log(2) = 1.442695 - // e^x = 2^(x*(1/log(2))) = 2^(x*1.442695)) - Value *divLog2 = CreateFMul(x, getRecipLog2(x->getType())); - Value *negDivLog2 = CreateFSub(ConstantFP::get(x->getType(), 0.0), divLog2); - Value *exp = CreateUnaryIntrinsic(Intrinsic::exp2, divLog2); - Value *expNeg = CreateUnaryIntrinsic(Intrinsic::exp2, negDivLog2); - Value *doubleSinh = CreateFSub(exp, expNeg); - Value *doubleCosh = CreateFAdd(exp, expNeg); - Value *result = fDivFast(doubleSinh, doubleCosh); - - if (!getFastMathFlags().noInfs()) { - // NOTE: If the fast math flags might have INFs, we should check the special case when the input is +INF or -INF. - // According to the limit of tanh(x), we have following definitions: - // / 1.0, when x -> +INF - // lim(tanh(x)) = - // \ -1.0, when x -> -INF - Value *one = ConstantFP::get(x->getType(), 1.0); - Value *isInf = CreateIsInf(x); - result = CreateSelect(isInf, CreateCopySign(one, x), result); - } - + // e = 2^(1/log(2)) + // e^-|2x| = 2^(-|2x|*(1/log(2))) + auto vTy = x->getType(); + Value *result = CreateIntrinsic(Intrinsic::fabs, vTy, x); + result = CreateFNeg(result); + result = CreateFMul(ConstantFP::get(vTy, 2.0), result); + result = CreateFMul(getRecipLog2(vTy), result); + result = CreateUnaryIntrinsic(Intrinsic::exp2, result); + result = CreateFAdd(ConstantFP::get(vTy, 1.0), result); + result = fDivFast(ConstantFP::get(vTy, 2.0), result); + result = CreateFSub(ConstantFP::get(vTy, 1.0), result); + result = CreateCopySign(result, x); result->setName(instName); return result; } diff --git a/lgc/builder/BuilderImpl.cpp b/lgc/builder/BuilderImpl.cpp index ad69faf624..0177fcd2be 100644 --- a/lgc/builder/BuilderImpl.cpp +++ b/lgc/builder/BuilderImpl.cpp @@ -249,11 +249,12 @@ Value *BuilderImpl::CreateIntegerDotProduct(Value *vector1, Value *vector2, Valu // ===================================================================================================================== // Get whether the context we are building in supports ds_bpermute or v_bpermute across all lanes in the wave -bool BuilderImpl::supportWaveWideBPermute() const { +// +// @param shaderStage : shader stage enum. +bool BuilderImpl::supportWaveWideBPermute(ShaderStageEnum shaderStage) const { auto gfxIp = getPipelineState()->getTargetInfo().getGfxIpVersion().major; auto supportBPermute = gfxIp == 8 || gfxIp == 9; - auto shaderStage = getShaderStage(GetInsertBlock()->getParent()); - auto waveSize = getPipelineState()->getShaderWaveSize(shaderStage.value()); + auto waveSize = getPipelineState()->getShaderWaveSize(shaderStage); supportBPermute = supportBPermute || waveSize == 32; return supportBPermute; } @@ -261,10 +262,7 @@ bool BuilderImpl::supportWaveWideBPermute() const { // ===================================================================================================================== // Get whether the context we are building in supports permute lane 64 DPP operations. bool BuilderImpl::supportPermLane64Dpp() const { - auto gfxip = getPipelineState()->getTargetInfo().getGfxIpVersion().major; - auto shaderStage = getShaderStage(GetInsertBlock()->getParent()); - auto waveSize = getPipelineState()->getShaderWaveSize(shaderStage.value()); - return gfxip >= 11 && waveSize == 64; + return getPipelineState()->getTargetInfo().getGfxIpVersion().major >= 11; } // ===================================================================================================================== diff --git a/lgc/builder/DescBuilder.cpp b/lgc/builder/DescBuilder.cpp index c837b2129a..6ef7fbbf69 100644 --- a/lgc/builder/DescBuilder.cpp +++ b/lgc/builder/DescBuilder.cpp @@ -394,45 +394,47 @@ Value *BuilderImpl::buildBufferCompactDesc(Value *desc, unsigned stride) { Value *descElem1 = CreateExtractElement(desc, 1); // Build normal buffer descriptor - // Dword 0 Value *bufDesc = PoisonValue::get(FixedVectorType::get(getInt32Ty(), 4)); - bufDesc = CreateInsertElement(bufDesc, descElem0, uint64_t(0)); - - // Dword 1 - SqBufRsrcWord1 sqBufRsrcWord1 = {}; - sqBufRsrcWord1.bits.baseAddressHi = UINT16_MAX; - descElem1 = CreateAnd(descElem1, getInt32(sqBufRsrcWord1.u32All)); - if (stride) { - SqBufRsrcWord1 sqBufRsrcWord1Stride = {}; - sqBufRsrcWord1Stride.bits.stride = stride; - descElem1 = CreateOr(descElem1, getInt32(sqBufRsrcWord1Stride.u32All)); - } - bufDesc = CreateInsertElement(bufDesc, descElem1, 1); - - // Dword 2 - SqBufRsrcWord2 sqBufRsrcWord2 = {}; - sqBufRsrcWord2.bits.numRecords = UINT32_MAX; - bufDesc = CreateInsertElement(bufDesc, getInt32(sqBufRsrcWord2.u32All), 2); - - // Dword 3 - SqBufRsrcWord3 sqBufRsrcWord3 = {}; - sqBufRsrcWord3.bits.dstSelX = BUF_DST_SEL_X; - sqBufRsrcWord3.bits.dstSelY = BUF_DST_SEL_Y; - sqBufRsrcWord3.bits.dstSelZ = BUF_DST_SEL_Z; - sqBufRsrcWord3.bits.dstSelW = BUF_DST_SEL_W; - if (gfxIp.major == 10) { - sqBufRsrcWord3.gfx10.format = BUF_FORMAT_32_UINT; - sqBufRsrcWord3.gfx10.resourceLevel = 1; - sqBufRsrcWord3.gfx10.oobSelect = stride ? 3 : 2; - assert(sqBufRsrcWord3.u32All == 0x21014FAC || sqBufRsrcWord3.u32All == 0x31014FAC); - } else if (gfxIp.major >= 11) { - sqBufRsrcWord3.gfx11.format = BUF_FORMAT_32_UINT; - sqBufRsrcWord3.gfx11.oobSelect = stride ? 3 : 2; - assert(sqBufRsrcWord3.u32All == 0x20014FAC || sqBufRsrcWord3.u32All == 0x30014FAC); - } else { - llvm_unreachable("Not implemented!"); + { + // Dword 0 + bufDesc = CreateInsertElement(bufDesc, descElem0, uint64_t(0)); + + // Dword 1 + SqBufRsrcWord1 sqBufRsrcWord1 = {}; + sqBufRsrcWord1.bits.baseAddressHi = UINT16_MAX; + descElem1 = CreateAnd(descElem1, getInt32(sqBufRsrcWord1.u32All)); + if (stride) { + SqBufRsrcWord1 sqBufRsrcWord1Stride = {}; + sqBufRsrcWord1Stride.bits.stride = stride; + descElem1 = CreateOr(descElem1, getInt32(sqBufRsrcWord1Stride.u32All)); + } + bufDesc = CreateInsertElement(bufDesc, descElem1, 1); + + // Dword 2 + SqBufRsrcWord2 sqBufRsrcWord2 = {}; + sqBufRsrcWord2.bits.numRecords = UINT32_MAX; + bufDesc = CreateInsertElement(bufDesc, getInt32(sqBufRsrcWord2.u32All), 2); + + // Dword 3 + SqBufRsrcWord3 sqBufRsrcWord3 = {}; + sqBufRsrcWord3.bits.dstSelX = BUF_DST_SEL_X; + sqBufRsrcWord3.bits.dstSelY = BUF_DST_SEL_Y; + sqBufRsrcWord3.bits.dstSelZ = BUF_DST_SEL_Z; + sqBufRsrcWord3.bits.dstSelW = BUF_DST_SEL_W; + if (gfxIp.major == 10) { + sqBufRsrcWord3.gfx10.format = BUF_FORMAT_32_UINT; + sqBufRsrcWord3.gfx10.resourceLevel = 1; + sqBufRsrcWord3.gfx10.oobSelect = stride ? 3 : 2; + assert(sqBufRsrcWord3.u32All == 0x21014FAC || sqBufRsrcWord3.u32All == 0x31014FAC); + } else if (gfxIp.major >= 11) { + sqBufRsrcWord3.gfx11.format = BUF_FORMAT_32_UINT; + sqBufRsrcWord3.gfx11.oobSelect = stride ? 3 : 2; + assert(sqBufRsrcWord3.u32All == 0x20014FAC || sqBufRsrcWord3.u32All == 0x30014FAC); + } else { + llvm_unreachable("Not implemented!"); + } + bufDesc = CreateInsertElement(bufDesc, getInt32(sqBufRsrcWord3.u32All), 3); } - bufDesc = CreateInsertElement(bufDesc, getInt32(sqBufRsrcWord3.u32All), 3); return bufDesc; } diff --git a/lgc/builder/ImageBuilder.cpp b/lgc/builder/ImageBuilder.cpp index 9b2fdb6d0e..363ebefd7c 100644 --- a/lgc/builder/ImageBuilder.cpp +++ b/lgc/builder/ImageBuilder.cpp @@ -423,14 +423,9 @@ static Type *convertToFloatingPointType(Type *origTy) { // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateImageLoad(Type *resultTy, unsigned dim, unsigned flags, Value *imageDesc, Value *coord, Value *mipLevel, const Twine &instName) { - imageDesc = fixImageDescForRead(imageDesc); - // Mark usage of images, to allow the compute workgroup reconfiguration optimization. - getPipelineState()->getShaderResourceUsage(m_shaderStage.value())->useImages = true; - getPipelineState()->getShaderResourceUsage(m_shaderStage.value())->resourceRead = true; - assert(coord->getType()->getScalarType()->isIntegerTy(32)); - coord = handleFragCoordViewIndex(coord, flags, dim); + if (isa(imageDesc)) + return PoisonValue::get(resultTy); - unsigned dmask = 1; Type *origTexelTy = resultTy; if (auto structResultTy = dyn_cast(resultTy)) origTexelTy = structResultTy->getElementType(0); @@ -444,6 +439,21 @@ Value *BuilderImpl::CreateImageLoad(Type *resultTy, unsigned dim, unsigned flags texelTy = FixedVectorType::get(getHalfTy(), 4); } + bool isTexelBuffer = (dim == Dim1DBuffer || dim == Dim1DArrayBuffer); + bool needFullDesc = texelTy != origTexelTy && origTexelTy->isIntOrIntVectorTy(64) && origTexelTy->isVectorTy() && + m_pipelineState->getOptions().allowNullDescriptor; + imageDesc = transformImageDesc(imageDesc, needFullDesc, isTexelBuffer, resultTy); + const bool isVecTyDesc = imageDesc->getType()->isVectorTy(); + if (isVecTyDesc) + imageDesc = fixImageDescForRead(imageDesc); + // Mark usage of images, to allow the compute workgroup reconfiguration optimization. + getPipelineState()->getShaderResourceUsage(m_shaderStage.value())->useImages = true; + getPipelineState()->getShaderResourceUsage(m_shaderStage.value())->resourceRead = true; + assert(coord->getType()->getScalarType()->isIntegerTy(32)); + coord = handleFragCoordViewIndex(coord, flags, dim); + + unsigned dmask = 1; + if (auto vectorResultTy = dyn_cast(texelTy)) dmask = (1U << vectorResultTy->getNumElements()) - 1; @@ -462,7 +472,7 @@ Value *BuilderImpl::CreateImageLoad(Type *resultTy, unsigned dim, unsigned flags SmallVector args; Instruction *imageInst = nullptr; unsigned imageDescArgIndex = 0; - if (imageDesc->getType() == getDescTy(ResourceNodeType::DescriptorResource)) { + if (!isTexelBuffer) { // Not texel buffer; use image load instruction. // Build the intrinsic arguments. bool tfe = isa(intrinsicDataTy); @@ -509,11 +519,13 @@ Value *BuilderImpl::CreateImageLoad(Type *resultTy, unsigned dim, unsigned flags // Add a waterfall loop if needed. Value *result = imageInst; - if (flags & ImageFlagNonUniformImage) - result = createWaterfallLoop(imageInst, imageDescArgIndex, - getPipelineState()->getShaderOptions(m_shaderStage.value()).scalarizeWaterfallLoads); - else if (flags & ImageFlagEnforceReadFirstLaneImage) - enforceReadFirstLane(imageInst, imageDescArgIndex); + if (imageDesc->getType()->isVectorTy()) { + if (flags & ImageFlagNonUniformImage) + result = createWaterfallLoop(imageInst, imageDescArgIndex, + getPipelineState()->getShaderOptions(m_shaderStage.value()).scalarizeWaterfallLoads); + else if (flags & ImageFlagEnforceReadFirstLaneImage) + enforceReadFirstLane(imageInst, imageDescArgIndex); + } if (texelTy != origTexelTy) { Value *texel = result; @@ -581,6 +593,8 @@ Value *BuilderImpl::CreateImageLoad(Type *resultTy, unsigned dim, unsigned flags // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateImageLoadWithFmask(Type *resultTy, unsigned dim, unsigned flags, Value *imageDesc, Value *fmaskDesc, Value *coord, Value *sampleNum, const Twine &instName) { + if (isa(imageDesc)) + return PoisonValue::get(resultTy); // Load texel from F-mask image. unsigned fmaskDim = dim; switch (dim) { @@ -596,7 +610,7 @@ Value *BuilderImpl::CreateImageLoadWithFmask(Type *resultTy, unsigned dim, unsig } // When the shadow table is disabled, we don't need to load F-mask descriptor - if (m_pipelineState->getOptions().enableFmask) { + if (m_pipelineState->getOptions().enableFmask && !isa(fmaskDesc)) { Value *fmaskTexel = CreateImageLoad(FixedVectorType::get(getInt32Ty(), 4), fmaskDim, flags, fmaskDesc, coord, nullptr, instName + ".fmaskload"); @@ -607,6 +621,11 @@ Value *BuilderImpl::CreateImageLoadWithFmask(Type *resultTy, unsigned dim, unsig calcSampleNum = CreateAnd(calcSampleNum, getInt32(15)); // Check whether the F-mask descriptor has a BUF_DATA_FORMAT_INVALID (0) format (dword[1].bit[20-25]). + if (!fmaskDesc->getType()->isVectorTy()) { + auto callInst = cast(fmaskTexel); + unsigned argIdx = callInst->arg_size() == 5 ? 0 : callInst->arg_size() - 3; + fmaskDesc = callInst->getArgOperand(argIdx); + } Value *fmaskFormat = CreateExtractElement(fmaskDesc, 1); fmaskFormat = CreateAnd(fmaskFormat, getInt32(63 << 20)); Value *fmaskValidFormat = CreateICmpNE(fmaskFormat, getInt32(0)); @@ -634,6 +653,8 @@ Value *BuilderImpl::CreateImageLoadWithFmask(Type *resultTy, unsigned dim, unsig // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateImageStore(Value *texel, unsigned dim, unsigned flags, Value *imageDesc, Value *coord, Value *mipLevel, const Twine &instName) { + if (isa(imageDesc)) + return PoisonValue::get(texel->getType()); // Mark usage of images, to allow the compute workgroup reconfiguration optimization. getPipelineState()->getShaderResourceUsage(m_shaderStage.value())->resourceWrite = true; assert(coord->getType()->getScalarType()->isIntegerTy(32)); @@ -658,11 +679,14 @@ Value *BuilderImpl::CreateImageStore(Value *texel, unsigned dim, unsigned flags, SmallVector derivatives; dim = prepareCoordinate(dim, coord, nullptr, nullptr, nullptr, coords, derivatives); + bool isTexelBuffer = (dim == Dim1DBuffer || dim == Dim1DArrayBuffer); + imageDesc = transformImageDesc(imageDesc, false, isTexelBuffer, texel->getType()); + Type *texelTy = texel->getType(); SmallVector args; Instruction *imageStore = nullptr; unsigned imageDescArgIndex = 0; - if (imageDesc->getType() == getDescTy(ResourceNodeType::DescriptorResource)) { + if (!isTexelBuffer) { // Not texel buffer; use image store instruction. // Build the intrinsic arguments. unsigned dmask = 1; @@ -717,12 +741,14 @@ Value *BuilderImpl::CreateImageStore(Value *texel, unsigned dim, unsigned flags, CreateIntrinsic(Intrinsic::amdgcn_struct_buffer_store_format, texel->getType(), args, nullptr, instName); } - // Add a waterfall loop if needed. - if (flags & ImageFlagNonUniformImage) - createWaterfallLoop(imageStore, imageDescArgIndex, - getPipelineState()->getShaderOptions(m_shaderStage.value()).scalarizeWaterfallLoads); - else if (flags & ImageFlagEnforceReadFirstLaneImage) - enforceReadFirstLane(imageStore, imageDescArgIndex); + if (imageDesc->getType()->isVectorTy()) { + // Add a waterfall loop if needed. + if (flags & ImageFlagNonUniformImage) + createWaterfallLoop(imageStore, imageDescArgIndex, + getPipelineState()->getShaderOptions(m_shaderStage.value()).scalarizeWaterfallLoads); + else if (flags & ImageFlagEnforceReadFirstLaneImage) + enforceReadFirstLane(imageStore, imageDescArgIndex); + } return imageStore; } @@ -805,6 +831,10 @@ Value *BuilderImpl::CreateImageSampleConvertYCbCr(Type *resultTy, unsigned dim, Value *imageDesc = imageDescArray; if (isa(imageDescArray->getType())) imageDesc = CreateExtractValue(imageDescArray, 0); + if (isa(imageDesc)) + imageDesc = PoisonValue::get(FixedVectorType::get(getInt32Ty(), 8)); + else + imageDesc = transformImageDesc(imageDesc, true, false, resultTy); imageDesc = fixImageDescForRead(imageDesc); YCbCrSampleInfo sampleInfoLuma = {resultTy, dim, flags, imageDesc, samplerDescLuma, address, instName.str(), true}; @@ -817,6 +847,10 @@ Value *BuilderImpl::CreateImageSampleConvertYCbCr(Type *resultTy, unsigned dim, // Set image descriptor for chroma channel for (unsigned planeIdx = 1; planeIdx < yCbCrMetaData.word1.planes; ++planeIdx) { imageDesc = CreateExtractValue(imageDescArray, planeIdx); + if (isa(imageDesc)) + imageDesc = PoisonValue::get(FixedVectorType::get(getInt32Ty(), 8)); + else + imageDesc = transformImageDesc(imageDesc, true, false, resultTy); imageDesc = fixImageDescForRead(imageDesc); YCbCrConverter.SetImgDescChroma(planeIdx, imageDesc); } @@ -843,6 +877,9 @@ Value *BuilderImpl::CreateImageSampleConvertYCbCr(Type *resultTy, unsigned dim, // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateImageGather(Type *resultTy, unsigned dim, unsigned flags, Value *imageDesc, Value *samplerDesc, ArrayRef address, const Twine &instName) { + if (isa(imageDesc) || isa(samplerDesc)) + return PoisonValue::get(resultTy); + Value *coord = address[ImageAddressIdxCoordinate]; assert(coord->getType()->getScalarType()->isFloatTy() || coord->getType()->getScalarType()->isHalfTy()); @@ -861,8 +898,7 @@ Value *BuilderImpl::CreateImageGather(Type *resultTy, unsigned dim, unsigned fla gatherTy = StructType::get(getContext(), {gatherTy, getInt32Ty()}); } - // Only the first 4 dwords are sampler descriptor, we need to extract these values under any condition - samplerDesc = CreateShuffleVector(samplerDesc, samplerDesc, ArrayRef{0, 1, 2, 3}); + samplerDesc = transformSamplerDesc(samplerDesc); if (m_pipelineState->getOptions().disableTruncCoordForGather) { samplerDesc = modifySamplerDescForGather(samplerDesc); @@ -930,7 +966,16 @@ Value *BuilderImpl::CreateImageGather(Type *resultTy, unsigned dim, unsigned fla Value *BuilderImpl::CreateImageSampleGather(Type *resultTy, unsigned dim, unsigned flags, Value *coord, Value *imageDesc, Value *samplerDesc, ArrayRef address, const Twine &instName, bool isSample) { - imageDesc = fixImageDescForRead(imageDesc); + if (isa(imageDesc) || isa(samplerDesc)) + return PoisonValue::get(resultTy); + + imageDesc = transformImageDesc(imageDesc, false, false, resultTy); + const bool isVecTyDesc = imageDesc->getType()->isVectorTy(); + if (isVecTyDesc) + imageDesc = fixImageDescForRead(imageDesc); + + samplerDesc = transformSamplerDesc(samplerDesc); + // Mark usage of images, to allow the compute workgroup reconfiguration optimization. getPipelineState()->getShaderResourceUsage(m_shaderStage.value())->useImages = true; // Set up the mask of address components provided, for use in searching the intrinsic ID table @@ -1057,16 +1102,22 @@ Value *BuilderImpl::CreateImageSampleGather(Type *resultTy, unsigned dim, unsign // Add a waterfall loop if needed. SmallVector nonUniformArgIndexes; - if (flags & ImageFlagNonUniformImage) - nonUniformArgIndexes.push_back(imageDescArgIndex); - else if (flags & ImageFlagEnforceReadFirstLaneImage) - enforceReadFirstLane(imageOp, imageDescArgIndex); + if (imageDesc->getType()->isVectorTy()) { + if (flags & ImageFlagNonUniformImage) + nonUniformArgIndexes.push_back(imageDescArgIndex); + else if (flags & ImageFlagEnforceReadFirstLaneImage) + enforceReadFirstLane(imageOp, imageDescArgIndex); + } - const unsigned samplerDescArgIndex = imageDescArgIndex + 1; - if (flags & ImageFlagNonUniformSampler) - nonUniformArgIndexes.push_back(samplerDescArgIndex); - else if (flags & ImageFlagEnforceReadFirstLaneSampler) - enforceReadFirstLane(imageOp, samplerDescArgIndex); + if (samplerDesc->getType()->isVectorTy()) { + const unsigned samplerDescArgIndex = imageDescArgIndex + 1; + if (flags & ImageFlagNonUniformSampler) { + nonUniformArgIndexes.push_back(samplerDescArgIndex); + } else { + // TODO: Re-add the condition once backend fix the waterfall loop bug. + enforceReadFirstLane(imageOp, samplerDescArgIndex); + } + } if (!nonUniformArgIndexes.empty()) imageOp = createWaterfallLoop(imageOp, nonUniformArgIndexes, @@ -1123,6 +1174,8 @@ Value *BuilderImpl::CreateImageAtomicCompareSwap(unsigned dim, unsigned flags, A Value *BuilderImpl::CreateImageAtomicCommon(unsigned atomicOp, unsigned dim, unsigned flags, AtomicOrdering ordering, Value *imageDesc, Value *coord, Value *inputValue, Value *comparatorValue, const Twine &instName) { + if (isa(imageDesc)) + return PoisonValue::get(inputValue->getType()); getPipelineState()->getShaderResourceUsage(m_shaderStage.value())->resourceWrite = true; assert(coord->getType()->getScalarType()->isIntegerTy(32)); coord = handleFragCoordViewIndex(coord, flags, dim); @@ -1131,7 +1184,7 @@ Value *BuilderImpl::CreateImageAtomicCommon(unsigned atomicOp, unsigned dim, uns case AtomicOrdering::Release: case AtomicOrdering::AcquireRelease: case AtomicOrdering::SequentiallyConsistent: - CreateFence(AtomicOrdering::Release, SyncScope::System); + CreateFence(AtomicOrdering::Release, getContext().getOrInsertSyncScopeID("agent")); break; default: break; @@ -1142,10 +1195,13 @@ Value *BuilderImpl::CreateImageAtomicCommon(unsigned atomicOp, unsigned dim, uns SmallVector derivatives; dim = prepareCoordinate(dim, coord, nullptr, nullptr, nullptr, coords, derivatives); + bool isTexelBuffer = (dim == Dim1DBuffer || dim == Dim1DArrayBuffer); + imageDesc = transformImageDesc(imageDesc, false, isTexelBuffer, nullptr); + SmallVector args; Instruction *atomicInst = nullptr; unsigned imageDescArgIndex = 0; - if (imageDesc->getType() == getDescTy(ResourceNodeType::DescriptorResource)) { + if (!isTexelBuffer) { // Resource descriptor. Use the image atomic instruction. args.push_back(inputValue); if (atomicOp == AtomicOpCompareSwap) @@ -1176,18 +1232,20 @@ Value *BuilderImpl::CreateImageAtomicCommon(unsigned atomicOp, unsigned dim, uns atomicInst = CreateIntrinsic(StructBufferAtomicIntrinsicTable[atomicOp], inputValue->getType(), args, nullptr, instName); } - if (flags & ImageFlagNonUniformImage) - atomicInst = - createWaterfallLoop(atomicInst, imageDescArgIndex, - getPipelineState()->getShaderOptions(m_shaderStage.value()).scalarizeWaterfallLoads); - else if (flags & ImageFlagEnforceReadFirstLaneImage) - enforceReadFirstLane(atomicInst, imageDescArgIndex); + if (imageDesc->getType()->isVectorTy()) { + if (flags & ImageFlagNonUniformImage) + atomicInst = + createWaterfallLoop(atomicInst, imageDescArgIndex, + getPipelineState()->getShaderOptions(m_shaderStage.value()).scalarizeWaterfallLoads); + else if (flags & ImageFlagEnforceReadFirstLaneImage) + enforceReadFirstLane(atomicInst, imageDescArgIndex); + } switch (ordering) { case AtomicOrdering::Acquire: case AtomicOrdering::AcquireRelease: case AtomicOrdering::SequentiallyConsistent: - CreateFence(AtomicOrdering::Acquire, SyncScope::System); + CreateFence(AtomicOrdering::Acquire, getContext().getOrInsertSyncScopeID("agent")); break; default: break; @@ -1204,8 +1262,12 @@ Value *BuilderImpl::CreateImageAtomicCommon(unsigned atomicOp, unsigned dim, uns // @param imageDesc : Image descriptor or texel buffer descriptor // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateImageQueryLevels(unsigned dim, unsigned flags, Value *imageDesc, const Twine &instName) { + if (isa(imageDesc)) + return PoisonValue::get(getInt32Ty()); dim = dim == DimCubeArray ? DimCube : dim; + imageDesc = transformImageDesc(imageDesc, true, false, nullptr); + Value *numMipLevel = nullptr; GfxIpVersion gfxIp = getPipelineState()->getTargetInfo().getGfxIpVersion(); SqImgRsrcRegHandler proxySqRsrcRegHelper(this, imageDesc, &gfxIp); @@ -1242,6 +1304,10 @@ Value *BuilderImpl::CreateImageQueryLevels(unsigned dim, unsigned flags, Value * // @param imageDesc : Image descriptor or texel buffer descriptor // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateImageQuerySamples(unsigned dim, unsigned flags, Value *imageDesc, const Twine &instName) { + if (isa(imageDesc)) + return PoisonValue::get(getInt32Ty()); + + imageDesc = transformImageDesc(imageDesc, true, false, nullptr); Value *descWord3 = CreateExtractElement(imageDesc, 3); Value *lastLevel = nullptr; if (m_pipelineState->getTargetInfo().getGfxIpVersion().major <= 11) { @@ -1299,7 +1365,11 @@ Value *BuilderImpl::CreateImageQuerySamples(unsigned dim, unsigned flags, Value // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateImageQuerySize(unsigned dim, unsigned flags, Value *imageDesc, Value *lod, const Twine &instName) { - if (imageDesc->getType() == getDescTy(ResourceNodeType::DescriptorTexelBuffer)) { + if (isa(imageDesc)) + return PoisonValue::get(getInt32Ty()); + bool isTexelBuffer = (dim == Dim1DBuffer || dim == Dim1DArrayBuffer); + imageDesc = transformImageDesc(imageDesc, true, isTexelBuffer, nullptr); + if (isTexelBuffer) { // Texel buffer. // Extract NUM_RECORDS (SQ_BUF_RSRC_WORD2) Value *numRecords = CreateExtractElement(imageDesc, 2); @@ -1396,6 +1466,9 @@ Value *BuilderImpl::CreateImageQuerySize(unsigned dim, unsigned flags, Value *im // @param instName : Name to give instruction(s) Value *BuilderImpl::CreateImageGetLod(unsigned dim, unsigned flags, Value *imageDesc, Value *samplerDesc, Value *coord, const Twine &instName) { + if (isa(imageDesc) || isa(samplerDesc)) + return PoisonValue::get(FixedVectorType::get(getFloatTy(), 2)); + // Remove array from dimension if any. switch (dim) { case Dim1DArray: @@ -1417,8 +1490,13 @@ Value *BuilderImpl::CreateImageGetLod(unsigned dim, unsigned flags, Value *image SmallVector derivatives; dim = prepareCoordinate(dim, coord, nullptr, nullptr, nullptr, coords, derivatives); - // Only the first 4 dwords are sampler descriptor, we need to extract these values under any condition - samplerDesc = CreateShuffleVector(samplerDesc, samplerDesc, ArrayRef{0, 1, 2, 3}); + imageDesc = transformImageDesc(imageDesc, false, false, nullptr); + if (isa(samplerDesc->getType())) { + // Only the first 4 dwords are sampler descriptor, we need to extract these values under any condition + samplerDesc = CreateShuffleVector(samplerDesc, ArrayRef{0, 1, 2, 3}); + } else { + samplerDesc = transformSamplerDesc(samplerDesc); + } SmallVector args; args.push_back(getInt32(3)); // dmask @@ -1432,19 +1510,23 @@ Value *BuilderImpl::CreateImageGetLod(unsigned dim, unsigned flags, Value *image Instruction *result = CreateIntrinsic(ImageGetLodIntrinsicTable[dim], {FixedVectorType::get(getFloatTy(), 2), getFloatTy()}, args, nullptr, instName); - // Add a waterfall loop if needed. - SmallVector nonUniformArgIndexes; - if (flags & ImageFlagNonUniformImage) - nonUniformArgIndexes.push_back(imageDescArgIndex); - else if (flags & ImageFlagEnforceReadFirstLaneImage) - enforceReadFirstLane(result, imageDescArgIndex); - const unsigned samplerDescArgIndex = imageDescArgIndex + 1; - if (flags & ImageFlagNonUniformSampler) - nonUniformArgIndexes.push_back(samplerDescArgIndex); - else if (flags & ImageFlagEnforceReadFirstLaneSampler) - enforceReadFirstLane(result, samplerDescArgIndex); + SmallVector nonUniformArgIndexes; + if (imageDesc->getType()->isVectorTy()) { + // Add a waterfall loop if needed. + if (flags & ImageFlagNonUniformImage) + nonUniformArgIndexes.push_back(imageDescArgIndex); + else if (flags & ImageFlagEnforceReadFirstLaneImage) + enforceReadFirstLane(result, imageDescArgIndex); + } + if (samplerDesc->getType()->isVectorTy()) { + const unsigned samplerDescArgIndex = imageDescArgIndex + 1; + if (flags & ImageFlagNonUniformSampler) + nonUniformArgIndexes.push_back(samplerDescArgIndex); + else if (flags & ImageFlagEnforceReadFirstLaneSampler) + enforceReadFirstLane(result, samplerDescArgIndex); + } if (!nonUniformArgIndexes.empty()) result = createWaterfallLoop(result, nonUniformArgIndexes, getPipelineState()->getShaderOptions(m_shaderStage.value()).scalarizeWaterfallLoads); @@ -1911,3 +1993,40 @@ Value *BuilderImpl::modifySamplerDescForGather(Value *samplerDesc) { return samplerDesc; } + +// ===================================================================================================================== +// Transform image descriptor pointer to a i32 type or a descriptor load instruction. +// +// @param imageDesc : image descriptor pointer +// @param mustLoad : Whether to load image descriptor from the pointer +// @param isTexelBuffer : Whether it is a texel buffer +// @param texelType : The type of the texel +// @returns The transformed descriptor +Value *BuilderImpl::transformImageDesc(Value *imageDesc, bool mustLoad, bool isTexelBuffer, Type *texelType) { + assert(!isa(imageDesc)); + if (isa(imageDesc->getType())) + return imageDesc; + + // Explicitly load the descriptor from the descriptor pointer + Type *descType = FixedVectorType::get(getInt32Ty(), isTexelBuffer ? 4 : 8); + Value *desc = CreateLoad(descType, imageDesc); + cast(desc)->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(getContext(), {})); + return desc; +} + +// ===================================================================================================================== +// Transform sampler descriptor pointer to a i32 type or a descriptor load instruction. +// +// @param samplerDesc : descriptor pointer or a full descriptor +// @returns Transformed sampler descriptor +Value *BuilderImpl::transformSamplerDesc(Value *samplerDesc) { + assert(!isa(samplerDesc)); + if (isa(samplerDesc->getType())) + return samplerDesc; + + // Explicitly load the descriptor from the descriptor pointer + Type *descType = FixedVectorType::get(getInt32Ty(), 4); + Value *desc = CreateLoad(descType, samplerDesc); + cast(desc)->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(getContext(), {})); + return desc; +} diff --git a/lgc/builder/InOutBuilder.cpp b/lgc/builder/InOutBuilder.cpp index 4172a0aa6b..14cd7b5032 100644 --- a/lgc/builder/InOutBuilder.cpp +++ b/lgc/builder/InOutBuilder.cpp @@ -430,8 +430,8 @@ void BuilderImpl::markGenericInputOutputUsage(bool isOutput, unsigned location, if (isOutput) { // Keep all locations if the next stage of the output is fragment shader or is unspecified if (m_shaderStage != ShaderStage::Fragment) { - ShaderStageEnum nextStage = m_pipelineState->getNextShaderStage(m_shaderStage.value()); - keepAllLocations = nextStage == ShaderStage::Fragment || nextStage == ShaderStage::Invalid; + auto nextStage = m_pipelineState->getNextShaderStage(m_shaderStage.value()); + keepAllLocations = nextStage == ShaderStage::Fragment || !nextStage; } } else { // Keep all locations if it is the input of fragment shader diff --git a/lgc/builder/SubgroupBuilder.cpp b/lgc/builder/SubgroupBuilder.cpp index 3a74d5bc01..c62acd661c 100644 --- a/lgc/builder/SubgroupBuilder.cpp +++ b/lgc/builder/SubgroupBuilder.cpp @@ -79,31 +79,27 @@ unsigned BuilderImpl::getShaderWaveSize() { // // @param instName : Name to give final instruction. Value *SubgroupBuilder::CreateSubgroupElect(const Twine &instName) { - bool excludeHelperLanes = false; - if (getShaderStage(GetInsertBlock()->getParent()).value() == ShaderStage::Fragment) - excludeHelperLanes = m_pipelineState->getShaderModes()->getFragmentShaderMode().waveOpsExcludeHelperLanes; - return CreateICmpEQ(CreateSubgroupMbcnt(createGroupBallot(getTrue(), excludeHelperLanes)), getInt32(0)); + auto shaderStage = getShaderStage(GetInsertBlock()->getParent()); + return CreateICmpEQ(CreateSubgroupMbcnt(createGroupBallot(getTrue(), shaderStage.value())), getInt32(0)); } // ===================================================================================================================== // Create a subgroup all call. // // @param value : The value to compare across the subgroup. Must be an integer type. +// @param shaderStage : shader stage enum. // @param instName : Name to give final instruction. -Value *SubgroupBuilder::CreateSubgroupAll(Value *const value, const Twine &instName) { - bool ballotExcludeHelperLanes = false; +Value *SubgroupBuilder::createSubgroupAll(Value *const value, ShaderStageEnum shaderStage, const Twine &instName) { bool includeHelperLanes = false; bool requireHelperLanes = false; - if (getShaderStage(GetInsertBlock()->getParent()).value() == ShaderStage::Fragment) { + if (shaderStage == ShaderStage::Fragment) { const auto &fragmentMode = m_pipelineState->getShaderModes()->getFragmentShaderMode(); - ballotExcludeHelperLanes = fragmentMode.waveOpsExcludeHelperLanes; includeHelperLanes = !fragmentMode.waveOpsExcludeHelperLanes; requireHelperLanes = fragmentMode.waveOpsRequireHelperLanes; } - Value *result = CreateICmpEQ(createGroupBallot(value, ballotExcludeHelperLanes), - createGroupBallot(getTrue(), ballotExcludeHelperLanes)); + Value *result = CreateICmpEQ(createGroupBallot(value, shaderStage), createGroupBallot(getTrue(), shaderStage)); result = CreateSelect(CreateUnaryIntrinsic(Intrinsic::is_constant, value), value, result); // Helper invocations of whole quad mode should be included in the subgroup vote execution @@ -122,18 +118,18 @@ Value *SubgroupBuilder::CreateSubgroupAll(Value *const value, const Twine &instN // @param value : The value to compare across the subgroup. Must be an integer type. // @param instName : Name to give final instruction. Value *SubgroupBuilder::CreateSubgroupAny(Value *const value, const Twine &instName) { - bool ballotExcludeHelperLanes = false; + auto shaderStage = getShaderStage(GetInsertBlock()->getParent()); + bool includeHelperLanes = false; bool requireHelperLanes = false; if (getShaderStage(GetInsertBlock()->getParent()).value() == ShaderStage::Fragment) { const auto &fragmentMode = m_pipelineState->getShaderModes()->getFragmentShaderMode(); - ballotExcludeHelperLanes = fragmentMode.waveOpsExcludeHelperLanes; includeHelperLanes = !fragmentMode.waveOpsExcludeHelperLanes; requireHelperLanes = fragmentMode.waveOpsRequireHelperLanes; } - Value *result = CreateICmpNE(createGroupBallot(value, ballotExcludeHelperLanes), getInt64(0)); + Value *result = CreateICmpNE(createGroupBallot(value, shaderStage.value()), getInt64(0)); result = CreateSelect(CreateUnaryIntrinsic(Intrinsic::is_constant, value), value, result); // Helper invocations of whole quad mode should be included in the subgroup vote execution @@ -152,9 +148,11 @@ Value *SubgroupBuilder::CreateSubgroupAny(Value *const value, const Twine &instN // @param value : The value to compare across the subgroup. Must be an integer type. // @param instName : Name to give final instruction. Value *SubgroupBuilder::CreateSubgroupAllEqual(Value *const value, const Twine &instName) { + auto shaderStage = getShaderStage(GetInsertBlock()->getParent()).value(); + Type *const type = value->getType(); - Value *compare = CreateSubgroupBroadcastFirst(value, instName); + Value *compare = createSubgroupBroadcastFirst(value, shaderStage, instName); if (type->isFPOrFPVectorTy()) compare = CreateFCmpOEQ(compare, value); @@ -169,9 +167,9 @@ Value *SubgroupBuilder::CreateSubgroupAllEqual(Value *const value, const Twine & for (unsigned i = 1, compCount = cast(type)->getNumElements(); i < compCount; i++) result = CreateAnd(result, CreateExtractElement(compare, i)); - return CreateSubgroupAll(result, instName); + return createSubgroupAll(result, shaderStage, instName); } - return CreateSubgroupAll(compare, instName); + return createSubgroupAll(compare, shaderStage, instName); } // ===================================================================================================================== @@ -183,6 +181,8 @@ Value *SubgroupBuilder::CreateSubgroupAllEqual(Value *const value, const Twine & // @param instName : Name to give final instruction. Value *SubgroupBuilder::CreateSubgroupRotate(Value *const value, Value *const delta, Value *const clusterSize, const Twine &instName) { + auto shaderStage = getShaderStage(GetInsertBlock()->getParent()).value(); + // LocalId = SubgroupLocalInvocationId // RotationGroupSize = hasClusterSIze? ClusterSize : SubgroupSize. // Invocation ID = ((LocalId + Delta) & (RotationGroupSize - 1)) + (LocalId & ~(RotationGroupSize - 1)) @@ -194,7 +194,7 @@ Value *SubgroupBuilder::CreateSubgroupRotate(Value *const value, Value *const de CreateOr(CreateAnd(invocationId, rotationGroupSize), CreateAnd(localId, CreateNot(rotationGroupSize))); } - return CreateSubgroupShuffle(value, invocationId, instName); + return createSubgroupShuffle(value, invocationId, shaderStage, instName); } // ===================================================================================================================== @@ -232,12 +232,14 @@ Value *BuilderImpl::CreateSubgroupBroadcastWaterfall(Value *const value, Value * // Create a subgroup broadcastfirst call. // // @param value : The value to read from the first active lane into all other active lanes. +// @param shaderStage : shader stage enum. // @param instName : Name to give final instruction. -Value *BuilderImpl::CreateSubgroupBroadcastFirst(Value *const value, const Twine &instName) { - const auto &fragmentMode = m_pipelineState->getShaderModes()->getFragmentShaderMode(); +Value *BuilderImpl::createSubgroupBroadcastFirst(Value *const value, ShaderStageEnum shaderStage, + const Twine &instName) { // For waveOpsExcludeHelperLanes mode, we need filter out the helperlane and use readlane instead. - if (m_shaderStage == ShaderStage::Fragment && fragmentMode.waveOpsExcludeHelperLanes) { - Value *ballot = createGroupBallot(getTrue()); + if (shaderStage == ShaderStage::Fragment && + m_pipelineState->getShaderModes()->getFragmentShaderMode().waveOpsExcludeHelperLanes) { + Value *ballot = createGroupBallot(getTrue(), shaderStage); Value *firstlane = CreateIntrinsic(Intrinsic::cttz, getInt64Ty(), {ballot, getTrue()}); firstlane = CreateTrunc(firstlane, getInt32Ty()); @@ -384,10 +386,12 @@ Value *BuilderImpl::CreateSubgroupBallotFindMsb(Value *const value, const Twine // // @param value : The value to shuffle. // @param index : The index to shuffle from. +// @param shaderStage : shader stage enum. // @param instName : Name to give final instruction. -Value *BuilderImpl::CreateSubgroupShuffle(Value *const value, Value *const index, const Twine &instName) { +Value *BuilderImpl::createSubgroupShuffle(Value *const value, Value *const index, ShaderStageEnum shaderStage, + const Twine &instName) { - if (supportWaveWideBPermute()) { + if (supportWaveWideBPermute(shaderStage)) { auto mapFunc = [](BuilderBase &builder, ArrayRef mappedArgs, ArrayRef passthroughArgs) -> Value * { return builder.CreateIntrinsic(Intrinsic::amdgcn_ds_bpermute, {}, {passthroughArgs[0], mappedArgs[0]}); @@ -398,7 +402,7 @@ Value *BuilderImpl::CreateSubgroupShuffle(Value *const value, Value *const index } if (supportPermLane64Dpp()) { - assert(getShaderWaveSize() == 64); + assert(getPipelineState()->getShaderWaveSize(shaderStage) == 64); // Start the WWM section by setting the inactive lanes. Value *const poisonValue = PoisonValue::get(value->getType()); @@ -431,9 +435,9 @@ Value *BuilderImpl::CreateSubgroupShuffle(Value *const value, Value *const index auto result = CreateSelect(indexInSameHalf, bPermSameHalf, bPermOtherHalf); // If required, force inputs of the operation to be computed in WQM. - if (m_shaderStage == ShaderStage::Fragment && + if (shaderStage == ShaderStage::Fragment && m_pipelineState->getShaderModes()->getFragmentShaderMode().waveOpsRequireHelperLanes) - result = createWqm(result); + result = createWqm(result, shaderStage); return result; } @@ -630,12 +634,15 @@ Value *BuilderImpl::CreateSubgroupClusteredReduction(GroupArithOp groupArithOp, // Use a permute lane to cross rows (row 1 <-> row 0, row 3 <-> row 2). result = createGroupArithmeticOperation(groupArithOp, result, createPermLaneX16(result, result, UINT32_MAX, UINT32_MAX, true, false)); + if (waveSize == 32) + result = createReadFirstLane(result); } if (clusterSize == 64) { assert(waveSize == 64); if (supportPermLane64Dpp()) { result = createGroupArithmeticOperation(groupArithOp, result, createPermLane64(result)); + result = createReadFirstLane(result); } else { Value *const broadcast31 = CreateSubgroupBroadcast(result, getInt32(31), instName); Value *const broadcast63 = CreateSubgroupBroadcast(result, getInt32(63), instName); @@ -1303,6 +1310,18 @@ Value *BuilderImpl::createPermLane64(Value *const updateValue) { return CreateMapToSimpleType(mapFunc, updateValue, {}); } +// ===================================================================================================================== +// Create a call to get the first lane. +// +// @param updateValue : The value to update with. +Value *BuilderImpl::createReadFirstLane(Value *const updateValue) { + auto mapFunc = [](BuilderBase &builder, ArrayRef mappedArgs, ArrayRef passthroughArgs) -> Value * { + return builder.CreateIntrinsic(builder.getInt32Ty(), Intrinsic::amdgcn_readfirstlane, {mappedArgs[0]}); + }; + + return CreateMapToSimpleType(mapFunc, updateValue, {}); +} + // ===================================================================================================================== // Create a call to ds swizzle. // @@ -1333,12 +1352,13 @@ Value *BuilderImpl::createWwm(Value *const value) { // Only in fragment shader stage. // // @param value : The value to pass to the soft WQM call. -Value *BuilderImpl::createWqm(Value *const value) { +// @param shaderStage : shader stage enum. +Value *BuilderImpl::createWqm(Value *const value, ShaderStageEnum shaderStage) { auto mapFunc = [](BuilderBase &builder, ArrayRef mappedArgs, ArrayRef) -> Value * { return builder.CreateUnaryIntrinsic(Intrinsic::amdgcn_wqm, mappedArgs[0]); }; - if (m_shaderStage == ShaderStage::Fragment) + if (shaderStage == ShaderStage::Fragment) return CreateMapToSimpleType(mapFunc, value, {}); return value; @@ -1398,15 +1418,16 @@ Value *BuilderImpl::createThreadMaskedSelect(Value *const threadMask, uint64_t a // Do group ballot, turning a per-lane boolean value (in a VGPR) into a subgroup-wide shared SGPR. // // @param value : The value to contribute to the SGPR, must be an boolean type. -// @param excludeHelperLanes : exclude helper lanes. -Value *BuilderImpl::createGroupBallot(Value *const value, bool excludeHelperLanes) { +// @param shaderStage : shader stage enum. +Value *BuilderImpl::createGroupBallot(Value *const value, ShaderStageEnum shaderStage) { // Check the type is definitely an boolean. assert(value->getType()->isIntegerTy(1)); Value *result = value; // For waveOpsExcludeHelperLanes mode, we need mask away the helperlane. - if (excludeHelperLanes) { + if (shaderStage == ShaderStage::Fragment && + m_pipelineState->getShaderModes()->getFragmentShaderMode().waveOpsExcludeHelperLanes) { auto isLive = CreateIntrinsic(Intrinsic::amdgcn_live_mask, {}, {}, nullptr, {}); result = CreateAnd(isLive, result); } @@ -1426,11 +1447,7 @@ Value *BuilderImpl::createGroupBallot(Value *const value, bool excludeHelperLane // // @param value : The value to contribute to the SGPR, must be an boolean type. Value *BuilderImpl::createGroupBallot(Value *const value) { - // For waveOpsExcludeHelperLanes mode, we need mask away the helperlane. - bool excludeHelperLanes = false; - if (m_shaderStage == ShaderStage::Fragment) - excludeHelperLanes = m_pipelineState->getShaderModes()->getFragmentShaderMode().waveOpsExcludeHelperLanes; - return createGroupBallot(value, excludeHelperLanes); + return createGroupBallot(value, m_shaderStage.value()); } // ===================================================================================================================== diff --git a/lgc/include/lgc/builder/BuilderImpl.h b/lgc/include/lgc/builder/BuilderImpl.h index 98057d0670..652b7b920c 100644 --- a/lgc/include/lgc/builder/BuilderImpl.h +++ b/lgc/include/lgc/builder/BuilderImpl.h @@ -74,7 +74,7 @@ class BuilderImpl : public BuilderDefs { PipelineState *getPipelineState() const { return m_pipelineState; } // Get whether the context we are building in supports ds_bpermute or v_bpermute across all lanes in the wave. - bool supportWaveWideBPermute() const; + bool supportWaveWideBPermute(ShaderStageEnum shaderStage) const; // Get whether the context we are building in supports permute lane 64 DPP operations. bool supportPermLane64Dpp() const; @@ -441,6 +441,12 @@ class BuilderImpl : public BuilderDefs { // Modify sampler descriptor to force set trunc_coord as 0 for gather4 instruction. llvm::Value *modifySamplerDescForGather(llvm::Value *samplerDesc); + // Transform 32-bit image descriptor pointer to a i32 type or a descriptor load instruction. + llvm::Value *transformImageDesc(llvm::Value *imageDesc, bool mustLoad, bool isTexelBuffer, llvm::Type *texelType); + + // Transform 32-bit sampler descriptor pointer to a i32 type or a descriptor load instruction. + llvm::Value *transformSamplerDesc(llvm::Value *samplerDesc); + enum ImgDataFormat { IMG_DATA_FORMAT_32 = 4, IMG_DATA_FORMAT_8_8_8_8 = 10, @@ -657,7 +663,9 @@ class BuilderImpl : public BuilderDefs { const llvm::Twine &instName = ""); // Create a subgroup broadcast first. - llvm::Value *CreateSubgroupBroadcastFirst(llvm::Value *const value, const llvm::Twine &instName = ""); + llvm::Value *CreateSubgroupBroadcastFirst(llvm::Value *const value, const llvm::Twine &instName = "") { + return createSubgroupBroadcastFirst(value, m_shaderStage.value(), instName); + } // Create a subgroup ballot. llvm::Value *CreateSubgroupBallot(llvm::Value *const value, const llvm::Twine &instName = ""); @@ -686,7 +694,9 @@ class BuilderImpl : public BuilderDefs { // Create a subgroup shuffle. llvm::Value *CreateSubgroupShuffle(llvm::Value *const value, llvm::Value *const index, - const llvm::Twine &instName = ""); + const llvm::Twine &instName = "") { + return createSubgroupShuffle(value, index, m_shaderStage.value(), instName); + } // Create a subgroup shuffle xor. llvm::Value *CreateSubgroupShuffleXor(llvm::Value *const value, llvm::Value *const mask, @@ -771,20 +781,28 @@ class BuilderImpl : public BuilderDefs { llvm::Value *createPermLaneX16(llvm::Value *const origValue, llvm::Value *const updateValue, unsigned selectBitsLow, unsigned selectBitsHigh, bool fetchInactive, bool boundCtrl); llvm::Value *createPermLane64(llvm::Value *const updateValue); + llvm::Value *createReadFirstLane(llvm::Value *const updateValue); llvm::Value *createDsSwizzle(llvm::Value *const value, uint16_t dsPattern); llvm::Value *createWwm(llvm::Value *const value); - llvm::Value *createWqm(llvm::Value *const value); + llvm::Value *createWqm(llvm::Value *const value) { return createWqm(value, m_shaderStage.value()); } llvm::Value *createThreadMask(); llvm::Value *createThreadMaskedSelect(llvm::Value *const threadMask, uint64_t andMask, llvm::Value *const value1, llvm::Value *const value2); uint16_t getDsSwizzleBitMode(uint8_t xorMask, uint8_t orMask, uint8_t andMask); uint16_t getDsSwizzleQuadMode(uint8_t lane0, uint8_t lane1, uint8_t lane2, uint8_t lane3); -protected: - llvm::Value *createGroupBallot(llvm::Value *const value, bool excludeHelperLanes); llvm::Value *createGroupBallot(llvm::Value *const value); + +protected: + // The subgroup operation with explicit shader stage as parameter. llvm::Value *createFindMsb(llvm::Value *const mask); + llvm::Value *createGroupBallot(llvm::Value *const value, ShaderStageEnum shaderStage); + llvm::Value *createSubgroupBroadcastFirst(llvm::Value *const value, ShaderStageEnum shaderStage, + const llvm::Twine &instName); + llvm::Value *createSubgroupShuffle(llvm::Value *const value, llvm::Value *const index, ShaderStageEnum shaderStage, + const llvm::Twine &instName); + llvm::Value *createWqm(llvm::Value *const value, ShaderStageEnum shaderStage); }; } // namespace lgc diff --git a/lgc/include/lgc/builder/SubgroupBuilder.h b/lgc/include/lgc/builder/SubgroupBuilder.h index afd0c82b0c..6497951021 100644 --- a/lgc/include/lgc/builder/SubgroupBuilder.h +++ b/lgc/include/lgc/builder/SubgroupBuilder.h @@ -59,7 +59,9 @@ class SubgroupBuilder : public BuilderImpl { // // @param value : The value to compare // @param instName : Name to give instruction(s) - llvm::Value *CreateSubgroupAll(llvm::Value *const value, const llvm::Twine &instName = ""); + llvm::Value *CreateSubgroupAll(llvm::Value *const value, const llvm::Twine &instName = "") { + return createSubgroupAll(value, getShaderStage(GetInsertBlock()->getParent()).value(), instName); + } // Create a subgroup all equal. // @@ -80,6 +82,9 @@ class SubgroupBuilder : public BuilderImpl { SubgroupBuilder() = delete; SubgroupBuilder(const SubgroupBuilder &) = delete; SubgroupBuilder &operator=(const SubgroupBuilder &) = delete; + + // The subgroup operation with explicit shader stage as parameter. + llvm::Value *createSubgroupAll(llvm::Value *const value, ShaderStageEnum shaderStage, const llvm::Twine &instName); }; } // namespace lgc diff --git a/lgc/include/lgc/patch/LowerCooperativeMatrix.h b/lgc/include/lgc/patch/LowerCooperativeMatrix.h index 7deb5cbee9..e277d2e23b 100644 --- a/lgc/include/lgc/patch/LowerCooperativeMatrix.h +++ b/lgc/include/lgc/patch/LowerCooperativeMatrix.h @@ -212,9 +212,8 @@ class LowerCooperativeMatrix : public Patch, public llvm::PassInfoMixin { void setupElfsPrintfStrings(); llvm::DenseMap m_elfInfos; llvm::SmallVector m_toErase; + llvm::Value *m_debugPrintfBuffer = nullptr; PipelineState *m_pipelineState = nullptr; }; diff --git a/lgc/include/lgc/patch/SystemValues.h b/lgc/include/lgc/patch/SystemValues.h index 069ea1de16..3153bc3882 100644 --- a/lgc/include/lgc/patch/SystemValues.h +++ b/lgc/include/lgc/patch/SystemValues.h @@ -92,6 +92,9 @@ class ShaderSystemValues { // Get pointers to emit counters (GS) std::pair> getEmitCounterPtr(); + // Get pointer to total emit counter (GS) + llvm::Value *getTotalEmitCounterPtr(); + // Get global internal table pointer as pointer to i8. llvm::Instruction *getInternalGlobalTablePtr(); @@ -141,6 +144,7 @@ class ShaderSystemValues { llvm::Value *m_tessCoord = nullptr; // Tessellated coordinate (TES) llvm::Value *m_esGsOffsets = nullptr; // ES -> GS offsets (GS in) llvm::SmallVector m_emitCounterPtrs; // Pointers to emit counters (GS) + llvm::Value *m_totalEmitCounterPtr; // Pointer to total emit counter (GS) llvm::SmallVector m_descTablePtrs; // Descriptor table pointers llvm::SmallVector m_shadowDescTablePtrs; // Shadow descriptor table pointers diff --git a/lgc/include/lgc/state/AbiMetadata.h b/lgc/include/lgc/state/AbiMetadata.h index b687fa1576..a11fa5bef9 100644 --- a/lgc/include/lgc/state/AbiMetadata.h +++ b/lgc/include/lgc/state/AbiMetadata.h @@ -34,6 +34,8 @@ */ #pragma once +#include "lgc/CommonDefs.h" +#include "llvm/Support/ErrorHandling.h" #include namespace lgc { @@ -622,8 +624,27 @@ typedef enum SPI_SHADER_EX_FORMAT { } SPI_SHADER_EX_FORMAT; // The names of API shader stages used in PAL metadata, in ShaderStageEnum order. -static const char *const ApiStageNames[] = {".task", ".vertex", ".hull", ".domain", - ".geometry", ".mesh", ".pixel", ".compute"}; +inline const char *shaderStageToApiName(ShaderStageEnum stage) { + switch (stage) { + case ShaderStage::Task: + return ".task"; + case ShaderStage::Vertex: + return ".vertex"; + case ShaderStage::TessControl: + return ".hull"; + case ShaderStage::TessEval: + return ".domain"; + case ShaderStage::Geometry: + return ".geometry"; + case ShaderStage::Mesh: + return ".mesh"; + case ShaderStage::Fragment: + return ".pixel"; + case ShaderStage::Compute: + return ".compute"; + } + llvm::report_fatal_error("No api name for this shader stage"); +} // The names of hardware shader stages used in PAL metadata, in Util::Abi::HardwareStage order. static const char *const HwStageNames[static_cast(Util::Abi::HardwareStage::Count)] = {".hs", ".gs", ".vs", diff --git a/lgc/include/lgc/state/PipelineState.h b/lgc/include/lgc/state/PipelineState.h index 9a2ad7bebd..9bc8bed882 100644 --- a/lgc/include/lgc/state/PipelineState.h +++ b/lgc/include/lgc/state/PipelineState.h @@ -41,6 +41,7 @@ #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include +#include namespace llvm { @@ -256,9 +257,9 @@ class PipelineState final : public Pipeline { bool hasShaderStage(ShaderStageEnum stage) { return getShaderStageMask().contains(stage); } bool isGraphics(); bool isComputeLibrary() const { return m_computeLibrary; } - ShaderStageEnum getLastVertexProcessingStage() const; - ShaderStageEnum getPrevShaderStage(ShaderStageEnum shaderStage) const; - ShaderStageEnum getNextShaderStage(ShaderStageEnum shaderStage) const; + std::optional getLastVertexProcessingStage() const; + std::optional getPrevShaderStage(ShaderStageEnum shaderStage) const; + std::optional getNextShaderStage(ShaderStageEnum shaderStage) const; // Get client name const char *getClient() const { return m_client.c_str(); } diff --git a/lgc/interface/lgc/Builder.h b/lgc/interface/lgc/Builder.h index f345b7010c..85ef8a388a 100644 --- a/lgc/interface/lgc/Builder.h +++ b/lgc/interface/lgc/Builder.h @@ -200,17 +200,19 @@ class BuilderDefs : public BuilderCommon { // Possible values for dimension argument for image methods. enum { - Dim1D = 0, // Coordinate: x - Dim2D = 1, // Coordinate: x, y - Dim3D = 2, // Coordinate: x, y, z - DimCube = 3, // Coordinate: x, y, face - Dim1DArray = 4, // Coordinate: x, slice - Dim2DArray = 5, // Coordinate: x, y, slice - Dim2DMsaa = 6, // Coordinate: x, y, fragid - Dim2DArrayMsaa = 7, // Coordinate: x, y, slice, fragid - DimCubeArray = 8, // Coordinate: x, y, face, slice (despite both SPIR-V and ISA - // combining face and slice into one component) - DimRect = 9, // Coordinate: x, y + Dim1D = 0, // Coordinate: x + Dim2D = 1, // Coordinate: x, y + Dim3D = 2, // Coordinate: x, y, z + DimCube = 3, // Coordinate: x, y, face + Dim1DArray = 4, // Coordinate: x, slice + Dim2DArray = 5, // Coordinate: x, y, slice + Dim2DMsaa = 6, // Coordinate: x, y, fragid + Dim2DArrayMsaa = 7, // Coordinate: x, y, slice, fragid + DimCubeArray = 8, // Coordinate: x, y, face, slice (despite both SPIR-V and ISA + // combining face and slice into one component) + DimRect = 9, // Coordinate: x, y + Dim1DBuffer = 10, // Coordinate: x (identify a texel buffer) + Dim1DArrayBuffer = 11, // Coordinate: x, slice (identify a texel buffer) }; // Get the number of coordinates for the specified dimension argument. @@ -219,6 +221,7 @@ class BuilderDefs : public BuilderCommon { static unsigned getImageNumCoords(unsigned dim) { switch (dim) { case Dim1D: + case Dim1DBuffer: return 1; case Dim2D: return 2; @@ -227,6 +230,7 @@ class BuilderDefs : public BuilderCommon { case DimCube: return 3; case Dim1DArray: + case Dim1DArrayBuffer: return 2; case Dim2DArray: return 3; @@ -249,6 +253,7 @@ class BuilderDefs : public BuilderCommon { static unsigned getImageQuerySizeComponentCount(unsigned dim) { switch (dim) { case Dim1D: + case Dim1DBuffer: return 1; case Dim2D: return 2; @@ -257,6 +262,7 @@ class BuilderDefs : public BuilderCommon { case DimCube: return 2; case Dim1DArray: + case Dim1DArrayBuffer: return 2; case Dim2DArray: return 3; @@ -279,6 +285,7 @@ class BuilderDefs : public BuilderCommon { static unsigned getImageDerivativeComponentCount(unsigned dim) { switch (dim) { case Dim1D: + case Dim1DBuffer: return 1; case Dim2D: return 2; @@ -287,6 +294,7 @@ class BuilderDefs : public BuilderCommon { case DimCube: return 3; case Dim1DArray: + case Dim1DArrayBuffer: return 1; case Dim2DArray: return 2; diff --git a/lgc/interface/lgc/CommonDefs.h b/lgc/interface/lgc/CommonDefs.h index 1cace83670..39af5ff976 100644 --- a/lgc/interface/lgc/CommonDefs.h +++ b/lgc/interface/lgc/CommonDefs.h @@ -31,6 +31,7 @@ #pragma once #include "EnumIterator.h" +#include "llvm/ADT/DenseMap.h" #include #include @@ -63,6 +64,34 @@ enum ShaderStage : unsigned { // TODO Temporary definition until ShaderStage is converted to a class enum. using ShaderStageEnum = ShaderStage::ShaderStage; +/// All shader stages +[[maybe_unused]] constexpr const std::array ShaderStages = { + ShaderStage::Compute, ShaderStage::Fragment, ShaderStage::Vertex, + ShaderStage::Geometry, ShaderStage::TessControl, ShaderStage::TessEval, + ShaderStage::Task, ShaderStage::Mesh, ShaderStage::CopyShader, +}; + +/// All graphics shader stages. +/// These are in execution order. +[[maybe_unused]] constexpr const std::array ShaderStagesGraphics = { + ShaderStage::Task, ShaderStage::Vertex, ShaderStage::TessControl, ShaderStage::TessEval, + ShaderStage::Geometry, ShaderStage::Mesh, ShaderStage::Fragment, +}; + +/// Graphics and compute shader stages. +/// The graphics stages are in execution order. +[[maybe_unused]] constexpr const std::array ShaderStagesNative = { + ShaderStage::Task, ShaderStage::Vertex, ShaderStage::TessControl, ShaderStage::TessEval, + ShaderStage::Geometry, ShaderStage::Mesh, ShaderStage::Fragment, ShaderStage::Compute, +}; + +/// Graphics and compute shader stages and copy shader. +/// The graphics stages are in execution order. +[[maybe_unused]] constexpr const std::array ShaderStagesNativeCopy = { + ShaderStage::Task, ShaderStage::Vertex, ShaderStage::TessControl, ShaderStage::TessEval, ShaderStage::Geometry, + ShaderStage::Mesh, ShaderStage::Fragment, ShaderStage::Compute, ShaderStage::CopyShader, +}; + class ShaderStageMask { public: constexpr ShaderStageMask() {} @@ -77,6 +106,11 @@ class ShaderStageMask { *this |= ShaderStageMask(stage); }; + template constexpr explicit ShaderStageMask(const std::array &stages) { + for (auto stage : stages) + *this |= ShaderStageMask(stage); + }; + constexpr static ShaderStageMask fromRaw(uint32_t mask) { ShaderStageMask result; result.m_value = mask; @@ -98,6 +132,7 @@ class ShaderStageMask { constexpr bool contains(ShaderStageEnum stage) const; constexpr bool contains_any(std::initializer_list stages) const; + template constexpr bool contains_any(const std::array &stages) const; constexpr bool empty() const { return m_value == 0; } uint32_t m_value = 0; @@ -133,6 +168,10 @@ constexpr bool ShaderStageMask::contains_any(std::initializer_list constexpr bool ShaderStageMask::contains_any(const std::array &stages) const { + return (*this & ShaderStageMask(stages)).m_value != 0; +} + enum AddrSpace { ADDR_SPACE_FLAT = 0, // Flat memory ADDR_SPACE_GLOBAL = 1, // Global memory @@ -202,4 +241,13 @@ namespace llvm { // Enable iteration over resource node type with `lgc::enumRange()`. LGC_DEFINE_DEFAULT_ITERABLE_ENUM(lgc::ResourceNodeType); +template <> struct DenseMapInfo { + using T = lgc::ShaderStageEnum; + + static T getEmptyKey() { return static_cast(DenseMapInfo::getEmptyKey()); } + static T getTombstoneKey() { return static_cast(DenseMapInfo::getTombstoneKey()); } + static unsigned getHashValue(const T &Val) { return static_cast(Val); } + static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; } +}; + } // namespace llvm diff --git a/lgc/interface/lgc/LgcDialect.td b/lgc/interface/lgc/LgcDialect.td index 7dbfd25551..2f80b43bf9 100644 --- a/lgc/interface/lgc/LgcDialect.td +++ b/lgc/interface/lgc/LgcDialect.td @@ -163,7 +163,7 @@ def LoadStridedBufferDescOp : LgcOp<"load.strided.buffer.desc", [Memory<[]>, Wil } def DebugPrintfOp : LgcOp<"debug.printf", [Memory<[(readwrite InaccessibleMem)]>, WillReturn]> { - let arguments = (ins BufferPointer:$buffer, ConstantPointer:$format, varargs:$args); + let arguments = (ins ImmutableStringAttr:$format, varargs:$args); let results = (outs); let summary = "print a formatted message"; diff --git a/lgc/interface/lgc/Pipeline.h b/lgc/interface/lgc/Pipeline.h index 1c30ffe785..7bdb636f6c 100644 --- a/lgc/interface/lgc/Pipeline.h +++ b/lgc/interface/lgc/Pipeline.h @@ -625,7 +625,7 @@ struct TessellationMode { }; // Kind of GS input primitives. -enum class InputPrimitives : unsigned { Points, Lines, LinesAdjacency, Triangles, TrianglesAdjacency }; +enum class InputPrimitives : unsigned { Points, Lines, LinesAdjacency, Triangles, TrianglesAdjacency, Patch }; // Kind of GS/mesh shader output primitives enum class OutputPrimitives : unsigned { @@ -645,6 +645,7 @@ struct GeometryShaderMode { OutputPrimitives outputPrimitive; // Kind of output primitives unsigned invocations; // Number of times to invoke shader for each input primitive unsigned outputVertices; // Max number of vertices the shader will emit in one invocation + unsigned controlPoints; // Number of control points when the input primitive is a patch unsigned robustGsEmits; // robust buffer access }; diff --git a/llpc/context/GfxRuntimeContext.h b/lgc/interface/lgc/RuntimeContext.h similarity index 91% rename from llpc/context/GfxRuntimeContext.h rename to lgc/interface/lgc/RuntimeContext.h index 83639d10d1..fcf50e4778 100644 --- a/llpc/context/GfxRuntimeContext.h +++ b/lgc/interface/lgc/RuntimeContext.h @@ -24,8 +24,8 @@ **********************************************************************************************************************/ /** *********************************************************************************************************************** - * @file GfxRuntimeContext.h - * @brief LLVMContext extension that stores a GfxRuntime library module + * @file RuntimeContext.h + * @brief LLVMContext extension that stores a Runtime library module *********************************************************************************************************************** */ #pragma once @@ -40,16 +40,16 @@ class Module; namespace lgc { // This extension can be attached to an LLVMContext and queried via the -// GfxRuntimeContext::get method inherited from the base class. +// RuntimeContext::get method inherited from the base class. // -// Compiler drivers (like LLPC) are expected to set theModule to the GfxRuntime +// Compiler drivers (like LLPC) are expected to set theModule to the Runtime // library, so that advanced blend pass can cross-module inline // functions implemented there. + class GfxRuntimeContext : public llvm_dialects::ContextExtensionImpl { public: explicit GfxRuntimeContext(llvm::LLVMContext &) {} - ~GfxRuntimeContext(); - + ~GfxRuntimeContext() = default; static Key theKey; std::unique_ptr theModule; }; diff --git a/lgc/patch/ConfigBuilderBase.cpp b/lgc/patch/ConfigBuilderBase.cpp index 2d2d57147b..9302cc39df 100644 --- a/lgc/patch/ConfigBuilderBase.cpp +++ b/lgc/patch/ConfigBuilderBase.cpp @@ -111,10 +111,11 @@ void ConfigBuilderBase::addApiHwShaderMapping(ShaderStageEnum apiStage, unsigned // Get the MsgPack map node for the specified API shader in the ".shaders" map // // @param apiStage : API shader stage -msgpack::MapDocNode ConfigBuilderBase::getApiShaderNode(unsigned apiStage) { +msgpack::MapDocNode ConfigBuilderBase::getApiShaderNode(ShaderStageEnum apiStage) { if (m_apiShaderNodes[apiStage].isEmpty()) { m_apiShaderNodes[apiStage] = - m_pipelineNode[Util::Abi::PipelineMetadataKey::Shaders].getMap(true)[ApiStageNames[apiStage]].getMap(true); + m_pipelineNode[Util::Abi::PipelineMetadataKey::Shaders].getMap(true)[shaderStageToApiName(apiStage)].getMap( + true); } return m_apiShaderNodes[apiStage]; } @@ -139,7 +140,7 @@ msgpack::MapDocNode ConfigBuilderBase::getHwShaderNode(Util::Abi::HardwareStage // @param apiStage : API shader stage unsigned ConfigBuilderBase::setShaderHash(ShaderStageEnum apiStage) { const ShaderOptions &shaderOptions = m_pipelineState->getShaderOptions(apiStage); - auto hashNode = getApiShaderNode(unsigned(apiStage))[Util::Abi::ShaderMetadataKey::ApiShaderHash].getArray(true); + auto hashNode = getApiShaderNode(apiStage)[Util::Abi::ShaderMetadataKey::ApiShaderHash].getArray(true); hashNode[0] = shaderOptions.hash[0]; hashNode[1] = shaderOptions.hash[1]; return shaderOptions.hash[0] >> 32 ^ shaderOptions.hash[0] ^ shaderOptions.hash[1] >> 32 ^ shaderOptions.hash[1]; @@ -314,7 +315,7 @@ void ConfigBuilderBase::setThreadgroupDimensions(llvm::ArrayRef values } // ===================================================================================================================== -// Set stream-out vertex strides (GFX11+) +// Set stream-out vertex strides // // @param values : Values to set void ConfigBuilderBase::setStreamOutVertexStrides(ArrayRef values) { diff --git a/lgc/patch/ConfigBuilderBase.h b/lgc/patch/ConfigBuilderBase.h index 84f030e6a0..31c6c57acb 100644 --- a/lgc/patch/ConfigBuilderBase.h +++ b/lgc/patch/ConfigBuilderBase.h @@ -126,11 +126,11 @@ class ConfigBuilderBase { private: // Get the MsgPack map node for the specified API shader in the ".shaders" map - llvm::msgpack::MapDocNode getApiShaderNode(unsigned apiStage); + llvm::msgpack::MapDocNode getApiShaderNode(ShaderStageEnum apiStage); llvm::msgpack::Document *m_document; // The MsgPack document llvm::msgpack::MapDocNode m_pipelineNode; // MsgPack map node for amdpal.pipelines[0] - llvm::msgpack::MapDocNode m_apiShaderNodes[ShaderStage::NativeStageCount]; + llvm::DenseMap m_apiShaderNodes; // MsgPack map node for each API shader's node in // ".shaders" llvm::msgpack::MapDocNode m_hwShaderNodes[unsigned(Util::Abi::HardwareStage::Count)]; diff --git a/lgc/patch/LowerCooperativeMatrix.cpp b/lgc/patch/LowerCooperativeMatrix.cpp index 5dc9181dcb..f5d20ea013 100644 --- a/lgc/patch/LowerCooperativeMatrix.cpp +++ b/lgc/patch/LowerCooperativeMatrix.cpp @@ -1060,6 +1060,7 @@ Value *LowerCooperativeMatrix::cooperativeMatrixReshapeBetween16bitAnd32bitOnAcc } else { resultValue = builder.CreateBitCast(resultValue, FixedVectorType::get(builder.getFloatTy(), 4)); // 1st case:after convert + resultValue = builder.CreateShuffleVector(resultValue, {0, 1, 2, 3, -1, -1, -1, -1}); } return resultValue; } @@ -1542,8 +1543,8 @@ void LowerCooperativeMatrix::visitCooperativeMatrixMulAddOp(CooperativeMatrixMul mulAB1 = createDotProductFp16Fp16(rowData1, colData, accumulator1, isSatOrOpsel, instName, &muladd); mulAB2 = createDotProductFp16Fp16(rowData2, colData, accumulator2, isSatOrOpsel, instName, &muladd); } else { - mulAB1 = createDotProductInt16Int16(rowData1, colData, accumulator1, flags, isSatOrOpsel, instName, &muladd); - mulAB2 = createDotProductInt16Int16(rowData2, colData, accumulator2, flags, isSatOrOpsel, instName, &muladd); + mulAB1 = createDotProductInt(rowData1, colData, accumulator1, flags, isSatOrOpsel, instName, &muladd); + mulAB2 = createDotProductInt(rowData2, colData, accumulator2, flags, isSatOrOpsel, instName, &muladd); } dotProductValue = builder.CreateInsertElement(dotProductValue, mulAB1, accIdx); dotProductValue = builder.CreateInsertElement(dotProductValue, mulAB2, accIdx + 1); @@ -1575,6 +1576,8 @@ Value *LowerCooperativeMatrix::createDotProductFp16Fp32(Value *const vector1, Va BuilderBase builder(*m_context); builder.SetInsertPoint(insertPos); + // Dot instructions are not available on gfx1010 + const bool emulateDot = m_gfxIp.isGfx(10, 1) && m_gfxIp.stepping == 0; const unsigned compCount = cast(vector1->getType())->getNumElements(); Value *scalar = initAccumulator; auto intrinsicDot = Intrinsic::amdgcn_fdot2; @@ -1583,8 +1586,18 @@ Value *LowerCooperativeMatrix::createDotProductFp16Fp32(Value *const vector1, Va input1 = builder.CreateBitCast(input1, FixedVectorType::get(builder.getHalfTy(), 2)); Value *input2 = builder.CreateExtractElement(vector2, i); input2 = builder.CreateBitCast(input2, FixedVectorType::get(builder.getHalfTy(), 2)); - scalar = - builder.CreateIntrinsic(intrinsicDot, {}, {input1, input2, scalar, builder.getInt1(isSat)}, nullptr, instName); + if (emulateDot) { + Value *input1Fp32 = builder.CreateFPCast(input1, FixedVectorType::get(builder.getFloatTy(), 2)); + Value *input2Fp32 = builder.CreateFPCast(input2, FixedVectorType::get(builder.getFloatTy(), 2)); + for (unsigned j = 0; j < 2; ++j) { + Value *lhs = builder.CreateExtractElement(input1Fp32, j); + Value *rhs = builder.CreateExtractElement(input2Fp32, j); + scalar = builder.CreateIntrinsic(Intrinsic::fmuladd, lhs->getType(), {lhs, rhs, scalar}); + } + } else { + scalar = builder.CreateIntrinsic(intrinsicDot, {}, {input1, input2, scalar, builder.getInt1(isSat)}, nullptr, + instName); + } } scalar->setName(instName); return scalar; @@ -1638,6 +1651,8 @@ Value *LowerCooperativeMatrix::createDotProductInt8Int32(Value *vector1, Value * BuilderBase builder(*m_context); builder.SetInsertPoint(insertPos); + // Dot instructions are not available on gfx1010 + const bool emulateDot = m_gfxIp.isGfx(10, 1) && m_gfxIp.stepping == 0; const bool isSigned = (flags & lgc::Builder::FirstVectorSigned); auto intrinsicDot = isSigned ? Intrinsic::amdgcn_sdot4 : Intrinsic::amdgcn_udot4; @@ -1646,8 +1661,14 @@ Value *LowerCooperativeMatrix::createDotProductInt8Int32(Value *vector1, Value * for (unsigned i = 0; i < compCount; ++i) { Value *input1 = builder.CreateExtractElement(vector1, i); Value *input2 = builder.CreateExtractElement(vector2, i); - scalar = - builder.CreateIntrinsic(intrinsicDot, {}, {input1, input2, scalar, builder.getInt1(false)}, nullptr, instName); + if (emulateDot) { + input1 = builder.CreateBitCast(input1, FixedVectorType::get(builder.getInt8Ty(), 4)); + input2 = builder.CreateBitCast(input2, FixedVectorType::get(builder.getInt8Ty(), 4)); + scalar = createDotProductInt(input1, input2, scalar, flags, isSat, instName, insertPos); + } else { + scalar = builder.CreateIntrinsic(intrinsicDot, {}, {input1, input2, scalar, builder.getInt1(false)}, nullptr, + instName); + } } // Always use sadd_sat here as uint32@C is not supported. @@ -1677,6 +1698,8 @@ Value *LowerCooperativeMatrix::createDotProductInt16Int32(Value *vector1, Value BuilderBase builder(*m_context); builder.SetInsertPoint(insertPos); + // Dot instructions are not available on gfx1010 + const bool emulateDot = m_gfxIp.isGfx(10, 1) && m_gfxIp.stepping == 0; const bool isSigned = (flags & lgc::Builder::FirstVectorSigned); auto intrinsicDot = isSigned ? Intrinsic::amdgcn_sdot2 : Intrinsic::amdgcn_udot2; @@ -1687,8 +1710,12 @@ Value *LowerCooperativeMatrix::createDotProductInt16Int32(Value *vector1, Value input1 = builder.CreateBitCast(input1, FixedVectorType::get(builder.getInt16Ty(), 2)); Value *input2 = builder.CreateExtractElement(vector2, i); input2 = builder.CreateBitCast(input2, FixedVectorType::get(builder.getInt16Ty(), 2)); - scalar = - builder.CreateIntrinsic(intrinsicDot, {}, {input1, input2, scalar, builder.getInt1(isSat)}, nullptr, instName); + if (emulateDot) { + scalar = createDotProductInt(input1, input2, scalar, flags, isSat, instName, insertPos); + } else { + scalar = builder.CreateIntrinsic(intrinsicDot, {}, {input1, input2, scalar, builder.getInt1(isSat)}, nullptr, + instName); + } } scalar->setName(instName); return scalar; @@ -1704,9 +1731,8 @@ Value *LowerCooperativeMatrix::createDotProductInt16Int32(Value *vector1, Value // @param isSat: SaturatingAccumulation for calculation // @param instName : Name to give instruction(s) // @param insertPos : Where to insert the instruction -Value *LowerCooperativeMatrix::createDotProductInt16Int16(Value *vector1, Value *vector2, Value *accumulator, - unsigned flags, bool isSat, const Twine &instName, - Instruction *insertPos) { +Value *LowerCooperativeMatrix::createDotProductInt(Value *vector1, Value *vector2, Value *accumulator, unsigned flags, + bool isSat, const Twine &instName, Instruction *insertPos) { BuilderBase builder(*m_context); builder.SetInsertPoint(insertPos); Type *inputTy = vector1->getType(); @@ -1720,9 +1746,13 @@ Value *LowerCooperativeMatrix::createDotProductInt16Int16(Value *vector1, Value // as unsigned. const bool isMixed = (flags == lgc::Builder::FirstVectorSigned); - Type *targetTy = builder.getInt64Ty(); + const auto outputSizeInBits = outputTy->getScalarSizeInBits(); + const auto compSizeInBits = inputTy->getScalarSizeInBits(); + Type *targetTy = compSizeInBits * 2 >= outputSizeInBits ? builder.getIntNTy(outputSizeInBits * 2) : outputTy; + const auto targetSizeInBits = targetTy->getScalarSizeInBits(); + assert(targetSizeInBits <= 64); // Emulate dot product with no HW support cases - Value *scalar = builder.getInt64(0); + Value *scalar = builder.getIntN(targetSizeInBits, 0); for (unsigned elemIdx = 0; elemIdx < compCount; ++elemIdx) { Value *elem1 = builder.CreateExtractElement(vector1, elemIdx); elem1 = isSigned ? builder.CreateSExt(elem1, targetTy) : builder.CreateZExt(elem1, targetTy); @@ -1732,28 +1762,27 @@ Value *LowerCooperativeMatrix::createDotProductInt16Int16(Value *vector1, Value scalar = builder.CreateAdd(product, scalar); } - scalar = builder.CreateTrunc(scalar, builder.getInt32Ty()); - accumulator = builder.CreateTrunc(accumulator, builder.getInt32Ty()); + scalar = builder.CreateTrunc(scalar, outputTy); + accumulator = builder.CreateTrunc(accumulator, outputTy); Intrinsic::ID addIntrinsic = isSigned ? Intrinsic::sadd_sat : Intrinsic::uadd_sat; scalar = builder.CreateBinaryIntrinsic(addIntrinsic, scalar, accumulator, nullptr, instName); - const unsigned bitWidth = outputTy->getScalarSizeInBits(); - auto unsignedMax = (2ULL << (bitWidth - 1)) - 1; + auto unsignedMax = (2ULL << (targetSizeInBits - 1)) - 1; auto signedMax = unsignedMax >> 1; auto signedMin = -1ULL - signedMax; Value *minimum = nullptr, *maximum = nullptr; Value *isUnderflow = nullptr, *isOverflow = nullptr; if (isSigned) { - scalar = builder.CreateSExt(scalar, builder.getInt64Ty()); - minimum = ConstantInt::getSigned(builder.getInt64Ty(), signedMin); - maximum = ConstantInt::getSigned(builder.getInt64Ty(), signedMax); + scalar = builder.CreateSExt(scalar, targetTy); + minimum = ConstantInt::getSigned(targetTy, signedMin); + maximum = ConstantInt::getSigned(targetTy, signedMax); isUnderflow = builder.CreateICmpSLT(scalar, minimum); isOverflow = builder.CreateICmpSGT(scalar, maximum); } else { - scalar = builder.CreateZExt(scalar, builder.getInt64Ty()); - minimum = builder.getInt64(0); - maximum = builder.getInt64(unsignedMax); + scalar = builder.CreateZExt(scalar, targetTy); + minimum = builder.getIntN(targetSizeInBits, 0); + maximum = builder.getIntN(targetSizeInBits, unsignedMax); isUnderflow = builder.CreateICmpULT(scalar, minimum); isOverflow = builder.CreateICmpUGT(scalar, maximum); } diff --git a/lgc/patch/LowerDebugPrintf.cpp b/lgc/patch/LowerDebugPrintf.cpp index 7de0ef8752..3ccc0d5862 100644 --- a/lgc/patch/LowerDebugPrintf.cpp +++ b/lgc/patch/LowerDebugPrintf.cpp @@ -30,20 +30,24 @@ */ #include "lgc/patch/LowerDebugPrintf.h" #include "lgc/LgcDialect.h" +#include "lgc/builder/BuilderImpl.h" #include "lgc/patch/Patch.h" #include "lgc/state/PalMetadata.h" #include "lgc/state/PipelineState.h" #include "llvm-dialects/Dialect/Visitor.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SetVector.h" #include "llvm/BinaryFormat/MsgPackDocument.h" #include "llvm/InitializePasses.h" #include "llvm/Support/Debug.h" +#include #define DEBUG_TYPE "lower-debug-printf" using namespace llvm; using namespace lgc; +constexpr unsigned PrintfBufferBindingId = 6; namespace lgc { // ===================================================================================================================== @@ -57,10 +61,40 @@ PreservedAnalyses LowerDebugPrintf::run(Module &module, ModuleAnalysisManager &a PipelineState *pipelineState = analysisManager.getResult(module).getPipelineState(); m_pipelineState = pipelineState; - static const auto visitor = - llvm_dialects::VisitorBuilder().add(&LowerDebugPrintf::visitDebugPrintf).build(); + // Find the function which contains DebugPrintf dialect + typedef SmallSetVector FuncSet; + FuncSet printfFuncs; + static const auto debugPrintfFuncsVisitor = + llvm_dialects::VisitorBuilder() + .setStrategy(llvm_dialects::VisitorStrategy::ByFunctionDeclaration) + .add([](FuncSet &pfunc, auto &inst) { pfunc.insert(inst.getFunction()); }) + .build(); + debugPrintfFuncsVisitor.visit(printfFuncs, module); - visitor.visit(*this, module); + if (printfFuncs.empty()) + return PreservedAnalyses::all(); + + bool hasPrintfDesc = + pipelineState + ->findResourceNode(ResourceNodeType::DescriptorBuffer, InternalDescriptorSetId, PrintfBufferBindingId) + .second != nullptr; + + static const auto lowerDebugfPrintOpVisitor = llvm_dialects::VisitorBuilder() + .setStrategy(llvm_dialects::VisitorStrategy::ByFunctionDeclaration) + .add(&LowerDebugPrintf::visitDebugPrintf) + .build(); + + BuilderImpl builder(m_pipelineState); + for (auto func : printfFuncs) { + // Create printbuffer Descriptor at the beginning of the function which contains DebugPrintf dialect ops + builder.SetInsertPointPastAllocas(func); + m_debugPrintfBuffer = hasPrintfDesc + ? m_debugPrintfBuffer = builder.create(builder.CreateBufferDesc( + InternalDescriptorSetId, PrintfBufferBindingId, builder.getInt32(0), 2)) + : nullptr; + + lowerDebugfPrintOpVisitor.visit(*this, *func); + } for (auto inst : m_toErase) inst->eraseFromParent(); @@ -79,10 +113,11 @@ PreservedAnalyses LowerDebugPrintf::run(Module &module, ModuleAnalysisManager &a void LowerDebugPrintf::visitDebugPrintf(DebugPrintfOp &op) { m_toErase.push_back(&op); - Value *debugPrintfBuffer = op.getBuffer(); - if (isa(debugPrintfBuffer)) + if (!m_debugPrintfBuffer) return; + Value *debugPrintfBuffer = m_debugPrintfBuffer; + BuilderBase builder(&op); // Printf output variables in DWORDs @@ -94,8 +129,7 @@ void LowerDebugPrintf::visitDebugPrintf(DebugPrintfOp &op) { getDwordValues(var, printArgs, bit64Vector, builder); } - GlobalVariable *globalStr = cast(op.getFormat()); - StringRef strDebugStr = (cast(globalStr->getInitializer()))->getAsString(); + StringRef strDebugStr = op.getFormat(); uint64_t hash = hash_value(strDebugStr); diff --git a/lgc/patch/MeshTaskShader.cpp b/lgc/patch/MeshTaskShader.cpp index c1b259d425..6e47c76187 100644 --- a/lgc/patch/MeshTaskShader.cpp +++ b/lgc/patch/MeshTaskShader.cpp @@ -998,13 +998,14 @@ void MeshTaskShader::lowerEmitMeshTasks(EmitMeshTasksOp &emitMeshTasksOp) { auto emitMeshTasksBlock = checkEmitMeshTasksBlock->splitBasicBlock(emitMeshTasksCall, ".emitMeshTasks"); auto endEmitMeshTasksBlock = emitMeshTasksBlock->splitBasicBlock(emitMeshTasksCall, ".endEmitMeshTasks"); + SyncScope::ID agentScope = m_builder.getContext().getOrInsertSyncScopeID("agent"); // Modify ".checkEmitMeshTasks" block { m_builder.SetInsertPoint(checkEmitMeshTasksBlock->getTerminator()); if (m_accessTaskPayload) { // Make sure the task payload read/write access is completed - m_builder.CreateFence(AtomicOrdering::Release, SyncScope::System); + m_builder.CreateFence(AtomicOrdering::Release, agentScope); createBarrier(); } @@ -1043,7 +1044,7 @@ void MeshTaskShader::lowerEmitMeshTasks(EmitMeshTasksOp &emitMeshTasksOp) { valueToAdd = m_builder.CreateBitCast(valueToAdd, m_builder.getInt64Ty()); m_builder.CreateAtomicRMW(AtomicRMWInst::Add, meshPipeStatsBufEntryPtr, valueToAdd, MaybeAlign(), - AtomicOrdering::Monotonic, SyncScope::System); + AtomicOrdering::Monotonic, agentScope); } // @@ -2082,7 +2083,7 @@ void MeshTaskShader::exportVertex() { if (waAtmPrecedesPos) { // Before the first export call of vertex position data, add s_wait_vscnt 0 to make sure the completion of all // attributes being written to the attribute ring buffer - m_builder.CreateFence(AtomicOrdering::Release, SyncScope::System); + m_builder.CreateFence(AtomicOrdering::Release, m_builder.getContext().getOrInsertSyncScopeID("agent")); doExport(ExportKind::Pos, posExports); } @@ -2101,6 +2102,7 @@ void MeshTaskShader::collectMeshStatsInfo(Function *entryPoint, Value *numMeshPr const uint64_t numMeshThreads = meshMode.workgroupSizeX * meshMode.workgroupSizeY * meshMode.workgroupSizeZ; Value *meshPipeStatsBufPtr = m_pipelineSysValues.get(entryPoint)->getMeshPipeStatsBufPtr(); + SyncScope::ID agentScope = m_builder.getContext().getOrInsertSyncScopeID("agent"); // // Record numMeshThreads @@ -2122,7 +2124,7 @@ void MeshTaskShader::collectMeshStatsInfo(Function *entryPoint, Value *numMeshPr valueToAdd = m_builder.CreateBitCast(valueToAdd, m_builder.getInt64Ty()); m_builder.CreateAtomicRMW(AtomicRMWInst::Add, meshPipeStatsBufEntryPtr, valueToAdd, MaybeAlign(), - AtomicOrdering::Monotonic, SyncScope::System); + AtomicOrdering::Monotonic, agentScope); } // @@ -2147,7 +2149,7 @@ void MeshTaskShader::collectMeshStatsInfo(Function *entryPoint, Value *numMeshPr valueToAdd = m_builder.CreateBitCast(valueToAdd, m_builder.getInt64Ty()); m_builder.CreateAtomicRMW(AtomicRMWInst::Add, meshPipeStatsBufEntryPtr, valueToAdd, MaybeAlign(), - AtomicOrdering::Monotonic, SyncScope::System); + AtomicOrdering::Monotonic, agentScope); } } diff --git a/lgc/patch/NggPrimShader.cpp b/lgc/patch/NggPrimShader.cpp index bca8196fef..24db846493 100644 --- a/lgc/patch/NggPrimShader.cpp +++ b/lgc/patch/NggPrimShader.cpp @@ -4068,12 +4068,13 @@ void NggPrimShader::writeGsOutput(Value *output, unsigned location, unsigned com const unsigned attribOffset = (location * 4) + component; auto ldsOffset = m_builder.CreateAdd(vertexOffset, m_builder.getInt32(attribOffset)); + IRBuilder<>::InsertPointGuard guard(m_builder); + + // Skip GS-VS ring write if the emit is invalid if (geometryMode.robustGsEmits) { - // skip the lds write by writing to a dummy offset. - // ldsOffset = (totalEmitVerts >= outputVertices) ? InvalidValue : ldsOffset - auto dummyOffset = m_builder.getInt32(0x80000000); - auto outOfRange = m_builder.CreateICmpUGE(totalEmitVerts, m_builder.getInt32(geometryMode.outputVertices)); - ldsOffset = m_builder.CreateSelect(outOfRange, dummyOffset, ldsOffset); + // validEmit = totalEmitVerts < outputVertices + auto validEmit = m_builder.CreateICmpULT(totalEmitVerts, m_builder.getInt32(geometryMode.outputVertices)); + m_builder.CreateIf(validEmit, false); } writeValueToLds(output, ldsOffset); @@ -4246,7 +4247,7 @@ Function *NggPrimShader::createGsEmitHandler() { totalEmitVerts = m_builder.CreateLoad(m_builder.getInt32Ty(), totalEmitVertsPtr); // totalEmitVerts++ totalEmitVerts = m_builder.CreateAdd(totalEmitVerts, m_builder.getInt32(1)); - // outVerts = (totalEmitVerts >= outputVertices) ? 0 : outVerts + // outVerts = (totalEmitVerts > outputVertices) ? 0 : outVerts Value *outOfRange = m_builder.CreateICmpUGT(totalEmitVerts, m_builder.getInt32(geometryMode.outputVertices)); outVerts = m_builder.CreateSelect(outOfRange, m_builder.getInt32(0), outVerts); } @@ -6253,7 +6254,7 @@ void NggPrimShader::processVertexAttribExport(Function *&target) { // Before the first export call, add s_wait_vscnt 0 to make sure the completion of all attributes being written // to the attribute ring buffer m_builder.SetInsertPoint(exportCalls[0]); - m_builder.CreateFence(AtomicOrdering::Release, SyncScope::System); + m_builder.CreateFence(AtomicOrdering::Release, m_builder.getContext().getOrInsertSyncScopeID("agent")); } // Remove calls diff --git a/lgc/patch/NggPrimShader.h b/lgc/patch/NggPrimShader.h index 7332661439..71a8e27982 100644 --- a/lgc/patch/NggPrimShader.h +++ b/lgc/patch/NggPrimShader.h @@ -32,6 +32,7 @@ #include "lgc/state/PipelineState.h" #include "lgc/state/TargetInfo.h" +#include "lgc/util/BuilderBase.h" #include "llvm/IR/Module.h" namespace lgc { @@ -419,7 +420,7 @@ class NggPrimShader { VertexCullInfoOffsets m_vertCullInfoOffsets; // A collection of offsets within an item of vertex cull info StreamOutControlCbOffsets m_streamOutControlCbOffsets; // A collection of offsets within stream-out control buffer - llvm::IRBuilder<> m_builder; // LLVM IR builder + BuilderBase m_builder; // LLVM IR builder llvm::Constant *m_lds = nullptr; // Global variable to model primitive shader LDS PrimShaderLdsLayout m_ldsLayout; // Primitive shader LDS layout diff --git a/lgc/patch/Patch.cpp b/lgc/patch/Patch.cpp index 1c94ed3a4c..9e759fec1e 100644 --- a/lgc/patch/Patch.cpp +++ b/lgc/patch/Patch.cpp @@ -180,7 +180,6 @@ void Patch::addPasses(PipelineState *pipelineState, lgc::PassManager &passMgr, T } passMgr.addPass(IPSCCPPass()); - passMgr.addPass(LowerDebugPrintf()); passMgr.addPass(createModuleToFunctionPassAdaptor(CombineCooperativeMatrix())); // Lower the cooperative matrix @@ -201,6 +200,7 @@ void Patch::addPasses(PipelineState *pipelineState, lgc::PassManager &passMgr, T passMgr.addPass(PatchCopyShader()); passMgr.addPass(LowerVertexFetch()); passMgr.addPass(LowerFragColorExport()); + passMgr.addPass(LowerDebugPrintf()); passMgr.addPass(LowerDesc()); passMgr.addPass(PatchEntryPointMutate()); passMgr.addPass(PatchInitializeWorkgroupMemory()); diff --git a/lgc/patch/PatchEntryPointMutate.cpp b/lgc/patch/PatchEntryPointMutate.cpp index bfc06831de..3deff7bf30 100644 --- a/lgc/patch/PatchEntryPointMutate.cpp +++ b/lgc/patch/PatchEntryPointMutate.cpp @@ -55,6 +55,7 @@ #include "lgc/patch/PatchEntryPointMutate.h" #include "ShaderMerger.h" +#include "compilerutils/CompilerUtils.h" #include "lgc/LgcContext.h" #include "lgc/LgcCpsDialect.h" #include "lgc/LgcDialect.h" @@ -847,7 +848,8 @@ Function *PatchEntryPointMutate::lowerCpsFunction(Function *func, ArrayRefgetType()); vsp = builder.CreateConstInBoundsGEP1_32(builder.getInt8Ty(), vsp, -alignTo(stateSize, ContinuationStackAlignment)); - Value *newState = builder.CreateLoad(state->getType(), vsp, "cps.state"); + auto *newState = builder.CreateLoad(state->getType(), vsp, "cps.state"); + CompilerUtils::setIsLastUseLoad(*newState); state->replaceAllUsesWith(newState); } vsp = builder.CreatePtrToInt(vsp, builder.getInt32Ty()); @@ -1101,7 +1103,7 @@ void PatchEntryPointMutate::gatherUserDataUsage(Module *module) { // offsets to calculate numbers of written primitives/dwords and update the counters. auto lastVertexStage = auto lastVertexStage = m_pipelineState->getLastVertexProcessingStage(); lastVertexStage = lastVertexStage == ShaderStage::CopyShader ? ShaderStage::Geometry : lastVertexStage; - getUserDataUsage(lastVertexStage)->usesStreamOutTable = true; + getUserDataUsage(lastVertexStage.value())->usesStreamOutTable = true; } } } diff --git a/lgc/patch/PatchInOutImportExport.cpp b/lgc/patch/PatchInOutImportExport.cpp index fb16894137..09027bf9fb 100644 --- a/lgc/patch/PatchInOutImportExport.cpp +++ b/lgc/patch/PatchInOutImportExport.cpp @@ -1082,6 +1082,14 @@ void PatchInOutImportExport::visitCallInst(CallInst &callInst) { Value *emitCounter = builder.CreateLoad(emitCounterTy, emitCounterPtr); emitCounter = builder.CreateAdd(emitCounter, builder.getInt32(1)); builder.CreateStore(emitCounter, emitCounterPtr); + + // Increment total emit vertex counter + if (m_pipelineState->getShaderModes()->getGeometryShaderMode().robustGsEmits) { + auto totalEmitCounterPtr = m_pipelineSysValues.get(m_entryPoint)->getTotalEmitCounterPtr(); + Value *totalEmitCounter = builder.CreateLoad(builder.getInt32Ty(), totalEmitCounterPtr); + totalEmitCounter = builder.CreateAdd(totalEmitCounter, builder.getInt32(1)); + builder.CreateStore(totalEmitCounter, totalEmitCounterPtr); + } } } } @@ -1101,7 +1109,7 @@ void PatchInOutImportExport::visitReturnInst(ReturnInst &retInst) { // Whether this shader stage has to use "exp" instructions to export outputs const bool useExpInst = ((m_shaderStage == ShaderStage::Vertex || m_shaderStage == ShaderStage::TessEval || m_shaderStage == ShaderStage::CopyShader) && - (nextStage == ShaderStage::Invalid || nextStage == ShaderStage::Fragment)); + (!nextStage || nextStage == ShaderStage::Fragment)); BuilderBase builder(&retInst); @@ -1329,7 +1337,7 @@ void PatchInOutImportExport::visitReturnInst(ReturnInst &retInst) { } // NOTE: We have to export gl_ClipDistance[] or gl_CullDistancep[] via generic outputs as well. - assert(nextStage == ShaderStage::Invalid || nextStage == ShaderStage::Fragment); + assert(!nextStage || nextStage == ShaderStage::Fragment); bool hasClipCullExport = true; if (nextStage == ShaderStage::Fragment) { @@ -1385,7 +1393,7 @@ void PatchInOutImportExport::visitReturnInst(ReturnInst &retInst) { bool hasPrimitiveIdExport = false; if (nextStage == ShaderStage::Fragment) { hasPrimitiveIdExport = nextBuiltInUsage.primitiveId; - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { if (m_shaderStage == ShaderStage::CopyShader) { hasPrimitiveIdExport = m_pipelineState->getShaderResourceUsage(ShaderStage::Geometry)->builtInUsage.gs.primitiveId; @@ -1466,7 +1474,7 @@ void PatchInOutImportExport::visitReturnInst(ReturnInst &retInst) { bool hasViewportIndexExport = true; if (nextStage == ShaderStage::Fragment) { hasViewportIndexExport = nextBuiltInUsage.viewportIndex; - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { hasViewportIndexExport = false; } @@ -1485,7 +1493,7 @@ void PatchInOutImportExport::visitReturnInst(ReturnInst &retInst) { bool hasLayerExport = true; if (nextStage == ShaderStage::Fragment) { hasLayerExport = nextBuiltInUsage.layer; - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { hasLayerExport = false; } @@ -1533,8 +1541,8 @@ void PatchInOutImportExport::visitReturnInst(ReturnInst &retInst) { } else if (m_shaderStage == ShaderStage::Geometry) { // NOTE: Per programming guide, we should do a "s_waitcnt 0,0,0 + s_waitcnt_vscnt 0" before issuing a "done", so // we use fence release to generate s_waitcnt vmcnt lgkmcnt/s_waitcnt_vscnt before s_sendmsg(MSG_GS_DONE) - SyncScope::ID scope = - m_pipelineState->isGsOnChip() ? m_context->getOrInsertSyncScopeID("workgroup") : SyncScope::System; + StringRef scopeName = m_pipelineState->isGsOnChip() ? "workgroup" : "agent"; + SyncScope::ID scope = m_context->getOrInsertSyncScopeID(scopeName); builder.CreateFence(AtomicOrdering::Release, scope); auto &entryArgIdxs = m_pipelineState->getShaderInterfaceData(ShaderStage::Geometry)->entryArgIdxs.gs; @@ -4001,6 +4009,18 @@ void PatchInOutImportExport::storeValueToGsVsRing(Value *storeValue, unsigned lo auto ringOffset = calcGsVsRingOffsetForOutput(location, compIdx, streamId, emitCounter, gsVsOffset, builder); + IRBuilder<>::InsertPointGuard guard(builder); + + // Skip GS-VS ring write if the emit is invalid + const auto &geometryMode = m_pipelineState->getShaderModes()->getGeometryShaderMode(); + if (geometryMode.robustGsEmits) { + auto totalEmitCounterPtr = m_pipelineSysValues.get(m_entryPoint)->getTotalEmitCounterPtr(); + auto totalEmitCounter = builder.CreateLoad(builder.getInt32Ty(), totalEmitCounterPtr); + // validEmit = totalEmitCounter < outputVertices + auto validEmit = builder.CreateICmpULT(totalEmitCounter, builder.getInt32(geometryMode.outputVertices)); + builder.CreateIf(validEmit, false); + } + if (m_pipelineState->isGsOnChip()) { auto lds = Patch::getLdsVariable(m_pipelineState, m_entryPoint); Value *storePtr = builder.CreateGEP(builder.getInt32Ty(), lds, ringOffset); @@ -4048,7 +4068,6 @@ Value *PatchInOutImportExport::calcEsGsRingOffsetForOutput(unsigned location, un BuilderBase &builder) { // ES -> GS ring is always on-chip on GFX10+ // ringOffset = esGsOffset + threadId * esGsRingItemSize + location * 4 + compIdx - assert(m_pipelineState->hasShaderStage(ShaderStage::Geometry)); const auto &calcFactor = m_pipelineState->getShaderResourceUsage(ShaderStage::Geometry)->inOutUsage.gs.calcFactor; @@ -4071,12 +4090,37 @@ Value *PatchInOutImportExport::calcEsGsRingOffsetForOutput(unsigned location, un // @param builder : the builder to use Value *PatchInOutImportExport::calcEsGsRingOffsetForInput(unsigned location, unsigned compIdx, Value *vertexIdx, BuilderBase &builder) { + // ES -> GS ring is always on-chip on GFX10+ + assert(m_pipelineState->hasShaderStage(ShaderStage::Geometry)); + const auto &calcFactor = m_pipelineState->getShaderResourceUsage(ShaderStage::Geometry)->inOutUsage.gs.calcFactor; + auto esGsOffsets = m_pipelineSysValues.get(m_entryPoint)->getEsGsOffsets(); + const auto &geometryMode = m_pipelineState->getShaderModes()->getGeometryShaderMode(); - // ES -> GS ring is always on-chip on GFX10+ - Value *vertexOffset = builder.CreateExtractElement(esGsOffsets, vertexIdx); + Value *vertexOffset = nullptr; + if (geometryMode.inputPrimitive == InputPrimitives::Patch) { + assert(geometryMode.controlPoints > 0); // Must have control points + + // NOTE: If the input primitive is a patch, the calculation of vertex offset is different from other input primitive + // types as follow: + // + // vertexOffset = esGsOffset0 + vertexIdx * esGsRingItemSize + // + // The esGsOffset0 is the starting offset of control points for each patch with such HW layout: + // + // +-----------------+-----------------+-----+-------------------+ + // | Control Point 0 | Control Point 1 | ... | Control Point N-1 | + // +-----------------+-----------------+-----+-------------------+ + // |<-------------------------- Patch -------------------------->| + // + vertexOffset = builder.CreateMul(vertexIdx, builder.getInt32(calcFactor.esGsRingItemSize)); + vertexOffset = builder.CreateAdd(builder.CreateExtractElement(esGsOffsets, static_cast(0)), vertexOffset); + } else { + // vertexOffset = esGsOffsets[vertexIdx] (vertexIdx < 6) + vertexOffset = builder.CreateExtractElement(esGsOffsets, vertexIdx); + } - // ringOffset = vertexOffset[N] + (location * 4 + compIdx); + // ringOffset = vertexOffset + (location * 4 + compIdx); Value *ringOffset = builder.CreateAdd(vertexOffset, builder.getInt32(location * 4 + compIdx)); return ringOffset; } @@ -4620,7 +4664,7 @@ void PatchInOutImportExport::addExportInstForGenericOutput(Value *output, unsign const auto nextStage = m_pipelineState->getNextShaderStage(m_shaderStage); const bool useExpInst = ((m_shaderStage == ShaderStage::Vertex || m_shaderStage == ShaderStage::TessEval || m_shaderStage == ShaderStage::CopyShader) && - (nextStage == ShaderStage::Invalid || nextStage == ShaderStage::Fragment)); + (!nextStage || nextStage == ShaderStage::Fragment)); assert(useExpInst); (void(useExpInst)); // unused diff --git a/lgc/patch/PatchReadFirstLane.cpp b/lgc/patch/PatchReadFirstLane.cpp index ee9c388585..301e0c46a0 100644 --- a/lgc/patch/PatchReadFirstLane.cpp +++ b/lgc/patch/PatchReadFirstLane.cpp @@ -361,7 +361,12 @@ void ReadFirstLaneOptimizer::collectAssumeUniforms(BasicBlock *block, while (!candidates.empty()) { Instruction *candidate = candidates.pop_back_val(); - + if (auto intrinsic = dyn_cast(candidate)) { + // Don't lift readfirstlane that is manually added after permlane64 or permlanex16 in subgroupClusteredReduction + if (intrinsic->getIntrinsicID() == Intrinsic::amdgcn_permlane64 || + intrinsic->getIntrinsicID() == Intrinsic::amdgcn_permlanex16) + continue; + } if (isAllUsersAssumedUniform(candidate)) tryPropagate(candidate, false); } diff --git a/lgc/patch/PatchResourceCollect.cpp b/lgc/patch/PatchResourceCollect.cpp index d9a091bda7..4d8f42f2b6 100644 --- a/lgc/patch/PatchResourceCollect.cpp +++ b/lgc/patch/PatchResourceCollect.cpp @@ -123,7 +123,7 @@ PreservedAnalyses PatchResourceCollect::run(Module &module, ModuleAnalysisManage if (func.isDeclaration()) continue; auto stage = getShaderStage(&func); - if (!m_shaderStage || &func == pipelineShaders.getEntryPoint(m_shaderStage)) + if (!stage || &func == pipelineShaders.getEntryPoint(stage.value())) continue; m_shaderStage = stage.value(); m_entryPoint = &func; @@ -462,6 +462,9 @@ bool PatchResourceCollect::checkGsOnChipValidity() { useAdjacency = true; inVertsPerPrim = 6; break; + case InputPrimitives::Patch: + inVertsPerPrim = geometryMode.controlPoints; + break; default: llvm_unreachable("Unexpected input primitive type!"); break; @@ -1640,7 +1643,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { auto &inOutUsage = resUsage->inOutUsage; const auto nextStage = m_pipelineState->getNextShaderStage(m_shaderStage); - auto nextResUsage = nextStage != ShaderStage::Invalid ? m_pipelineState->getShaderResourceUsage(nextStage) : nullptr; + auto nextResUsage = nextStage ? m_pipelineState->getShaderResourceUsage(nextStage.value()) : nullptr; assert(inOutUsage.builtInInputLocMap.empty()); // Should be empty assert(inOutUsage.builtInOutputLocMap.empty()); @@ -1812,7 +1815,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { } builtInUsage.vs.primitiveShadingRate = false; - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { // VS only if (builtInUsage.vs.clipDistance > 0 || builtInUsage.vs.cullDistance > 0) { unsigned mapLoc = availOutMapLoc++; @@ -1975,7 +1978,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { if (inOutUsage.builtInOutputLocMap.find(BuiltInCullDistance) != inOutUsage.builtInOutputLocMap.end() && inOutUsage.builtInOutputLocMap[BuiltInCullDistance] == InvalidValue) inOutUsage.builtInOutputLocMap[BuiltInCullDistance] = availOutMapLoc++; - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { // TCS only if (builtInUsage.tcs.position) inOutUsage.builtInOutputLocMap[BuiltInPosition] = availOutMapLoc++; @@ -2033,7 +2036,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { // incorrectness of location assignment during builtin-to-generic mapping. const auto prevStage = m_pipelineState->getPrevShaderStage(m_shaderStage); if (prevStage == ShaderStage::TessControl) { - const auto &prevBuiltInUsage = m_pipelineState->getShaderResourceUsage(prevStage)->builtInUsage.tcs; + const auto &prevBuiltInUsage = m_pipelineState->getShaderResourceUsage(prevStage.value())->builtInUsage.tcs; clipDistanceCount = std::max(clipDistanceCount, prevBuiltInUsage.clipDistance); } @@ -2047,7 +2050,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { const auto prevStage = m_pipelineState->getPrevShaderStage(m_shaderStage); if (prevStage == ShaderStage::TessControl) { - const auto &prevBuiltInUsage = m_pipelineState->getShaderResourceUsage(prevStage)->builtInUsage.tcs; + const auto &prevBuiltInUsage = m_pipelineState->getShaderResourceUsage(prevStage.value())->builtInUsage.tcs; cullDistanceCount = std::max(cullDistanceCount, prevBuiltInUsage.clipDistance); } @@ -2158,7 +2161,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { } else { builtInUsage.tes.viewportIndex = 0; } - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { // TES only if (builtInUsage.tes.clipDistance > 0 || builtInUsage.tes.cullDistance > 0) { unsigned mapLoc = availOutMapLoc++; @@ -2282,7 +2285,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { const unsigned mapLoc = nextInOutUsage.builtInInputLocMap[BuiltInViewportIndex]; builtInOutLocs[BuiltInViewportIndex] = mapLoc; } - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { // GS only unsigned availOutMapLoc = inOutUsage.outputLocInfoMap.size(); // Reset available location @@ -2368,7 +2371,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { const unsigned mapLoc = nextInOutUsage.builtInInputLocMap[BuiltInCullDistance]; inOutUsage.mesh.vertexBuiltInExportSlots[BuiltInCullDistance] = mapLoc; } - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { // Mesh shader only unsigned availExportLoc = inOutUsage.outputMapLocCount; @@ -2416,7 +2419,7 @@ void PatchResourceCollect::mapBuiltInToGenericInOut() { const unsigned mapLoc = nextInOutUsage.perPrimitiveBuiltInInputLocMap[BuiltInViewportIndex]; inOutUsage.mesh.primitiveBuiltInExportSlots[BuiltInViewportIndex] = mapLoc; } - } else if (nextStage == ShaderStage::Invalid) { + } else if (!nextStage) { // Mesh shader only unsigned availPerPrimitiveExportLoc = inOutUsage.perPrimitiveOutputMapLocCount; @@ -2682,7 +2685,7 @@ void PatchResourceCollect::updateInputLocInfoMapWithUnpack() { auto preStage = m_pipelineState->getPrevShaderStage(m_shaderStage); if (preStage == ShaderStage::TessControl || preStage == ShaderStage::Mesh) { if (!inputLocInfoMap.empty()) { - auto &outputLocInfoMap = m_pipelineState->getShaderResourceUsage(preStage)->inOutUsage.outputLocInfoMap; + auto &outputLocInfoMap = m_pipelineState->getShaderResourceUsage(preStage.value())->inOutUsage.outputLocInfoMap; for (auto &infoPair : outputLocInfoMap) { if (infoPair.second != InvalidValue) { inputLocInfoMap[infoPair.first] = InvalidValue; @@ -2692,7 +2695,8 @@ void PatchResourceCollect::updateInputLocInfoMapWithUnpack() { } auto &perPatchInLocMap = inOutUsage.perPatchInputLocMap; if (!perPatchInLocMap.empty()) { - auto &perPatchOutLocMap = m_pipelineState->getShaderResourceUsage(preStage)->inOutUsage.perPatchOutputLocMap; + auto &perPatchOutLocMap = + m_pipelineState->getShaderResourceUsage(preStage.value())->inOutUsage.perPatchOutputLocMap; for (auto &locPair : perPatchOutLocMap) { if (locPair.second != InvalidValue) { perPatchInLocMap[locPair.first] = InvalidValue; @@ -2756,10 +2760,10 @@ void PatchResourceCollect::updateInputLocInfoMapWithUnpack() { // ===================================================================================================================== // Clear unused output from outputLocInfoMap, perPatchOutputLocMap, and perPrimitiveOutputLocMap void PatchResourceCollect::clearUnusedOutput() { - ShaderStageEnum nextStage = m_pipelineState->getNextShaderStage(m_shaderStage); + auto nextStage = m_pipelineState->getNextShaderStage(m_shaderStage); auto &inOutUsage = m_pipelineState->getShaderResourceUsage(m_shaderStage)->inOutUsage; auto &outputLocInfoMap = inOutUsage.outputLocInfoMap; - if (nextStage != ShaderStage::Invalid) { + if (nextStage) { // Collect the locations of TCS's imported outputs DenseSet importOutputLocs; if (m_shaderStage == ShaderStage::TessControl) { @@ -2784,7 +2788,7 @@ void PatchResourceCollect::clearUnusedOutput() { // Do normal input/output matching SmallVector unusedLocInfos; - auto nextResUsage = m_pipelineState->getShaderResourceUsage(nextStage); + auto nextResUsage = m_pipelineState->getShaderResourceUsage(nextStage.value()); const auto &nextInLocInfoMap = nextResUsage->inOutUsage.inputLocInfoMap; for (auto &locInfoPair : outputLocInfoMap) { @@ -2899,8 +2903,9 @@ void PatchResourceCollect::updateOutputLocInfoMapWithUnpack() { // If we don't have to keep the locations and the next stage is valid, try to get location map of the outputs from // corresponding inputs of next stage. const bool keepLocation = m_shaderStage == ShaderStage::Geometry && !canChangeOutputLocationsForGs(); - if (!keepLocation && nextStage != ShaderStage::Invalid) { - auto &nextStageInputLocInfoMap = m_pipelineState->getShaderResourceUsage(nextStage)->inOutUsage.inputLocInfoMap; + if (!keepLocation && nextStage) { + auto &nextStageInputLocInfoMap = + m_pipelineState->getShaderResourceUsage(nextStage.value())->inOutUsage.inputLocInfoMap; for (auto &locInfoPair : outputLocInfoMap) { const auto &locationInfo = locInfoPair.first; auto &newLocationInfo = locInfoPair.second; @@ -3000,9 +3005,9 @@ void PatchResourceCollect::updateOutputLocInfoMapWithUnpack() { assert(m_shaderStage == ShaderStage::TessControl); // If the next stage is valid, try to get location map of the outputs from corresponding inputs of next stage. - if (nextStage != ShaderStage::Invalid) { + if (nextStage) { auto &nextStagePerPatchInputLocInfoMap = - m_pipelineState->getShaderResourceUsage(nextStage)->inOutUsage.perPatchInputLocMap; + m_pipelineState->getShaderResourceUsage(nextStage.value())->inOutUsage.perPatchInputLocMap; for (auto &locPair : perPatchOutputLocMap) { if (locPair.second != InvalidValue) continue; // Skip mapped locations @@ -3046,9 +3051,9 @@ void PatchResourceCollect::updateOutputLocInfoMapWithUnpack() { assert(m_shaderStage == ShaderStage::Mesh); // If the next stage is valid, try to get location map of the outputs from corresponding inputs of next stage. - if (nextStage != ShaderStage::Invalid) { + if (nextStage) { auto &nextStagePerPrimitiveInputLocMap = - m_pipelineState->getShaderResourceUsage(nextStage)->inOutUsage.perPrimitiveInputLocMap; + m_pipelineState->getShaderResourceUsage(nextStage.value())->inOutUsage.perPrimitiveInputLocMap; for (auto &locPair : perPrimitiveOutputLocMap) { if (locPair.second != InvalidValue) continue; // Skip mapped locations @@ -3096,7 +3101,7 @@ bool PatchResourceCollect::canChangeOutputLocationsForGs() { return true; if (m_pipelineState->getPalMetadata()->haveFsInputMappings()) return true; - if (m_pipelineState->getNextShaderStage(ShaderStage::Geometry) != ShaderStage::Invalid) + if (m_pipelineState->getNextShaderStage(ShaderStage::Geometry)) return true; return false; } @@ -3157,8 +3162,8 @@ void PatchResourceCollect::updateOutputLocInfoMapWithPack() { assert(m_shaderStage == ShaderStage::Vertex || m_shaderStage == ShaderStage::TessEval || m_shaderStage == ShaderStage::Geometry); auto nextStage = m_pipelineState->getNextShaderStage(m_shaderStage); - assert(nextStage != ShaderStage::Invalid); - auto &nextStageInputLocInfoMap = m_pipelineState->getShaderResourceUsage(nextStage)->inOutUsage.inputLocInfoMap; + auto &nextStageInputLocInfoMap = + m_pipelineState->getShaderResourceUsage(nextStage.value())->inOutUsage.inputLocInfoMap; // Remove unused outputs and update the output map if (m_shaderStage != m_pipelineState->getLastVertexProcessingStage()) { @@ -3707,7 +3712,7 @@ void PatchResourceCollect::clearUndefinedOutput() { for (auto call : candidateCalls) { // For unlinked case, we should keep the location info map unchanged. - if (m_pipelineState->getNextShaderStage(m_shaderStage) != ShaderStage::Invalid) { + if (m_pipelineState->getNextShaderStage(m_shaderStage)) { // Remove the output location info if it exists unsigned index = m_shaderStage == ShaderStage::Mesh ? 2 : 1; unsigned component = cast(call->getArgOperand(index))->getZExtValue(); diff --git a/lgc/patch/RegisterMetadataBuilder.cpp b/lgc/patch/RegisterMetadataBuilder.cpp index 6042c4313d..8e452560e8 100644 --- a/lgc/patch/RegisterMetadataBuilder.cpp +++ b/lgc/patch/RegisterMetadataBuilder.cpp @@ -129,9 +129,9 @@ void RegisterMetadataBuilder::buildPalMetadata() { if (hwStageMask & (Util::Abi::HwShaderGs | Util::Abi::HwShaderVs)) buildPaSpecificRegisters(); - if (lastVertexProcessingStage != ShaderStage::Invalid && m_pipelineState->isUnlinked()) { + if (lastVertexProcessingStage && m_pipelineState->isUnlinked()) { // Fill ".preraster_output_semantic" - auto resUsage = m_pipelineState->getShaderResourceUsage(lastVertexProcessingStage); + auto resUsage = m_pipelineState->getShaderResourceUsage(lastVertexProcessingStage.value()); auto &outputLocInfoMap = resUsage->inOutUsage.outputLocInfoMap; auto &builtInOutputLocMap = resUsage->inOutUsage.builtInOutputLocMap; // Collect semantic info for generic input and builtIns {gl_ClipDistance, gl_CulDistance, gl_Layer, @@ -200,6 +200,8 @@ void RegisterMetadataBuilder::buildLsHsRegisters() { lsVgprCompCnt = 3; // Enable all LS VGPRs (LS VGPR2 - VGPR5) else lsVgprCompCnt = 1; // Must enable relative vertex ID (LS VGPR2 and VGPR3) + } else { + llvm_unreachable("Not implemented!"); } getGraphicsRegNode()[Util::Abi::GraphicsRegisterMetadataKey::LsVgprCompCnt] = lsVgprCompCnt; @@ -226,6 +228,7 @@ void RegisterMetadataBuilder::buildEsGsRegisters() { const auto gsResUsage = m_pipelineState->getShaderResourceUsage(ShaderStage::Geometry); const auto &gsBuiltInUsage = gsResUsage->builtInUsage.gs; const auto &gsInOutUsage = gsResUsage->inOutUsage; + const auto &geometryMode = m_pipelineState->getShaderModes()->getGeometryShaderMode(); const auto &calcFactor = gsInOutUsage.gs.calcFactor; const auto tesResUsage = m_pipelineState->getShaderResourceUsage(ShaderStage::TessEval); const auto &tesBuiltInUsage = tesResUsage->builtInUsage.tes; @@ -233,11 +236,12 @@ void RegisterMetadataBuilder::buildEsGsRegisters() { // ES_VGPR_COMP_CNT in SPI_SHADER_PGM_RSRC2_GS unsigned gsVgprCompCnt = 0; - if (calcFactor.inputVertices > 4 || gsBuiltInUsage.invocationId) + if ((calcFactor.inputVertices > 4 && geometryMode.inputPrimitive != InputPrimitives::Patch) || + gsBuiltInUsage.invocationId) gsVgprCompCnt = 3; // Enable vtx4/vtx5 offset (GS VGPR3) or GS instance ID (GS VGPR4) else if (gsBuiltInUsage.primitiveIdIn) gsVgprCompCnt = 2; // Enable primitive ID (GS VGPR2) - else if (calcFactor.inputVertices > 2) + else if (calcFactor.inputVertices > 2 && geometryMode.inputPrimitive != InputPrimitives::Patch) gsVgprCompCnt = 1; // Enable vtx2/vtx3 offset (GS VGPR1) getGraphicsRegNode()[Util::Abi::GraphicsRegisterMetadataKey::GsVgprCompCnt] = gsVgprCompCnt; @@ -257,7 +261,6 @@ void RegisterMetadataBuilder::buildEsGsRegisters() { getHwShaderNode(Util::Abi::HardwareStage::Gs)[Util::Abi::HardwareStageMetadataKey::OffchipLdsEn] = hasTs; // VGT_GS_MAX_VERT_OUT - const auto &geometryMode = m_pipelineState->getShaderModes()->getGeometryShaderMode(); unsigned maxVertOut = std::max(1u, static_cast(geometryMode.outputVertices)); getGraphicsRegNode()[Util::Abi::GraphicsRegisterMetadataKey::VgtGsMaxVertOut] = maxVertOut; @@ -345,6 +348,13 @@ void RegisterMetadataBuilder::buildEsGsRegisters() { // VGT_ESGS_RING_ITEMSIZE getGraphicsRegNode()[Util::Abi::GraphicsRegisterMetadataKey::VgtEsgsRingItemsize] = calcFactor.esGsRingItemSize; + // VGT_LS_HS_CONFIG + if (geometryMode.inputPrimitive == InputPrimitives::Patch) { + assert(geometryMode.controlPoints > 0); + auto vgtLsHsConfig = getGraphicsRegNode()[Util::Abi::GraphicsRegisterMetadataKey::VgtLsHsConfig].getMap(true); + vgtLsHsConfig[Util::Abi::VgtLsHsConfigMetadataKey::HsNumInputCp] = geometryMode.controlPoints; + } + // GE_MAX_OUTPUT_PER_SUBGROUP and VGT_GS_MAX_PRIMS_PER_SUBGROUP const unsigned maxPrimsPerSubgroup = std::min(gsInstPrimsInSubgrp * maxVertOut, MaxGsThreadsPerSubgroup); getGraphicsRegNode()[Util::Abi::GraphicsRegisterMetadataKey::MaxVertsPerSubgroup] = maxPrimsPerSubgroup; @@ -380,11 +390,12 @@ void RegisterMetadataBuilder::buildPrimShaderRegisters() { unsigned gsVgprCompCnt = 0; if (m_gfxIp.major <= 11) { if (m_hasGs) { - if (calcFactor.inputVertices > 4 || gsBuiltInUsage.invocationId) + if ((calcFactor.inputVertices > 4 && geometryMode.inputPrimitive != InputPrimitives::Patch) || + gsBuiltInUsage.invocationId) gsVgprCompCnt = 3; // Enable vtx4/vtx5 offset (GS VGPR3) or GS instance ID (GS VGPR4) else if (gsBuiltInUsage.primitiveIdIn) gsVgprCompCnt = 2; // Enable primitive ID (GS VGPR2) - else if (calcFactor.inputVertices > 2) + else if (calcFactor.inputVertices > 2 && geometryMode.inputPrimitive != InputPrimitives::Patch) gsVgprCompCnt = 1; // Enable vtx2/vtx3 offset (GS VGPR1) } else if (m_hasVs) { // NOTE: When GS is absent, only those VGPRs are required: vtx0/vtx1 offset, vtx2/vtx3 offset, @@ -584,6 +595,13 @@ void RegisterMetadataBuilder::buildPrimShaderRegisters() { (m_hasGs ? calcFactor.esGsRingItemSize : 1); } + // VGT_LS_HS_CONFIG + if (geometryMode.inputPrimitive == InputPrimitives::Patch) { + assert(geometryMode.controlPoints > 0); + auto vgtLsHsConfig = getGraphicsRegNode()[Util::Abi::GraphicsRegisterMetadataKey::VgtLsHsConfig].getMap(true); + vgtLsHsConfig[Util::Abi::VgtLsHsConfigMetadataKey::HsNumInputCp] = geometryMode.controlPoints; + } + const auto nggControl = m_pipelineState->getNggControl(); assert(nggControl->enableNgg); if (!nggControl->passthroughMode) { @@ -1285,7 +1303,7 @@ void RegisterMetadataBuilder::buildPaSpecificRegisters() { // On 10.3+ all auxiliary position exports are optimized, not just the misc exports. if (m_gfxIp >= GfxIpVersion{10, 3}) - paClClipCntl[Util::Abi::PaClVsOutCntlMetadataKey::VsOutMiscSideBusEna] = true; + paClVsOutCntl[Util::Abi::PaClVsOutCntlMetadataKey::VsOutMiscSideBusEna] = true; } // PA_CL_VTE_CNTL @@ -1385,7 +1403,7 @@ void RegisterMetadataBuilder::setVgtShaderStagesEn(unsigned hwStageMask) { ShaderStageEnum apiStage = ShaderStage::Vertex; if (m_hasGs || m_hasMesh) { apiStage = m_hasGs ? ShaderStage::Geometry : ShaderStage::Mesh; - vgtShaderStagesEn[Util::Abi::VgtShaderStagesEnMetadataKey::GsStageEn] = GS_STAGE_ON; + vgtShaderStagesEn[Util::Abi::VgtShaderStagesEnMetadataKey::GsStageEn] = true; } else if (m_hasTes) { apiStage = ShaderStage::TessEval; } diff --git a/lgc/patch/ShaderMerger.cpp b/lgc/patch/ShaderMerger.cpp index 4b6a4b8121..14b49e5dc1 100644 --- a/lgc/patch/ShaderMerger.cpp +++ b/lgc/patch/ShaderMerger.cpp @@ -728,10 +728,12 @@ Function *ShaderMerger::generateEsGsEntryPoint(Function *esEntryPoint, Function ArrayRef vgprArgs(args.begin() + NumSpecialSgprInputs + 1, args.end()); // GS VGPRs + const auto &geometryMode = m_pipelineState->getShaderModes()->getGeometryShaderMode(); + Value *esGsOffsets01 = vgprArgs[0]; Value *esGsOffsets23 = PoisonValue::get(builder.getInt32Ty()); - if (calcFactor.inputVertices > 2) { + if (calcFactor.inputVertices > 2 && geometryMode.inputPrimitive != InputPrimitives::Patch) { // NOTE: ES to GS offset (vertex 2 and 3) is valid once the primitive type has more than 2 vertices. esGsOffsets23 = vgprArgs[1]; } @@ -740,7 +742,7 @@ Function *ShaderMerger::generateEsGsEntryPoint(Function *esEntryPoint, Function Value *invocationId = vgprArgs[3]; Value *esGsOffsets45 = PoisonValue::get(builder.getInt32Ty()); - if (calcFactor.inputVertices > 4) { + if (calcFactor.inputVertices > 4 && geometryMode.inputPrimitive != InputPrimitives::Patch) { // NOTE: ES to GS offset (vertex 4 and 5) is valid once the primitive type has more than 4 vertices. esGsOffsets45 = vgprArgs[4]; } diff --git a/lgc/patch/SystemValues.cpp b/lgc/patch/SystemValues.cpp index 0deecd5e06..1f8396c9f3 100644 --- a/lgc/patch/SystemValues.cpp +++ b/lgc/patch/SystemValues.cpp @@ -240,6 +240,7 @@ Value *ShaderSystemValues::getEsGsOffsets() { auto insertPos = &*m_entryPoint->front().getFirstNonPHIOrDbgOrAlloca(); auto intfData = m_pipelineState->getShaderInterfaceData(m_shaderStage); + // TODO: We should only insert those offsets required by the specified input primitive. m_esGsOffsets = PoisonValue::get(FixedVectorType::get(Type::getInt32Ty(*m_context), 6)); for (unsigned i = 0; i < InterfaceData::MaxEsGsOffsetCount; ++i) { auto esGsOffset = @@ -320,8 +321,6 @@ std::pair> ShaderSystemValues::getEmitCounterPtr() { assert(m_shaderStage == ShaderStage::Geometry); auto *emitCounterTy = Type::getInt32Ty(*m_context); if (m_emitCounterPtrs.empty()) { - // TODO: We should only insert those offsets required by the specified input primitive. - // Setup GS emit vertex counter auto &dataLayout = m_entryPoint->getParent()->getDataLayout(); auto insertPos = &*m_entryPoint->front().getFirstNonPHIOrDbgOrAlloca(); @@ -334,6 +333,21 @@ std::pair> ShaderSystemValues::getEmitCounterPtr() { return std::make_pair(emitCounterTy, ArrayRef(m_emitCounterPtrs)); } +// ===================================================================================================================== +// Get pointer to total emit counter (GS) +Value *ShaderSystemValues::getTotalEmitCounterPtr() { + assert(m_shaderStage == ShaderStage::Geometry); + assert(m_pipelineState->getShaderModes()->getGeometryShaderMode().robustGsEmits); // Must enable robust GS emits + if (!m_totalEmitCounterPtr) { + // Setup GS total emit vertex counter + BuilderBase builder(&*m_entryPoint->front().getFirstNonPHIOrDbgOrAlloca()); + + m_totalEmitCounterPtr = builder.CreateAlloca(builder.getInt32Ty()); + builder.CreateStore(builder.getInt32(0), m_totalEmitCounterPtr); + } + return m_totalEmitCounterPtr; +} + // ===================================================================================================================== // Get internal global table pointer as pointer to i8. Instruction *ShaderSystemValues::getInternalGlobalTablePtr() { diff --git a/lgc/patch/VertexFetch.cpp b/lgc/patch/VertexFetch.cpp index c8cf1f7e44..70c618aeff 100644 --- a/lgc/patch/VertexFetch.cpp +++ b/lgc/patch/VertexFetch.cpp @@ -118,9 +118,10 @@ class VertexFetchImpl : public VertexFetch { Value *loadVertexBufferDescriptor(unsigned binding, BuilderImpl &builderImpl); - void addVertexFetchInst(Value *vbDesc, Value *vbIndex, Value *srdStride, unsigned numChannels, unsigned offset, - unsigned dfmt, unsigned nfmt, unsigned inputCompBytes, unsigned fetchCompBytes, bool isSigned, - bool isPacked, bool fetchInByte, BuilderImpl &builderImpl, Value **ppFetch) const; + void addVertexFetchInst(Value *vbDesc, Value *vbIndex, Value *srdStride, Type *inputTy, unsigned numChannels, + unsigned offset, unsigned dfmt, unsigned nfmt, unsigned inputCompBytes, + unsigned fetchCompBytes, bool isSigned, bool isPacked, bool fetchInByte, + BuilderImpl &builderImpl, Value **ppFetch) const; bool needPostShuffle(const VertexInputDescription *inputDesc, std::vector &shuffleMask) const; @@ -715,8 +716,8 @@ Value *VertexFetchImpl::fetchVertex(InputImportGenericOp *inst, Value *descPtr, m_instanceIndex = ShaderInputs::getInstanceIndex(builder, *m_lgcContext); } - // Get the vertex buffer table pointer as pointer to v4i32 descriptor. - Type *vbDescTy = FixedVectorType::get(Type::getInt32Ty(*m_context), 4); + Type *vbDescTy = nullptr; + { vbDescTy = FixedVectorType::get(Type::getInt32Ty(*m_context), 4); } if (!m_vertexBufTablePtr) { IRBuilderBase::InsertPointGuard ipg(builder); builder.SetInsertPointPastAllocas(inst->getFunction()); @@ -835,13 +836,16 @@ Value *VertexFetchImpl::fetchVertex(InputImportGenericOp *inst, Value *descPtr, assert(bitWidth == 8 || bitWidth == 16 || bitWidth == 32 || bitWidth == 64); Intrinsic::ID instId = Intrinsic::amdgcn_struct_buffer_load_format; - if (m_useSoftwareVertexBufferDescriptors) { - instId = Intrinsic::amdgcn_raw_buffer_load_format; - auto srdStride = builder.CreateExtractElement(vbDesc, 3); - byteOffset = builder.CreateAdd(builder.CreateMul(vbIndex, srdStride), byteOffset); + + { + if (m_useSoftwareVertexBufferDescriptors) { + instId = Intrinsic::amdgcn_raw_buffer_load_format; + auto srdStride = builder.CreateExtractElement(vbDesc, 3); + byteOffset = builder.CreateAdd(builder.CreateMul(vbIndex, srdStride), byteOffset); + } + // Replace buffer format + vbDesc = builder.CreateInsertElement(vbDesc, bufferFormat, 3); } - // Replace buffer format - vbDesc = builder.CreateInsertElement(vbDesc, bufferFormat, 3); SmallVector args; args.push_back(vbDesc); @@ -849,7 +853,7 @@ Value *VertexFetchImpl::fetchVertex(InputImportGenericOp *inst, Value *descPtr, args.push_back(vbIndex); unsigned offsetIdx = args.size(); args.push_back(byteOffset); - args.push_back(builder.getInt32(0)); + { args.push_back(builder.getInt32(0)); } args.push_back(builder.getInt32(0)); if (disablePerCompFetch) { @@ -1251,9 +1255,9 @@ Value *VertexFetchImpl::fetchVertex(Type *inputTy, const VertexInputDescription // After back-end optimization, intrinsics may be combined to fetch the whole vertex in generated ISA codes. // To make sure combination works, we need to keep tbuffer_load formats as same as possible when visit this function. // To avoid redundant extract and insert operation, we need to keep component bit width as same as input component. - addVertexFetchInst(vbDesc, vbIndex, srdStride, numChannels, description->offset, compFormatInfo->fetchDfmt, - description->nfmt, inputCompBytes, fetchCompBytes, numFormatInfo->isSigned, isPacked, fetchInByte, - builderImpl, &vertexFetch); + addVertexFetchInst(vbDesc, vbIndex, srdStride, inputCompTy, numChannels, description->offset, + compFormatInfo->fetchDfmt, description->nfmt, inputCompBytes, fetchCompBytes, + numFormatInfo->isSigned, isPacked, fetchInByte, builderImpl, &vertexFetch); // When do fetch in Byte, we need to emulate final results manually. postFetchEmulation(description, fetchInByte, inputCompBytes, numChannels, numFormatInfo, compFormatInfo, builderImpl, @@ -1611,10 +1615,10 @@ void VertexFetchImpl::postFetchEmulation(const VertexInputDescription *descripti // @param fetchInByte: Do fetch in Byte if the vertex attribute offset and stride are not aligned. // @param builderImpl : BuilderImpl to use to insert vertex fetch instructions // @param [out] ppFetch : Destination of vertex fetch -void VertexFetchImpl::addVertexFetchInst(Value *vbDesc, Value *vbIndex, Value *srdStride, unsigned numChannels, - unsigned offset, unsigned dfmt, unsigned nfmt, unsigned inputCompBytes, - unsigned fetchCompBytes, bool isSigned, bool isPacked, bool fetchInByte, - BuilderImpl &builderImpl, Value **ppFetch) const { +void VertexFetchImpl::addVertexFetchInst(Value *vbDesc, Value *vbIndex, Value *srdStride, Type *inputTy, + unsigned numChannels, unsigned offset, unsigned dfmt, unsigned nfmt, + unsigned inputCompBytes, unsigned fetchCompBytes, bool isSigned, bool isPacked, + bool fetchInByte, BuilderImpl &builderImpl, Value **ppFetch) const { Intrinsic::ID instId = Intrinsic::amdgcn_struct_tbuffer_load; Value *instOffset = builderImpl.getInt32(0); if (m_useSoftwareVertexBufferDescriptors) { @@ -1703,7 +1707,11 @@ void VertexFetchImpl::addVertexFetchInst(Value *vbDesc, Value *vbIndex, Value *s if (inputCompBytes < compBytes) compVal = builderImpl.CreateTrunc(compVal, inputCompTy); else if (inputCompBytes > compBytes) { - if (isSigned) + if (inputTy->isFloatTy() && nfmt == BufNumFormatFloat) { + compVal = builderImpl.CreateBitCast(compVal, builderImpl.getHalfTy()); + compVal = builderImpl.CreateFPExt(compVal, builderImpl.getFloatTy()); + compVal = builderImpl.CreateBitCast(compVal, inputCompTy); + } else if (isSigned) compVal = builderImpl.CreateSExt(compVal, inputCompTy); else compVal = builderImpl.CreateZExt(compVal, inputCompTy); @@ -1783,15 +1791,14 @@ std::pair VertexFetchImpl::convertSrdToOffsetMode(Value *vbDes // uint32 strideInBytes; // }; + GfxIpVersion gfxIp = m_lgcContext->getTargetInfo().getGfxIpVersion(); // Stride is from the third DWORD. auto srdStride = builder.CreateExtractElement(vbDesc, 3); - SqBufRsrcWord3 sqBufRsrcWord3 = {}; sqBufRsrcWord3.bits.dstSelX = BUF_DST_SEL_X; sqBufRsrcWord3.bits.dstSelY = BUF_DST_SEL_Y; sqBufRsrcWord3.bits.dstSelZ = BUF_DST_SEL_Z; sqBufRsrcWord3.bits.dstSelW = BUF_DST_SEL_W; - GfxIpVersion gfxIp = m_lgcContext->getTargetInfo().getGfxIpVersion(); if (gfxIp.major == 10) { sqBufRsrcWord3.gfx10.format = BUF_FORMAT_32_UINT; sqBufRsrcWord3.gfx10.resourceLevel = 1; diff --git a/lgc/state/PipelineState.cpp b/lgc/state/PipelineState.cpp index 5734ce2b56..a4379a9c8d 100644 --- a/lgc/state/PipelineState.cpp +++ b/lgc/state/PipelineState.cpp @@ -497,41 +497,43 @@ void PipelineState::readShaderStageMask(Module *module) { // ===================================================================================================================== // Get the last vertex processing shader stage in this pipeline, or ShaderStage::Invalid if none. -ShaderStageEnum PipelineState::getLastVertexProcessingStage() const { - if (m_stageMask.contains(ShaderStage::CopyShader)) - return ShaderStage::CopyShader; - if (m_stageMask.contains(ShaderStage::Geometry)) - return ShaderStage::Geometry; - if (m_stageMask.contains(ShaderStage::TessEval)) - return ShaderStage::TessEval; - if (m_stageMask.contains(ShaderStage::Vertex)) - return ShaderStage::Vertex; - return ShaderStage::Invalid; +std::optional PipelineState::getLastVertexProcessingStage() const { + for (auto stage : {ShaderStage::CopyShader, ShaderStage::Geometry, ShaderStage::TessEval, ShaderStage::Vertex}) { + if (m_stageMask.contains(stage)) + return stage; + } + return std::nullopt; } // ===================================================================================================================== // Gets the previous active shader stage in this pipeline // // @param shaderStage : Current shader stage -ShaderStageEnum PipelineState::getPrevShaderStage(ShaderStageEnum shaderStage) const { +std::optional PipelineState::getPrevShaderStage(ShaderStageEnum shaderStage) const { if (shaderStage == ShaderStage::Compute) - return ShaderStage::Invalid; + return std::nullopt; if (shaderStage == ShaderStage::CopyShader) { // Treat copy shader as part of geometry shader shaderStage = ShaderStage::Geometry; } - assert(shaderStage < ShaderStage::GfxCount); + std::optional prevStage; - ShaderStageEnum prevStage = ShaderStage::Invalid; + bool foundCurrent = false; + for (auto stage : llvm::reverse(ShaderStagesGraphics)) { + if (!foundCurrent) { + if (stage == shaderStage) + foundCurrent = true; + continue; + } - for (int stage = shaderStage - 1; stage >= 0; --stage) { - if (m_stageMask.contains(static_cast(stage))) { - prevStage = static_cast(stage); + if (m_stageMask.contains(stage)) { + prevStage = stage; break; } } + assert(foundCurrent); return prevStage; } @@ -540,28 +542,34 @@ ShaderStageEnum PipelineState::getPrevShaderStage(ShaderStageEnum shaderStage) c // Gets the next active shader stage in this pipeline // // @param shaderStage : Current shader stage -ShaderStageEnum PipelineState::getNextShaderStage(ShaderStageEnum shaderStage) const { +std::optional PipelineState::getNextShaderStage(ShaderStageEnum shaderStage) const { if (shaderStage == ShaderStage::Compute) - return ShaderStage::Invalid; + return std::nullopt; if (shaderStage == ShaderStage::CopyShader) { // Treat copy shader as part of geometry shader shaderStage = ShaderStage::Geometry; } - assert(shaderStage < ShaderStage::GfxCount); - - ShaderStageEnum nextStage = ShaderStage::Invalid; + std::optional nextStage; auto stageMask = m_stageMask; if (isPartPipeline()) stageMask |= ShaderStageMask(ShaderStage::Fragment); - for (unsigned stage = shaderStage + 1; stage < ShaderStage::GfxCount; ++stage) { - if (stageMask.contains(static_cast(stage))) { - nextStage = static_cast(stage); + bool foundCurrent = false; + for (auto stage : ShaderStagesGraphics) { + if (!foundCurrent) { + if (stage == shaderStage) + foundCurrent = true; + continue; + } + + if (stageMask.contains(stage)) { + nextStage = stage; break; } } + assert(foundCurrent); return nextStage; } @@ -1434,8 +1442,8 @@ void PipelineState::buildAbiHwShaderMap() { } else { if (hasGs) { auto preGsStage = getPrevShaderStage(ShaderStage::Geometry); - if (preGsStage != ShaderStage::Invalid) - m_abiHwShaderMap[preGsStage] = Util::Abi::HwShaderGs; + if (preGsStage.has_value()) + m_abiHwShaderMap[preGsStage.value()] = Util::Abi::HwShaderGs; } if (hasTcs) { m_abiHwShaderMap[ShaderStage::TessControl] = Util::Abi::HwShaderHs; @@ -1444,16 +1452,16 @@ void PipelineState::buildAbiHwShaderMap() { } auto lastVertexProcessingStage = getLastVertexProcessingStage(); - if (lastVertexProcessingStage != ShaderStage::Invalid) { + if (lastVertexProcessingStage.has_value()) { if (lastVertexProcessingStage == ShaderStage::CopyShader) lastVertexProcessingStage = ShaderStage::Geometry; if (isNggEnabled()) { - m_abiHwShaderMap[lastVertexProcessingStage] = Util::Abi::HwShaderGs; + m_abiHwShaderMap[lastVertexProcessingStage.value()] = Util::Abi::HwShaderGs; m_abiPipelineType = hasTs ? Util::Abi::PipelineType::NggTess : Util::Abi::PipelineType::Ngg; } else { - m_abiHwShaderMap[lastVertexProcessingStage] = Util::Abi::HwShaderVs; + m_abiHwShaderMap[lastVertexProcessingStage.value()] = Util::Abi::HwShaderVs; if (hasGs) - m_abiHwShaderMap[lastVertexProcessingStage] |= Util::Abi::HwShaderGs; + m_abiHwShaderMap[lastVertexProcessingStage.value()] |= Util::Abi::HwShaderGs; if (hasTs && hasGs) m_abiPipelineType = Util::Abi::PipelineType::GsTess; @@ -1688,7 +1696,7 @@ bool PipelineState::enableSwXfb() { auto lastVertexStage = getLastVertexProcessingStage(); lastVertexStage = lastVertexStage == ShaderStage::CopyShader ? ShaderStage::Geometry : lastVertexStage; - if (lastVertexStage == ShaderStage::Invalid) { + if (!lastVertexStage) { assert(isUnlinked()); // Unlinked fragment shader or part-pipeline return false; } @@ -1933,16 +1941,16 @@ void PipelineState::initializeInOutPackState() { // We are assuming that if any of the vertex processing, then the vertex processing stages are complete. For // example, if we see a vertex shader and geometry shader with no tessellation shaders, then we will assume we can // pack the vertex outputs and geometry inputs because no tessellation shader will be added later. - for (ShaderStageEnum stage : lgc::enumRange(ShaderStage::GfxCount)) { + for (auto stage : ShaderStagesGraphics) { if (!m_stageMask.contains(stage)) continue; if (stage == ShaderStage::TessEval) continue; - ShaderStageEnum preStage = getPrevShaderStage(stage); - if (preStage == ShaderStage::Invalid) + auto preStage = getPrevShaderStage(stage); + if (!preStage) continue; m_inputPackState[stage] = true; - m_outputPackState[preStage] = true; + m_outputPackState[*preStage] = true; } } } @@ -1952,12 +1960,12 @@ void PipelineState::initializeInOutPackState() { // // @param shaderStage : The given shader stage bool PipelineState::canPackInput(ShaderStageEnum shaderStage) { - ShaderStageEnum preStage = getPrevShaderStage(shaderStage); + auto preStage = getPrevShaderStage(shaderStage); // The input packable state of the current stage should match the output packable state of the previous stage, except // that the current stage has no previous and it is a null FS. - if (preStage != ShaderStage::Invalid && + if (preStage && !(shaderStage == ShaderStage::Fragment && getShaderResourceUsage(shaderStage)->inOutUsage.fs.isNullFs)) - assert(m_inputPackState[shaderStage] == m_outputPackState[preStage]); + assert(m_inputPackState[shaderStage] == m_outputPackState[preStage.value()]); return m_inputPackState[shaderStage]; } @@ -1966,25 +1974,30 @@ bool PipelineState::canPackInput(ShaderStageEnum shaderStage) { // // @param shaderStage : The given shader stage bool PipelineState::canPackOutput(ShaderStageEnum shaderStage) { - ShaderStageEnum nextStage = getNextShaderStage(shaderStage); + auto nextStage = getNextShaderStage(shaderStage); // The output packable state of the current stage should match the input packable state of the next stage, except that // the current stage has no next stage or a null FS. - if (nextStage != ShaderStage::Invalid && - !(nextStage == ShaderStage::Fragment && getShaderResourceUsage(nextStage)->inOutUsage.fs.isNullFs)) - assert(m_outputPackState[shaderStage] == m_inputPackState[nextStage]); + if (nextStage && !(nextStage == ShaderStage::Fragment && getShaderResourceUsage(*nextStage)->inOutUsage.fs.isNullFs)) + assert(m_outputPackState[shaderStage] == m_inputPackState[*nextStage]); return m_outputPackState[shaderStage]; } // ===================================================================================================================== // Get the count of vertices per primitive. For GS, the count is for output primitive. unsigned PipelineState::getVerticesPerPrimitive() { - if (hasShaderStage(ShaderStage::Geometry)) { - const auto &geometryMode = getShaderModes()->getGeometryShaderMode(); - switch (geometryMode.outputPrimitive) { + if (hasShaderStage(ShaderStage::Geometry) || hasShaderStage(ShaderStage::Mesh)) { + OutputPrimitives outputPrimitive = OutputPrimitives::Points; + if (hasShaderStage(ShaderStage::Geometry)) + outputPrimitive = getShaderModes()->getGeometryShaderMode().outputPrimitive; + else + outputPrimitive = getShaderModes()->getMeshShaderMode().outputPrimitive; + switch (outputPrimitive) { case OutputPrimitives::Points: return 1; + case OutputPrimitives::Lines: case OutputPrimitives::LineStrip: return 2; + case OutputPrimitives::Triangles: case OutputPrimitives::TriangleStrip: return 3; default: diff --git a/llpc/context/GfxRuntimeContext.cpp b/lgc/state/RuntimeContext.cpp similarity index 90% rename from llpc/context/GfxRuntimeContext.cpp rename to lgc/state/RuntimeContext.cpp index d7932edf6b..644b892748 100644 --- a/llpc/context/GfxRuntimeContext.cpp +++ b/lgc/state/RuntimeContext.cpp @@ -24,17 +24,15 @@ **********************************************************************************************************************/ /** *********************************************************************************************************************** - * @file GfxRuntimeContext.cpp - * @brief LLVMContext extension that stores a GfxRuntime library module + * @file RuntimeContext.cpp + * @brief LLVMContext extension that stores a Runtime library module *********************************************************************************************************************** */ -#include "GfxRuntimeContext.h" +#include "lgc/RuntimeContext.h" #include "llvm/IR/Module.h" using namespace llvm; using namespace lgc; GfxRuntimeContext::Key GfxRuntimeContext::theKey; - -GfxRuntimeContext::~GfxRuntimeContext() = default; diff --git a/lgc/state/ShaderStage.cpp b/lgc/state/ShaderStage.cpp index c7eb5d2f75..78b3868fea 100644 --- a/lgc/state/ShaderStage.cpp +++ b/lgc/state/ShaderStage.cpp @@ -82,8 +82,9 @@ void lgc::setShaderStage(GlobalObject *func, std::optional stag MDNode::get(func->getContext(), {ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(func->getContext()), stage.value()))}); func->setMetadata(mdKindId, stageMetaNode); - } else + } else { func->eraseMetadata(mdKindId); + } } // ===================================================================================================================== @@ -137,13 +138,28 @@ bool lgc::isShaderEntryPoint(const Function *func) { // // @param shaderStage : Shader stage const char *lgc::getShaderStageAbbreviation(ShaderStageEnum shaderStage) { - if (shaderStage == ShaderStage::CopyShader) + switch (shaderStage) { + case ShaderStage::Compute: + return "CS"; + case ShaderStage::Fragment: + return "FS"; + case ShaderStage::Vertex: + return "VS"; + case ShaderStage::Geometry: + return "GS"; + case ShaderStage::CopyShader: return "COPY"; - if (shaderStage > ShaderStage::Compute) - return "Bad"; - - static const char *ShaderStageAbbrs[] = {"TASK", "VS", "TCS", "TES", "GS", "MESH", "FS", "CS"}; - return ShaderStageAbbrs[static_cast(shaderStage)]; + case ShaderStage::TessControl: + return "TCS"; + case ShaderStage::TessEval: + return "TES"; + case ShaderStage::Task: + return "TASK"; + case ShaderStage::Mesh: + return "MESH"; + default: + llvm_unreachable("Unhandled ShaderStage"); + } } // ===================================================================================================================== diff --git a/lgc/test/CsLowerDebugPrintf.lgc b/lgc/test/CsLowerDebugPrintf.lgc index f4e21a52b0..d380f37da8 100644 --- a/lgc/test/CsLowerDebugPrintf.lgc +++ b/lgc/test/CsLowerDebugPrintf.lgc @@ -6,27 +6,29 @@ source_filename = "llpc_compute_8" target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7" target triple = "amdgcn--amdpal" -@str.1 = internal addrspace(4) constant [10 x i8] c"Output:%d\0A" +@0 = private unnamed_addr constant [11 x i8] c"Output:%d\0A\00", align 1 +@1 = private unnamed_addr constant [22 x i8] c"workgroup size:%f,%f\0A\00", align 1 ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.CS.main() local_unnamed_addr #0 !spirv.ExecutionModel !7 !lgc.shaderstage !8 { .entry: - %0 = call <3 x i32> @lgc.shader.input.WorkgroupId(i32 0) #1 + %0 = call <3 x i32> @lgc.shader.input.WorkgroupId(i32 0) #2 %1 = mul <3 x i32> %0, - %2 = call <3 x i32> @lgc.shader.input.LocalInvocationId(i32 47) #1 - %3 = insertelement <3 x i32> %2, i32 0, i64 1 - %4 = insertelement <3 x i32> %3, i32 0, i64 2 - %5 = call <3 x i32> @lgc.reconfigure.local.invocation.id(<3 x i32> %4, i32 0) #1 - %6 = add <3 x i32> %1, %5 - %__llpc_input_proxy_gl_GlobalInvocationID.0.vec.extract = extractelement <3 x i32> %6, i64 0 - %7 = call ptr addrspace(4) @lgc.descriptor.table.addr(i32 6, i32 6, i32 -1, i32 6, i32 -1) #1 - %8 = getelementptr i8, ptr addrspace(4) %7, i32 0 - %9 = load <4 x i32>, ptr addrspace(4) %8, align 16 - %10 = call ptr addrspace(7) @lgc.buffer.desc.to.ptr(<4 x i32> %9) - %11 = insertelement <2 x i32> poison, i32 0, i64 0 - %12 = insertelement <2 x i32> %11, i32 0, i64 1 - %13 = bitcast <2 x i32> %12 to i64 - call void (...) @lgc.debug.printf(ptr addrspace(7) %10, ptr addrspace(4) @str.1, i32 %__llpc_input_proxy_gl_GlobalInvocationID.0.vec.extract, i64 %13) + %2 = call i32 @lgc.shader.input.LocalInvocationId(i32 49) #2 + %3 = and i32 %2, 1023 + %4 = insertelement <3 x i32> poison, i32 %3, i64 0 + %5 = lshr i32 %2, 10 + %6 = and i32 %5, 1023 + %7 = insertelement <3 x i32> %4, i32 %6, i64 1 + %8 = lshr i32 %5, 10 + %9 = insertelement <3 x i32> %7, i32 %8, i64 2 + %10 = insertelement <3 x i32> %9, i32 0, i64 1 + %11 = insertelement <3 x i32> %10, i32 0, i64 2 + %12 = call <3 x i32> @lgc.reconfigure.local.invocation.id(<3 x i32> %11, i32 0) #2 + %13 = add <3 x i32> %1, %12 + %__llpc_input_proxy_gl_GlobalInvocationID.0.vec.extract = extractelement <3 x i32> %13, i64 0 + call void (...) @lgc.debug.printf(ptr nonnull @0, i32 %__llpc_input_proxy_gl_GlobalInvocationID.0.vec.extract) + call void (...) @lgc.debug.printf(ptr nonnull @1, double 1.000000e+00, double 1.000000e+00) ret void } @@ -70,42 +72,64 @@ attributes #2 = { nounwind willreturn memory(none) } !8 = !{i32 7} ; CHECK-LABEL: @lgc.shader.CS.main( ; CHECK-NEXT: .entry: -; CHECK-NEXT: [[TMP0:%.*]] = call <3 x i32> @lgc.shader.input.WorkgroupId(i32 0) #[[ATTR1:[0-9]+]] -; CHECK-NEXT: [[TMP1:%.*]] = mul <3 x i32> [[TMP0]], -; CHECK-NEXT: [[TMP2:%.*]] = call <3 x i32> @lgc.shader.input.LocalInvocationId(i32 47) #[[ATTR1]] -; CHECK-NEXT: [[TMP3:%.*]] = insertelement <3 x i32> [[TMP2]], i32 0, i64 1 -; CHECK-NEXT: [[TMP4:%.*]] = insertelement <3 x i32> [[TMP3]], i32 0, i64 2 -; CHECK-NEXT: [[TMP5:%.*]] = call <3 x i32> @lgc.reconfigure.local.invocation.id(<3 x i32> [[TMP4]], i32 0) #[[ATTR1]] -; CHECK-NEXT: [[TMP6:%.*]] = add <3 x i32> [[TMP1]], [[TMP5]] -; CHECK-NEXT: [[__LLPC_INPUT_PROXY_GL_GLOBALINVOCATIONID_0_VEC_EXTRACT:%.*]] = extractelement <3 x i32> [[TMP6]], i64 0 -; CHECK-NEXT: [[TMP7:%.*]] = call ptr addrspace(4) @lgc.descriptor.table.addr(i32 6, i32 6, i32 -1, i32 6, i32 -1) #[[ATTR1]] -; CHECK-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP7]], i32 0 -; CHECK-NEXT: [[TMP9:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP8]], align 16 -; CHECK-NEXT: [[TMP10:%.*]] = call ptr addrspace(7) @lgc.buffer.desc.to.ptr(<4 x i32> [[TMP9]]) -; CHECK-NEXT: [[TMP11:%.*]] = insertelement <2 x i32> poison, i32 0, i64 0 -; CHECK-NEXT: [[TMP12:%.*]] = insertelement <2 x i32> [[TMP11]], i32 0, i64 1 -; CHECK-NEXT: [[TMP13:%.*]] = bitcast <2 x i32> [[TMP12]] to i64 -; CHECK-NEXT: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 -; CHECK-NEXT: [[TMP15:%.*]] = lshr i64 [[TMP13]], 32 -; CHECK-NEXT: [[TMP16:%.*]] = trunc i64 [[TMP15]] to i32 -; CHECK-NEXT: [[TMP17:%.*]] = atomicrmw add ptr addrspace(7) [[TMP10]], i64 5 monotonic, align 8 -; CHECK-NEXT: [[TMP18:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP17]], i64 536870912) -; CHECK-NEXT: [[TMP19:%.*]] = trunc i64 [[TMP18]] to i32 -; CHECK-NEXT: [[TMP20:%.*]] = add i32 [[TMP19]], 4 -; CHECK-NEXT: [[TMP21:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP10]], i32 [[TMP20]] -; CHECK-NEXT: store i32 {{-?[0-9]+}}, ptr addrspace(7) [[TMP21]], align 4 -; CHECK-NEXT: [[TMP22:%.*]] = add i32 [[TMP20]], 1 -; CHECK-NEXT: [[TMP23:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP10]], i32 [[TMP22]] -; CHECK-NEXT: store i32 {{-?[0-9]+}}, ptr addrspace(7) [[TMP23]], align 4 -; CHECK-NEXT: [[TMP24:%.*]] = add i32 [[TMP22]], 1 -; CHECK-NEXT: [[TMP25:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP10]], i32 [[TMP24]] -; CHECK-NEXT: store i32 [[__LLPC_INPUT_PROXY_GL_GLOBALINVOCATIONID_0_VEC_EXTRACT]], ptr addrspace(7) [[TMP25]], align 4 -; CHECK-NEXT: [[TMP26:%.*]] = add i32 [[TMP24]], 1 -; CHECK-NEXT: [[TMP27:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP10]], i32 [[TMP26]] -; CHECK-NEXT: store i32 [[TMP14]], ptr addrspace(7) [[TMP27]], align 4 +; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() +; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> +; CHECK-NEXT: [[TMP2:%.*]] = call i32 @lgc.load.user.data__i32(i32 0) +; CHECK-NEXT: [[TMP3:%.*]] = insertelement <2 x i32> [[TMP1]], i32 [[TMP2]], i64 0 +; CHECK-NEXT: [[TMP4:%.*]] = bitcast <2 x i32> [[TMP3]] to i64 +; CHECK-NEXT: [[TMP5:%.*]] = inttoptr i64 [[TMP4]] to ptr addrspace(4) +; CHECK-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP5]], i32 0 +; CHECK-NEXT: [[TMP7:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP6]], align 16 +; CHECK-NEXT: [[TMP8:%.*]] = call ptr addrspace(7) @lgc.buffer.desc.to.ptr(<4 x i32> [[TMP7]]) +; CHECK-NEXT: [[TMP9:%.*]] = call <3 x i32> @lgc.shader.input.WorkgroupId(i32 0) #[[ATTR2:[0-9]+]] +; CHECK-NEXT: [[TMP10:%.*]] = mul <3 x i32> [[TMP9]], +; CHECK-NEXT: [[TMP11:%.*]] = call i32 @lgc.shader.input.LocalInvocationId(i32 49) #[[ATTR2]] +; CHECK-NEXT: [[TMP12:%.*]] = and i32 [[TMP11]], 1023 +; CHECK-NEXT: [[TMP13:%.*]] = insertelement <3 x i32> poison, i32 [[TMP12]], i64 0 +; CHECK-NEXT: [[TMP14:%.*]] = lshr i32 [[TMP11]], 10 +; CHECK-NEXT: [[TMP15:%.*]] = and i32 [[TMP14]], 1023 +; CHECK-NEXT: [[TMP16:%.*]] = insertelement <3 x i32> [[TMP13]], i32 [[TMP15]], i64 1 +; CHECK-NEXT: [[TMP17:%.*]] = lshr i32 [[TMP14]], 10 +; CHECK-NEXT: [[TMP18:%.*]] = insertelement <3 x i32> [[TMP16]], i32 [[TMP17]], i64 2 +; CHECK-NEXT: [[TMP19:%.*]] = insertelement <3 x i32> [[TMP18]], i32 0, i64 1 +; CHECK-NEXT: [[TMP20:%.*]] = insertelement <3 x i32> [[TMP19]], i32 0, i64 2 +; CHECK-NEXT: [[TMP21:%.*]] = call <3 x i32> @lgc.reconfigure.local.invocation.id(<3 x i32> [[TMP20]], i32 0) #[[ATTR2]] +; CHECK-NEXT: [[TMP22:%.*]] = add <3 x i32> [[TMP10]], [[TMP21]] +; CHECK-NEXT: [[__LLPC_INPUT_PROXY_GL_GLOBALINVOCATIONID_0_VEC_EXTRACT:%.*]] = extractelement <3 x i32> [[TMP22]], i64 0 +; CHECK-NEXT: [[TMP23:%.*]] = atomicrmw add ptr addrspace(7) [[TMP8]], i64 3 monotonic, align 8 +; CHECK-NEXT: [[TMP24:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP23]], i64 536870912) +; CHECK-NEXT: [[TMP25:%.*]] = trunc i64 [[TMP24]] to i32 +; CHECK-NEXT: [[TMP26:%.*]] = add i32 [[TMP25]], 4 +; CHECK-NEXT: [[TMP27:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP26]] +; CHECK-NEXT: store i32 {{-?[0-9]+}}, ptr addrspace(7) [[TMP27]], align 4 ; CHECK-NEXT: [[TMP28:%.*]] = add i32 [[TMP26]], 1 -; CHECK-NEXT: [[TMP29:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP10]], i32 [[TMP28]] -; CHECK-NEXT: store i32 [[TMP16]], ptr addrspace(7) [[TMP29]], align 4 +; CHECK-NEXT: [[TMP29:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP28]] +; CHECK-NEXT: store i32 {{-?[0-9]+}}, ptr addrspace(7) [[TMP29]], align 4 ; CHECK-NEXT: [[TMP30:%.*]] = add i32 [[TMP28]], 1 +; CHECK-NEXT: [[TMP31:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP30]] +; CHECK-NEXT: store i32 [[__LLPC_INPUT_PROXY_GL_GLOBALINVOCATIONID_0_VEC_EXTRACT]], ptr addrspace(7) [[TMP31]], align 4 +; CHECK-NEXT: [[TMP32:%.*]] = add i32 [[TMP30]], 1 +; CHECK-NEXT: [[TMP33:%.*]] = atomicrmw add ptr addrspace(7) [[TMP8]], i64 6 monotonic, align 8 +; CHECK-NEXT: [[TMP34:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP33]], i64 536870912) +; CHECK-NEXT: [[TMP35:%.*]] = trunc i64 [[TMP34]] to i32 +; CHECK-NEXT: [[TMP36:%.*]] = add i32 [[TMP35]], 4 +; CHECK-NEXT: [[TMP37:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP36]] +; CHECK-NEXT: store i32 {{-?[0-9]+}}, ptr addrspace(7) [[TMP37]], align 4 +; CHECK-NEXT: [[TMP38:%.*]] = add i32 [[TMP36]], 1 +; CHECK-NEXT: [[TMP39:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP38]] +; CHECK-NEXT: store i32 {{-?[0-9]+}}, ptr addrspace(7) [[TMP39]], align 4 +; CHECK-NEXT: [[TMP40:%.*]] = add i32 [[TMP38]], 1 +; CHECK-NEXT: [[TMP41:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP40]] +; CHECK-NEXT: store i32 0, ptr addrspace(7) [[TMP41]], align 4 +; CHECK-NEXT: [[TMP42:%.*]] = add i32 [[TMP40]], 1 +; CHECK-NEXT: [[TMP43:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP42]] +; CHECK-NEXT: store i32 {{-?[0-9]+}}, ptr addrspace(7) [[TMP43]], align 4 +; CHECK-NEXT: [[TMP44:%.*]] = add i32 [[TMP42]], 1 +; CHECK-NEXT: [[TMP45:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP44]] +; CHECK-NEXT: store i32 0, ptr addrspace(7) [[TMP45]], align 4 +; CHECK-NEXT: [[TMP46:%.*]] = add i32 [[TMP44]], 1 +; CHECK-NEXT: [[TMP47:%.*]] = getelementptr i32, ptr addrspace(7) [[TMP8]], i32 [[TMP46]] +; CHECK-NEXT: store i32 {{-?[0-9]+}}, ptr addrspace(7) [[TMP47]], align 4 +; CHECK-NEXT: [[TMP48:%.*]] = add i32 [[TMP46]], 1 ; CHECK-NEXT: ret void ; diff --git a/lgc/test/CsReconfigWorkgroup.lgc b/lgc/test/CsReconfigWorkgroup.lgc index 0ef36e6515..3235ced729 100644 --- a/lgc/test/CsReconfigWorkgroup.lgc +++ b/lgc/test/CsReconfigWorkgroup.lgc @@ -51,8 +51,7 @@ define dllexport spir_func void @lgc.shader.CS.main() local_unnamed_addr #0 !lgc %2 = bitcast i8 addrspace(7)* %0 to <3 x i32> addrspace(7)* store <3 x i32> %1, <3 x i32> addrspace(7)* %2, align 4 %imgdescptr = call <8 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.v8i32(i32 1, i32 0, i32 0, i32 1) - %imgdesc = load <8 x i32>, <8 x i32> addrspace(4)* %imgdescptr - %imgload = call <2 x float> (...) @lgc.create.image.load.v2f32(i32 1, i32 0, <8 x i32> %imgdesc, <2 x i32>) + %imgload = call <2 x float> (...) @lgc.create.image.load.v2f32(i32 1, i32 0, <8 x i32> addrspace(4)* %imgdescptr, <2 x i32>) %storeptr = getelementptr i8, i8 addrspace(7)* %0, i64 16 %storeptrcast = bitcast i8 addrspace(7)* %storeptr to <2 x float> addrspace(7)* store <2 x float> %imgload, <2 x float> addrspace(7)* %storeptrcast @@ -99,8 +98,7 @@ define dllexport spir_func void @lgc.shader.CS.main() local_unnamed_addr #0 !lgc %2 = bitcast i8 addrspace(7)* %0 to <3 x i32> addrspace(7)* store <3 x i32> %1, <3 x i32> addrspace(7)* %2, align 4 %imgdescptr = call <8 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.v8i32(i32 1, i32 0, i32 0, i32 1) - %imgdesc = load <8 x i32>, <8 x i32> addrspace(4)* %imgdescptr - %imgload = call <2 x float> (...) @lgc.create.image.load.v2f32(i32 1, i32 0, <8 x i32> %imgdesc, <2 x i32>) + %imgload = call <2 x float> (...) @lgc.create.image.load.v2f32(i32 1, i32 0, <8 x i32> addrspace(4)* %imgdescptr, <2 x i32>) %storeptr = getelementptr i8, i8 addrspace(7)* %0, i64 16 %storeptrcast = bitcast i8 addrspace(7)* %storeptr to <2 x float> addrspace(7)* store <2 x float> %imgload, <2 x float> addrspace(7)* %storeptrcast diff --git a/lgc/test/ElfRelocationSize.lgc b/lgc/test/ElfRelocationSize.lgc index e77214a9c1..3125c72577 100644 --- a/lgc/test/ElfRelocationSize.lgc +++ b/lgc/test/ElfRelocationSize.lgc @@ -66,12 +66,10 @@ entry: %0 = extractelement <2 x float> %texcoordadj, i32 0 %1 = extractelement <2 x float> %texcoordadj, i32 1 %2 = call <8 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.p4v8i32(i32 1, i32 0, i32 0, i32 1) - %3 = load <8 x i32>, <8 x i32> addrspace(4)* %2, align 32 %4 = call <4 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.p4v4i32(i32 2, i32 0, i32 0, i32 2) - %5 = load <4 x i32>, <4 x i32> addrspace(4)* %4, align 16 %6 = insertelement <2 x float> undef, float %0, i64 0 %7 = insertelement <2 x float> %6, float %1, i64 1 - %8 = call <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, <8 x i32> %3, <4 x i32> %5, i32 1, <2 x float> %7) + %8 = call <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, <8 x i32> addrspace(4)* %2, <4 x i32> addrspace(4)* %4, i32 1, <2 x float> %7) %9 = extractelement <4 x float> %8, i64 0 %10 = insertvalue %types.ResRet.f32.1 undef, float %9, 0 %11 = extractelement <4 x float> %8, i64 1 diff --git a/lgc/test/PartPipeline.lgc b/lgc/test/PartPipeline.lgc index a39eb3f36b..d368f9394c 100644 --- a/lgc/test/PartPipeline.lgc +++ b/lgc/test/PartPipeline.lgc @@ -74,12 +74,10 @@ entry: %0 = extractelement <2 x float> %texcoordadj, i32 0 %1 = extractelement <2 x float> %texcoordadj, i32 1 %2 = call <8 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.p4v8i32(i32 1, i32 1, i32 0, i32 1) - %3 = load <8 x i32>, <8 x i32> addrspace(4)* %2, align 32 %4 = call <4 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.p4v4i32(i32 2, i32 2, i32 0, i32 2) - %5 = load <4 x i32>, <4 x i32> addrspace(4)* %4, align 16 %6 = insertelement <2 x float> undef, float %0, i64 0 %7 = insertelement <2 x float> %6, float %1, i64 1 - %8 = call <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, <8 x i32> %3, <4 x i32> %5, i32 1, <2 x float> %7) + %8 = call <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, <8 x i32> addrspace(4)* %2, <4 x i32> addrspace(4)* %4, i32 1, <2 x float> %7) %9 = extractelement <4 x float> %8, i64 0 %10 = insertvalue %types.ResRet.f32.1 undef, float %9, 0 %11 = extractelement <4 x float> %8, i64 1 diff --git a/lgc/test/PatchInvalidImageDescriptor.lgc b/lgc/test/PatchInvalidImageDescriptor.lgc index 32a48a7f9f..debed60f1e 100644 --- a/lgc/test/PatchInvalidImageDescriptor.lgc +++ b/lgc/test/PatchInvalidImageDescriptor.lgc @@ -4,7 +4,7 @@ ; CHECK-LABEL: IR Dump After Patch LLVM for workarounds ; GFX1010: extractelement <8 x i32> %{{[0-9]+}}, i64 3 -; GFX1010-NEXT: icmp sge i32 +; GFX1010: icmp sge i32 ; GFX1010-NEXT: and i32 ; GFX1010-NEXT: select i1 ; GFX1010-NEXT: [[PATCHED_DESC0:%[.a-zA-Z0-9]+]] = insertelement <8 x i32> %{{[0-9]+}} @@ -12,7 +12,7 @@ ; GFX1010: call void @llvm.amdgcn.image.store.2d.v4f32.i32(<4 x float> zeroinitializer, i32 15, i32 0, i32 0, <8 x i32> %{{[0-9]+}}, i32 0, i32 0) -; GFX1010: %.sample = call <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> %{{[0-9]+}}, <4 x i32> %.sampler, i1 false, i32 0, i32 0) +; GFX1010: %.sample = call <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, i1 false, i32 0, i32 0) ; GFX1010: %.gather = call <4 x float> @llvm.amdgcn.image.gather4.l.2d.v4f32.f32(i32 1, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, <8 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, i1 false, i32 0, i32 0) @@ -40,22 +40,20 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !lgc %.desc.ptr1 = bitcast <8 x i32> addrspace(4)* %.desc.ptr2 to i8 addrspace(4)* %.desc.ptr0 = getelementptr i8, i8 addrspace(4)* %.desc.ptr1, i64 0 %.desc.ptr = bitcast i8 addrspace(4)* %.desc.ptr0 to <8 x i32> addrspace(4)* - %.desc = load <8 x i32>, <8 x i32> addrspace(4)* %.desc.ptr, align 32 %.sampler.ptr = call <4 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.p4v4i32(i32 2, i32 2, i32 0, i32 13) - %.sampler = load <4 x i32>, <4 x i32> addrspace(4)* %.sampler.ptr, align 16 - %.load = call <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 128, <8 x i32> %.desc, i32 1) - call void (...) @lgc.create.image.store(<4 x float> zeroinitializer, i32 1, i32 128, <8 x i32> %.desc, <2 x i32> zeroinitializer) + %.load = call <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 128, <8 x i32> addrspace(4)* %.desc.ptr, i32 1) + call void (...) @lgc.create.image.store(<4 x float> zeroinitializer, i32 1, i32 128, <8 x i32> addrspace(4)* %.desc.ptr, <2 x i32> zeroinitializer) - %.sample = call <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 128, <8 x i32> %.desc, <4 x i32> %.sampler, i32 1, <2 x float> zeroinitializer) - %.gather = call <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 128, <8 x i32> %.desc, <4 x i32> %.sampler, i32 37, <2 x float> zeroinitializer, i32 0, float 0.000000e+00) + %.sample = call <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 128, <8 x i32> addrspace(4)* %.desc.ptr, <4 x i32> addrspace(4)* %.sampler.ptr, i32 1, <2 x float> zeroinitializer) + %.gather = call <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 128, <8 x i32> addrspace(4)* %.desc.ptr, <4 x i32> addrspace(4)* %.sampler.ptr, i32 37, <2 x float> zeroinitializer, i32 0, float 0.000000e+00) - %.atomic = call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 0, i32 128, i32 0, <8 x i32> %.desc, i32 0, i32 1) #0 + %.atomic = call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 0, i32 128, i32 0, <8 x i32> addrspace(4)* %.desc.ptr, i32 0, i32 1) #0 - %.lod = call <2 x float> (...) @lgc.create.image.get.lod.v2f32(i32 1, i32 128, <8 x i32> %.desc, <4 x i32> %.sampler, <2 x float> zeroinitializer) + %.lod = call <2 x float> (...) @lgc.create.image.get.lod.v2f32(i32 1, i32 128, <8 x i32> addrspace(4)* %.desc.ptr, <4 x i32> addrspace(4)* %.sampler.ptr, <2 x float> zeroinitializer) - %.query.size = call <2 x i32> (...) @lgc.create.image.query.size.v2i32(i32 1, i32 128, <8 x i32> %.desc, i32 0) - %.query.levels = call i32 (...) @lgc.create.image.query.levels.i32(i32 1, i32 128, <8 x i32> %.desc) + %.query.size = call <2 x i32> (...) @lgc.create.image.query.size.v2i32(i32 1, i32 128, <8 x i32> addrspace(4)* %.desc.ptr, i32 0) + %.query.levels = call i32 (...) @lgc.create.image.query.levels.i32(i32 1, i32 128, <8 x i32> addrspace(4)* %.desc.ptr) %lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0) ; just some source of divergence %ofs = mul i32 %lane, 32 @@ -65,8 +63,7 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !lgc %.desc2.ptr1 = bitcast <8 x i32> addrspace(4)* %.desc2.ptr2 to i8 addrspace(4)* %.desc2.ptr0 = getelementptr i8, i8 addrspace(4)* %.desc2.ptr1, i32 %ofs %.desc2.ptr = bitcast i8 addrspace(4)* %.desc2.ptr0 to <8 x i32> addrspace(4)* - %.desc2 = load <8 x i32>, <8 x i32> addrspace(4)* %.desc2.ptr, align 32 - call void (...) @lgc.create.image.store(<4 x float> zeroinitializer, i32 0, i32 8, <8 x i32> %.desc2, i32 zeroinitializer) + call void (...) @lgc.create.image.store(<4 x float> zeroinitializer, i32 0, i32 8, <8 x i32> addrspace(4)* %.desc2.ptr, i32 zeroinitializer) ret void } diff --git a/lgc/test/SubgroupClusteredReduction.lgc b/lgc/test/SubgroupClusteredReduction.lgc new file mode 100644 index 0000000000..40b53f9584 --- /dev/null +++ b/lgc/test/SubgroupClusteredReduction.lgc @@ -0,0 +1,51 @@ +; NOTE: Assertions have been autogenerated by tool/update_llpc_test_checks.py UTC_ARGS: --tool lgc +; RUN: lgc -o - --mcpu=gfx1100 --emit-llvm %s | FileCheck -check-prefixes=CHECK %s + +define dllexport spir_func i32 @fn(i32 %value1, i32 %value2) !lgc.shaderstage !0 { +.entry: + %r1 = call i32 (...) @lgc.create.subgroup.clustered.reduction.i32(i32 11, i32 %value1, i32 64) + %r2 = call i32 (...) @lgc.create.subgroup.clustered.reduction.i32(i32 11, i32 %value2, i32 32) + %r = add i32 %r1, %r2 + ret i32 %r +} + +declare i32 @lgc.create.subgroup.clustered.reduction.i32(...) + +; ShaderStage::Compute +!0 = !{i32 7} + +; Setting Threadgroup Dimensions to 64 x 1 x 1 +!llpc.compute.mode = !{!1} +!1 = !{i32 64, i32 1, i32 1} +; CHECK-LABEL: @_amdgpu_cs_main( +; CHECK-NEXT: .entry: +; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.set.inactive.i32(i32 [[VALUE1:%.*]], i32 0) +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 undef, i32 [[TMP0]], i32 177, i32 15, i32 15, i1 true) +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[TMP0]] +; CHECK-NEXT: [[TMP3:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 undef, i32 [[TMP2]], i32 78, i32 15, i32 15, i1 true) +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 undef, i32 [[TMP4]], i32 321, i32 15, i32 15, i1 true) +; CHECK-NEXT: [[TMP6:%.*]] = or i32 [[TMP4]], [[TMP5]] +; CHECK-NEXT: [[TMP7:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 undef, i32 [[TMP6]], i32 320, i32 15, i32 15, i1 true) +; CHECK-NEXT: [[TMP8:%.*]] = or i32 [[TMP6]], [[TMP7]] +; CHECK-NEXT: [[TMP9:%.*]] = call i32 @llvm.amdgcn.permlanex16(i32 undef, i32 [[TMP8]], i32 -1, i32 -1, i1 true, i1 false) +; CHECK-NEXT: [[TMP10:%.*]] = or i32 [[TMP8]], [[TMP9]] +; CHECK-NEXT: [[TMP11:%.*]] = call i32 @llvm.amdgcn.permlane64(i32 [[TMP10]]) +; CHECK-NEXT: [[TMP12:%.*]] = or i32 [[TMP10]], [[TMP11]] +; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.readfirstlane(i32 [[TMP12]]) +; CHECK-NEXT: [[R1:%.*]] = call i32 @llvm.amdgcn.wwm.i32(i32 [[TMP13]]) +; CHECK-NEXT: [[TMP14:%.*]] = call i32 @llvm.amdgcn.set.inactive.i32(i32 [[VALUE2:%.*]], i32 0) +; CHECK-NEXT: [[TMP15:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 undef, i32 [[TMP14]], i32 177, i32 15, i32 15, i1 true) +; CHECK-NEXT: [[TMP16:%.*]] = or i32 [[TMP15]], [[TMP14]] +; CHECK-NEXT: [[TMP17:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 undef, i32 [[TMP16]], i32 78, i32 15, i32 15, i1 true) +; CHECK-NEXT: [[TMP18:%.*]] = or i32 [[TMP16]], [[TMP17]] +; CHECK-NEXT: [[TMP19:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 undef, i32 [[TMP18]], i32 321, i32 15, i32 15, i1 true) +; CHECK-NEXT: [[TMP20:%.*]] = or i32 [[TMP18]], [[TMP19]] +; CHECK-NEXT: [[TMP21:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 undef, i32 [[TMP20]], i32 320, i32 15, i32 15, i1 true) +; CHECK-NEXT: [[TMP22:%.*]] = or i32 [[TMP20]], [[TMP21]] +; CHECK-NEXT: [[TMP23:%.*]] = call i32 @llvm.amdgcn.permlanex16(i32 undef, i32 [[TMP22]], i32 -1, i32 -1, i1 true, i1 false) +; CHECK-NEXT: [[TMP24:%.*]] = or i32 [[TMP22]], [[TMP23]] +; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.amdgcn.wwm.i32(i32 [[TMP24]]) +; CHECK-NEXT: [[R:%.*]] = add i32 [[R2]], [[R1]] +; CHECK-NEXT: ret i32 [[R]] +; diff --git a/lgc/test/TaskShaderOps.lgc b/lgc/test/TaskShaderOps.lgc index 16d98df3dd..88a85fee82 100644 --- a/lgc/test/TaskShaderOps.lgc +++ b/lgc/test/TaskShaderOps.lgc @@ -51,7 +51,7 @@ ; CHECK-NEXT: [[meshPipeStatsBufAddr64:%[0-9]*]] = bitcast <2 x i32> [[meshPipeStatsBufAddr2x32]] to i64 ; CHECK-NEXT: [[meshPipeStatsBufAddr:%[0-9]*]] = inttoptr i64 [[meshPipeStatsBufAddr64]] to ptr addrspace(1) ; CHECK: [[numTaskThreadsPtr8:%[0-9]*]] = getelementptr i8, ptr addrspace(1) [[meshPipeStatsBufAddr]], i64 16 -; CHECK: %{{[0-9]*}} = atomicrmw add ptr addrspace(1) [[numTaskThreadsPtr8]], i64 %{{[0-9]*}} monotonic, align 8 +; CHECK: %{{[0-9]*}} = atomicrmw add ptr addrspace(1) [[numTaskThreadsPtr8]], i64 %{{[0-9]*}} syncscope("agent") monotonic, align 8 ; CHECK: [[ringSize:%[0-9]*]] = extractelement <4 x i32> [[drawDataRingDesc]], i64 2 ; CHECK-NEXT: [[numEntries:%[0-9]*]] = lshr i32 [[ringSize]], 4 ; CHECK-NEXT: [[wrapMask:%[0-9]*]] = add nuw nsw i32 [[numEntries]], 268435455 diff --git a/lgc/test/TestWaterfallLoopForStruct.lgc b/lgc/test/TestWaterfallLoopForStruct.lgc index 448a7ceee2..c43691bddf 100644 --- a/lgc/test/TestWaterfallLoopForStruct.lgc +++ b/lgc/test/TestWaterfallLoopForStruct.lgc @@ -17,10 +17,7 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spi %6 = mul i32 %0, %2 %7 = sext i32 %6 to i64 %8 = getelementptr i8, ptr addrspace(4) %1, i64 %7 - %9 = insertvalue { ptr addrspace(4), i32, i32, i32 } %5, ptr addrspace(4) %8, 0 - %10 = load <8 x i32>, ptr addrspace(4) %8, align 32, !invariant.load !12 - %11 = insertvalue [3 x <8 x i32>] poison, <8 x i32> %10, 0 - %12 = call { <4 x float>, i32 } (...) @"lgc.create.image.load.s[v4f32,i32]"(i32 1, i32 8, <8 x i32> %10, <2 x i32> ) + %12 = call { <4 x float>, i32 } (...) @"lgc.create.image.load.s[v4f32,i32]"(i32 1, i32 8, ptr addrspace(4) %8, <2 x i32> ) %13 = extractvalue { <4 x float>, i32 } %12, 1 %14 = extractvalue { <4 x float>, i32 } %12, 0 %15 = icmp sgt i32 %13, 0 @@ -92,22 +89,20 @@ attributes #2 = { nounwind willreturn memory(read) } ; CHECK-NEXT: [[TMP11:%.*]] = mul i32 [[TMP2]], 32 ; CHECK-NEXT: [[TMP12:%.*]] = sext i32 [[TMP11]] to i64 ; CHECK-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP7]], i64 [[TMP12]] -; CHECK-NEXT: [[TMP14:%.*]] = insertvalue { ptr addrspace(4), i32, i32, i32 } [[TMP10]], ptr addrspace(4) [[TMP13]], 0 -; CHECK-NEXT: [[TMP15:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP13]], align 32, !invariant.load !12 -; CHECK-NEXT: [[TMP16:%.*]] = insertvalue [3 x <8 x i32>] poison, <8 x i32> [[TMP15]], 0 -; CHECK-NEXT: [[TMP17:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP11]]) -; CHECK-NEXT: [[TMP18:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.readfirstlane.v8i32.v8i32(i32 [[TMP17]], <8 x i32> [[TMP15]]) -; CHECK-NEXT: [[TMP19:%.*]] = call { <4 x float>, i32 } @llvm.amdgcn.image.load.2d.sl_v4f32i32s.i32(i32 15, i32 1, i32 1, <8 x i32> [[TMP18]], i32 1, i32 0) -; CHECK-NEXT: [[TMP20:%.*]] = extractvalue { <4 x float>, i32 } [[TMP19]], 0 -; CHECK-NEXT: [[TMP21:%.*]] = call <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP17]], <4 x float> [[TMP20]]) -; CHECK-NEXT: [[TMP22:%.*]] = extractvalue { <4 x float>, i32 } [[TMP19]], 1 -; CHECK-NEXT: [[TMP23:%.*]] = call i32 @llvm.amdgcn.waterfall.end.i32(i32 [[TMP17]], i32 [[TMP22]]) -; CHECK-NEXT: [[TMP24:%.*]] = insertvalue { <4 x float>, i32 } poison, <4 x float> [[TMP21]], 0 -; CHECK-NEXT: [[TMP25:%.*]] = insertvalue { <4 x float>, i32 } [[TMP24]], i32 [[TMP23]], 1 -; CHECK-NEXT: [[TMP26:%.*]] = extractvalue { <4 x float>, i32 } [[TMP25]], 1 -; CHECK-NEXT: [[TMP27:%.*]] = extractvalue { <4 x float>, i32 } [[TMP25]], 0 -; CHECK-NEXT: [[TMP28:%.*]] = icmp sgt i32 [[TMP26]], 0 -; CHECK-NEXT: [[TMP29:%.*]] = select i1 [[TMP28]], <4 x float> [[TMP27]], <4 x float> zeroinitializer -; CHECK-NEXT: call void @lgc.output.export.generic.i32.i32.v4f32(i32 0, i32 0, <4 x float> [[TMP29]]) #[[ATTR5:[0-9]+]] +; CHECK-NEXT: [[TMP14:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP13]], align 32, !invariant.load !12 +; CHECK-NEXT: [[TMP15:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP11]]) +; CHECK-NEXT: [[TMP16:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.readfirstlane.v8i32.v8i32(i32 [[TMP15]], <8 x i32> [[TMP14]]) +; CHECK-NEXT: [[TMP17:%.*]] = call { <4 x float>, i32 } @llvm.amdgcn.image.load.2d.sl_v4f32i32s.i32(i32 15, i32 1, i32 1, <8 x i32> [[TMP16]], i32 1, i32 0) +; CHECK-NEXT: [[TMP18:%.*]] = extractvalue { <4 x float>, i32 } [[TMP17]], 0 +; CHECK-NEXT: [[TMP19:%.*]] = call <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP15]], <4 x float> [[TMP18]]) +; CHECK-NEXT: [[TMP20:%.*]] = extractvalue { <4 x float>, i32 } [[TMP17]], 1 +; CHECK-NEXT: [[TMP21:%.*]] = call i32 @llvm.amdgcn.waterfall.end.i32(i32 [[TMP15]], i32 [[TMP20]]) +; CHECK-NEXT: [[TMP22:%.*]] = insertvalue { <4 x float>, i32 } poison, <4 x float> [[TMP19]], 0 +; CHECK-NEXT: [[TMP23:%.*]] = insertvalue { <4 x float>, i32 } [[TMP22]], i32 [[TMP21]], 1 +; CHECK-NEXT: [[TMP24:%.*]] = extractvalue { <4 x float>, i32 } [[TMP23]], 1 +; CHECK-NEXT: [[TMP25:%.*]] = extractvalue { <4 x float>, i32 } [[TMP23]], 0 +; CHECK-NEXT: [[TMP26:%.*]] = icmp sgt i32 [[TMP24]], 0 +; CHECK-NEXT: [[TMP27:%.*]] = select i1 [[TMP26]], <4 x float> [[TMP25]], <4 x float> zeroinitializer +; CHECK-NEXT: call void @lgc.output.export.generic.i32.i32.v4f32(i32 0, i32 0, <4 x float> [[TMP27]]) #[[ATTR5:[0-9]+]] ; CHECK-NEXT: ret void ; diff --git a/lgc/test/TextureRange.lgc b/lgc/test/TextureRange.lgc index 0f50ab4c50..3cda8fc4f8 100644 --- a/lgc/test/TextureRange.lgc +++ b/lgc/test/TextureRange.lgc @@ -87,11 +87,9 @@ define dllexport spir_func void @lgc.shader.FS.PSMain() local_unnamed_addr #0 !s %13 = fmul reassoc nnan nsz arcp contract afn float %10, %12 %14 = call ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 3221225472, i32 1) %15 = call i32 (...) @lgc.create.get.desc.stride__i32(i32 1, i32 1, i64 3221225472, i32 1) - %16 = load <8 x i32>, ptr addrspace(4) %14, align 32 %17 = call ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 2147483648, i32 0) %18 = call i32 (...) @lgc.create.get.desc.stride__i32(i32 2, i32 2, i64 2147483648, i32 0) - %19 = load <4 x i32>, ptr addrspace(4) %17, align 16 - %20 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample__v4f32(i32 1, i32 512, <8 x i32> %16, <4 x i32> %19, i32 1, <2 x float> %6) + %20 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample__v4f32(i32 1, i32 512, ptr addrspace(4) %14, ptr addrspace(4) %17, i32 1, <2 x float> %6) %.splatinsert = insertelement <4 x float> poison, float %13, i64 0 %21 = shufflevector <4 x float> %.splatinsert, <4 x float> poison, <4 x i32> zeroinitializer %scale = fmul reassoc nnan nsz arcp contract afn <4 x float> %20, %21 diff --git a/lgc/test/Transforms/LowerCooperativeMatrix/gfx1010muladd.lgc b/lgc/test/Transforms/LowerCooperativeMatrix/gfx1010muladd.lgc new file mode 100644 index 0000000000..90ffa98e22 --- /dev/null +++ b/lgc/test/Transforms/LowerCooperativeMatrix/gfx1010muladd.lgc @@ -0,0 +1,32 @@ +; RUN: lgc -march=amdgcn -o - --mcpu=gfx1010 -filetype=asm %s | FileCheck -check-prefixes=CHECK %s + +define void @matmul_f16f32_emulator(ptr addrspace(3) %out0, <8 x float> %a, <8 x float> %b, <8 x float> %c0) !lgc.shaderstage !0 { +; CHECK-NOT: v_dot + %value = call <8 x float> (...) @lgc.cooperative.matrix.muladd__v8f8(<8 x float> %a, <8 x float> %b, <8 x float> %c0, i1 true, i1 true, i1 false, i1 false, i32 2, i32 1) + call void (...) @lgc.cooperative.matrix.store(ptr addrspace(3) %out0, i32 4, i1 true, i32 1, i32 0, i32 0, i32 16, <8 x float> %value) + ret void +} + +define void @matmul_i16i32_emulator(ptr addrspace(3) %out0, <8 x i32> %a, <8 x i32> %b, <8 x i32> %c0) !lgc.shaderstage !0 { +; CHECK-NOT: v_dot + %value = call <8 x i32> (...) @lgc.cooperative.matrix.muladd__v8i32(<8 x i32> %a, <8 x i32> %b, <8 x i32> %c0, i1 true, i1 true, i1 false, i1 false, i32 5, i32 4) + call void (...) @lgc.cooperative.matrix.store(ptr addrspace(3) %out0, i32 4, i1 true, i32 1, i32 0, i32 0, i32 16, <8 x i32> %value) + ret void +} + +define void @matmul_i8i32_emulator(ptr addrspace(3) %out0, <8 x i32> %a, <8 x i32> %b, <8 x i32> %c0) !lgc.shaderstage !0 { +; CHECK-NOT: v_dot + %value = call <8 x i32> (...) @lgc.cooperative.matrix.muladd__v8i32(<8 x i32> %a, <8 x i32> %b, <8 x i32> %c0, i1 true, i1 true, i1 false, i1 false, i32 5, i32 3) + call void (...) @lgc.cooperative.matrix.store(ptr addrspace(3) %out0, i32 4, i1 true, i32 1, i32 0, i32 0, i32 16, <8 x i32> %value) + ret void +} + +declare <8 x float> @lgc.cooperative.matrix.muladd__v8f8(...) +declare <8 x i32> @lgc.cooperative.matrix.muladd__v8i32(...) +declare void @lgc.cooperative.matrix.store(...) + +; ShaderStage::Compute +!0 = !{i32 7} +; Setting Threadgroup Dimensions to 64 x 1 x 1 +!llpc.compute.mode = !{!1} +!1 = !{i32 64, i32 1, i32 1} diff --git a/lgc/test/Transforms/LowerCooperativeMatrix/gfx1011muladd.lgc b/lgc/test/Transforms/LowerCooperativeMatrix/gfx1011muladd.lgc new file mode 100644 index 0000000000..88292bf642 --- /dev/null +++ b/lgc/test/Transforms/LowerCooperativeMatrix/gfx1011muladd.lgc @@ -0,0 +1,33 @@ +; RUN: lgc -march=amdgcn -o - --mcpu=gfx1011 -filetype=asm %s | FileCheck -check-prefixes=CHECK %s + +define void @matmul_f16f32_emulator(ptr addrspace(3) %out0, <8 x float> %a, <8 x float> %b, <8 x float> %c0) !lgc.shaderstage !0 { +; CHECK: v_dot2c_f32_f16 + %value = call <8 x float> (...) @lgc.cooperative.matrix.muladd__v8f8(<8 x float> %a, <8 x float> %b, <8 x float> %c0, i1 true, i1 true, i1 false, i1 false, i32 2, i32 1) + call void (...) @lgc.cooperative.matrix.store(ptr addrspace(3) %out0, i32 4, i1 true, i32 1, i32 0, i32 0, i32 16, <8 x float> %value) + ret void +} + +define void @matmul_i16i32_emulator(ptr addrspace(3) %out0, <8 x i32> %a, <8 x i32> %b, <8 x i32> %c0) !lgc.shaderstage !0 { +; CHECK: v_dot2_i32_i16 + %value = call <8 x i32> (...) @lgc.cooperative.matrix.muladd__v8i32(<8 x i32> %a, <8 x i32> %b, <8 x i32> %c0, i1 true, i1 true, i1 false, i1 false, i32 5, i32 4) + call void (...) @lgc.cooperative.matrix.store(ptr addrspace(3) %out0, i32 4, i1 true, i32 1, i32 0, i32 0, i32 16, <8 x i32> %value) + ret void +} + +define void @matmul_i8i32_emulator(ptr addrspace(3) %out0, <8 x i32> %a, <8 x i32> %b, <8 x i32> %c0) !lgc.shaderstage !0 { +; CHECK: v_dot4c_i32_i8 + %value = call <8 x i32> (...) @lgc.cooperative.matrix.muladd__v8i32(<8 x i32> %a, <8 x i32> %b, <8 x i32> %c0, i1 true, i1 true, i1 false, i1 false, i32 5, i32 3) + call void (...) @lgc.cooperative.matrix.store(ptr addrspace(3) %out0, i32 4, i1 true, i32 1, i32 0, i32 0, i32 16, <8 x i32> %value) + ret void +} + +declare <8 x float> @lgc.cooperative.matrix.muladd__v8f8(...) +declare <8 x i32> @lgc.cooperative.matrix.muladd__v8i32(...) +declare void @lgc.cooperative.matrix.store(...) + +; ShaderStage::Compute +!0 = !{i32 7} +; Setting Threadgroup Dimensions to 64 x 1 x 1 +!llpc.compute.mode = !{!1} +!1 = !{i32 64, i32 1, i32 1} + diff --git a/lgc/test/Transforms/LowerDebugPrintf/basic.lgc b/lgc/test/Transforms/LowerDebugPrintf/basic.lgc index a20f4e0fd5..312478af57 100644 --- a/lgc/test/Transforms/LowerDebugPrintf/basic.lgc +++ b/lgc/test/Transforms/LowerDebugPrintf/basic.lgc @@ -1,15 +1,19 @@ -; RUN: lgc -o - -passes='require,lgc-lower-debug-printf' %s | FileCheck --check-prefixes=IR %s -; RUN: lgc -o - -passes='require,lgc-lower-debug-printf,print' %s -o /dev/null 2>&1 | FileCheck --check-prefixes=PALMD %s +; RUN: lgc -o - -passes="require,lgc-lower-debug-printf" %s | FileCheck --check-prefixes=IR %s +; RUN: lgc -o - -passes="require,lgc-lower-debug-printf,print" %s -o /dev/null 2>&1 | FileCheck --check-prefixes=PALMD %s -@str = internal addrspace(4) global [8 x i8] c"Test: %u" +@str = private unnamed_addr constant [8 x i8] c"Test: %u", align 1 -define spir_func void @simple(ptr addrspace(7) %buffer) !lgc.shaderstage !0 { +define spir_func void @simple() !lgc.shaderstage !0 { ; IR-LABEL: @simple( ; IR-NOT: call {{.*}} @lgc.debug.printf - call void (...) @lgc.debug.printf(ptr addrspace(7) %buffer, ptr addrspace(4) @str, i32 42) + call void (...) @lgc.debug.printf(ptr nonnull @str, i32 42) ret void } +!lgc.user.data.nodes = !{!4, !5} +!4 = !{!"DescriptorTableVaPtr", i32 7, i32 0, i32 0, i32 1, i32 1} +!5 = !{!"DescriptorBuffer", i32 6, i32 0, i32 0, i32 4, i32 -1, i32 6, i32 4} + ; IR: !amdgpu.pal.metadata.msgpack = ; PALMD: amdpal.format_strings: diff --git a/lgc/test/lgcdis.lgc b/lgc/test/lgcdis.lgc index 7b970b75ac..b90f44f093 100644 --- a/lgc/test/lgcdis.lgc +++ b/lgc/test/lgcdis.lgc @@ -95,10 +95,8 @@ define dllexport void @lgc.shader.FS.main() !lgc.shaderstage !25 { entry: %TEXCOORD = call <2 x float> (...) @lgc.create.read.generic.input.v2f32(i32 1, i32 0, i32 0, i32 1, i32 16, i32 poison) %imageptr = call <8 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.p4v8i32(i32 1, i32 1, i32 0, i32 1) - %image = load <8 x i32>, <8 x i32> addrspace(4)* %imageptr, align 32 %samplerptr = call <4 x i32> addrspace(4)* (...) @lgc.create.get.desc.ptr.p4v4i32(i32 2, i32 2, i32 0, i32 2) - %sampler = load <4 x i32>, <4 x i32> addrspace(4)* %samplerptr, align 16 - %sample = call <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, <8 x i32> %image, <4 x i32> %sampler, i32 1, <2 x float> %TEXCOORD) + %sample = call <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, <8 x i32> addrspace(4)* %imageptr, <4 x i32> addrspace(4)* %samplerptr, i32 1, <2 x float> %TEXCOORD) call void (...) @lgc.create.write.generic.output(<4 x float> %sample, i32 0, i32 0, i32 0, i32 1, i32 0, i32 poison) ret void } diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest1.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest1.lgc index cf01ecaead..186f904c28 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest1.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest1.lgc @@ -8,31 +8,31 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spirv.ExecutionModel !14 !lgc.shaderstage !15 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.VS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !14 !lgc.shaderstage [[META15:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META14:![0-9]+]] !lgc.shaderstage [[META15:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i32 @lgc.input.import.generic__i32(i1 false, i32 0, i32 0, i32 0, i32 poison) ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[TMP0]], poison ; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64 ; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP2]] -; CHECK-NEXT: [[TMP4:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP3]], align 32, !invariant.load [[META16:![0-9]+]] ; CHECK-NEXT: [[TMP5:%.*]] = mul i32 [[TMP0]], poison ; CHECK-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 ; CHECK-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP6]] -; CHECK-NEXT: [[TMP8:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP7]], align 16, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP8:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP7]], align 32, !invariant.load [[META16:![0-9]+]] ; CHECK-NEXT: [[TMP9:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP5]]) ; CHECK-NEXT: [[TMP10:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP9]], i32 [[TMP5]]) ; CHECK-NEXT: [[TMP11:%.*]] = sext i32 [[TMP10]] to i64 ; CHECK-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP11]] -; CHECK-NEXT: [[TMP13:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP12]], align 16, !invariant.load [[META16]] -; CHECK-NEXT: [[TMP14:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.struct.buffer.load.format.v4f32(<4 x i32> [[TMP13]], i32 0, i32 0, i32 0, i32 0) +; CHECK-NEXT: [[TMP13:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP12]], align 32, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP14:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.load.1d.v4f32.i32(i32 15, i32 0, <8 x i32> [[TMP13]], i32 0, i32 0) ; CHECK-NEXT: [[TMP15:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP9]], <4 x float> [[TMP14]]) +; CHECK-NEXT: [[TMP22:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP3]], align 32, !invariant.load [[META16]] ; CHECK-NEXT: [[TMP16:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP1]]) ; CHECK-NEXT: [[TMP17:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP16]], i32 [[TMP1]]) ; CHECK-NEXT: [[TMP18:%.*]] = sext i32 [[TMP17]] to i64 ; CHECK-NEXT: [[TMP19:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP18]] -; CHECK-NEXT: [[TMP20:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP19]], align 32, !invariant.load [[META16]] -; CHECK-NEXT: [[TMP21:%.*]] = call <4 x i32> @llvm.amdgcn.waterfall.last.use.v4i32(i32 [[TMP16]], <4 x i32> [[TMP20]]) -; CHECK-NEXT: call void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float> [[TMP15]], <4 x i32> [[TMP21]], i32 1, i32 0, i32 0, i32 0) +; CHECK-NEXT: [[TMP20:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP19]], align 32, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP21:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.last.use.v8i32(i32 [[TMP16]], <8 x i32> [[TMP20]]) +; CHECK-NEXT: call void @llvm.amdgcn.image.store.1d.v4f32.i32(<4 x float> [[TMP15]], i32 15, i32 1, <8 x i32> [[TMP21]], i32 0, i32 0) ; CHECK-NEXT: ret void ; .entry: @@ -42,13 +42,11 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spi %3 = mul i32 %0, %2 %4 = sext i32 %3 to i64 %5 = getelementptr i8, ptr addrspace(4) %1, i64 %4 - %6 = load <4 x i32>, ptr addrspace(4) %5, align 32, !invariant.load !16 %7 = mul i32 %0, %2 %8 = sext i32 %7 to i64 %9 = getelementptr i8, ptr addrspace(4) %1, i64 %8 - %10 = load <4 x i32>, ptr addrspace(4) %9, align 16, !invariant.load !16 - %11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 8, <4 x i32> %10, i32 0) - call void (...) @lgc.create.image.store(<4 x float> %11, i32 0, i32 8, <4 x i32> %6, i32 1) + %11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 8, ptr addrspace(4) %9, i32 0) + call void (...) @lgc.create.image.store(<4 x float> %11, i32 0, i32 8, ptr addrspace(4) %5, i32 1) ret void } @@ -99,3 +97,8 @@ attributes #3 = { nounwind memory(write) } !14 = !{i32 0} !15 = !{i32 1} !16 = !{} +;. +; CHECK: [[META14]] = !{i32 0} +; CHECK: [[META15]] = !{i32 1} +; CHECK: [[META16]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest10.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest10.lgc index 7835bf62e7..8d8609b8ea 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest10.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest10.lgc @@ -10,7 +10,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -44,8 +44,8 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I6:%.*]] = mul i32 [[PHI_IND]], [[PHI]] ; CHECK-NEXT: [[I7:%.*]] = sext i32 [[I6]] to i64 ; CHECK-NEXT: [[I8:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] -; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10:![0-9]+]] -; CHECK-NEXT: [[I10:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP21:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10:![0-9]+]] +; CHECK-NEXT: [[TMP22:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I3]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP12]], i32 [[I3]]) ; CHECK-NEXT: [[TMP14:%.*]] = sext i32 [[TMP13]] to i64 @@ -90,9 +90,7 @@ loop.latch: ; preds = %bb2, %bb1 %i6 = mul i32 %phi.ind, %phi %i7 = sext i32 %i6 to i64 %i8 = getelementptr i8, ptr addrspace(4) %i2, i64 %i7 - %i9 = load <4 x i32>, ptr addrspace(4) %i8, align 16, !invariant.load !10 - %i10 = load <8 x i32>, ptr addrspace(4) %i5, align 32, !invariant.load !10 - %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %i10, <4 x i32> %i9, i32 1, <2 x float> zeroinitializer) + %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %i5, ptr addrspace(4) %i8, i32 1, <2 x float> zeroinitializer) call void (...) @lgc.create.write.generic.output(<4 x float> %i11, i32 0, i32 0, i32 0, i32 0, i32 0, i32 poison) %ind = add i32 %phi.ind, 1 %cond2 = icmp ne i32 %ind, 1000 @@ -147,3 +145,8 @@ attributes #3 = { nounwind } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest11.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest11.lgc index 2a2d450d1b..68797e0c4e 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest11.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest11.lgc @@ -10,7 +10,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -44,8 +44,8 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: br label [[LOOP_LATCH]] ; CHECK: loop.latch: ; CHECK-NEXT: [[PHI:%.*]] = phi ptr addrspace(4) [ [[I5]], [[BB1]] ], [ [[I8]], [[BB2]] ] -; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[PHI]], align 16, !invariant.load [[META10:![0-9]+]] -; CHECK-NEXT: [[I10:%.*]] = load <8 x i32>, ptr addrspace(4) [[PHI]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[I10:%.*]] = load <8 x i32>, ptr addrspace(4) [[PHI]], align 32, !invariant.load [[META10:![0-9]+]] +; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[PHI]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.v8i32(i32 0, <8 x i32> [[I10]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.v4i32(i32 [[TMP12]], <4 x i32> [[I9]]) ; CHECK-NEXT: [[TMP14:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.readfirstlane.v8i32.v8i32(i32 [[TMP13]], <8 x i32> [[I10]]) @@ -86,9 +86,7 @@ bb2: ; preds = %loop loop.latch: ; preds = %bb2, %bb1 %phi = phi ptr addrspace(4) [ %i5, %bb1 ], [ %i8, %bb2 ] - %i9 = load <4 x i32>, ptr addrspace(4) %phi, align 16, !invariant.load !10 - %i10 = load <8 x i32>, ptr addrspace(4) %phi, align 32, !invariant.load !10 - %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %i10, <4 x i32> %i9, i32 1, <2 x float> zeroinitializer) + %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %phi, ptr addrspace(4) %phi, i32 1, <2 x float> zeroinitializer) call void (...) @lgc.create.write.generic.output(<4 x float> %i11, i32 0, i32 0, i32 0, i32 0, i32 0, i32 poison) %ind = add i32 %phi.ind, 1 %cond2 = icmp ne i32 %ind, 1000 @@ -143,3 +141,8 @@ attributes #3 = { nounwind } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest12.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest12.lgc index afd0072c01..e5909c6acb 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest12.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest12.lgc @@ -11,7 +11,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -38,8 +38,8 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I6:%.*]] = mul i32 [[PHI_IND]], 48 ; CHECK-NEXT: [[I7:%.*]] = sext i32 [[I6]] to i64 ; CHECK-NEXT: [[I8:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] -; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10:![0-9]+]] -; CHECK-NEXT: [[I10:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP21:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10:![0-9]+]] +; CHECK-NEXT: [[TMP22:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I3]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP12]], i32 [[I3]]) ; CHECK-NEXT: [[TMP14:%.*]] = sext i32 [[TMP13]] to i64 @@ -75,9 +75,7 @@ loop: ; preds = %loop, %.entry %i6 = mul i32 %phi.ind, %b %i7 = sext i32 %i6 to i64 %i8 = getelementptr i8, ptr addrspace(4) %i2, i64 %i7 - %i9 = load <4 x i32>, ptr addrspace(4) %i8, align 16, !invariant.load !10 - %i10 = load <8 x i32>, ptr addrspace(4) %i5, align 32, !invariant.load !10 - %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %i10, <4 x i32> %i9, i32 1, <2 x float> zeroinitializer) + %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %i5, ptr addrspace(4) %i8, i32 1, <2 x float> zeroinitializer) %i12 = fadd <4 x float> %phi.img, %ind = add i32 %phi.ind, 1 %cond = icmp ne i32 %ind, 1000 @@ -133,3 +131,8 @@ attributes #3 = { nounwind } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest13.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest13.lgc index cd41d3a2bf..9cb2e24f8f 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest13.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest13.lgc @@ -11,7 +11,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -31,16 +31,15 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I3:%.*]] = mul i32 [[I]], 48 ; CHECK-NEXT: [[I4:%.*]] = sext i32 [[I3]] to i64 ; CHECK-NEXT: [[I5:%.*]] = getelementptr i8, ptr addrspace(4) [[I1]], i64 [[I4]] -; CHECK-NEXT: [[L:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10:![0-9]+]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[PHI_IND:%.*]] = phi i32 [ 0, [[DOTENTRY:%.*]] ], [ [[IND:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[PHI_LOAD:%.*]] = phi <8 x i32> [ [[L]], [[DOTENTRY]] ], [ [[I10:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PHI_LOAD1:%.*]] = phi ptr addrspace(4) [ [[I5]], [[DOTENTRY]] ], [ [[I8:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[I6:%.*]] = mul i32 [[PHI_IND]], 48 ; CHECK-NEXT: [[I7:%.*]] = sext i32 [[I6]] to i64 -; CHECK-NEXT: [[I8:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] -; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10]] -; CHECK-NEXT: [[I10]] = load <8 x i32>, ptr addrspace(4) [[I8]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[I8]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] +; CHECK-NEXT: [[PHI_LOAD:%.*]] = load <8 x i32>, ptr addrspace(4) [[PHI_LOAD1]], align 32, !invariant.load [[META10:![0-9]+]] +; CHECK-NEXT: [[TMP20:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.v8i32(i32 0, <8 x i32> [[PHI_LOAD]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 [[TMP12]], i32 [[I6]]) ; CHECK-NEXT: [[TMP14:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.readfirstlane.v8i32.v8i32(i32 [[TMP13]], <8 x i32> [[PHI_LOAD]]) @@ -65,19 +64,16 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi %i3 = mul i32 %i, %a %i4 = sext i32 %i3 to i64 %i5 = getelementptr i8, ptr addrspace(4) %i1, i64 %i4 - %l = load <8 x i32>, ptr addrspace(4) %i5, align 32, !invariant.load !10 br label %loop loop: ; preds = %loop, %.entry %phi.ind = phi i32 [ 0, %.entry ], [ %ind, %loop ] - %phi.load = phi <8 x i32> [ %l, %.entry ], [ %i10, %loop ] + %phi.load = phi ptr addrspace(4) [ %i5, %.entry ], [ %i8, %loop ] %b = call i32 (...) @lgc.create.get.desc.stride__i32(i32 2, i32 2, i64 0, i32 7) %i6 = mul i32 %phi.ind, %b %i7 = sext i32 %i6 to i64 %i8 = getelementptr i8, ptr addrspace(4) %i2, i64 %i7 - %i9 = load <4 x i32>, ptr addrspace(4) %i8, align 16, !invariant.load !10 - %i10 = load <8 x i32>, ptr addrspace(4) %i8, align 32, !invariant.load !10 - %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %phi.load, <4 x i32> %i9, i32 1, <2 x float> zeroinitializer) + %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %phi.load, ptr addrspace(4) %i8, i32 1, <2 x float> zeroinitializer) call void (...) @lgc.create.write.generic.output(<4 x float> %i11, i32 0, i32 0, i32 0, i32 0, i32 0, i32 poison) %ind = add i32 %phi.ind, 1 %cond = icmp ne i32 %ind, 1000 @@ -132,3 +128,8 @@ attributes #3 = { nounwind } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest14.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest14.lgc index bba218fbc6..34edce02c5 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest14.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest14.lgc @@ -12,7 +12,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -39,8 +39,8 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I6:%.*]] = mul i32 [[PHI_IND]], 48 ; CHECK-NEXT: [[I7:%.*]] = sext i32 [[I6]] to i64 ; CHECK-NEXT: [[I8:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] -; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10:![0-9]+]] -; CHECK-NEXT: [[I10:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP25:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10:![0-9]+]] +; CHECK-NEXT: [[TMP26:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I3]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP12]], i32 [[I3]]) ; CHECK-NEXT: [[TMP14:%.*]] = sext i32 [[TMP13]] to i64 @@ -56,13 +56,14 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[IND]], 1000 ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: +; CHECK-NEXT: [[TMP27:%.*]] = load <8 x i32>, ptr addrspace(4) [[I8]], align 32, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP21:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I6]]) ; CHECK-NEXT: [[TMP22:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP21]], i32 [[I6]]) ; CHECK-NEXT: [[TMP23:%.*]] = sext i32 [[TMP22]] to i64 ; CHECK-NEXT: [[TMP24:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[TMP23]] -; CHECK-NEXT: [[TMP25:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP24]], align 16, !invariant.load [[META10]] -; CHECK-NEXT: [[TMP26:%.*]] = call <4 x i32> @llvm.amdgcn.waterfall.last.use.v4i32(i32 [[TMP21]], <4 x i32> [[TMP25]]) -; CHECK-NEXT: call void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float> [[I12]], <4 x i32> [[TMP26]], i32 1, i32 0, i32 0, i32 0) +; CHECK-NEXT: [[TMP28:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP24]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP29:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.last.use.v8i32(i32 [[TMP21]], <8 x i32> [[TMP28]]) +; CHECK-NEXT: call void @llvm.amdgcn.image.store.1d.v4f32.i32(<4 x float> [[I12]], i32 15, i32 1, <8 x i32> [[TMP29]], i32 0, i32 0) ; CHECK-NEXT: ret void ; .entry: @@ -82,16 +83,14 @@ loop: ; preds = %loop, %.entry %i6 = mul i32 %phi.ind, %b %i7 = sext i32 %i6 to i64 %i8 = getelementptr i8, ptr addrspace(4) %i2, i64 %i7 - %i9 = load <4 x i32>, ptr addrspace(4) %i8, align 16, !invariant.load !10 - %i10 = load <8 x i32>, ptr addrspace(4) %i5, align 32, !invariant.load !10 - %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %i10, <4 x i32> %i9, i32 1, <2 x float> zeroinitializer) + %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %i5, ptr addrspace(4) %i8, i32 1, <2 x float> zeroinitializer) %i12 = fadd <4 x float> %phi.img, %ind = add i32 %phi.ind, 1 %cond = icmp ne i32 %ind, 1000 br i1 %cond, label %loop, label %exit exit: ; preds = %loop - call void (...) @lgc.create.image.store(<4 x float> %i12, i32 0, i32 8, <4 x i32> %i9, i32 1) + call void (...) @lgc.create.image.store(<4 x float> %i12, i32 0, i32 8, ptr addrspace(4) %i8, i32 1) ret void } @@ -140,3 +139,8 @@ attributes #3 = { nounwind memory(write) } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest15.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest15.lgc index c22cf5fc59..ab426db63d 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest15.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest15.lgc @@ -11,7 +11,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -38,8 +38,8 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I6:%.*]] = mul i32 [[PHI_IND]], 48 ; CHECK-NEXT: [[I7:%.*]] = sext i32 [[I6]] to i64 ; CHECK-NEXT: [[I8:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] -; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10:![0-9]+]] -; CHECK-NEXT: [[I10:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP25:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10:![0-9]+]] +; CHECK-NEXT: [[TMP26:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I3]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP12]], i32 [[I3]]) ; CHECK-NEXT: [[TMP14:%.*]] = sext i32 [[TMP13]] to i64 @@ -51,13 +51,14 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[TMP20:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[TMP16]], <4 x i32> [[TMP19]], i1 false, i32 0, i32 0) ; CHECK-NEXT: [[I11]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP12]], <4 x float> [[TMP20]]) ; CHECK-NEXT: [[I12:%.*]] = fadd <4 x float> [[PHI_IMG]], +; CHECK-NEXT: [[TMP27:%.*]] = load <8 x i32>, ptr addrspace(4) [[I8]], align 32, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP21:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I6]]) ; CHECK-NEXT: [[TMP22:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP21]], i32 [[I6]]) ; CHECK-NEXT: [[TMP23:%.*]] = sext i32 [[TMP22]] to i64 ; CHECK-NEXT: [[TMP24:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[TMP23]] -; CHECK-NEXT: [[TMP25:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP24]], align 16, !invariant.load [[META10]] -; CHECK-NEXT: [[TMP26:%.*]] = call <4 x i32> @llvm.amdgcn.waterfall.last.use.v4i32(i32 [[TMP21]], <4 x i32> [[TMP25]]) -; CHECK-NEXT: call void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float> [[I12]], <4 x i32> [[TMP26]], i32 1, i32 0, i32 0, i32 0) +; CHECK-NEXT: [[TMP28:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP24]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP29:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.last.use.v8i32(i32 [[TMP21]], <8 x i32> [[TMP28]]) +; CHECK-NEXT: call void @llvm.amdgcn.image.store.1d.v4f32.i32(<4 x float> [[I12]], i32 15, i32 1, <8 x i32> [[TMP29]], i32 0, i32 0) ; CHECK-NEXT: [[IND]] = add i32 [[PHI_IND]], 1 ; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[IND]], 1000 ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] @@ -81,11 +82,9 @@ loop: ; preds = %loop, %.entry %i6 = mul i32 %phi.ind, %b %i7 = sext i32 %i6 to i64 %i8 = getelementptr i8, ptr addrspace(4) %i2, i64 %i7 - %i9 = load <4 x i32>, ptr addrspace(4) %i8, align 16, !invariant.load !10 - %i10 = load <8 x i32>, ptr addrspace(4) %i5, align 32, !invariant.load !10 - %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %i10, <4 x i32> %i9, i32 1, <2 x float> zeroinitializer) + %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %i5, ptr addrspace(4) %i8, i32 1, <2 x float> zeroinitializer) %i12 = fadd <4 x float> %phi.img, - call void (...) @lgc.create.image.store(<4 x float> %i12, i32 0, i32 8, <4 x i32> %i9, i32 1) + call void (...) @lgc.create.image.store(<4 x float> %i12, i32 0, i32 8, ptr addrspace(4) %i8, i32 1) %ind = add i32 %phi.ind, 1 %cond = icmp ne i32 %ind, 1000 br i1 %cond, label %loop, label %exit @@ -139,3 +138,8 @@ attributes #3 = { nounwind memory(write) } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest16.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest16.lgc index 573c55b677..39f2ed7d68 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest16.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest16.lgc @@ -11,7 +11,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -37,16 +37,16 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I6:%.*]] = mul i32 [[PHI_IND]], 48 ; CHECK-NEXT: [[I7:%.*]] = sext i32 [[I6]] to i64 ; CHECK-NEXT: [[I8:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] -; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10:![0-9]+]] -; CHECK-NEXT: [[I10:%.*]] = load <4 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[I10:%.*]] = load <4 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10:![0-9]+]] ; CHECK-NEXT: [[TMP12:%.*]] = bitcast <4 x i32> [[I10]] to <4 x float> +; CHECK-NEXT: [[TMP17:%.*]] = load <8 x i32>, ptr addrspace(4) [[I8]], align 32, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I6]]) ; CHECK-NEXT: [[TMP14:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP13]], i32 [[I6]]) ; CHECK-NEXT: [[TMP15:%.*]] = sext i32 [[TMP14]] to i64 ; CHECK-NEXT: [[TMP16:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[TMP15]] -; CHECK-NEXT: [[TMP17:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP16]], align 16, !invariant.load [[META10]] -; CHECK-NEXT: [[TMP18:%.*]] = call <4 x i32> @llvm.amdgcn.waterfall.last.use.v4i32(i32 [[TMP13]], <4 x i32> [[TMP17]]) -; CHECK-NEXT: call void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float> [[TMP12]], <4 x i32> [[TMP18]], i32 1, i32 0, i32 0, i32 0) +; CHECK-NEXT: [[TMP18:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP16]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP19:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.last.use.v8i32(i32 [[TMP13]], <8 x i32> [[TMP18]]) +; CHECK-NEXT: call void @llvm.amdgcn.image.store.1d.v4f32.i32(<4 x float> [[TMP12]], i32 15, i32 1, <8 x i32> [[TMP19]], i32 0, i32 0) ; CHECK-NEXT: [[IND]] = add i32 [[PHI_IND]], 1 ; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[IND]], 1000 ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] @@ -69,9 +69,8 @@ loop: ; preds = %loop, %.entry %i6 = mul i32 %phi.ind, %b %i7 = sext i32 %i6 to i64 %i8 = getelementptr i8, ptr addrspace(4) %i2, i64 %i7 - %i9 = load <4 x i32>, ptr addrspace(4) %i8, align 16, !invariant.load !10 %i10 = load <4 x i32>, ptr addrspace(4) %i5, align 32, !invariant.load !10 - call void (...) @lgc.create.image.store(<4 x i32> %i10, i32 0, i32 8, <4 x i32> %i9, i32 1) + call void (...) @lgc.create.image.store(<4 x i32> %i10, i32 0, i32 8, ptr addrspace(4) %i8, i32 1) %ind = add i32 %phi.ind, 1 %cond = icmp ne i32 %ind, 1000 br i1 %cond, label %loop, label %exit @@ -125,3 +124,8 @@ attributes #3 = { nounwind memory(write) } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest2.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest2.lgc index bca91884fb..c3ed6f1215 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest2.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest2.lgc @@ -8,23 +8,23 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spirv.ExecutionModel !14 !lgc.shaderstage !15 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.VS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !14 !lgc.shaderstage [[META15:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META14:![0-9]+]] !lgc.shaderstage [[META15:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i32 @lgc.input.import.generic__i32(i1 false, i32 0, i32 0, i32 0, i32 poison) ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[TMP0]], poison ; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64 ; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP2]] -; CHECK-NEXT: [[TMP4:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP3]], align 16, !invariant.load [[META16:![0-9]+]] ; CHECK-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP2]] -; CHECK-NEXT: [[TMP6:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP5]], align 16, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP6:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP5]], align 16, !invariant.load [[META16:![0-9]+]] ; CHECK-NEXT: [[TMP7:%.*]] = bitcast <4 x i32> [[TMP6]] to <4 x float> +; CHECK-NEXT: [[TMP14:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP3]], align 32, !invariant.load [[META16]] ; CHECK-NEXT: [[TMP8:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP1]]) ; CHECK-NEXT: [[TMP9:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP8]], i32 [[TMP1]]) ; CHECK-NEXT: [[TMP10:%.*]] = sext i32 [[TMP9]] to i64 ; CHECK-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP10]] -; CHECK-NEXT: [[TMP12:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP11]], align 16, !invariant.load [[META16]] -; CHECK-NEXT: [[TMP13:%.*]] = call <4 x i32> @llvm.amdgcn.waterfall.last.use.v4i32(i32 [[TMP8]], <4 x i32> [[TMP12]]) -; CHECK-NEXT: call void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float> [[TMP7]], <4 x i32> [[TMP13]], i32 1, i32 0, i32 0, i32 0) +; CHECK-NEXT: [[TMP12:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP11]], align 32, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP13:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.last.use.v8i32(i32 [[TMP8]], <8 x i32> [[TMP12]]) +; CHECK-NEXT: call void @llvm.amdgcn.image.store.1d.v4f32.i32(<4 x float> [[TMP7]], i32 15, i32 1, <8 x i32> [[TMP13]], i32 0, i32 0) ; CHECK-NEXT: ret void ; .entry: @@ -34,10 +34,9 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spi %3 = mul i32 %0, %2 %4 = sext i32 %3 to i64 %5 = getelementptr i8, ptr addrspace(4) %1, i64 %4 - %6 = load <4 x i32>, ptr addrspace(4) %5, align 16, !invariant.load !16 %7 = getelementptr i8, ptr addrspace(4) %1, i64 %4 %8 = load <4 x i32>, ptr addrspace(4) %7, align 16, !invariant.load !16 - call void (...) @lgc.create.image.store(<4 x i32> %8, i32 0, i32 8, <4 x i32> %6, i32 1) + call void (...) @lgc.create.image.store(<4 x i32> %8, i32 0, i32 8, ptr addrspace(4) %5, i32 1) ret void } @@ -86,3 +85,8 @@ attributes #4 = { nounwind } !14 = !{i32 0} !15 = !{i32 1} !16 = !{} +;. +; CHECK: [[META14]] = !{i32 0} +; CHECK: [[META15]] = !{i32 1} +; CHECK: [[META16]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest3.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest3.lgc index 21d460b530..4616e701a2 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest3.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest3.lgc @@ -8,7 +8,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spirv.ExecutionModel !14 !lgc.shaderstage !15 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.VS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !14 !lgc.shaderstage [[META15:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META14:![0-9]+]] !lgc.shaderstage [[META15:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i32 @lgc.input.import.generic__i32(i1 false, i32 0, i32 0, i32 0, i32 poison) ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[TMP0]], poison @@ -18,12 +18,12 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[TMP5:%.*]] = mul i32 [[TMP0]], poison ; CHECK-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 ; CHECK-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP6]] -; CHECK-NEXT: [[TMP8:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP7]], align 16, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP8:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP7]], align 32, !invariant.load [[META16]] ; CHECK-NEXT: [[TMP9:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP5]]) ; CHECK-NEXT: [[TMP10:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP9]], i32 [[TMP5]]) ; CHECK-NEXT: [[TMP11:%.*]] = sext i32 [[TMP10]] to i64 ; CHECK-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP11]] -; CHECK-NEXT: [[TMP13:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP12]], align 16, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP13:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP12]], align 32, !invariant.load [[META16]] ; CHECK-NEXT: [[TMP14:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[TMP13]], <4 x i32> , i1 false, i32 0, i32 0) ; CHECK-NEXT: [[TMP15:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP9]], <4 x float> [[TMP14]]) ; CHECK-NEXT: ret void @@ -39,8 +39,7 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spi %7 = mul i32 %0, %2 %8 = sext i32 %7 to i64 %9 = getelementptr i8, ptr addrspace(4) %1, i64 %8 - %10 = load <8 x i32>, ptr addrspace(4) %9, align 16, !invariant.load !16 - %11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %10, <4 x i32> , i32 1, <2 x float> zeroinitializer) + %11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %9, <4 x i32> , i32 1, <2 x float> zeroinitializer) ret void } @@ -87,3 +86,8 @@ attributes #2 = { nounwind memory(none) } !14 = !{i32 0} !15 = !{i32 1} !16 = !{} +;. +; CHECK: [[META14]] = !{i32 0} +; CHECK: [[META15]] = !{i32 1} +; CHECK: [[META16]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest4.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest4.lgc index a6076a3787..1fbc044bd6 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest4.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest4.lgc @@ -10,7 +10,7 @@ declare <4 x i32> @foo1(i32 %V) ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spirv.ExecutionModel !14 !lgc.shaderstage !15 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.VS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !14 !lgc.shaderstage [[META15:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META14:![0-9]+]] !lgc.shaderstage [[META15:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i32 @lgc.input.import.generic__i32(i1 false, i32 0, i32 0, i32 0, i32 poison) ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[TMP0]], poison @@ -20,14 +20,15 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[TMP5:%.*]] = mul i32 [[TMP0]], poison ; CHECK-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 ; CHECK-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP6]] -; CHECK-NEXT: [[TMP8:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP7]], align 16, !invariant.load [[META16]] -; CHECK-NEXT: [[TMP9:%.*]] = call <4 x i32> @foo1(i32 [[TMP0]]) +; CHECK-NEXT: [[TMP8:%.*]] = call ptr addrspace(4) @foo1(i32 [[TMP0]]) +; CHECK-NEXT: [[TMP19:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP7]], align 32, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP9:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP8]], align 16, !invariant.load [[META16]] ; CHECK-NEXT: [[TMP10:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP5]]) ; CHECK-NEXT: [[TMP11:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.v4i32(i32 [[TMP10]], <4 x i32> [[TMP9]]) ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP11]], i32 [[TMP5]]) ; CHECK-NEXT: [[TMP13:%.*]] = sext i32 [[TMP12]] to i64 ; CHECK-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP13]] -; CHECK-NEXT: [[TMP15:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP14]], align 16, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP15:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP14]], align 32, !invariant.load [[META16]] ; CHECK-NEXT: [[TMP16:%.*]] = call <4 x i32> @llvm.amdgcn.waterfall.readfirstlane.v4i32.v4i32(i32 [[TMP11]], <4 x i32> [[TMP9]]) ; CHECK-NEXT: [[TMP17:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[TMP15]], <4 x i32> [[TMP16]], i1 false, i32 0, i32 0) ; CHECK-NEXT: [[TMP18:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP11]], <4 x float> [[TMP17]]) @@ -44,9 +45,8 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spi %7 = mul i32 %0, %2 %8 = sext i32 %7 to i64 %9 = getelementptr i8, ptr addrspace(4) %1, i64 %8 - %10 = load <8 x i32>, ptr addrspace(4) %9, align 16, !invariant.load !16 - %11 = call <4 x i32> @foo1(i32 %0) - %12 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %10, <4 x i32> %11, i32 1, <2 x float> zeroinitializer) + %11 = call ptr addrspace(4) @foo1(i32 %0) + %12 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %9, ptr addrspace(4) %11, i32 1, <2 x float> zeroinitializer) ret void } @@ -93,3 +93,8 @@ attributes #2 = { nounwind memory(none) } !14 = !{i32 0} !15 = !{i32 1} !16 = !{} +;. +; CHECK: [[META14]] = !{i32 0} +; CHECK: [[META15]] = !{i32 1} +; CHECK: [[META16]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest5.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest5.lgc index 6cb1fdfdcc..085be16a66 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest5.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest5.lgc @@ -8,7 +8,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spirv.ExecutionModel !14 !lgc.shaderstage !15 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.VS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !14 !lgc.shaderstage [[META15:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META14:![0-9]+]] !lgc.shaderstage [[META15:![0-9]+]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i32 @lgc.input.import.generic__i32(i1 false, i32 0, i32 0, i32 0, i32 poison) ; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[TMP0]], 0 @@ -17,25 +17,25 @@ define dllexport spir_func void @lgc.shader.VS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[TMP0]], poison ; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64 ; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP2]] -; CHECK-NEXT: [[TMP4:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP3]], align 16, !invariant.load [[META16:![0-9]+]] ; CHECK-NEXT: [[TMP5:%.*]] = mul i32 [[TMP0]], poison ; CHECK-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 ; CHECK-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP6]] -; CHECK-NEXT: [[TMP8:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP7]], align 16, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP8:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP7]], align 32, !invariant.load [[META16:![0-9]+]] ; CHECK-NEXT: [[TMP9:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP5]]) ; CHECK-NEXT: [[TMP10:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP9]], i32 [[TMP5]]) ; CHECK-NEXT: [[TMP11:%.*]] = sext i32 [[TMP10]] to i64 ; CHECK-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP11]] -; CHECK-NEXT: [[TMP13:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP12]], align 16, !invariant.load [[META16]] -; CHECK-NEXT: [[TMP14:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.struct.buffer.load.format.v4f32(<4 x i32> [[TMP13]], i32 0, i32 0, i32 0, i32 0) +; CHECK-NEXT: [[TMP13:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP12]], align 32, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP14:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.load.1d.v4f32.i32(i32 15, i32 0, <8 x i32> [[TMP13]], i32 0, i32 0) ; CHECK-NEXT: [[TMP15:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP9]], <4 x float> [[TMP14]]) +; CHECK-NEXT: [[TMP22:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP3]], align 32, !invariant.load [[META16]] ; CHECK-NEXT: [[TMP16:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP1]]) ; CHECK-NEXT: [[TMP17:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP16]], i32 [[TMP1]]) ; CHECK-NEXT: [[TMP18:%.*]] = sext i32 [[TMP17]] to i64 ; CHECK-NEXT: [[TMP19:%.*]] = getelementptr i8, ptr addrspace(4) poison, i64 [[TMP18]] -; CHECK-NEXT: [[TMP20:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP19]], align 16, !invariant.load [[META16]] -; CHECK-NEXT: [[TMP21:%.*]] = call <4 x i32> @llvm.amdgcn.waterfall.last.use.v4i32(i32 [[TMP16]], <4 x i32> [[TMP20]]) -; CHECK-NEXT: call void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float> [[TMP15]], <4 x i32> [[TMP21]], i32 1, i32 0, i32 0, i32 0) +; CHECK-NEXT: [[TMP20:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP19]], align 32, !invariant.load [[META16]] +; CHECK-NEXT: [[TMP21:%.*]] = call <8 x i32> @llvm.amdgcn.waterfall.last.use.v8i32(i32 [[TMP16]], <8 x i32> [[TMP20]]) +; CHECK-NEXT: call void @llvm.amdgcn.image.store.1d.v4f32.i32(<4 x float> [[TMP15]], i32 15, i32 1, <8 x i32> [[TMP21]], i32 0, i32 0) ; CHECK-NEXT: br label [[RET]] ; CHECK: ret: ; CHECK-NEXT: ret void @@ -51,13 +51,11 @@ bb: ; preds = %entry %3 = mul i32 %0, %2 %4 = sext i32 %3 to i64 %5 = getelementptr i8, ptr addrspace(4) %1, i64 %4 - %6 = load <4 x i32>, ptr addrspace(4) %5, align 16, !invariant.load !16 %7 = mul i32 %0, %2 %8 = sext i32 %7 to i64 %9 = getelementptr i8, ptr addrspace(4) %1, i64 %8 - %10 = load <4 x i32>, ptr addrspace(4) %9, align 16, !invariant.load !16 - %11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 8, <4 x i32> %10, i32 0) - call void (...) @lgc.create.image.store(<4 x float> %11, i32 0, i32 8, <4 x i32> %6, i32 1) + %11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 8, ptr addrspace(4) %9, i32 0) + call void (...) @lgc.create.image.store(<4 x float> %11, i32 0, i32 8, ptr addrspace(4) %5, i32 1) br label %ret ret: ; preds = %bb, %entry @@ -111,3 +109,8 @@ attributes #3 = { nounwind memory(write) } !14 = !{i32 0} !15 = !{i32 1} !16 = !{} +;. +; CHECK: [[META14]] = !{i32 0} +; CHECK: [[META15]] = !{i32 1} +; CHECK: [[META16]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest6.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest6.lgc index cf57f85ba7..42398f1ce4 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest6.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest6.lgc @@ -8,7 +8,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !22 !lgc.shaderstage !23 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !22 !lgc.shaderstage [[META23:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META22:![0-9]+]] !lgc.shaderstage [[META23:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -35,8 +35,8 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[TMP16:%.*]] = bitcast <2 x i32> [[TMP15]] to i64 ; CHECK-NEXT: [[TMP17:%.*]] = inttoptr i64 [[TMP16]] to ptr addrspace(4) ; CHECK-NEXT: [[TMP18:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP17]], i32 0 -; CHECK-NEXT: [[TMP19:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP18]], align 16, !invariant.load [[META24:![0-9]+]] -; CHECK-NEXT: [[TMP20:%.*]] = call <4 x i32> @llvm.amdgcn.struct.buffer.load.format.v4i32(<4 x i32> [[TMP19]], i32 [[DOT0]], i32 0, i32 0, i32 0), !invariant.load [[META24]] +; CHECK-NEXT: [[TMP19:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP18]], align 32, !invariant.load [[META24:![0-9]+]] +; CHECK-NEXT: [[TMP20:%.*]] = call <4 x i32> @llvm.amdgcn.image.load.1d.v4i32.i32(i32 15, i32 [[DOT0]], <8 x i32> [[TMP19]], i32 0, i32 0), !invariant.load [[META24]] ; CHECK-NEXT: [[TMP21:%.*]] = extractelement <4 x i32> [[TMP20]], i64 0 ; CHECK-NEXT: [[TMP22:%.*]] = call i32 @lgc.load.user.data__i32(i32 36) ; CHECK-NEXT: [[TMP23:%.*]] = insertelement <2 x i32> [[TMP3]], i32 [[TMP22]], i64 0 @@ -46,12 +46,12 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[TMP27:%.*]] = mul i32 [[TMP21]], 32 ; CHECK-NEXT: [[TMP28:%.*]] = sext i32 [[TMP27]] to i64 ; CHECK-NEXT: [[TMP29:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP26]], i64 [[TMP28]] -; CHECK-NEXT: [[TMP30:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP29]], align 32, !invariant.load [[META24]] ; CHECK-NEXT: [[TMP31:%.*]] = call i32 @lgc.load.user.data__i32(i32 36) ; CHECK-NEXT: [[TMP32:%.*]] = insertelement <2 x i32> [[TMP1]], i32 [[TMP31]], i64 0 ; CHECK-NEXT: [[TMP33:%.*]] = bitcast <2 x i32> [[TMP32]] to i64 ; CHECK-NEXT: [[TMP34:%.*]] = inttoptr i64 [[TMP33]] to ptr addrspace(4) ; CHECK-NEXT: [[TMP35:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP34]], i32 0 +; CHECK-NEXT: [[TMP52:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP29]], align 32, !invariant.load [[META24]] ; CHECK-NEXT: [[TMP36:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP35]], align 16, !invariant.load [[META24]] ; CHECK-NEXT: [[TMP37:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP27]]) ; CHECK-NEXT: [[TMP38:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP37]], i32 [[TMP27]]) @@ -64,26 +64,29 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[TMP45:%.*]] = sext i32 [[TMP44]] to i64 ; CHECK-NEXT: [[TMP46:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP26]], i64 [[TMP45]] ; CHECK-NEXT: [[TMP47:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP46]], align 32, !invariant.load [[META24]] +; CHECK-NEXT: [[TMP59:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP35]], align 16, !invariant.load [[META24]] ; CHECK-NEXT: [[TMP48:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP44]]) ; CHECK-NEXT: [[TMP49:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP48]], i32 [[TMP44]]) ; CHECK-NEXT: [[TMP50:%.*]] = sext i32 [[TMP49]] to i64 ; CHECK-NEXT: [[TMP51:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP26]], i64 [[TMP50]] -; CHECK-NEXT: [[TMP52:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP51]], align 32, !invariant.load [[META24]] -; CHECK-NEXT: [[TMP53:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[TMP52]], <4 x i32> [[TMP36]], i1 false, i32 0, i32 0) +; CHECK-NEXT: [[TMP67:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP51]], align 32, !invariant.load [[META24]] +; CHECK-NEXT: [[TMP53:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[TMP67]], <4 x i32> [[TMP59]], i1 false, i32 0, i32 0) ; CHECK-NEXT: [[TMP54:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP48]], <4 x float> [[TMP53]]) +; CHECK-NEXT: [[TMP68:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP29]], align 32, !invariant.load [[META24]] +; CHECK-NEXT: [[TMP69:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP35]], align 16, !invariant.load [[META24]] ; CHECK-NEXT: [[TMP55:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[TMP27]]) ; CHECK-NEXT: [[TMP56:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP55]], i32 [[TMP27]]) ; CHECK-NEXT: [[TMP57:%.*]] = sext i32 [[TMP56]] to i64 ; CHECK-NEXT: [[TMP58:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP26]], i64 [[TMP57]] -; CHECK-NEXT: [[TMP59:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP58]], align 32, !invariant.load [[META24]] -; CHECK-NEXT: [[TMP60:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[TMP59]], <4 x i32> [[TMP36]], i1 false, i32 0, i32 0) +; CHECK-NEXT: [[TMP70:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP58]], align 32, !invariant.load [[META24]] +; CHECK-NEXT: [[TMP60:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[TMP70]], <4 x i32> [[TMP69]], i1 false, i32 0, i32 0) ; CHECK-NEXT: [[TMP61:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP55]], <4 x float> [[TMP60]]) ; CHECK-NEXT: [[TMP62]] = fadd reassoc nnan nsz arcp contract afn <4 x float> [[DOT09]], [[TMP61]] ; CHECK-NEXT: [[TMP63:%.*]] = fadd reassoc nnan nsz arcp contract afn <4 x float> [[TMP43]], [[TMP54]] ; CHECK-NEXT: [[TMP64]] = fadd reassoc nnan nsz arcp contract afn <4 x float> [[DOT010]], [[TMP63]] ; CHECK-NEXT: [[TMP65]] = add i32 [[DOT0]], 1 ; CHECK-NEXT: br label [[TMP9]], !llvm.loop [[LOOP25:![0-9]+]] -; CHECK: 66: +; CHECK: 69: ; CHECK-NEXT: ret void ; .entry: @@ -105,24 +108,20 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi 7: ; preds = %3 %8 = call ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 4, i32 4, i64 1, i32 12) %9 = call i32 (...) @lgc.create.get.desc.stride__i32(i32 4, i32 4, i64 1, i32 12) - %10 = load <4 x i32>, ptr addrspace(4) %8, align 16, !invariant.load !24 - %11 = call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 0, i32 1536, <4 x i32> %10, i32 %.0) + %11 = call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 0, i32 1536, ptr addrspace(4) %8, i32 %.0) %12 = extractelement <4 x i32> %11, i64 0 %13 = call ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 6) %14 = call i32 (...) @lgc.create.get.desc.stride__i32(i32 1, i32 1, i64 0, i32 6) %15 = mul i32 %12, %14 %16 = sext i32 %15 to i64 %17 = getelementptr i8, ptr addrspace(4) %13, i64 %16 - %18 = load <8 x i32>, ptr addrspace(4) %17, align 32, !invariant.load !24 %19 = call ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 5) - %20 = load <4 x i32>, ptr addrspace(4) %19, align 16, !invariant.load !24 - %21 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %18, <4 x i32> %20, i32 1, <2 x float> zeroinitializer) + %21 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %17, ptr addrspace(4) %19, i32 1, <2 x float> zeroinitializer) %22 = mul i32 %1, %14 %23 = sext i32 %22 to i64 %24 = getelementptr i8, ptr addrspace(4) %13, i64 %23 - %25 = load <8 x i32>, ptr addrspace(4) %24, align 32, !invariant.load !24 - %26 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %25, <4 x i32> %20, i32 1, <2 x float> zeroinitializer) - %27 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %18, <4 x i32> %20, i32 1, <2 x float> zeroinitializer) + %26 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %24, ptr addrspace(4) %19, i32 1, <2 x float> zeroinitializer) + %27 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %17, ptr addrspace(4) %19, i32 1, <2 x float> zeroinitializer) %28 = fadd reassoc nnan nsz arcp contract afn <4 x float> %.09, %27 %29 = fadd reassoc nnan nsz arcp contract afn <4 x float> %21, %26 %30 = fadd reassoc nnan nsz arcp contract afn <4 x float> %.010, %29 @@ -191,3 +190,9 @@ attributes #2 = { nounwind memory(none) } !23 = !{i32 6} !24 = !{} !25 = distinct !{!25} +;. +; CHECK: [[META22]] = !{i32 4} +; CHECK: [[META23]] = !{i32 6} +; CHECK: [[META24]] = !{} +; CHECK: [[LOOP25]] = distinct !{[[LOOP25]]} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest7.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest7.lgc index 445a355b8d..4b1edb4ae3 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest7.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest7.lgc @@ -10,7 +10,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -37,18 +37,15 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I8:%.*]] = mul i32 [[I]], 48 ; CHECK-NEXT: [[I9:%.*]] = sext i32 [[I8]] to i64 ; CHECK-NEXT: [[I10:%.*]] = getelementptr i8, ptr addrspace(4) [[I3]], i64 [[I9]] -; CHECK-NEXT: [[I11:%.*]] = load <4 x i32>, ptr addrspace(4) [[I10]], align 16, !invariant.load [[META10:![0-9]+]] ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb3: -; CHECK-NEXT: [[I12:%.*]] = load <8 x i32>, ptr addrspace(4) [[I7]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP14:%.*]] = load <8 x i32>, ptr addrspace(4) [[I7]], align 32, !invariant.load [[META10:![0-9]+]] +; CHECK-NEXT: [[TMP19:%.*]] = load <4 x i32>, ptr addrspace(4) [[I3]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I5]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP12]], i32 [[I5]]) -; CHECK-NEXT: [[TMP14:%.*]] = sext i32 [[TMP13]] to i64 -; CHECK-NEXT: [[TMP15:%.*]] = getelementptr i8, ptr addrspace(4) [[I1]], i64 [[TMP14]] -; CHECK-NEXT: [[TMP16:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP15]], align 32, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP17:%.*]] = sext i32 [[TMP13]] to i64 -; CHECK-NEXT: [[TMP18:%.*]] = getelementptr i8, ptr addrspace(4) [[I3]], i64 [[TMP17]] -; CHECK-NEXT: [[TMP19:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP18]], align 16, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP18:%.*]] = getelementptr i8, ptr addrspace(4) [[I1]], i64 [[TMP17]] +; CHECK-NEXT: [[TMP16:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP18]], align 32, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP20:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[TMP16]], <4 x i32> [[TMP19]], i1 false, i32 0, i32 0) ; CHECK-NEXT: [[I13:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.waterfall.end.v4f32(i32 [[TMP12]], <4 x float> [[TMP20]]) ; CHECK-NEXT: call void @lgc.output.export.generic.i32.i32.v4f32(i32 0, i32 0, <4 x float> [[I13]]) #[[ATTR5:[0-9]+]] @@ -72,12 +69,10 @@ bb2: ; preds = %bb1 %i8 = mul i32 %i, %i4 %i9 = sext i32 %i8 to i64 %i10 = getelementptr i8, ptr addrspace(4) %i3, i64 %i9 - %i11 = load <4 x i32>, ptr addrspace(4) %i10, align 16, !invariant.load !10 br label %bb3 bb3: ; preds = %bb2 - %i12 = load <8 x i32>, ptr addrspace(4) %i7, align 32, !invariant.load !10 - %i13 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %i12, <4 x i32> %i11, i32 1, <2 x float> zeroinitializer) + %i13 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %i7, ptr addrspace(4) %i3, i32 1, <2 x float> zeroinitializer) call void (...) @lgc.create.write.generic.output(<4 x float> %i13, i32 0, i32 0, i32 0, i32 0, i32 0, i32 poison) ret void } @@ -127,3 +122,8 @@ attributes #3 = { nounwind } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest8.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest8.lgc index 03b16464d2..4958e7432e 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest8.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest8.lgc @@ -10,7 +10,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -41,8 +41,8 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I6:%.*]] = mul i32 [[I]], [[PHI]] ; CHECK-NEXT: [[I7:%.*]] = sext i32 [[I6]] to i64 ; CHECK-NEXT: [[I8:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] -; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10:![0-9]+]] -; CHECK-NEXT: [[I10:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP21:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10:![0-9]+]] +; CHECK-NEXT: [[TMP22:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I3]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP12]], i32 [[I3]]) ; CHECK-NEXT: [[TMP14:%.*]] = sext i32 [[TMP13]] to i64 @@ -79,9 +79,7 @@ bb3: ; preds = %bb2, %bb1 %i6 = mul i32 %i, %phi %i7 = sext i32 %i6 to i64 %i8 = getelementptr i8, ptr addrspace(4) %i2, i64 %i7 - %i9 = load <4 x i32>, ptr addrspace(4) %i8, align 16, !invariant.load !10 - %i10 = load <8 x i32>, ptr addrspace(4) %i5, align 32, !invariant.load !10 - %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %i10, <4 x i32> %i9, i32 1, <2 x float> zeroinitializer) + %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %i5, ptr addrspace(4) %i8, i32 1, <2 x float> zeroinitializer) call void (...) @lgc.create.write.generic.output(<4 x float> %i11, i32 0, i32 0, i32 0, i32 0, i32 0, i32 poison) ret void } @@ -131,3 +129,8 @@ attributes #3 = { nounwind } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/scalarizationOfDescriptorLoadsTest9.lgc b/lgc/test/scalarizationOfDescriptorLoadsTest9.lgc index 97e7f1777c..c188e6376b 100644 --- a/lgc/test/scalarizationOfDescriptorLoadsTest9.lgc +++ b/lgc/test/scalarizationOfDescriptorLoadsTest9.lgc @@ -9,7 +9,7 @@ target triple = "amdgcn--amdpal" ; Function Attrs: nounwind define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spirv.ExecutionModel !8 !lgc.shaderstage !9 { ; CHECK-LABEL: define dllexport spir_func void @lgc.shader.FS.main( -; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel !8 !lgc.shaderstage [[META9:![0-9]+]] { +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !spirv.ExecutionModel [[META8:![0-9]+]] !lgc.shaderstage [[META9:![0-9]+]] { ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> @@ -37,6 +37,8 @@ define dllexport spir_func void @lgc.shader.FS.main() local_unnamed_addr #0 !spi ; CHECK-NEXT: [[I8:%.*]] = getelementptr i8, ptr addrspace(4) [[I2]], i64 [[I7]] ; CHECK-NEXT: [[I9:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10:![0-9]+]] ; CHECK-NEXT: [[I10:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP21:%.*]] = load <8 x i32>, ptr addrspace(4) [[I5]], align 32, !invariant.load [[META10]] +; CHECK-NEXT: [[TMP22:%.*]] = load <4 x i32>, ptr addrspace(4) [[I8]], align 16, !invariant.load [[META10]] ; CHECK-NEXT: [[TMP12:%.*]] = call i32 @llvm.amdgcn.waterfall.begin.i32(i32 0, i32 [[I3]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @llvm.amdgcn.waterfall.readfirstlane.i32.i32(i32 [[TMP12]], i32 [[I3]]) ; CHECK-NEXT: [[TMP14:%.*]] = sext i32 [[TMP13]] to i64 @@ -72,7 +74,7 @@ loop: ; preds = %loop, %.entry %i8 = getelementptr i8, ptr addrspace(4) %i2, i64 %i7 %i9 = load <4 x i32>, ptr addrspace(4) %i8, align 16, !invariant.load !10 %i10 = load <8 x i32>, ptr addrspace(4) %i5, align 32, !invariant.load !10 - %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, <8 x i32> %i10, <4 x i32> %i9, i32 1, <2 x float> zeroinitializer) + %i11 = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 24, ptr addrspace(4) %i5, ptr addrspace(4) %i8, i32 1, <2 x float> zeroinitializer) call void (...) @lgc.create.write.generic.output(<4 x float> %i11, i32 0, i32 0, i32 0, i32 0, i32 0, i32 poison) %ind = add i32 %phi.ind, 1 %cond = icmp ne i32 %ind, 1000 @@ -127,3 +129,8 @@ attributes #3 = { nounwind } !8 = !{i32 4} !9 = !{i32 6} !10 = !{} +;. +; CHECK: [[META8]] = !{i32 4} +; CHECK: [[META9]] = !{i32 6} +; CHECK: [[META10]] = !{} +;. diff --git a/lgc/test/tanh.lgc b/lgc/test/tanh.lgc new file mode 100644 index 0000000000..977bc458fb --- /dev/null +++ b/lgc/test/tanh.lgc @@ -0,0 +1,54 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --tool lgc --march amdgcn --version 4 +; RUN: lgc -mcpu=gfx1100 -filetype=asm -o - %s | FileCheck --check-prefixes=CHECK %s + +; ModuleID = 'LLPC module' +source_filename = "LLPC module" +target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9" +target triple = "amdgcn--amdpal" + +define float @sample(float %x) !lgc.shaderstage !1 { +; CHECK-LABEL: sample: +; CHECK: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; CHECK-NEXT: v_mul_f32_e64 v1, |v0|, -2.0 +; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) +; CHECK-NEXT: v_mul_f32_e32 v1, 0x3fb8aa3b, v1 +; CHECK-NEXT: v_exp_f32_e32 v1, v1 +; CHECK-NEXT: s_waitcnt_depctr 0xfff +; CHECK-NEXT: v_add_f32_e32 v1, 1.0, v1 +; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) +; CHECK-NEXT: v_cmp_lt_f32_e64 s[0:1], 0x6f800000, |v1| +; CHECK-NEXT: v_cndmask_b32_e64 v2, 1.0, 0x2f800000, s[0:1] +; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) +; CHECK-NEXT: v_mul_f32_e32 v1, v1, v2 +; CHECK-NEXT: v_rcp_f32_e32 v1, v1 +; CHECK-NEXT: s_waitcnt_depctr 0xfff +; CHECK-NEXT: v_add_f32_e32 v1, v1, v1 +; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) +; CHECK-NEXT: v_mul_f32_e32 v1, v2, v1 +; CHECK-NEXT: v_sub_f32_e32 v1, 1.0, v1 +; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1) +; CHECK-NEXT: v_bfi_b32 v0, 0x7fffffff, v1, v0 +; CHECK-NEXT: s_setpc_b64 s[30:31] + %y = call float @lgc.create.tanh.f32(float %x) + ret float %y +} + +; Function Attrs: nounwind willreturn memory(read) +declare !lgc.create.opcode !2 i32 @lgc.create.read.builtin.input.i32(...) #0 + +; Function Attrs: nounwind willreturn memory(none) +declare ptr addrspace(7) @lgc.load.buffer.desc(i64, i32, i32, i32) #1 + +; Function Attrs: nounwind memory(none) +declare !lgc.create.opcode !3 float @lgc.create.tanh.f32(...) #2 + +attributes #0 = { nounwind willreturn memory(read) } +attributes #1 = { nounwind willreturn memory(none) } +attributes #2 = { nounwind memory(none) } + +!llpc.compute.mode = !{!0} + +!0 = !{i32 8, i32 8, i32 1} +!1 = !{i32 7} +!2 = !{i32 77} +!3 = !{i32 17} diff --git a/llpc/CMakeLists.txt b/llpc/CMakeLists.txt index 16120f7005..277bde621a 100644 --- a/llpc/CMakeLists.txt +++ b/llpc/CMakeLists.txt @@ -205,7 +205,6 @@ if(ICD_BUILD_LLPC) context/llpcGraphicsContext.cpp context/llpcPipelineContext.cpp context/llpcRayTracingContext.cpp - context/GfxRuntimeContext.cpp ) # llpc/lower diff --git a/llpc/context/llpcCompiler.cpp b/llpc/context/llpcCompiler.cpp index 6544139aa1..bc85bd630c 100644 --- a/llpc/context/llpcCompiler.cpp +++ b/llpc/context/llpcCompiler.cpp @@ -64,6 +64,7 @@ #include "lgc/LgcCpsDialect.h" #include "lgc/LgcRtDialect.h" #include "lgc/PassManager.h" +#include "lgc/RuntimeContext.h" #include "llvm-dialects/Dialect/Dialect.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallSet.h" @@ -657,7 +658,7 @@ Result Compiler::BuildShaderModule(const ShaderModuleBuildInfo *shaderInfo, Shad std::vector imageSymbolInfo; std::vector atomicCounterSymbolInfo; std::vector defaultUniformSymbolInfo; - if (shaderInfo->options.pipelineOptions.buildResourcesDataForShaderModule && + if (shaderInfo->options.pipelineOptions.getGlState().buildResourcesDataForShaderModule && moduleData.binType == BinaryType::Spirv) { buildShaderModuleResourceUsage(shaderInfo, resourceNodes, inputSymbolInfo, outputSymbolInfo, uniformBufferInfo, storageBufferInfo, textureSymbolInfo, imageSymbolInfo, atomicCounterSymbolInfo, @@ -700,7 +701,7 @@ Result Compiler::BuildShaderModule(const ShaderModuleBuildInfo *shaderInfo, Shad pShaderModuleData->binCode.pCode = bufferWritePtr; bufferWritePtr += codeBuffer.size() * sizeof(unsigned); - if (shaderInfo->options.pipelineOptions.buildResourcesDataForShaderModule && + if (shaderInfo->options.pipelineOptions.getGlState().buildResourcesDataForShaderModule && moduleData.binType == BinaryType::Spirv) { memcpy(bufferWritePtr, &resourceNodes, sizeof(ResourcesNodes)); pResourcesNodes = reinterpret_cast(bufferWritePtr); @@ -763,6 +764,7 @@ static bool getSymbolInfoFromSpvVariable(const SPIRVVariable *spvVar, ResourceNo SPIRVWord varId = 0; BasicType basicType = BasicType::Unknown; symbolInfo->columnCount = 1; + symbolInfo->componentCount = 1; SPIRVWord builtIn = false; bool isBuiltIn = spvVar->hasDecorate(DecorationBuiltIn, 0, &builtIn); @@ -784,6 +786,8 @@ static bool getSymbolInfoFromSpvVariable(const SPIRVVariable *spvVar, ResourceNo } if (varElemTy->getOpCode() == OpTypeMatrix) { symbolInfo->columnCount = varElemTy->getMatrixColumnCount(); + if (varElemTy->getMatrixColumnType()->getOpCode() == OpTypeVector) + symbolInfo->componentCount = varElemTy->getMatrixColumnType()->getVectorComponentCount(); varElemTy = varElemTy->getMatrixColumnType(); } if (varElemTy->getOpCode() == OpTypeVector) @@ -3378,37 +3382,39 @@ void Compiler::adjustRayTracingElf(ElfPackage *pipelineElf, RayTracingContext *r auto &shaderFunctionSection = pipeline.getMap(true)[PalAbi::PipelineMetadataKey::ShaderFunctions].getMap(true); // Get the shader function - auto shaderFunctionName = shaderFunctionSection.begin()->first.getString(); - auto &shaderFunction = shaderFunctionSection.begin()->second.getMap(true); - - // 1. Add raytracing pipeline indirect pipeline metadata - // The metadata is needed for RGP to correctly show different subtype of shaders. - // Determine the shader subtype by name - auto subtype = "Unknown"; - if (auto shaderStage = tryGetLgcRtShaderStageFromName(shaderFunctionName)) { - auto stage = shaderStage.value(); - if (stage == lgc::rt::RayTracingShaderStage::RayGeneration) - subtype = "RayGeneration"; - else if (stage == lgc::rt::RayTracingShaderStage::Miss) - subtype = "Miss"; - else if (stage == lgc::rt::RayTracingShaderStage::AnyHit) - subtype = "AnyHit"; - else if (stage == lgc::rt::RayTracingShaderStage::ClosestHit) - subtype = "ClosestHit"; - else if (stage == lgc::rt::RayTracingShaderStage::Intersection) - subtype = "Intersection"; - else if (stage == lgc::rt::RayTracingShaderStage::Callable) - subtype = "Callable"; - else if (stage == lgc::rt::RayTracingShaderStage::Traversal) - subtype = "Traversal"; - } - shaderFunction[".shader_subtype"] = subtype; - - // 2. Apply the .internal_pipeline_hash to .api_shader_hash in .shader_functions section - // NOTE: this is needed for RGP to recognize different shader subtype - auto pipelineHash = pipeline.getMap(true)[PalAbi::PipelineMetadataKey::InternalPipelineHash].getArray(true); - shaderFunction[PalAbi::ShaderMetadataKey::ApiShaderHash].getArray(true)[0] = pipelineHash[0]; - shaderFunction[PalAbi::ShaderMetadataKey::ApiShaderHash].getArray(true)[1] = pipelineHash[1]; + for (auto &funcSection : shaderFunctionSection) { + auto shaderFunctionName = funcSection.first.getString(); + auto &shaderFunction = funcSection.second.getMap(true); + + // 1. Add raytracing pipeline indirect pipeline metadata + // The metadata is needed for RGP to correctly show different subtype of shaders. + // Determine the shader subtype by name + auto subtype = "Unknown"; + if (auto shaderStage = tryGetLgcRtShaderStageFromName(shaderFunctionName)) { + auto stage = shaderStage.value(); + if (stage == lgc::rt::RayTracingShaderStage::RayGeneration) + subtype = "RayGeneration"; + else if (stage == lgc::rt::RayTracingShaderStage::Miss) + subtype = "Miss"; + else if (stage == lgc::rt::RayTracingShaderStage::AnyHit) + subtype = "AnyHit"; + else if (stage == lgc::rt::RayTracingShaderStage::ClosestHit) + subtype = "ClosestHit"; + else if (stage == lgc::rt::RayTracingShaderStage::Intersection) + subtype = "Intersection"; + else if (stage == lgc::rt::RayTracingShaderStage::Callable) + subtype = "Callable"; + else if (stage == lgc::rt::RayTracingShaderStage::Traversal) + subtype = "Traversal"; + } + shaderFunction[".shader_subtype"] = subtype; + + // 2. Apply the .internal_pipeline_hash to .api_shader_hash in .shader_functions section + // NOTE: this is needed for RGP to recognize different shader subtype + auto pipelineHash = pipeline.getMap(true)[PalAbi::PipelineMetadataKey::InternalPipelineHash].getArray(true); + shaderFunction[PalAbi::ShaderMetadataKey::ApiShaderHash].getArray(true)[0] = pipelineHash[0]; + shaderFunction[PalAbi::ShaderMetadataKey::ApiShaderHash].getArray(true)[1] = pipelineHash[1]; + } // Write modified metadata to the pipeline ELF ElfNote newMetaNote = metaNote; @@ -3590,6 +3596,7 @@ void Compiler::buildShaderCacheHash(Context *context, unsigned stageMask, ArrayR auto pipelineInfo = reinterpret_cast(context->getPipelineBuildInfo()); auto pipelineOptions = pipelineContext->getPipelineOptions(); + ShaderStage preStage = ShaderStageInvalid; // Build hash per shader stage for (ShaderStage stage : gfxShaderStages()) { if ((stageMask & getLgcShaderStageMask(stage)) == 0) @@ -3619,10 +3626,21 @@ void Compiler::buildShaderCacheHash(Context *context, unsigned stageMask, ArrayR // Add per stage hash code to fragmentHasher or nonFragmentHasher per shader stage auto shaderHashCode = MetroHash::compact64(&hash); - if (stage == ShaderStageFragment) + if (stage == ShaderStageFragment) { fragmentHasher.Update(shaderHashCode); - else + const ShaderModuleData *moduleData = reinterpret_cast(shaderInfo->pModuleData); + if (moduleData && moduleData->usage.useBarycentric) { + // If fragment uses barycentrics, we still need to care about the previous stage, because the primitive type + // might be specified there. + if ((preStage != ShaderStageInvalid) && (preStage != ShaderStageVertex)) { + auto preShaderInfo = pipelineContext->getPipelineShaderInfo(preStage); + moduleData = reinterpret_cast(preShaderInfo->pModuleData); + fragmentHasher.Update(moduleData->cacheHash); + } + } + } else nonFragmentHasher.Update(shaderHashCode); + preStage = stage; } // Add additional pipeline state to final hasher diff --git a/llpc/context/llpcContext.cpp b/llpc/context/llpcContext.cpp index 58b1d25c6b..b148ed4ef1 100644 --- a/llpc/context/llpcContext.cpp +++ b/llpc/context/llpcContext.cpp @@ -29,7 +29,6 @@ *********************************************************************************************************************** */ #include "llpcContext.h" -#include "GfxRuntimeContext.h" #include "LowerAdvancedBlend.h" #include "ProcessGfxRuntimeLibrary.h" #include "SPIRVInternal.h" @@ -55,6 +54,7 @@ #include "lgc/LgcDialect.h" #include "lgc/LgcRtDialect.h" #include "lgc/PassManager.h" +#include "lgc/RuntimeContext.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Bitstream/BitstreamReader.h" @@ -71,6 +71,10 @@ #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/ADCE.h" +#include "llvm/Transforms/Scalar/InstSimplifyPass.h" +#include "llvm/Transforms/Scalar/SROA.h" +#include "llvm/Transforms/Scalar/SimplifyCFG.h" #include "llvm/Transforms/Utils/Cloning.h" #define DEBUG_TYPE "llpc-context" @@ -241,6 +245,8 @@ void Context::ensureGpurtLibrary() { ShaderModuleData moduleData = {}; moduleData.binCode = rtState->gpurtShaderLibrary; + if (moduleData.binCode.codeSize == 0) + report_fatal_error("No GPURT library available"); moduleData.binType = BinaryType::Spirv; moduleData.usage.keepUnusedFunctions = true; moduleData.usage.rayQueryLibrary = true; @@ -277,6 +283,18 @@ void Context::ensureGpurtLibrary() { lowerPassMgr->addPass(AlwaysInlinerPass()); lowerPassMgr->addPass(SpirvLowerAccessChain()); lowerPassMgr->addPass(SpirvLowerGlobal()); + + // Run some basic optimization to simplify the code. This should be more efficient than optimizing them after they are + // inlined into the caller. + FunctionPassManager fpm; + fpm.addPass(SROAPass(SROAOptions::ModifyCFG)); + fpm.addPass(InstSimplifyPass()); + fpm.addPass(SimplifyCFGPass()); + // DCE is particularly useful for removing dead instructions after continuation call, which may help reducing + // continuation stack size. + fpm.addPass(ADCEPass()); + lowerPassMgr->addPass(createModuleToFunctionPassAdaptor(std::move(fpm))); + timerProfiler.addTimerStartStopPass(*lowerPassMgr, TimerTranslate, false); lowerPassMgr->run(*gpurt); diff --git a/llpc/context/llpcPipelineContext.cpp b/llpc/context/llpcPipelineContext.cpp index 808cf24cdd..5338cffcd0 100644 --- a/llpc/context/llpcPipelineContext.cpp +++ b/llpc/context/llpcPipelineContext.cpp @@ -311,10 +311,10 @@ Options PipelineContext::computePipelineOptions() const { // Driver report full subgroup lanes for compute shader, here we just set fullSubgroups as default options options.fullSubgroups = true; options.internalRtShaders = getPipelineOptions()->internalRtShaders; - options.disableSampleMask = getPipelineOptions()->disableSampleMask; - options.disableTruncCoordForGather = getPipelineOptions()->disableTruncCoordForGather; + options.disableSampleMask = getPipelineOptions()->getGlState().disableSampleMask; + options.disableTruncCoordForGather = getPipelineOptions()->getGlState().disableTruncCoordForGather; options.enablePrimGeneratedQuery = getPipelineOptions()->enablePrimGeneratedQuery; - options.enableFragColor = getPipelineOptions()->enableFragColor; + options.enableFragColor = getPipelineOptions()->getGlState().enableFragColor; options.rtBoxSortHeuristicMode = m_rtState.boxSortHeuristicMode; options.rtStaticPipelineFlags = m_rtState.staticPipelineFlags; @@ -481,7 +481,7 @@ void PipelineContext::convertResourceNode(ResourceNode &dst, const ResourceMappi else dst.concreteType = static_cast(src.type); - if (getPipelineOptions()->replaceSetWithResourceType && src.srdRange.set == 0) { + if (getPipelineOptions()->getGlState().replaceSetWithResourceType && src.srdRange.set == 0) { // Special value InternalDescriptorSetId(-1) will be passed in for internal usage dst.set = getGlResourceNodeSetFromType(src.type); } else { diff --git a/llpc/docs/DdnBindlessTexture.md b/llpc/docs/DdnBindlessTexture.md index da974d90bf..30f506efde 100644 --- a/llpc/docs/DdnBindlessTexture.md +++ b/llpc/docs/DdnBindlessTexture.md @@ -250,7 +250,7 @@ If a bindless texture is declared as uvec2, it behaves identically to a normal The ARB_bindless_texture extension was published in 2013, when we implemented this extension in OGLP driver there was no SPIR-V opcode or extension support it, so we had to add two flags to indicate whether the bindless texture/image are used in the program, we can get this state from glslang, when one texture/image in a shader is declared as bindless, all the textures/images in the given program will be handled as bindless mode, which can simplify our driver’s implementation, so in LLPC’s implementation we will continue to follow this way. -Two pipeline options are added to indicate whether the bindless texture or image is used, these flags are set at program link-time, so that when Llpc::Compiler::buildShaderModuleResourceUsage() is called, the texture variables can be recognized as its real type variables (eg. if declared as `layout(bindless_sampler) uniform sampler2D s1;`, it will be recognized as a 64bit uint typed default uniform variable, instead of a texture), so that we can create the correct resourceMappingNode table for each kind of resource. And these two flags will also be checked at pipeline compile-time, so that we can generate the correct LLVM IR for bindless texture. +Two pipeline options are added to indicate whether the bindless texture or image is used, these two flags will be checked at pipeline compile-time, so that we can generate the correct LLVM IR for bindless texture. ``` c++ struct PipelineOptions { @@ -314,7 +314,7 @@ If declare a bindless texture handle as samplerXX type, it will be a `OpTypeSamp - At program link-time, when calling `Llpc::Compiler::buildShaderModuleResourceUsage()`, we need to recognize `OpTypeSampledImage` type variable as a 64-bit unsigned integer typed default uniform, so that we will not generate resource mapping node for texture, but generate a default uniform instead; - At pipeline compile time, we only need to add two patches in spirvReader: - 1). When calls `SPIRVToLLVM::transVariable()` to translate variable `%13`, we need to force to change the variable type from `OpTypedSapledImage` to int64, so that we can generate a uniform variable’s declaration, and we can handle `OpLoad` instruction correctly; + 1). When calls `SPIRVToLLVM::transVariable()` to translate variable `%13`, we need to force to change the variable type from `OpTypedSampledImage` to int64, so that we can generate a uniform variable’s declaration; ``` %11 = OpTypeSampledImage %10 @@ -329,19 +329,16 @@ If declare a bindless texture handle as samplerXX type, it will be a `OpTypeSamp %18 = OpLoad %15 %17 %19 = OpImageSampleImplicitLod %7 %14 %18 ``` - 2). When calling `SPIRVToLLVM::transValueWithOpcode()` to load the bindless texture handle, we need to do two things: - i). Load 64-bit image descriptor address, then convert it to an int pointer with correct address space; + 2). When calling `SPIRVToLLVM::transValueWithOpcode()` to load the bindless texture handle, we need to load the imageDescPointer by the bindless handle; +The above solution works for the simple cases, but in real implementation, we found if the texture is declared as an array, multi-dimensional array, or declared as a struct member or block member, it is hard to handle the accessChain instruction, especially when translate the type of a bindless texture to a 64-bit unsigned integer. To handle the aggregate data types, we provided a new solution in Spirv-Builder: +1). Convert the OpTypeSampledImage typed variable to a uvec2 type variable; +2). before the texture function is called, insert a bitcast opCode to convert the uvec2 type handle to a sampler type variable; - ii). Currently image descriptor, sampler descriptor and fmask descriptor are stored in a structure, we need to obtain the each descriptor after loading the image descriptor address, then insert all descriptors in the structure; - -After the above change, we can see the pipeline dumps for the above shader, the pass “LLPC translate SPIR-V binary to LLVM IR” and the ISA code dump looks as following, the cases that declare bindless textures handle as sampler2D can run correctly. - -![](./DdnBindlessTexturePipelineDumpDeclSamplerType.PNG) +The above solution can significantly simplify the implementation in LLPC, after this change, we don't need to convert the data types at At program link-time, we don't need to change the variable's type when calling SPIRVToLLVM::transVariable(), and we don't need to do any change to handle the accessChain instructions for the aggregate types, the bindless handle will be treated just as a uvec2 type variable, and handling the case that declare a bindless texture by a samplerXX type variable would be exactly same as that declare a bindless texutre by a uvec2 type. #### 2. Declare bindless texture handle as uvec2 type -If declare a bindless texture as uniform uvec2 type, the solution would be much easier, we don’t need to change the variable’s data type at program link-time or when `SPIRVToLLVM::transVariable()` is called, an `OpBitcast` instruction was added by SPIR-V builder to convert a 64-bit handle to a sampler, which need to handle specially for bindless texture. As the bindless handle is a native 64-bit data type, so the result of this instruction `%14 = OpLoad %11 %13` is a 64-bit texture handle, when translate the following instruction -`%17 = OpBitcast %16 %14`, we need to do the same thing as above case(declared the handle by sampler2D): - +If declare a bindless texture as uniform uvec2 type, the solution would be much easier, an `OpBitcast` instruction was added by SPIR-V builder to convert a 64-bit handle to a sampler, which need to handle specially for bindless texture. As the bindless handle is a native 64-bit data type, so the result of this instruction `%14 = OpLoad %11 %13` is a 64-bit texture handle, when translate the following instruction +`%17 = OpBitcast %16 %14` - Load 64-bit image descriptor address, then convert it to an int pointer with correct address space; - Obtain the each descriptor’s pointer after image descriptor address is loaded, then insert all descriptors in the structure; diff --git a/llpc/docs/DdnBindlessTexturePipelineDumpDeclSamplerType.PNG b/llpc/docs/DdnBindlessTexturePipelineDumpDeclSamplerType.PNG deleted file mode 100644 index eeb1a2a4b5d920c3c9d57c2eb1aec8ec9f66b16d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 139864 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�e_cUOG1 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�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 diff --git a/llpc/docs/DdnBindlessTexturePipelineDumpDeclUvec2Type.PNG b/llpc/docs/DdnBindlessTexturePipelineDumpDeclUvec2Type.PNG index 5c2eef2925659fcafd7343832926a8176389129d..e3c868e0a334a9685de7425bffde0457bfa285c8 100644 GIT binary patch literal 313823 zcmbrm2UL?=6Es!C3NXM6ctGbF+dQI zqCkR3i6A5p5RSAcz4vkho^!tQefM8?-F0skgcW$-{m!15J$vSPW`i&@(LZzQ+^Hi+ zj+`+x(7k=+$cYO2cj?I!^xu3~gtX9q9EIQ3*FI9##s7=`fx%ttme!FYxCE9R7e@ML z=KBV=@FPdK#SgxZ8r~LLIC5nFwV|$-4 z1rq6Rw$DkSbMR)TwDiWEiRStJy?Im7_pdi9G`A1G<_WYC&BmRIcI55=a(7eJXC+tv zyU*2wI}dJuvm~G|_`$bD=1Wdwe$2tEJxp?MU}AK1R1Q1zlbo=f`OlLwznHV`9F4KP za`^i2&t*0pa(@jcAG3SW&77DNVRE9jn*N$8h5*|M1cIv*F2nV=xIj1VZE%OD_z5tL z{*2Mla%ZDycPpZ1qXYd_Ce2;(*JZ>Gh-S2{6rfC$b0>vFAHT!NVzqCbBx51&{>P<&M$nVhy05WcTe+`gH zsEV=OaK^O%)<}iszeODscAKD2;qXrxvjj-mU&ChDZnVk#9-!mmzi;?Q{_K{2UHrFX zL@z*$?O(cry5Y`1tgifh!+_JjM0$q&Tc!VXgUer%@KzZ9`(ncXQIh|cqT>@D5#}|v zsLnW_YdPDWg40(2lCMJO-QPAF5IfIa(G^4r<+1c1{21fB8u@I$&T2K&x^b=`W=%q4 zpU*Wk28^)n=v3YYPHy-winq!Rx06czzTd2Bqde7Bm(7mQD4XnbzatwWe=z)j?0+

~6*v65Tj$?BlGS9*%J6TJN5X%ewwdV{ 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

|6Th=x^8L$xcN)<*a0DzhGPZ1WOiUunSjW1x ze=<6*O=nrIG~roJMnT&{gAXsp`p7l@xcepG-ref^S?e;$w-4TS?7y26{mN!dKy(Km z5;WbokDnitk^pf~2q~9%VsiuM=l^(3SXis(Lash}!l!OOTy$3iP)y%QwaP_b85kVk zTX?cKe{GH;+z;Z-A_i#B=%ibj2U6_ow|%P1zB<5ERShjK8u{A@)$kzdBc9V!{|yQt zOD2jqAO~%vd9t_0rOTed$+v3V6fHuK+1Zmr+g0nlFIjAv?>Y9`O%U*?aoS8e{(GE{ zG^Bi)E&uM}O28KbpCRp1D9xVF@ry%sD{0Rd&%L;o%fZyUnH@`cK`*5X_B=fMs8-(Y zOqGCm4v!BzFOvP4$$2FHkKOtg7Dn%kYPlU&d^7svH_rbzAk^aeQc3u04{{z6ASO}) znKCxGnQt~_!CbjzHq4w(#Ul>Ve`;q5)-l*EPu)A?&ydpNSRO91w_5!o|Z*rREnt`t^n|Ghyd*0$xX|2Tj*yP3XrIV1-3aFKkk0ujvG+%9IOnR;! z9at;u2bkE$HLC2eMD8nZ?Hp|-<%U1{$j;006jv~@70tD|R*$1v*`D&CF~#uc+J77J ztXK{BRo7lIhSugx^kfI;gn&weSlYr>L8@L~UtQM0+|NRNnivBlcs89Sa=G3*)@LcO zE6;HKF)yI8C{oaxkCl&__v%{A6Uwfbn`w|JE8c!;o)U`l66Hndf68?<-%CB0*3rQe z4T6w3EzTPa)ilS*>)e80rCR6jt&A@ZHthar5m@k*6>7=$=CaMS$>Y1XJYj0XGD*4- z$Ifzcz?6G{+lXkHmH7mp@SX*x+}6Rhzc(~pp|-c`vxOMqImA6`Ts>Z&EF4rjL#Z>q z84~N07%+WYQ{cAbH3rWKDpo;W(p-Mfclg9}+BR?b zYyo5+Qb}2WV(~w@h`5vS|89d)8v@+i?b|t*jRHq!$>V73-K+lN<35533h(x)oJ>3<|$rHY{jgO$em8Bj3iKaql^#uFdJ=yU`d`o_3*FH}Mc^p-fM++qX znnK%lhnO@-8QDLpc>I?Y=xlepzAL>awtXBQk#OM3CMQmSWmZuB4MaT&Te-#`4L{1M zQUj>-w^xW)Vy(o(!{ne3e1Xojrg$CQI5109VU&3Pt&dzBN3ZrPi#YcKRDKeU-?kGm zP}fr7j;Vm_&?_;TffabHd^Oy58?M@XMXK(u&qc{}rVWy=hnq33-5aGw0P-%YmAeh? z>}<{X^b@!jI~Y5sCcxFd)bkmEz2lnExLt$jTGFh^F~*6SZ$0RK=P(yNuSa^BlO}L> z@jL4K{*+bp^4m$9F*?_>Mi!g77`OGT8*MirhbODt-TKGTBFWjxjuDo?mw=(`&D&0ue&9t14`fi;ODeuI+cX^Z$U9XH@YEq2$@DDyCiwES`G*s3n zWxV~5qvIE6sz$^e>Jv}0UJ66MH;R1E-F@*7KB5-4jyqui_$OWP+$h)pGTf)aU zEg8bAX;Zu?NUxQdLfTD9U1bcNGL_e#(qxU=nlTJ=rn1SF!`DzINXTE!2}|3h>>azY zWsHdL6VJiS*WTnZ^N#TqaxP97OZ_Lc z(Jc$)dm3BTQ^}Xu2scXI#)@VIAGn4Jk?%<^H722336J_ob_gIB&OxnKXbl&F$j{YaCb1 zNk2YVlY4~{9IaPvRb=ZO;N6SSFuWTy_}8OBIa>$vo!X5skaSpP5yT?eUe~)~T9VQk z+{$NyN{yyIz0y)y-h7XdqB-;I_JRj*`+mKP6JJQgps3FW+F{xlUzSp5=`c$9oA+9G zM8RwE{h3v$X|Fi1*L8FN|5kQ*RwH4Zk{T{%fjdOZRX zk3L<1tlR#3$b?CSW#DtCPcE!3PMUct{7g9vJ|gE}m}Pf=KvzHtKth>sTTx}& zR{c&F%c5KUe%HkzMSd}Sfi3ghVw}G;q5`)1xvn`SsY zt?#CO?-w6RsA#hgb~$q-QWN)-?`2N=qLCiA$<_)q_Y=t1EE)^q{9-(t7R2?8Z;a|&Tm56++Mrm>jf8C1FVp=AccL{Q zTpwA5sBJaCCbt>Vox~?Z-uE3|=f=eN+~X>X9-3C^RD_^1)p@IoT-LJU}3wj=UR(h_jFj|-{&XJlKtHqg2 zRssI#NPU`R^@gL+Yu&Njgj$RW+`#bLcL4SVG79?qtET}pBaXD9BYe2xDY<_&VxN8o zrTQtzI30~*+hCZC@(am+6!Y=fNDbDMX9|K#%sXnMo=`AltgXz&!4_Y}gAicmssw}z z_%7gRZ~(7cMA(itPs^tS^i7w3gK9_iD*e}~10C5+YviLq8>}~@NxZ9fAaU-O%YOdt zdmiUGt)lL!#f|Q*1{ee*${;ucE`YVdUd1-D1Gze3hF&bIB6;X>NFL(t#HuU^Li2KSz-^5Ol zSK@4ummaq#$sjtKAv03LY6ow$ZOKG-yl{d`iy>l5$Ol5js=Hy?3TW84lev1?eZA}j zZO3t|PFDcDHhfyrp`2D|;J%@Kh*-wB2Dm%PSa>qwua8W!ffd=+4~2FR-k!ABBD*Pd zp^qZ#i3=K|=`$VKgRJe0``@T$f?3_4TWM+$?pL7foVcPyht11xPgk-o=1;`DP}LE% z?vGH76SYY|V;{z|{OYm7_57eRR(1;Q3!Ho9#5otee2ESbH=3rnlr(*cF?Ee^u%?%y zcF6`!n{2o#B5U1wfmZ0zH{y0;6Gx* zL$a*0r|mpIE)TSld4+M}DEk09Y}(J8AF~7j1juCzTv*L`s*cG(#8 z?9Kp8wYg)GKBws;3?K8;r4xnL`Q4!#(9FyN@KK@0KrvbX>2{a-`P@yb@N}WPg4xJy zsTkQX_Lywhe2GR{AgA!QNVt5;TIgI2rJ%l0khY0qLVBC>u4S~FS9bL`>i}^4_C4Bz zVth|}nk&?&2b+GV&RQkgDhY16_wF+jSY^xiwcqS!`OzkHmA(qqEEha^=~GJs;gIey z?hu;L@;$E^f>@G6?$fX?!+5YB+o$IC5~!5tjCleNdUce&@ptxcsMsSZfkk662B6Y0 zVsVhLoL*&3!+Y)ykaJm<^qOnX?;cquTZlfOX3cn{Pc&Fd-c`TDGa0?}%qiCglhbzA zHI8dkK-WoXgpX0{e&n8*dZg??>BUX0Rz4EeacP%(v>)s?gIEzqEX7`gy~=-=7qAFJ zM1i6(4n58SHZ?~g#5Vbxt`-cV0=F>cb`Rk3^>mx_>7R9OE+wn%lmk%7*e9Ge1K43Z`CW)**w?4LdFV^8Hn;!2 z^hK;qBFQN{aUdit3D2Zr&Gv@Te~!0>or;Iv<*nYi?&;~owoDW5U16CB~SoL z5A|bk9Ig!Bh_}GL;R?DF<>E@Sk(olcb~)2?h$2ZBtL$7CbAtm;%)TAmlbf>ro_jmz zct0s?2SpKiuv|-V&cdmY2AiLoc?NGob@0GC)x$*jfl_=h%vBfQ#FRD>I zI!7OQRu-ss&3lBEwqSS4)ekGV7R1#fc4rjJ)jABJgbwQ`>~nq=Z9xj|frYfNvA<3g z;iO}34})Q4ibNrNJMyWe+ymrDs+jvo;`_uH;c0Ee7}ebKyP!O&KD1Zn;QO5adf#B=N3*&KZ;G;_uS$ z)DJ<&d!yhxKMvBMBPPP6a=Z0HE}wOD1>1#mO<8O)_Nk4nbObNER^yz)M!4hBTblD+ zItMdop2~;Z`;`$xcEwPlHgWYG;jpW@>_tE)C{<;I^2k)j7PZe#VE--;700v0wDx2l zJ*~{%hQN)0iz6JZBZr(SQCiYCx>=oA4tA`rd9f6-Sa3JU9L~tJI5pmt_+ILs-6HSc zGF3u78K3b_{>3l^I6^*j`IbUP04T!)$kcT6KovQ6_P0ITL;=HY`+l8*+Xkqitci`5 z8z~{~YoZ{J^|S;b$CmU4k#1wjMenQ2s1_e*76h#)vdU_4EwL~f_@RS34v%!`&eJ_9_Wlmo zuy^fVPz6qs4I8JkFhC=De3x$SHIJ&&$sT z9{=_OZd_tA+~9&`YMWH+$maNY?7LqAXaq|9DNo1YT;ms2M9;e8A7j`5H@OyTRj1^F zU($s{{}rj_-nkByWb_lf5r=)qm}ZW_*~_i zbLhqV+q%XI#OkW9fZ~Hfq{kSmT%%o*`gK8UeY5qaG{3H#p}F0OBVwu*#;wp?q;WIq3ZzLb+=c2X6-Lo(Fw4(|8y4&H2N zk>29!n0Tl&+UXWVdOG>;d#~O5FIdN@Wmr~_(T?k-Xs-SiQ9?>F18IAS0e_oAE8nT( zZ2y(QI7HiaKDSGXoBoAsb%&ve+>1=pJS7Ji*Itaw454_o`?*W7+?kujgyY`Jn3Bbi z%})8U%s!y&A;O&ox7P{RdJDkZ%01A3n5^snFiU^~Q5z!R@ME%U+mpa6IJQEk8W0-b z%INOCUG`$7I5i8De^)m>`cUv3=W*uhNWZx;Rezys$NSwlE+5ZnLQBO}yo_*dX7<_; zmz%&q{}r@>Pqu4}Pk(I2(mCCJTE+)aHWd`uZ`N?b=|BuJ5u@6Kga81CUx_|L;n}-i zFpx2K&kY*j7d&0R>YO;{b;6LDBlCvUOkfGvo#v%Xg*xG5-;lWz@+Dl&(HxKb1mvzE%d^eI%uj(+$OC;;I&_+zUUcJR!Jp z?ff6k-aH=4_xl5`R4SD%*-Z;6M3d~yB$ZZ_#u`(m?2=@k8KLY;B_Yd%LSvb%QOs1v zDBDnsHL{Lo$TDWk%5$sF_xt(&p69>k|9NrW*LCi5UFV$l5*d)}(|(<8|2gD(OQYbS z8^o=S{d7Wl1?*g+I}{Bxdw}Kp(^zAyHwFk}l{HJi28S$GEl#H(X?I)t(6f&PEH~uB zW2|VxTK=+9XO=pY#a;R zL!}VzPwzGY&(4+bZyYVPWz8JC1+58xK(4TGJ3|EQ&?XwJ$k~3-lMIO=_de%iLDf+d z@s<6#1Y>h!GWZbh(GX$mYJz>%1L77!*WyJ4aB`sylsT<-ehofi`y9Ys4*6wn&|

    3jROL^m1f|t23HSOcy=;#GV$+sshd-;W(m3PQ?-4yqIZJ*Cdz2uXaV$zD_g8>Bn}Tg6lgDhV@CUDQx2S0p(r@Xz(U2~y)AYVguyR1Nnu0#Sf_b1X(3~na$cMNw) z37XRAobh=t&$PzUVW=#sUy66h9=?3!xB0R*W+S8|IWYT7EH#=T!y_6b2Txi{SB$|X zCIO^ET|skc$IH##cftpHwNm*{zwiPMJ+`^5zOK0%%8F_os~quxH1Xo;vOS$qGtMFk$W2DU8tp%4?iVfoQ#xG!kljGocazrQO)W*e>{NK-R)$y}l zTpG67qdMNii;sG&a9go7wGWHd>XMB@qHf(6jSOD3O&YJxGMFa5?|tr-Szc*CkBCDPLKJ(PhZ0aHeU zqZs1uPj>G@er4VcOOkyQOD9GZ?Rv-S)k{b1Bb#9y(eqU?MmdXadhY5N4-EYwsg)kj za=z|@`Emuy{`|<7mfH7_!0xc~G}CaH_y(W5_d}*duteV@WApSv( z(>_>qh<jlN+^(9M|7$j1x96)4=E5qxGKRA5f{QJTPvX>wNEB*OCSC(EZYZlRlno!b}HR zJ1qGiG!S`dpS4i@{5NpJkf|yOXs=ct|0xzX5sPy9oJz)~xHnMPi_&P?r1W_)3GIrq z8zXE&QpgmeXKk0E-k$&s+$UQGFO66+0CyPoOc7I8buIWRAEZ<{<$PgX4M!k>i8#niwo)tc*X zC%7FPy|`HBpv|}fpL;Dqv7Qf_16K1k+wNYuIPnVQL*QJ4=!T_`fpEe`uafeIBMRcccHd9c2N0q+8!PYjkwjA01q#g_? z$5N`)L)wGo;QrH_clazAt-4qaHS7gk<=9xiDeb@-sllSUPJIhNZ=!>&?zNG7RamYh z{kj!TKbk}aKSt4jppd|Iuk{zU^vh18bZ}f2(&cEP5fz#GGS8VR@2H-)RXM@Kx=hxw zJSz;+qdQoAhyQ(Wrp>JkT#M_HF&Id~5l^lj87mb09J$6U*cIsHIM^c72S`2k`|Ua& zO=%f!FJdj7asTb!$6dm!0UolFVTqPJcggIHTmWov)A@!H>AM@#O%X{M9^_?glQMK< z=g4vp^p^ko2I)kRX0z+gxVzHIlpT5#FCG%yp-+Tg4+T9d5-XXV; z$(ohKlq?qDmLmH4&jxm8PIpcm4s0*0a4BWTPE;ZD73Zc@=feEmo%V&_-@7HCACTCH zH}ElCxiDQ$I|w9+z#o=%5PRs1L&u71jxX)LllpW&mCs8;w=2%KAj=0O!Ux?gYRF!h zVFW6$AAOhKyMd$}wA?JLm?49jg6TFte`XKj?d&UVplOCRD5ZvLv zA>i?xl$`p|lvnl95499~PYzTnDV6-T(>Yh#28Czn8;;haUg;ciCr>pUrxtkP9y$$! zx(uS-ar<-=Q+<|iA8kM1*m){(7k(Nazke>RONi20bKc1dy2L$Ull*8SH?3DR8Z+K zH|hMG5Nh`JoPaMYYQ0l}mrl3)^t-ppsbYdYk{e>)@4nx-{YO^8T6}nN3d;z7QA+M0 zS@=C=0^g;JiQ4Nwc;_$l^)HG6KbG1Q)X4en8g;JSaCJaSot`w{J3QeHOjpbZ8r0L9 zt`RoSrP;Lf>&0mC9(Cg+-UH?u$XpSPQ67IPR)++^l8g}ZBUJL!+Sd0 zk%}msJ2icF14`YT3Ygd825Gt94KF_N{Jpn20rBKy>F>P6?E|})JX*8U=HoBc zYHQZM;pqj=$JdVN8-Cyztb~*uMahCYxHt7q#FaV z{=L%1=Vyf-xyg8!GGmZ$Xh~om z(1Q8#D+#0Ud+oVp)~GI3925ug^QHqYR;N{6UPgW%!A{8CHg@^KesORfrt=P&h+d(E z&YjT-5*a+}7r_fj`&giO%jiqd5&v(RyiRA@B|jV@Mg5ZyR_1K6mtZ)qw!#mKfddIo z?L=V8u-hyICu1oHF{;HU4l-WQWeTu#<`t)GLJ;cHGhVBm(^LtXWxLv1G~+fEc6y>Y z6!MN=N=o&i5w@s}IvzWli`zoIgkV(Fc}jXD{aC^UbR4ra#>oY>azkgRLSoQyM?u#1 zP-=y(-V_>Io9l^8(q>*t>@ZDyquM#Fx1hJfNPG~GNSchHl=5KSO~(EA+H179LAgi_ zgJ<^0g;J?)Q;qO)DmvwbSRD=@S{Gt}rvW(4iEi3;KpdlTZSlnxwLvSOm?FAuKC~m! z&ijL-*udd#z3FE@-y`=P$bG1Bp%<7`Kmja7&M5oq*h7B^Fv!3BTQF@2fET42;Uki(UbCnwH2ww1%*hW#{~6}ljH?fm|X@gRkF zeM(qv1*C^b(^l58OP9#_$X!}(cXIT?kO0LS(pR*nFQegYq9sfbGvPozbs!Hul3!jP@M?SHoPG&)hdr7J+L zMSLmF4q&s9;y%CG_gvXHZQqu`vtv@gmiFikR)e~Ab(3i-*dv+Qf;TeqAI{7JdzzBR z@<&;PIs4~KcLp>M{s#zfxX*w>_&nJZY% zg`|~jfjW8&N%*PVXWbuhtR~&zNS~3Rh)M`e)I4mY5q7q}G1y$u4)K}?RKoSBe|NR{ zZA-Sn1DT6G62op2IvcPFx}VtZ(J~jko*%94tvPGN+6byCzYr^bFxlx7cS%qwEj4hyGwwOB}bV+%6&@Anh4BgBLhZo*{TtIf3PCj2$ z@8vc3J!8$fTR%j!=3Vcq#)LJj#cj4*S6XEv7Q6sS5JOa8JIz^THLhUY7@$$MhWOwK zQMo$dd{TTzO(dUSYnb>UVmGk!o^<8IB+`?kS1Pq z^j`rE@lN=h*{xR8?b18#eHyR+`A|=tFQxjokv$tK432w}y{_5y*+h+Usi3M|JP$lnP18Xl<>ep2uwh-X!%lnna*ZsEM3pdMCecVnEhd!GZvzGFp(PBQ+U#TmH4yDZ$h zf_*OlW9?sG<=3T7G9;+4QG4x91ALrT$X`BA>N+21FTzW~WZ+p#f#Pe4M_9wSbAVM7 z&S?JgnIC&1;%cw#8AtV6y4cjN@N;)myd<1f1NbRnkvV}cELGlVlV;(-V4zPA<*C2u zlP(Y7?B)%r-}hG8oJo5r-m8^sFpxeb-Of*ViRN_pSEDP+(DuK37cY7;34;*^GKBQR zYdW|U55aGJ}-y^dwr4tL$XU|Fe@d(4g2R<5&00R>j& z8~fA%#**Q_E-NuJEX4Zdu|tt5r={X9?}1p06$j%C01dLIFAt6#tabB_J0JQv?!EC= zcuwE{m~sCRR1x*V(X?lUA91ju`$6KdvC`+NKLbWC6>X4n*9v^A$)^6th4I>lcxS&x z+9YRQsFp>r^neOtXaFOp#AUUuW0nOP0PsX`phK&myHo4+h0T-j)#WyCK8W9S;ZiZ` z673{CeW{*s?mNga?eVYe8(lJGuAP7SJjd_Zv#)6P-x>1d)aSv#D%>LFB;gy-yDI?%n7rux42Cw>RKh< zGsf0CQfq8u$_C}FFh|aNkdh!+--g`Hy0lpThM-@=w$#IBj{Hvik>8x$e#xrXush`b zp3C(?9@%x$vN_)=nQl9Q=E)^lqvI7EUR9gZAN>l<;g81nhF zK49MV^wF;Emeyy|6EC0#&oTDzn5s~JvgK1$?c-+AIISx$pWglE>1eY5#M%E#0Rx+B zTwN!C#R3Gd%sJxOKvIidoVPvug~%3oeiBD5?Cd&CW!4f%Gb`&zasIISI%ir4ICOw= z^E9DrNkoC5yp*6#xZai{NWUt|S$+3509e5mC>n0eBLqUwQS86$cM3S>q*Bg7-eK z6BDM@%vT6{4Ej~){IUsP9FPIT>_v8{>Pq|X!rPVbX_ed zFS^g&-0Cw)@^UvsYDeUGpkPxW3$IJVG!#{z-WzAj)#z3eIVG@GzDG}3K=jy;SCk8`_5!I(6-ZqzSx^(>aYc;I zA5KHopT=qo|7x37I{!csyqI|r!4x@2IMD+6s8!jkmCt>o+xIKI-55V;4!D)$N$}VR zIFWM(@~$jHUTF5hb0Qq+7UuWnNbSp@pn_O)*23Y>gs_*dJk5>A#%Uwwh)=8 ze4W4ePpIPoV7gw=pUT%gn}$ryjsxF7DJM}-_{^%MqAk?3sKt6uA^%QcCOdns6q+1? zYd^mfPp(I8LG`cX;;i=vwmUYLyaO#k2SeQ?9Fxs;g6Q7Mw0@ykm~n*3Ww+ zh1uce(m61pam{ZdDYkF-+D$)5>~H32#ZRZI2{%Z_K48}^j(M%A&wB1)y@;7 zXFTHtNUp)moN01Nr@NFYMSSRZ`26aYY~i_$00(hi?YDZ_`&^uqp?n$!He2TltBA7U z-=HZNw)BR?R+N(@;!#pU9nxe`@W+&3)C8S+)Q_xC7fS5PYl)__G}Grk8pzRl}l59Au=|ZUn@taNBJn%<^zo8(yx<-HxL6R;BLv$940W11XJu}U z)0T)-E^~U2L$IPNyaGDI-H-7=ac9afP?IY` z(9Z-t4c9po;P0|!n_R3|Xlq<#>^B~*0lZET#DEgv~L3?%dV-JG-}eNsz8(_+IL{`i7SHw`Qjw#VFxA7L{w=v+x{)}`p^>N{2FVr)P^|}i)nu$94Yi47x3BUbz)=JcgeHc zP5_cMz-CNuJNbv!IP35atx<3Ld9EBuZFS%NyL$fS`EPYt0dc@D{?;b{p@+Q&I57tQ z5VXKvAu?e*EOO^X&pq6K>(}*dPxF=A3eirKS~CSZy~tc|369H$sC5Kct~}ps?7_(^`kJ4lns_+&aHxdGK)?e&_MwT1hg6@MX)#k-;n3HH5|Ndbs2ZT*bLleNk@{&ffo<=q3R@q~5 zRHMTSgmLlE-QU&@tRn^5Ssw-GET3GEIr;O{?1B#R*qD;ynuW~5d>tF4RlBA0Fn!?c zC_q_bJ_&x(oGLirIwt*DG#|#g^7#_;-P`4$yyf?a`Ue5=o#VgW6dc}0`&HD6vvFDu zN`9V^_1 zTzTZ$od0zd{hNJUwQ&X6q)!UO1pT(>0&C;U6#e71rwzP0>RYGuR0h?n?~rbbo98O90MzeoqyiUY0Iu89Fb$etBs69}=|Ax_$RU(d~ds%`V9N^!%YKHY%>BtSbku z%pW;4XeCC)a^HN>LjG(drO905JOI>gg8r!8R22VFyTKk|nAT9M%ZL}_;Lon7cfXf9 zxB~(Udja^i|MTI@1OHexCmitTJ`pl$1ad~re zU!~XY#RVg%*T91Qf$ahh4QPIVKSUK_u{h8PQih@naz+qH)^o{cSSV;()_-gP^L(8oF>BDBPDaR{r6Gt)uiW{BO{m;|WYm9E`u`Fkfyd8azBOxKSK&y71_LgA zCqjlfw*P|*Qv0v}c7_i?H~g<&$2uRdg)pD+KQFetCiGpvz_OAFvXj42Wm6j%9|g{!s=5gjk+7m-@8)mjhWE^M7ZsJ|jSv ztDK5-^$H=bEAxDT^P6rqi8`@+$F_$ry&fY5q49|^VEWHwxA0aM${~Hgz(ICoZS2EN z_}X+5PS87kHo+Fckcy~3n!m>Ra&`(>bKSH7h4^FPzE1Ef{wsC8uKMKVXuv9Mi=Kz9VaMQWQ&0tW z{Cp%qUTHCxEV>fHlWLk9t+uv0<_hGGnyq5t$_MuE-oIlpUVn>y*VBwMAmSnBlj7#E znkkd~jE6@cQKUpmACF5WpB^21G}n`EGSwA)3Nh`suk$}kC=6WBfpBUM?GFUgHGNl? z7nVf`hS~SJ`*!cKJ<1Y&XFTy)Ub!nJM4-~tG|J$N*@rW0%BY#)oRy~Y()=F_T|wdK zx|ShLxUt9czM)CNDtT-#LGbDL9g_E^1beRss)Y`4s_GcF5(cNnynHrfDPE=aX@^)* zrLRPNB^zLP0dEVa^~?W9?q%`+uN1c7O^a!ga4R&N4v$_J=+Wn>6s6Dgonb}Y`#NQN z)Wxwz4`6cWg>e(4x6@3hF>7;oiMWQTt(!U(I|07!Gbpchp#X$;RsXbN-nb&tBp6w& zZ+2MXhVGkHdK==X=Z*w9Nh ziq{vXSo%!iWKR5fHNc-u3its363NbO9)G#*~YH zX|MWR=sIu~?8-L1z7VnWo}sD11Fp}{1^ZloEEk~>byHrDdqQBU={%Qzw-xTBoy{Ga z`x&!3J|ELUSi2}fm}gPieBb6Oz2irv>@r`S{t$D}nfrdsl^h0>RYkCbfCkgf&s{RH z7M_Ij;EQml*as@|mR?gh$bX+yJOSub10JnnHxF+!wXgnWXZ%QIhyf3o{%jL>UE+x@ zM_J;4_?9b22d9i8uU6v{C`jTqQ<3~1K(D&r3oNo2jUy*~?p*Y(^Va_rSrX$GJ_%Ym zO6D#=cUy9*N@8LfsUl4#qk){e!%yMT!Bv$Mtrw;OEPYRUdN_za;!AMRpTgmFjj0FM>Ttod7`&nJGzu>F zJA8zX6KQCkcRn#g-{i}ZB-oIeGJHM(%!6No4h`a=hlT7kbk^P~v2x`bztp#u5c<~B z@xNgY@JcR@@7N^lvg6dYap5gb@@U#yb|4O%Jy-g;|MU~~|3|9#p`6LsX(y#99Dok` ze@WrQ)Y&p+Sy7*nu*SzJ?8p>$d=h!j^ppws*;+%b+tX4;jq{`k_l{jH1H{<=ZuD_LVkL$6NW zu!Bvt)mKY-4+!z8vF_(BDud#2?jrWbzDZubvheuich8|v&k}Q>H&XUWA7%;L&W(Cl zsG-FCBaV~OF1}WnHg0~iR7QF`GWLAsd9lRW*y+rw=-7uP-sv-i8*D3>mxIb6(i?9B?K8HVG((2IO)0rCMHCClqeb-P(?PledVrD2x zHp0cGCfxe5mciCpTLo)|dwASN-OdPN{cY4SlEO{^@dRtSf)flWx^#g7(rR!I2d;qT zBS!mWpzQRuW5z52TuEu6Q$5BAm|7e0Whc7&wyX|&^|1mXkaH7HEKy^3+f?BzM3~e? zfWW){(%tbzSr(`PYd{rbn{xMdcSnH__BK&tI`ziZSj+yRczdp+J=?i=<=+>U0$x}Q zp}c#a!oIy4jODA*SGOOqCYIW%I$qq+3J+8D+x}tjOYN*JCFvhQozt?dc8MXU;=woL zU-mQnF16>+RI%KgT=vp!o}7dUd^9_nGTXi4-E^T5fC4UCVTCBY%Y1EVKu;|C_gz+z z^yjN8`epHMtGzl+=Rpmj!82imW5WU;1`yLWYf}?O1kHt*HJ>ApxoCDkggI(nBzi*0 zcd<32(WMNKXut$bMZ9*v{r!wd3cLU4F&=8xI4O3L_|5v*9%AJG=$tk@>B_@xDm|Tg zB#{G@w6~Q@nYp#`rzqDjVUSMos*IH5hg|2Ty;d`XZeEGpqmp2==(QCA&%?pJ=irg1ORWPWXF;boAM!Ei_>P6Rm>;w5qI1#!t?e26v~P{XfE|<`S-eE)ySEdBE%MSy-d=o&MY24RmYB38)_G|C@aC7uc`_WE6D=doU_`TR_Cnd~g2pnpqx{cwV?~T?sY+!k*1csgOTHsJ^*~9ZP;vF3-nX z2lE@J0IZl7K<&=E2Cv9y*08#?WdG!3eOA#N;JWsyg3QYqvk6~@2F9LmX&kE@iwoxl zy*>w9L;#_&Pz_z9EzGQ-{OZU?uD}!45ZCkc8!fFzML#0%228FHzQCp3+c*BB0;Y$BYeEB%M}R2R9kT?iWp^_xr!=?_8z@;t48)5bPc!R+1T zlGVwrpTGU+jr z&)`H(OmFyC`=nh1AbRL;+Y$OXHq!1TZl+|=G9vQElQ{sa{g;{)AE&#ASPuv*E{TAG zaei@<;}@oc0B%y^IyXrx&%Klg$(%uyJDzQSx)xHFR`=E5$;WFQ7*jxoTKWsxN?+J| zdR@=BC6|jGEACsJ+x;XCw{h|-R^$49Zxap~f82P9ucgThhEo7 zzyHgfhA!w;By1;VH>WCFnpVlkA)0{9nJN897dkol1(yZgZWiVjQxL(G) zhWpJj&~A0TAVJF2()fkmD058U@4K@J&L7xnr?^UjSJE2zahycn^N5OIT0BnVmiPLK zyGs3AoNJ5xt*IbmuP}{92~r?g)vd!4Uak?r*8C`FTlc)Ot^{#6F5jm0Ci=VM~dZ$9mLC;Thm2RPxXJ_lZ4RI#pkS^(=Se-y}*Oz)& zoVE89ELwN<{Yk*p@g^LgO`IyC7qZ zFxz$Ux||93gQTPP6%X7mZY)ostqux_C!lFsM$!)IX zger;U)q8j`X9a#93H%bxsK1faU$xWC=|TXfBTNB{0Dlg#syS z(oe$-HSA1oYfUdb>TYE#&l@>-?(=ZAc8!{iUy`_J+3hs9>-Z@i4jp}OD^P?153lmi z!*7b96{?0iei;`4*R#Aoc|r$xcy-ku=U6urwj0vKt3tnCQ$beU*qC_c$DyZr?Lsg` zuha*dBxW4w2TV&RtGI8YDYny7iy`E}wB=H6qUiw}!J;iMKjXOh@2Jrp=6D&ZQxLa> zk*G3UqQj)v_kzs>oHu~(g{kzuIe2rJ;j7sV%?avAOZ|o{)RdekTU@x}b~q*VD>VjU zXa)=GjCMKYIDHd8oA8C2iO;@W7Q;b=B{lJvF8XAslFs{-c$roFM9o?^+gzKN@GUVR z1{b3)_Q&x~IRa#+7tvt%@9%$WCw2t)D$RK0K8K5U7`-m*dVvj?WSsF1a0PTw10eTt z#gwX@{=Z8MjX2&UZK<1y$gLSMJY$4=S@yxCES^|_+M&$nqVcx#rRzSYA8xPHp8q5u z1BJ1YjU0Jf?)#4g_&(s2OdPOa)nvS$%zOAmty|^_R3ZY_D3K1!vAXxR#V*onuF@&) zrb<`DLp5EAOoNcG?-vaYof5ZtcHI{Fkb+~$VaR~J#LCBXeQCeU)UHAT7slKKWjHLz z5A~zpNz_Y8jF9+ohwHQF*jSWxX$etqy;_Ns>~9OAhMJ^jGY%#`$m)` zd=xp2#ItS*=+Y0gmWG}RTjB|lM(v|I8|LlKepkT!(zb?rG_3lUoXcFb@CX8t z+;0;`99(>4cjJ4VH3iGQJ(?jBHXo`7q{qO7zu5a)ArV{P!uT04R&{Rj3Gus|gun9m zvo4i4MMR~qr%;`7hAIo=cH&&3pSn!ys>!|aV@(QT029#c(zi(dA+YRR`y&&aji_&Jj5-BE}te!&{}-BgL|;=w7IMXEu?1Sd-mJr3|W7V_=GJEs2kHjtS5C&pLid zQTwXt-oysmAlwRKC{5V|mfJxgT0KQCYy+(O%2=i9gEi@3SseSVZ-}=_zbvkj`U(Pg ziZBe{ng%3e4HjNkdihu*56$Ud48Q@i|z zwh1=K0zix#Z(FxoY%hR+`^1l<2JkVV;-Qt)UNuy3_o4U16j3i?AAT> z`*4V?&+;d#THg5~8EutMj%#nNK38EAx}y6fn<`Fwil}_wuj-**jcbovTh2QEj#Y&f z$`Rg&_ouw7SS-Vm-`Wl~-6p3`mm+&OU)>y0Sc9+$*j-)q#pnvgu!MRg^dqtd99~_8 z1N{1CLObanNdrl>cINF2*`^|mYwbx#`y^4Jeo4C91A0SlUZ;)Qv3FJE6qBg_$!;PY z=?Jkm(_h{e&K#^jhztXFc0%)qWJNCTgM~If^c23*>X`zY@&Xzeetwa>5@HQ zzvBS0@sUcQwO5zN?8q72#?yVhUZYjX15>_T{8HR%W5oq_(9>0v$l|CkH>i@vS{hX- z3y1$!;RewwAs(0gCt3-w2ebv9&FYwm@P2xpiBo`vY-)Jcam~qa27Pq8S_s|u(uwKI zR3ctnd!yc&*>V#yYdG4F!ldsb?Ohsa4VqKLPr&C_3f7=uYf3slU}+&uCTGKO`?l{_ z?c67}`;@Z688^b`TMGi zPgFN-`cc-Twf)rRPY(_pj$eK}2IsZma<7XrGTUodBLTL(jdXOm4$1dguY-S?PTzH} zJ|`WVTc0**n8}=7w8SI)yH+p_wzDDpkvh%9yawrG=E=Z3Aw%FM?y@)h1{=`?>NM4v>~!9dmFX&a4^dw$PH>BEjDvUe6W+{=6JNiW z*mo%ezQx%(#RmqW+u2Hmv0l`)7

    O=^9so@-#+MU$NB`kul>|; zX(G)X!tXw{0K>FIf(Zwv-6X~`&(F_kOcPt=i!fECOl8N=EoY{NN6s(ZdP0o08xRS9 zi^Hvp#}S?PJy+iAoyj)rDdlKD+hl4q*|(acs= z$VmpK;=Hzgxk=o~r+;Sn`i+*5S=|bMM+~UWQxBg)kD_C)jYO!?ls%xsym_g6!Qe z#8PJba-XgO54^JI?1kN@YvXpFdJdCJC*YY$BItOT$t}c&73kAoGNGj!Z524 zf)k8qqd#6Qv-+??%E~Uf@}+-Hn3=1X?6f`^cNNhT^Q*^SM>vl6NWxNVREWh}2hBJ~ zy|%C}K*Tj2qu=hSL_>@={2nkv~wvJK0YJC2{A4XOi#@V)1DBVSUPc+%vTQMAb^6g(OZ`zE_ zy)B-**$Zx7Gq?;i0r1LwgYWf3f#{CK&`!hFh08vq-y6f@QP`vS*l4f!tpeiE0^IS} zo$%SMQ>cplXSlgArgZ}Md-@he0?PgO;^~i0Ry}kM|Ef6G zDYcb7I9)sEJf*u5%-Lk8iL-*7JP!4pgJbsQml!_4+3*$DRe@v7O^5t_+E38xf=cM= zRaXW+zsHR(>S&s&Bv+N2zPxZN*+eDXH0JicY7?_lJ}QlUDWN7EA60}9%3QsV-gC$( zy3`Z!(N>W(>E^iiewRDn`=!1(cyIpJ-ny1gBMv`G+!WSirS2vl_qEDq#UyTQ#-uvz za9U|fRo;~3gnJt$&&$qztU@@>DZoacJy;?D>Cv}qTm&ATrZ6&@cl+>?SJ zASXw6uBnU|&I5@CwXJnus|jF{JLl0c&7b@#A@>1trF2^VN@$S9#g1>3A>_+aJ~gug zbDa53#<>R=B{3-Xi4i2x&1rH}cMJCPT*?mbIrHo%5J0hn3&qyQUFr4?!$cJ%4txY* z=ZVH9+As}H$)1{n!RqzF30!HZ^*!s`S__WKmojRtb;u5apCmTTMF11b4*nUl2d{v= zC}eh2`i4q!@`bA<8e$6=)5~s0u!ed=r&WI?mpQ2Btw!>lrnC$UgF0|3T?zBk$z4x6 z@J?>`Qn#ynnmzOkPg^RSwQU4+ywgx=9II*0zQLRW(1{hx!v`vID-=y&(QBjl>&3#n z`d7soF%1A2y6R(EWk)J& z73>D2obc^JAn)sMrGXRi%}N1Y2HHNiosJYMTfvM$s}@}tVb<@$d<6-NJopUgLe#)V zv?wueiFni#n9;1!60SKxH=+J6z&q+Udy&nVxMm|dW(`x(iQiizjNM&h59fx(^W>%0 zZ>(n6xhUbBIk z?ud@@?lke>2zW|Fu)tH?7wWbb4LlVc?Gy@VYs<127|r@d<^=CW9DZu0rH>k|?!AD7 z{TU&U|K-{+k^?I>#2hJOD7gF9cM;-NdCD*?6>c-vVw1>u?ov~(_`D>MBH_NamY2c_ z)H@2CM8|=ZbM5OoAy~l36A;lf0ng|ZE*v$p_p)G2uz=@=`piJMXdXR}#Hr*HNqOf> zwoTH}0yGzo^m7gnyd#$ z9+Evq{PgCPo1O2K8-IaPYRO`YEuOz2NUP8H^*sAhRYFN3&#>jYq|td*kFrI01@Y7+ ziw*LOob%V+y>CvH_;`N{ zwH$(751$2gG{wd33$VUcTEAER)~0@)GvQ6wzE3KT;Yr0U!)CU#TB>j`CBrd!MsRCx zK|HW>+bQE&2TC#+uZ;6>l^ah^+s@&XbMmdb#LWSJoX6eo@QOY$ZX~GWb6b%Z1X3or#t_+^D)hQ?CRwP;{On2kL%bSJC)s zQ?uQhxaRd9l2z3 zUrS#7oS6|54*K&j4*IpSsMNwA8vMz4#Z;b~>eStICxb94PP?^u#gU_%WIOeTe$v|# zeGpYT`>7_zpOK{lEc(F%Tac3K)#wI*e**DmeQY4(Kk-Xw-# zT(x^(1r)Rh?n!iZvAP`?yq~!{gXehLQIP&f$rslD!k7}Q36ZJx1?s`9je76_OeZ#b zdu!V8D?dnI#lb^64$wy|R!vCj!C-~3-}@Jo^|O!5c@)dRS;RV7aHB>~EzUdy;MXOlZaXu}1XqH;TOI*PCXH z0Vk((fa9ll-VEL0T1ryi3hQ}`M{=6+^Hh%j%ZA(GKAvMW*=LeJ0p!h2iDAUKU68vV zc4ulDW5zT2J*^$J95tBH)@%*3x<4QNOXVn4wd3m2s(wj+(Ef_gHXnSQ@G_*l`W<0Z zb?>oO`9=F~oY`_I_#DA>EN}2?X1=d&)|0Xx8#>&jyJPq5BiKCF3c;7+@ALLM-;<)G zIb76ok`u(}bgEN;VTFW7XnhrmgAYF@hR%~kpT;eCXQa^{INQpsq^tX0b5APW6v)eB zFA*?jhHc*T@V*0WpW9c#)qcw^0p25Wf(QJ3$_0o?)|leRBY|=KPK4}}5Moti5%d-% zOR^vXML;u@gX0I-rBZH^3H_2Kk;pbrzh{19E>cp|3_FvV5lh*SL#9Zw3)>-QTuK&o z==k-nkMF*|JST~x!{?XRM+NEUT#vr1I6&WPdw_i9dHlKFA-8@Hzq{DBSm4O{I`F** zkQfG0lAX*vgsS!Yty63a!_LKSma9nKZZ4g#-a4L45lMPcQ17{HELFdFP(Q0>UyD30 z+%vxWuY%ARQDm8g*p;?7Pwvew)N#0msuRAG@Inm_CUdgEF-o4x+E=d`^8-`M(cANrFHa~ z_YGyqvSBun*zx+GPfTL$#*QwB$Hq=6wiYg6cbBE9Zd7QAt7QV>k>}dcAi+xr+FlKf z4=}xvvK`9?3#;_oiCn~g6db8Jcd$2mO!wUL$#f=lh(|WM(aGNS?#)TL8sO0KKjP_h zuvPJ$Amx!^uAh-bfjFej80*5xu#+vmQ5!RXaMAqdZB41s?bX-#Bo#F~BP1tpty|(K zu`_k2gScwXsZT{oej#+ftR&jp-m~FW%XSi*MpeaSVfd_|Q$z~sLcIk;RjxFo|FdL) z@1la#^Y%X#RIq$$(!e1?0Uv8O_=fcYU4Q>J;x3*o=v=IRc#qdF7nyH{dt%!uy-_8Y z6sM^^I4JvvOXCZye?>9r29bSmXzRORRdd zfMp`&H-^9d#km8K1tvhEoV_WHV~G>HFF$cb!z23H*AX|sqVD3Mn2U#jsIs8n7N0a* zY+^3f{;onfcw4jV%B@bv)X9FkbN-XkIm7@i@<;HhXm+aL zEtWq%ho?*ObFloEeq1P+7Ym_UqS<&s9=``W!h&)5Y$)nikAUOCRe=GUvI}!~rEl5JBK~?B35EzU%i}>$jGFP`dP-z4zJYd0zYd zJnwNjuQ~)eovqA3A81voGX!ybJY+)o1BDm1Fhv8>K%#U&uCAOzDHQ{f&9ok8F{ebC zsAM5zV*~RE#L<>O#e2X{M)Y&oJMR253Ik1NfC^4WqjKqUzL66c|K9r(=>Fj)_+MwDU@3-=|x1DE%f6VCCp=DtW`ne*RJ#2@ttGx1iz38q*`gX5(#xO_Y? z3d>6p&PxO3Jg$qPAEaP)Dov-MOl2bNWq?&$#4%xB!6Yb}%#+#NaKVNWggpp|IQ9d6 zVOePXbpxQJ>|MSI!@6s&-|@+c;mtI{xE3*@HIok=kT(|^-#=ij?sm;XqtfQ+suA$o zkg!GO1P45SsR_Z57PD8DD0g@#&yTgs_1Yj~&r1?&-XPc~+g5_-n#sy$<*!KPuITwy zYu;z#JkF`zEBst^+uGQ~QrP>^bxP1w^CAG+FSKyL)g(ziS-8&q*sumMGUbQM^4eh1 zz_Iu$4^&Q}$d#RpJD7r;HuPG>}PwdCUV*D7l)WCL4sam&&> z@&cYt#D4e)BrAVTu>tC2)A274ohgJ}mxF7-OLpncFxI#oe0qa*Od|}O>O``q=$f7j z!%(cSz&+J=J^OOH=nm2@@#cwlsb#01O7mZkqS&g6)|=s|H9_JWIM=Z7I+XKCm&JL> zhrP|-Wm0h+Fa1?OK!sDUmS-^h7WIBDe#v<*H z?n8$w4br^I`6%)Hl#eDiIzncyN!fCzoBGZTHDyrIuF1_SpI{hBesvtcT}J^*{SSDC zkV*ib+GlBrs|br&<{%hO3HJ^B96{$E5Ps?BU!|Id^}Y3=$oH^z5|}Ip1B}=1E53|P zeBQtx!(M@-L-@(6MMLMt6NOfhBUBTG#T`fV`EuXxg1W=jI`v+U7P6R_-Ui2Y#kR*= zcO27LZ(4W^f&A<-y$WAv-(aa|#2+V|O=4|PtxB~{r&I3t_yV1Sx zdxp$uRm4I_essj8^rz6iI9BYeO`%#M9;gi>b8?eAObWnDi~F|zupJR^(zY5Q1`wS(2&W880|H0IF;&SX>1qv3d>S88D=U# zr0bnS2ST06M$Y-}F)m&dTUZmb*)0Pi)98Ci7RX(NcFMlDlBQ-^XVps&>;BvS*`$6V zTOZ0BcfDim`(P(j(9EzMWmk$UW|W^y@p?Ea3Zy+v@9$)o!|U z?j?QK)p!C=XyKisSUpmAjN;mv;i>qr4!lY)akl zvHIXj;p5nhoRt!*(mPG+)%7}Mkya|`QD|k_Xlsa9Zg*5JH+*D!{AqJ=mLt#^I$bC! zxP!o#K@K8l-5Ra!1gs4f9AZHMx##z2HWvz5Lp0abbpt z2E%B&avq$uyC>`avaB?JHlu6#L37#f4G}M}2Jq1^bS5VW+qE#Z_0A)}gLGuc4*y|L7ZF^i9< z$*CjNgN||hOCGt9uqED)%S=Fiw;AOX7?_iDN0NM8@DYEl8(!FB-fht_Q@9!~Y~&I` zt%tw={dSJH3%Hxbr^akwn*crqn4E2&rV@bGsSobCoz(ozrr{o#68Y}O-gEF50Z85} zcDD{?O-{hQw@T{GMZtdekYG{SaSgE}+V-$2I&z1fjs2OW{^@ZMY!w`!nx7~caS(@& z-vECfRHtz|ZvnkRe%D{t_1=baW+Xidm<0J_wM%Z3X&P?~lbQOxM+RLwN(~QuMc_Mg zCwUW%9lc5&Xt$H!V{-B=<`=j~h%+tgHK?=0X}gu~#UZ-*QsfF0$?Y+{ZZ+sanwMGy zB7~m>%bl^%@1L;H8E`h!;IwtepPlc*Qafi|>~Z_!&|_Hv(um(_cWMHU@>B%Xlu_~k za9FhM7|h|?WIxp+o9oB^J+b)a+wci&ocL_U;ZT70Cn$oFmnLU;AqaQdiEtQ!o8er3Nw1b@^gROkZS? zxrp&gK(0wi2P9}i`@1L$KS6GRp};*qBo)WyH1=P%qwYQEzVr7yjWpNyt>t$ECb_PO z;dZKL;q-Z)51hS{5AEbybcs@`x}&WeWxZq`%0M{C&ENeh-jYnD8&}`1#%pDJRdE@x{6Rc3(F%F=L)bRk)Fh z-)y9!YEafXT-|lWm47Ydx!1sHz)D;A{hixW5|;cyNe3e(y@^^#>33|l{y}HeJO|3I zTptGmDb$ISwx*`LZezC-!A_oMzEtB)`F&0^KJJ-@aBT-zz7e9A@NSA;RM?g{4NcZ^ zyYk?g8m9dZwd+GT^wC(duR7yx1!16hx^eb1$)XMl6K4?p7ko@e>gPnkli zziOVA{jgB&x<)`8DQR}@dAGYv!kT+d=B}3CFUx_(p%dofN2M)&@d$YntO%h=GOi4R z)h9lqwy%^NR(5f%xs4X+jJP)HDnSjn4NPu% zn|yiV0zTJ;=7El?b?Dx$4H1QO(#9fQE$(U2UXxG{0G9s+nvPB5&wiXt)Q723SRWpQ zpR+=)+@{?na|WmE?@Hg6avcSY_csBxn$=CtCo2wHGCG*Y)JvGBPpQTnsk&+$mHwFEZ*B;WB5MhWtfUbJ9XHc;BNoUp4Xlz|DN6&+U?{$*wflU z!h3y=T|#n$r8&Bt|KD=W-caUZGg-B%M{?v;IZf8EfyR-h%*C@^UBdD+^Fe7dt?`pTf3sUfl`)47PLdPbo!KEJd!tm)pF$AOczwryy(fUxEeOW!0XVBE7 zQe~rb&`|hC%_}$D9oiG;m93p{KeRRbAHl#yfVrApD%u#S0VX9-Z|10e&U|NU(D2~& ze(v66jXmH?(n!Ny_gc;19jxX8W8}y~!r(s9mv`Gn|Fnb`=*$mg980LF0CxyA!M#rHvQp^O3zfeJClIB&gNXM)9B71G;0 z4|S2bA?mg3!)GD~nz2(ctUOxrX>|J+ZkiYzHaHrwd|~|72OkJ?MElRwT({zYx|B9& z3v`&dvR~%vKvx~|s@TEiVR$Iw8e>Y!_X1s#t&ahEbAfBKYwQnC?QDLq&|+|y4y)(2YYqQ zegi7*hH{H3@3x6ALAj4iXTw7as8})C%->ngdNmbRdh&@HGq>;Jd(D__O0UHw+#%^rhl9+Mdr1Jv=jG@<$U-BP|B?K2nE43X(7FvSku$jUX z(V$x!>f7SaAGZ`P7|2U6^~C3u_o$3K2@Erb=BcB#dt?_fjdAx)pVQ1nZdA5A;Nv@r zDd9jKyCZVDxOo!)(1slW(;bW5T4zJvXhMWR+Th@k7RjrL+~HME+_>(wyCx-xmgN@g(}5g$g{zI?6H` zkt45YRfRo?>5zHp1!dpK+0xnbp8mCjZhhs^;q(6rn+<&ve%t*bT^wAscjgOI*MxX8^$Hvqea__p=)%CyS!E=w&n-@5 z#?$684Dg;}zU1cLg8Jl<$3WIH@=~~u&RWX(D2@K%5~viSHW2sK=oBX&)jD z+-AOc2M$EjSU?C^9v(j{@uBBTUemG6Ek0Ed$p$72Ncu#Ov&%sS${<;>I>e zdFA4FiBn-!*I?baJhJqaJt%K#(U2xN6IYeC@Bn!GStiXiw~OX_ zxv=qE%<4h3_uxVtvFUS!~?()I7q830?;*2Bi^352X`408B~GYHS`e}X6j9WHm>J_TL@T|S zR>n-B3^5l*+^di=>cbea%uH%tgjmR-w!?fm1~pJYiU7VQaL{2sn*ac0`ac(la%_^; zAm&LN>c}c^NP~}%L(LY5}lcVg8nqkcZ5@Z;- zfrLMU0HU!zz>Ydyt6wv=n`4p1H&#sFVR9juIEb@|8jY661ro%2XV=j9ub1ZviKd~< z89#*56``=9h1g3m4Rdv7W_x{M%XugE{-&WR_7xQmnQrT6;dlF9RgBBOJ%k*=b=;~V zPE~U`oo~`v@g~MKN!vO3lIwECmJMqY%D??*R)8oNczq&wdLk)$q<+!pk-&#rZgwux z2m=40Sm}Oi*9>id+ypfny0zDCQ2FjSWCOS$0Y0asQq#=aQTF)xeG3qwTIe1F5-% zC%#=PZ4-m5aM3qJp?$hu6H_ixlXl#P_^;eU#_7Xbdgu0BUx$^-8&clVyQz?<5$bV3dkF)ub;sBrnk?im?Mv1J z7AHm5;X{#wYiutyJ10JM77eTzIa|>Eh_$WoMZ+5jv{r?NbkR?!H>`w>ZPWnV0gmr; zLhoNjYw3StO#H??elN=<+Ozu=S-r4Wh_Ec(%k?eAjv~FTN^(Zi@z&7~v84deM->N8JH$7L*K@GLdu;#MCJc0%m8n1Dw@MO=%Bb$-E z;6)c>FVC(dHZRur%8KtO5xrX_esyHWnyULZFOsoQFR_?-OCz{`S7Y_eX}4%`cM=O6 z0NzohguT6M)LNFFrjxc$bk4kX*~ojPN3SKxo;|M3*8e2P>|sY?_=^-6*gbEuJ{qeN ziKe`>QJqPWq+(4)A?&&Wiu@<8(*(7@>Is}_KJVd3{7_lAwW{Q5$Ax+tfl4yQrxSy> zGwh{~O@rvEHCO3oIhSFxqdpFGU(6=M{EPMLo}xKU2q^iAxVnz4lf;sY_74(4D7%Z$ zO|kM~F8|WWr9>xjS0WE5eoZGHo!ySnD?I-x3NCX`ahdDKH*NBa^mI`VjXA={4O?vA zv7_TJsn$>FAKYkRl|>)W>!tvB?BTO@4P{aArTu?9_Rp{^8(zJPgFRRHY4dwerZJ1ci0s#Z zj!qmlhPR1#`KFZ1s1|;}#hpn;aFPg~7j6)o3*c@BKPDR^^a@DY!l$%F>lJq1ySqNJ zLPY5)2k8i#-E%2dzAJ7*3VkL`okpj;mXa>QF>>wt$fB%rg?6mRjMSp$_+VAh5j52X zczOLF#Q5O&4mI1`2~k7%yC&ei1(=0L)j72K2u^-cFBoS&0MB09Jn=MN>-si7IHCefiGD zeapS2m72~Y^vMhf^ixAdraJRW=pRdB5TyZkT}LJr-^>F$pf{y(ZI^=B@L~uRKbS`qA%u4L`!yAQe$M!>Q?YsgR%+pb)k$mMlU}oz!%T-ILVIfSO;z5RPU-5Fvgpg zmBw8y`GyKmcLW8n;tDh7zY~?A_TP7!ZEa67X@ZUg4=ztf-Wyt3$-2zN>0KRh_}=u@ zZv>uppE+)5$0ZJ4;*F6vbcu>!wLq<{Is&r818d0g@0e}@hu&YJOF9PR z+>PKbwvPlUtUv6*5Z|P{9Ap`UB+8ZEzu6r>F0}RsRD9QQ9X7n8+XuI39(g@3ybSNu zTMscqvU#rdhZmCuI=5Fe;y#?oK^)xNYBrJ`ceNB|hc8_44>)l5)7^D;K=((BSiyI@ zcNsOlb{c>ar8y@jT&45fYTOr@et~pFQ>>!Z{HlIv^S6+3{#ir9E6?_m{8htIqT)^q zOU;=>aL^b^o}2s)OHE73*1}&CUu3>-Wp2j$1lG3+8_#@B6K}^J0*##`a$HIPucl2B{Q`*FP_WSE9jI;Q(wRM4T?Oj)ozXG%@Q5WURga%q_d+V&lUbd2(7EN!Ic>Td%^ z7RW<480*$ktO{tP_uKO%X6h)(e40g1jlpMz(3c?|52_ykWo)5!Q*K z4t1fZ&vQ4XZ$&7c*4{@r zV@?Q`C4PD}eW#2-WY56fO;u;%Pak{|7?QmhqZdY-C2^az?=aeVv*S&*p~|ixF?Tgw zqBcstVO;Gku$JGq?@8V?!TA zm6zldgdA>n-wwIH}14oT3$JgZ{vl(npaE zB^_qA*Gu)$5wr@wE!+Ik?jA=;2=~=r!armWZEF6q&tqkg_AZjm*mIbmw4cAMHc&<8h75F>T;QPAC6QJdv0U zWa}|IBFyyeUCbo=X#Jr2xJeUBmUcJOY_Ct`DBKc;funxU?yQ>wt#`;QU6Uu|XWkku zd8OSiYBTbLFTNHZhqn*wS4I`cdAsCK419{YGv`6!&-ViU+x4st>K+ud!Os6jMfaGW z_teajk5>0#W5Uo;o4~vFgNr1j%k4)u1Kw!Y(0MACs*?@GIf~O#9hP&{i7ltXp9Cbi z5MBZ!$JD4wm*+rF&c2{4SGlT}Who9KBGYrzk8~F~bjyo%NPx5sV5C;f#NTd>-?Q zL$E9acAHzd{5BetoZhyz^F3;06kpPOhx|qs*-;>cCty$Vz4gS-nEX@n?fsIQoTvgq zETBUA@!#zS=sSP-(sA)JjXz8yPHW=9&0orOktM)dJG!ve81`7Y)OMRjB3SrK4|qPu zbKAL$CHue${fXI7^kMrQ4#*GSQ0H4}8cj2`TJ!JtV5;EB_>lL^L{v$~Mj!i`kUq<0 z8Q|&Yx$K(+?oP9kA#N8;)qjG|WDXpwqwMyh^^DbC3c<(!!bV!j#9vRBvIX z{4ccrsiY$xq*Mhy41dIphWXOFgf9`{`U;(O`s@vQ)`wRlI?`fdtknOVWmo^QQVR|I zPr;!rlF%-OyQT%ttpMeFb` z_6=q3Sa13BT82+>Gl`HtOX%PmTa5MpOz3wQQY(^0=E{+Qd6oN2VVHuQ9Y_$S0pCQu zoe^HD{ms*Q*zf&6>_I!$6)6$K#9X+}3yQ_}~k~_pPK6>(j(&ZnZKrKx+)l<3A zaB$&gQUG-EbZ4XK|88i?|L_ef zN0SNv{c9?X1~CX(7l$Ag;-VO*nsR7sfBsXk3E}o9ulSRN{D1rwm!?y|AAFGX_aDwP z_=-~UY~b=XwDNN{P1bIFPd?o{-wN=9Y<|?NO@#vuZLn3+HXs?nWHdfA@T1BL=GlBe zy*0_7vP%CptN3BScv1Y0QAp$swJMv#Z;OU2u7j9!lQiv+-4>|y{Flnhj1q{Tn{$nx zfB^(JT>M#%0W5(YjWP7yZi76O7=0HQ9|$l8z=iou|5m$4!w+n1yK26f7Bz&8KKmt; zztdu7f+;Gdi6|G|Oo8SFO z5bqIg8OuzofjiDe`h}Xz#|%#uhgI`U2z+J#>vzR4F1`O{c_f?5jCd7i-;at^VPeY# z=TF-nBbRRN8p13#X-wUJTi}soHj-=N&GYNS^Zr14>N2Ja!`r>ucbg=`f6nLzS9#O8 zM7Xdv5DR5Af{*){ON7Ty?NCiDumMF@Jwy4cs6q)O4&b-GR%$Gp|FRWNP&L^8d*W(N z^4Ul;%ElT_Y_1ztWDzB@AeuY#g?@Pk zxbTtrDeBSb{h_ieqI9MKN1V=#%$^Eo(`sxa4IEvs)T(~@(kSb|uz|wb@b)?a%Pc_7 zRSTWoa%j0n9oWc*0D3EtT;~haTqb@y#;~FmCa*_+%XzvJSSTF*7EbQ^g%vX(kHbo9 zhc8Q(rlYS5Ee32~Sk9kf8xPIDbMJx9pHhSEdVsE!N#>sph!UTD)lzmFA#63Q=?Pmb zR|2x9Fmp+BqOE2XON&ckDD0nte>^T5SPI9QPxSjTWf=`M_>0$hyOEU+VIk9|s$EpO zCdCiC7n7aI8f2TZ6HOH^YXJ#+@fAX6k~C^^Opw2BvYo`tWu>4j3@`9ZftmAUh;^-qrS znZJci$0{DIX*BMKMei%k7{l39ZoUXG-F_@+2Xfz8yyF%ZU1ThHS2$o#lX=+d%;f%o zXEq4D_6^QO{^z7c?{}-F0cl3{SrEtz!zBh^a$|pLlY<|@E(7==iCbl1C?LNU!RuN& zddSjWl!Ay#5Q$qthf;cd_JmI8J!QA(BzQtf4IF-Tl${=E6XkXG-C%ds+-~ByzT_a;O-2HT^a;*h;ILG4zfFKQeEwtq zQH&{fMo8v}y4GLHV=JOyA1{M0peMf)&FwbQLKZ&ZV=ica#8)mAutjAdj!3fwJATv-z^?u3R{iy^{$&s<4j5t&Tbz&G#Fhr zDh_$Y00-LcUsDAxj^5}b2k*DFJgY_dI(9YQIAp5nWPNQtI5s7Tamnzrrz}}>bIDrS z6cM%O$w~m&W!3B3;XCa$V&{GkwaQ6-=?^9KTO5_v8htimO<)p)h18s?>n>|#JOiu) zNqJghPuR!{mum>T6`>_GxL%-I^OF8P(&b|?!D)EUOlZ`n%EJ0h@$6-l7p}G^BPnEnx%t55oedVg@#EgJ z-&YjkeL?TKunGzW^Oc})cF%h2&bf7YKfmm9XibHaiQudKqyve(^-(tp$xHpA;Z zWJivAX(z+p;+^RUUe{HvNsX~@+UOjTy~G9pS}NYg z4axQK|ST9&PA2*Bg}?*G#G7-M>}BT2g^7Z zsFh^pNKb#c1`+CgKwT22Ba1PTS&mV^U4W7MF$apN_hA;r%dbs!aX0(W7n^v)e(xEo zUzf<+HIXx!sAxUbn-vOgVfU88I07rbMY2P(E}%Pa%;eMwZo~ zI^O%rs5^^g-R`Nm6{)l4V`{qXsjPARF`y5M&`F+Qyhb^((N-hd;I~2I-u<7=^x#DW z3{J_RfY{5h6AxdKZ#qzpXIw;EveslkR4d!gSdz@YZl-a-=|65k;s*+wXMGmI>M}Bx zQ+()OCsO9Ng{4>slIA!~_!0w>$=O6mX_fF{r)P$6wTbQFD`(6nJ9(3sw`P9H(%pb3 zgXLyr`oqY}no!>9zV#LLtd(wvUMyv6Pjt7&-l@)=h{X_M(#Ixq=cpw~e(dI3gM z?Gf!UpCaAe>8_^`7C)m_mDtb5gnaH8D!ufc$p{^E=2-iC3QTbO=MKoDY7YB@;)pZp zh-qF^pFS1CRS6#QepA=g32;5InIi~XC%D7G@DBTzl5d#c`$&eu4)N-V0!v;P zwI+0z6*1O8|Dc`Kq_S0p{_BzTJ`sq9=&4KR&

    0;|2y5q3Lw2sFo!%jK|HG1x+BMEl&YoH;{agOXX$Ubh#U9zt-b5t{0CzEQks zM!#M=t9Q;Sn%H?8!Z|Cx7QtruEjK$m{;|@Dqc&IcD*5@Jo7K+7j0N%ewsZBybMw<_ z=#jZvn$JazUGqWiiOcS}%J-|8ZVxvjokBh}6QaOlMMFEAP4q5P9wRA3{-DB-sYmRO zyy_9p$#8dvpX+t zWY@(ib~)Jm(Sy<8AV)Q3^SsS3htNQPbayMmL9RK9Cao;fF1Ac8K}WDN$)3Eyk1189 zgX59$Q^GdUAFmn?9O$-T+s3_pwzx`>{@hZlvgCA4V=FWDhN#ucc4k~SINIwV7gP;I zXEGpGmWt7I=V|vF5Dq&RqsWAD$y4hV%B-0;@+EI0U2O)^GK-zR0ReS=L_Dn*3m3x6 z#w)&Y+e?;5crQOMxyH80fUncl_fScHJ4c*@nO4rwYfPU~&I*g%^jL`dcz# zPF<8V?{VGRMngMMelX}4S}3pX{e#!%dM`}@U~zgkvN^Sh_9s_#0MkcLoYGZ&p4$4Z zgLnE*lhLx4Wu<#7bB8&tOKUM=!8m;CQBhS*md20t)_k$UHD5xYQjLB5gG2{(J$ zN$IyTS!cvn1Zv-nPMTCd6tf5vgoyWwHS(i3oSo`;w%JKY{WiJ>Fk3R=oDO!u>ftyC z;2=F}F1dQY@0SUmrdIQ{vZfAMffd(P9ka=USJ>Y$a=M`4&Vl?v5ryVf;mDh8?tg1k z@UTx>^hjE-TIeR)O(F*Ld|Df0v%;;nr-ZwufITqNba$YoI}DEr51#LmhtG6rhwJ+o zu~!J*`nIKbIW)J1Rj&oGxI*BUp@#kPGWTCk0kaxG!%nqE1DX8m@zYXZ8R176|z?!jwP zpre=HxVM_);I+=jAGcggTX8(vjAy6%ut6(EnX3R7g(LJzHvS)idFD{S%BD}%Hl%Mr z{L^;k3!Bj@zAs7KmMT4>VOy=!)%!LQ_XS~MyC{EyjiJR#8`kAhR*1e6>oQZC>=NbRqV+n2$MUuZ{9As$&hUstVCy_HON`^@Saz*L}aB^sYkO z;lR0qT^y_6>>ZOQMkg#Pak;XnP?+KVKq4b=lt4d7uG%lsD-h+`1w_9_3B_i0Me!GD zL4m@E^AJ0QkGehx7;Kj~l&lTgA2HL_^_EF6{&EM_P5W*^rbjU%v-_nMAZ9Xg9372r zIxUaOw=@pTu1b1+js_~63!w;FxaHMRr0k&4tAmKxXsqPIAUQ6gfFU_44XtkD#G*jsgEu*OUPv8O;vlq9@hk+LPSFhy-9RKiYc1BbTbgg#q$-wVj z!^G`KtQe}FvTCW9jMq0aw!H0S-J0{h5%H?Qy^og1A7x)Di`>%5VFYTncpwM;k2^Ww zSqB7g&CN40-&m{wRK3Kyo}N8uxR+HIqW&{odjS1D1|(~z>`t9KzWVbq5K_Z-db=D+{bh0#)#`Ip zV{zvoOnz~(|FPNpWDRr4p`HgfQ=~4Mezta_y1OXW$Iv$IA9_hA0&*)CCg_im!{r9M zyBwuQP!u1|*hhxoxZ8Yoemsc|_85=4XpnGS4ekuZ2Q+2CgHx6l8Q}X#4O1*5!NZM< z{0xXb|>1Cf3L51_BZfNp_Nhn^Uf|OR-#C1p*aKt*{L2%$uk&c zO|ou4^CwsX(C)gmSaE@uoJm{Roh2q+%qIu=s^z84g=a{QP#)sx`xQGcTIM5W%cw6) z4&ezNcs8PlNP^kP*9S`@3wpUWgv<7iZ^X4>D~oU&LOu@}eUp_u8pHUA<6pCstOtw& zP+zwb?PHTl6Ur?PG_3s#>0H!Jh22vS)G;rM!CE;=mu6&4vX;`q$(Os&-aQ{aRxFGm zps14;#P1G$qI6E=D^n55$1Vf<>M|RKx3X!@#auW2Qr9g#v%8tIH3y*uWtmC^YNID) zcgNNF9P0W1^BN8Yo*(Uk2Cf4kVp*`?qU&fzOL?ZjTFH5MgXUK)tj4w~pHF`K^)44Z z+V!n)TsQiN9fhUhPp7QNgEp+*Cb&6CZS9)V=uB$*m|lZG#-G-Rb!pK;|5(Yq$c4cF zz(?I9WRS(1Zsd^|1#b0^Zx~s=nKx}H_C8;pXnhiWViIGInKk}QHo{$b{y+FD-}#Ly zgXUlC(27}ZSp&l``RB+X;;%7nIvy%ex%;qAx`lCWDPw)!TvIp6PzIX>5N}>PQEagV zLGFan5L>e6clZ0)q;g9w)E`+^m;=VjL9FYoOxHMq_?g0 z79YD^z02J=pW;VR_^tlOl#LeZa%wRmx7Zl1|DSikPsJN=UP7Or%iY)Yh>Sw5yM5+t zUjlf#)gVwEDZ8kou4k{~ez)5(cU*%I63;Z-`8A!ye~7FNXyQqdu;!0&3bm?xzUHNFT=8Bcz#ft~7rOdDo7Xs~U z2np$H6~sR~8z zCjIYV^gr^uzxS`&zbW{;1)%+B;t+QCuS2JWLhJud%1^+)PzL-@it*Q}z)uz4pVPPQ zXochd*9Au|Qp|7&!!2mJNF6V&2$a9;H0FFl$p?*zQg#^e!Nkm5$d^BrZS61ZB8x`4 z_>KH|1&T1Bm}0-zCh*mXgRz!|yv?$DxPu%NhjBqs4JCrK0Y%EmY>JT8l`3U!AdGbo z6fNla@9M<(rL&=5<}M6J2o_kgx6)=vyWNpkCM+g=`Pq5kU(xz+K&j{k@R04M1xD?i z^4nwn&O>&Ci(&pMKNWhs;6+xdV@di?In&L6_WpNLSB3%;n9Znaa2;C3r!*ifu>~>C zsK-Gg7TL&Gi^^ywCJkqP>MqYN-R>%*>KO~=CSE&M1V>crNV|%g zu+PYs#Zo)L%8X9mj9mHG>OrB=H=?M&<~w99=vsL7Og|`EE$A?C#+;q;Hl1> zt2WA}hzNV?IoRlxW!mp2o;jW?==El62@7U^+zGLhZ=HWLGKE=ThI9W+oWw(iVxwUH zURr>J!HHlp^6=SG=2sMQvGlW>Udy(!=~y$;&3P{%Ai0qmJgp_dt}z%CwX428F1|2c zwVADj2_4TJ_P1{^WS`fl?mUvMk4HnbMH)fs0yU7JRG&Y!NB?H}A#pSmt(hcueJ9MU z+thdOPKRZEXJi9p3G>xe8>_DOc|=QEpgn#n=#eyKoHL&U=K}h?**VkpM3@zp5XO1B z0;3L_Keviu&#|2Ofjw<^Eq8WmFOAe$cZ_IOy)m|8e3s<^z!Yu*3C5k<*E29+~ijvjzF9Bvxt>qbaaVw8rmErqdE;2YIet zdiN8zjW?WS`>=xpm@A`3F1OcwBFsV`;c#I^kXloX2Q`7yrbj8%vrURCN>Q zKWLizHUEETdVd(gu`7{L?o1W7XcPPj`niS^u50@s6L#)oaVmkJKZ0c+r`?c`&1PYL zt_%TBN`3>Fs(AHDQlGwiCVb?MhmTnF)3ixYd^Jjz$*H%Am=NV1hk1|FFvE>^(#LeP+QpkN{JX}}A%Kqe?~Ua90<}Kno_Kujd9^;6@<)%}R?4H(n#4! z&{qT;HLEK~7l$lwc-<7+SGnAf7&@^MFdFZUA82}SnN_?st72jKR&`h)DI+RnuZ{v4W z{GOtrhHSiVwQcR;FSp7@LkB2J76T>3Mh*U>w^G1YZC?OT`gh(xP?~i=Vl208(PSyv zqVUjW)j|MD-~Tt1-XH(}6G|`IN9ws~x0Lv2VRQVDW~3wfj_B2+vH83YuA>W;&E90w zEg5RT3jox)eN%yyWE7cRoSp>XLO9PiInO_zG##QqLd5K^oJKfzzsV=;2(O~^>UkK3 zkL}FQPK37dzq7h(eEZ>HAe%iLxVKZ@R3EEtql3G}M0CvoVbm%~1O98gKwA#+i)tvI zZ`3{ubEc77iZ@H5M04S{XU}k!MA~3hL;F12?{m^qAROe2iI~ZU>YZs)O|2J`&J}~P zQ6B$iDyQ?EUTbsSDf8 z>Y9&H=ms!~T^eQOz1+$wmW%S^S1>H*XaL!GCgE`|evMLQnbWcp-oN z6mrHDLL-Y|oZIPu%vAH~N9kO3Wwz$%SHYt_ri+8`OLrZO{kVlFx0H zt-`cx78zi~zkG&OVrOPcO;$6*X;p6`WBg_=BC6^jvr~E|>92#@1!PGFlsJ;|E^=I` zMbjP-=|4@wreM07Q(e`ETn1WcT&)Sxr(%u`V0CDS050v)_mA5BIM{me%@BKhbVU_Y zQg2m_(eeNM2+j)%j32Z{lr__&+c_&oa7g#~1OIO?CseZDRhA6wjyy9AlfRLHmxh9) ze?hK39r;CdYW`?OL^8ds(5O3d`>#df)Op*WXqWa7aF=69;)e{cgos=P8=w*)tH6ct zqe@|lj^Pyn9_s%?&r_EMvKZjVOK!>H=SNmGZ=Z4`o-cjmFsLR0#MKREQQz(jh566G zQVtrcmO+FEDZcBYU=Yx-5yU{TUzt)t7K2Te`3GfXVc~0ga zECY&Uof|wM9bFP`UMn`O^BjG=-~&wGv(vJwJ@d5>=o$vQ!ocPV;m2Y&&qA8F9zT*A z%)U}W<*B<@aGX1eBl`>97%A-V(eE}!3e0C8RRrDcq(xFST8g>bWi?e{z1+Na?#30y84$*Y4nPe0ci8>_IJ^F?<*l)H{>vvE;Vo*v zF-e7RwVV-X;2+P5~yKDtaKf&p9ln)x&-_(|z}I)D75L1Y8ZcM!M_GB2704{0IG z@hb|LwqCRoL(Q+%y+71s{(!At0uLX82!}p@z|hixML_XGXi|@Eb&GQ;3dTT<0Y)Y?2VdZr3^3Kw$**Aktz6A zp|KTr_#;bpSRkpQ9QABQyciRC+Nw2bbUPRPGL#Kc-ST~g+4+K+2K7kMlVUn0?Qld7 ze3BxUbM!E80oEz=7ffo;p1Jq`!8$EtYYwlny*-ePK8*3k(KPVcrAc4Iz0&U>&F679 z=6sDffcfsG_#q0w;Z)&C*X(PEzholn7HQyqzneYc8B4GmG#l+v|0p+DB0XF(_dGhT zeQT%w9RB)#Y68UkOGyIbO(!~PBvK<(V8pe38m)e)=Ss_j)n^Kd7S?K^9Xj`|g>fM; z#MFYnI1#bG$4g0RN)7p<;o|2t3$uz@O9z@w3;_?zU1P1a5uqoTZznryhkv`L71VHv zZ}sx9l&|N;xeJW2r>3yl2ta1aQ^1;hbPPjDhPDmX?={M7?yS^uWQI^7M9rreA@5$u z31)U(UkvEWJUcoJnF*Giteg!uI=aWx!Kn0FmuU7rWqHsI8#MCITO-}W;Xc@Tr9P9c zcRU60G8ZwRXnRiDL7D`PCigzeGTS(#DY`|qRPFD5cpq#DuNsqA|2tjo)B^oc&-E1z2VXNehBC75o07;K-b60P)>W;-?y__B*04^JnlE4(m<~)>Y=k}ZGEq5 zcM`}%)I{xv#DCVF-VdCYa9^V5MpIbnmQC6nru)vy-L86JD?@+`@(GQ|vSTn=vqHavrQzwMH$&*eSqPsJT89(&rQS8dq{nz66Y}AUF^9 zuG6k8eMqk|eNhWL^JY8zrRpcqA8XbDAFN0H>#mYlIq{nM&YsM`dkiBCVp?{FK5hKe zaX9Gp3YkIph9m%?97vT)yRA(11+EgKrV|aV!Yibe!w?SFYw5SeY*gQ?cK=JY+ec^v zRTiE%o)nPtuZ23$8#6oA5}3;796NB(xeVWM4AH}s{VIrnouqg zSk^;b9~ez6n+76HR_9smz{f{qY*9_{zir_U9@}acI3J^J4dx$2i7%VLALpOE9giq( zLm#;m&exu>!+D)%vW1`Z)i;YS6jR*Z=l1n3u4UI1!BC)nQ;cHtE4zMQrktt|FdE)< zP35V^^&5l=5gxc}&RtJY%C`#DET&Pm#SWTcK7E<<48xCmMskP$KqOqe%6z{>erM9- zRWxneRet)&dYS`PLe$Im_oxJf?bgk6d8BQdXw>zl9^u^Z_kTgnG0wD6(c-8^cEYjQR%&c*%5Mjh_R>2Hs0*Y{^ z$MuZCBs5Yb7|SiDdqr)mw>FIIFLRYq1Dc1BGmPXNpJ~pp5{*&hQd$Y+_M(szC_n>shwUgOJNT72BR($20Tr*dXQ`@wDD{nwk~&C6Nve$ zIZb0vC}ylQq%l9FLRGgQMyZ6pDC)m$?(Yb*b&%I--L_Mz7+p({x)}cS+xCbB%>>+` zu$AX{vy=XHwtYSzWOvFsCyx`VmLFg+Q#Ua*|hv$E(NExUqpqmM^qvh{dbk{Ol6dwfGA!16O^P5UcbY4!@ z&PT3;hB0i!X((=#j*5su$BYeB;1zmOY0C+jCEi&*?=^*Qj*f9xYznAdAEbECNXf>y zH?t;%LbB9Y7ey^0GI7=S?q4vMtz!#w`_-te1mR5tjkCd^QZMnn_Q-g@j{3I!z+0fL z_O``On!D{)rB8a`%xt?}oqqJ_Eqq?WGU8&DW^O3uZn{?{^9l93?M*4rc{p=T)KC}@ z?(sW!PDdC5?epDOtRbwts(i-=2YtJQ1i8K{?r*M`@XZqw$Jxs<;5t+g|K9q;T&Ad1 z!jPW7mNo?f3*EJHj=9pYJ(LbOtvF@f0!nwwm4xwX!nY4l)Ak73g#BzlDPk#1iudY_ zNdnD-#-`oZS~+;<5PD4M6T|S|>h-=Ah1qvae~h8z6s7IX^;t7@*S2Pw&F`%3jjSr^2gJhOzALPc}Y4HV&?E;zXo8S z^Cv8?C2lb~-Ga`O_DUOXwxvk{@bS)NE6~w;4C83$i2rULxL;KM9-kIDIb-FK?(sf_ zcYuk1g={bXUBd|$7C4bqK0E<6mDneYgx4Ry`)5YuciGi8IsXHK4d1iKA|&A4_Fb{p zFkO7};unR9@Fv*95MKYUV@V5K;+M^TW5_`{26Aq+ZAib*i?P@EMe=mBK#N)kzq9^0hy;|BiU!)aHYA6MNl|FNil5v&2l^uKV^|50Fh zL?i$(;E=93={i7XA$%=K&Be83EmvsmkN5@|_z1{q>^mk3S9|9uo&e zbp%1?(%xG_i|F}>m(L|pRw>Ypl-a-7$FC%N#CKrJWV&=2{Ah$+t#H@i(k&g5^=P_q zV1vh!1JtdT&^;O!wW3)YMhi;l85SV28razbhKA+2$*Hl*k zAX^~S7k)@CSQx8zEv2H}Eo`qyuU<8yrN5v4b{X=7319kPvgB7W+&jN<#5t4&Q70Gq z)6cgs)9MXl2?Ddo1DSCEKmW&9x2oUlHN#;XanB20T#>Q;&XSfu?chJA5=6=_r;k7;L-%=`sZ@7;l7{;c{6D@=sTt^s?Kd#0hDn_ z*G9-Y2zJMue_kJr(c<<=nQ55Cyf)n)m-)+zMxkMp0>4M6ra+L+IHGiy*`8DkTN6uEmFmoReXcz}XbmvimGHNZ^nSzbXp>-FRbM<47ns$OyxjRk{u}PD)Br!A z@O&kd0_1I!Q_GW3Hy^V1c+Tl~A|%*M31}zh_Mn(ZEw_n0y)>Iec1D%9T^jf@-s9A$e{4cWxd%HsgpOrQJ9LtU^QS*Vr7jIYrjnxE0#a&9-_^$MJw>Oy1nH4NRg>hc!J$ZXDZLMZbpkf+C$(8#!Pr3 zz#D4vjnB+}N1EsL9G*9!V6g2Slzx8np~@5)78lR8Fih}* zCxH$)t%Myus=wo-0efLFl*r4iQ$imUSocpve%)o%tL46!=>?b>eagClv?@J`=*C8m zT~sCHKOAe@Uc0AkvN9IVsO_;@IrG*%ZcT`PZ>`bhDd&@>52(q@J8OFieX}fsRH~@4 zi@GZP_9+G(!RFDl3qYB8Pj;#k!M3OsmAjlAl^Qia$~npWed@&xJMo`cW$s%piWi1_ zLBh_cTGqY~hu533k=O#ECqWS7$kFrImF4A9ZvFx;p#-4t;k1ggX?1sRW zbRSe#e^M+)p@S#g<&Z=X%v#>QRtn3aN)9eoU+6bu*7^F=!#^q-``ibgL=n9o1SC^m zHl_ojOF2V6nXWj-V#=hI6ZSCEf*t$A$d;;Kkux)9we(HILV8vYd9)9|b`8463PoF2 z77_2^TiV^){fH8EwRLi;(+0MyZ3d|)>YK5iHbaChOs4Ol$3)zpK#!A~6pN6$P@bV@ zMyYNIqJZv;QUoj;i-{{uK_kK|h<`HJ5%p!Jv_fXxebyi5}-g5w7&NPCV1ViI`su zhJ7DSb~vQ5l?(SEADgnOOQhK5-Nwar)eE-#m=U94jPbDD$jh<>c3A64)r|N;z_X5! z*OnVyT(`UcU81?Y)N$?w+*S!=pKDzZ*Yn+Y$Os2p=!=5{dJ6ys__2)RKe8Qc;oO&Vi=KVr*t?&*U9O3~f)h@@-l zA~!55F|uDE8vulO@thMztR0s zUrl(sbI#aYg14xSaq?T>-rHwWu%nZr(ybhFF!L65pTB*Wo;J06XLsIeK2gbf{24<) z{dFF1d(G>9_&A9|#(E>g)%RQM{j=sua85wbacmTpasFD~NJUbhF-(-144Hgj!wtL~ ze8IMFez7Gpxp}l`rD++Enb#SOPflGs(hbw)<@J7ArPWX!FF9$_YcBOXD9m2-Fy2hbb>FM=xWgH2skr@u*PcgJQY8SS zEi{;4yL?~ZvLa*J>Mr*nKKo&KzPmxv0pgbX@z1W^*{s(*7~Z^mF(nXuJiKtSFENz| ztP+EEc4KN4uTeINySCp4=H374R+Nlni-oShZ|@Npoo}7qSKuFv- zS`dCIZgPLurQ)#5n*=T4wjjJId@wPKsErY2ULISvDJv34Tad?y3y=Ue-#@V*8Bc3Y z8qigOjKl!p z8A;THXeud~AWr)*-8PKA?j#(<0*Sbgrp!eXQ?30~BK=Qft6uI#+|oUU%!+ zipo4Awq=fQz)VhH)yG`2kXyGJ0xtSLj4cjaNsQOH)$_m-ybJ#OH;A<7LcR^?;TUf& z3*6m06|)v}alBwEU`_C0NB=qk_-s{xv*$xe;*#|_lBQkK^(o0ed+zr|NqVe&7N<2) zI_~Z-OU-S}t4oD$!@ZoDgU^?3x8I{vi0SQ_X|`iNh+g2XTX@aCd2lI@hrQ_DuprL7 zNSlU@*erl&_Mf_@cPnAjf+K6E56Xk_fL8D(=f+`1R;OD};iXcNot1}Ftq}U6$zjHS z0X4Uw-*6Wrmr5#91dN&+Wr4YbTF7+I82KKxNK|43kt4&h)GUcu+Tq~NkYW~5Zq*_N zAp@(<^|${uVk*@E9V@03We%xSwe)*#O3Q|&gd*>Sx6bfulEO)ujev^&Y2kEmY1?s< z=t*j483es2@I?8HobOZ8Oj2yDE1;nLPsY%P)xZ;@#4j1R8?W0e&MD&FSi$_kFLz6S z!dx&rz8US8*z+7FZQGZC%LmGEU4*T^hN8uD2w?U1;-YP<`n&sCV-S65Ghsm#Guhxd zR+gY>f#{6BJ29*#vU|5J>Ue3!IzQX#&{q#tNHyA%^`!Jxn`+FNr8AkRy+@+9)Q)wD znWcUAD*0o%wKG$SuO!d}%~sD(g7gY!W5T#6pjO+dwoqd0eAFM^vMypwPHv!X`pcic zA2*&mvGQAyz|xqfD>dU7cB%ZH`)|insuW%H9LOhCg$zXB#Nrh~Nf}j7v_-_ol|MFS zT)eqG7#w`e)VCVT@KHn0VY*v(A#xz?@JI*b5!S_tg2P8cCpd` zzSJYamd=>~_Q^ry%gLLJ@Vk|GAFV00QpD?%{xc>)DkWDv5YbU>U3|l`S6e^di#qtc zfn~I8g;1xEZJlkqbf*5x^@b*Tr3-J~mB;*ctXw18^8B9xQkeHXNh2DVHw#Hlb)mKw z0S4h74u3?I;xLGNoPoRc8o-?H=si2*Qoc#AZ9|K>hhE^cPSF0@UWD03@6l+Q+h4m@TAXX9{+7?Ks}`UW-5yBphNT z1y%&;ZF7tMrU{HiAO(gyj2Vyx2j8#Gzt3#DnBAD)=bROjzqz2aO~nOm#n+s4F)f)b zppn}xu*(CoR8oUND}f116cA~@p#^$e`&kLqScMtQtb*zzIf9Z1{kjj!*EJ>#C(v(| zI=2O9pAj87RDbm4l$;}7E%;RJwC_qL^6TpXfg3m6)}_<9y?dNKv$Ft>Ff*e8PRakG zsCcgsoc9K0fqekF51f&1KzXp59+R@U;WakkUD08~<7e-B$Rd~7sU*cX#7rQo?(CYl z+wCYJ;Ca*iBO!ZL(7s{!V1j|jI+?%!3VK`#ojsa;>{cwZv4ih$Eh;T+!sT6g);aJH zTP`flgDpXdv=JRy_Pxcm6J$^nLbfmRx<*b?xFP&BxvhyQKhkIbK3>!IW6RPdB`epr zVLTr=ljteuT0X$elnXU^?z=`WL1lioTiHs@;viNG4ZlLBW}K+yTmSL~AS6lh8< zZd_`QfBnvlWo>5WF7;ze2Ead*6PEjHEp&W^NcKoY8gH)jS!}6rrL{RlLQ;?N%zS9S zWMkxp))P-+n;L)ow*Lp&fd6ACQ)0#6h+F9;uhfK3 znJ#|{SZT?v6;7%O{iOPnXcoiYCG(`eT>rik1(Qk|#Hm89!NqB8RM$6dZq!`LYI@&d z#E-k-FKs)Vy8N9rXpoJi_H}Hxbk9zCq5QYA-!ZSE!9_7)Y2mw8eOH|TX?+{$!izOP zU+h*;$8pNF(^h3jTYyTq2xO>_&tz!>`Oe2=lruvXG~D_u6OicY#;9&ofWd<=wO_QS z)h44SA+NNqxM7s(QhuE*388k4OGWmU{-goL@61P3)TNoi2kI^FA}#35l=l%i%+08C zba^(umntP*ipMN7%xjTOn^7ryJKGd<2;r^YLO$nx-R^5fC?&F4)zeGp@fy!aCMR8# zd1Fgs9s+Pn_>mp@9U!quRAMHNC^r}E3p}M70e&BWh&{Obl7;SpW<8J#_)R{P&`#Hq z&QAxMWEi0IEeF)s1CN>r7GzLBBb$OTA=DLs3OMIIVSEz*FwBG$q(5Ye*DkdT98LQ~e~?d)(j1sg zk4dn&f#oWhB8i)B{yZurl zku#N?e=L?SJ%8YWsVWfh(bwi_~CT5r5&MN*DcN-uI5H)gwj)_uVZ;e z`o42AgCZqj5-+bw0pOR}G_W!$Bkl`(9sKYQvtpZ4;(w}Ve!Ie@{*Lp|%d>*PJKWZ4 zNzd;)YkeY)f`62Oi+jqzzZHyA}~KG^MR>{IYtbqaEV!dG>|-3;xIunO$0_nGjNed)i) zx5z(S<+Fur=(5{4(=JFNdgu$lUA;bcd18a%9YBm7GJ{d4$aUv;S47P0U!3`6dhpD& z`Ag)EesZ{e=wDfs|Dr0d(&*Nm2jv!cd{DG}ekogHM0ayDIUf}R-W8^#USs)4{W#_j z_)@prNBEQO5hdYkb!do5^QRsw57WtnnU=&iPvsD)8yM+hMVz&P*7GS|s+_|KbFb?) z*`HGk!yh6RG{Y5DwVclgi-eXyMe1fur4OheiXED&ku=tatD30Cg3MbrZ?`jx&%D)) z>J7HUg*!HljkuTynyc-Ys#)I3fN37X)T6IaQ=g6QoI1R|CQ3yE@Ez1;nD3@=WnVR@ zsnYO&GwIT5tjIV%cVl5HQ$89y-IDxf#42lU-$-v~|D0Y}mf+PrlW6z%sKVSjVe2G6 zs9q6PoV&VUN;)<3@o7#BpT9~F^|+Y z*67xxX2BU0Lga%V<6HpXrzy#K4dh zm4|MY8y%urZ6dP)|KGGt&chvH_p(bJTJvIdHfWS-jaiiA#l*Y`>n&0ZAStNl1F~4f zTB$y!)Fdcpchmy%ygG7S|Cla4Z3pSb4EKDiDImO76|9DbR|BCHo(HRu{tKKB>3`V5 zDBXd^q5MNJMPG)2M9%}{=E)9iAZ7T+TYi-+3+}M=0XmI5Fm3+RMx0x?Z8XjS2|5kW zIbofyzAt%X2mDx{?uxTWdyjMzc*$s?v*#G|W&m85M|B6?NBd2AX4PQ5j6HMAhP(n& zoXk=veNR$t11~GXZ`>!AZd(BMnhW2vTQ+Hiz1822sW)kKI=vVQWc%0`TUfBPBW^OZ zFqde?o)h8e3;TgZ51-Xxy(r$#zMd)tOB4BJ4q5Wm$q%N+Wvvf8dK|3}HwtiU>NVNl zaQPFvu~#60jM3rJE=koE48%d`M9eBjtylv}Aa5W)46uv7f8(1H!7y5m{#u21(-4TY zfn}3xs#G&guY-0ijRxZxnR{s711y$5{v=?fA+X|K6*_MfTkw7N>W60u&CMtpKXtA^ z7PGVi$gR}UJm>+~5qAnaIf1}sqaMfCt#8)#NfogfiCr?klvtEsuMS>Dt8_7KYUVIt}+Uiw#szCAT_W>;{i zZkY88hgqFrMf|sp)fB3VRWrY5s=21`=%RT`@pSy=q?%48 zt<+$>u%*){0M|kMi)iZib&4&_^KbMaL7s3Tb7EihXDb_SM<(?N?m*{&ba%aHg!e5) z0$_yQQ=?t~5HfdB_WICo|It+J_#;ddT_}+yKHoZf3JwhV~ z7;hMcErJ2cUh*AATAu5}GafZAcGqe6aKBE`M6P+#gvW z`*_>E=;U8p1orbntG)5yT@l8i!^3~&EgN^4dtkfwZB?wQqIlE52a;|O{}s3#1OzUx z(;(Tiw*Hk)9jsL9cBx!5%Yr89nx=+I4ABYwoU!}(r<$Q9ohQ@~Rf2K#ygJ8L)bs9? zDaYoQ4)+;WRcyHM>r5#gBM2IeVlNr&jedcnlkG#sNJh!o zs77cT{f3`o@hQO74U1mKHrcrWa0TD=V^d)3(y~{&vo^6^&JqsguX8-;1(*-o?`XUM z0`@b-Fi2l<`B(7sv^!q?9ky#rH9s-8`=0SA)VvUeSp+iS-*l$hBXBi#IGw1jfJ@Xt z@2gLboq+jznxK08ZKK$K!9mtj1r)ITWW-v3;`kVmJxWxXYMW@e;#zB*C7<4^MxlmZ z4wmv<)$=y>Y77lD9;dxOo4C8#$GwEoiO!=&G31~yP!(I;R!#h~f$6tq1Sk}A3b_a3 zn}r5|i=l15Vovad=8}v2mh`be!@iZCQDR3Z&07X$!BJ80M!W}jPm-Q<$cagl2xtjK z7;NC1AJIctehFp;DX7NQK&*yIxK*j+znwal0k>=AW~%#<-QkW&7vM$?%0PrsdTUmk zY!>)qgvb8oWed=fBmDU*jirnG*Uug-nbsClpKU|mzz#enTHOvj-N5}j(ijCq8kZV*aoDlX02nXL!xL@hUI2;4q4fz2nAG~-NuZ$Y&lZ>hA0;|D>PiCd+s2k= zVg5t;&qh}J_e@}gDOM9OfkTvc)Yw|WXyXLNU zq2r#ec1XxxR>}0oxDw!e-ghYe&T=)?f#zarH+H!tP4Lu0DU?+l^qrX`*Hbrr{#g23 z?08z0+A`lTNTpa~LEt*G-G7z9M@7ZSu@cdqMFZt(VTE`kU~sPR(-v}U*-JLVT|F%i z(36@Ee??nAR)?>DoeeuHcSp~=K}!tICR^{)&lWj!jCgU4fq^x17NGh_zX3mixBR(D z7ph+}JqF|g?`ekl*~38D`0Ap$?9J#=mwIjZd7)=5?kMsW^8TT}FtJngDE5X0O z=1pG0Qb+?;3YajgMOU=?`ZZ#U225-u=BLs4YFcw4{`aCsJ!e2NjP&2m;KpO|J@40h zCbg~y#kkEJ+>_{-w3M{jS#dEqnFl^zaP@8N&h8fa8+dJTiA(R)){*KC1C2T3@%!MqT;sAy zlr)mYTZdF+q_@D@x5r8vq48SeGXSH<#`Ut%_R^-a{hAKGXssY9wkwL8*6GaHKFZqI z35mH{t^mUtR30@hVz-wNHA87dyBOIuMb{d4l=Qho>3>_E>*M|bW5&ZUM<)xXObR#~ zYb*H`zS@Qmp!AmcsrmXY995tDfdaHw%Dfx`7e)3LX-<7pp-s1!%y!iivBzYt4k!W% zx<7W_t2oT5c}HOtBfr_py3DuM3*WW+6CVX6Wrb5-0LcUj zCG&-s;~v@7#>Qs;1L8>BwMWNwWgi(XbuRPesv6X=&l5D|C<9(Zw!aO?_|n*kjtB@k zbwhT}B>nn{IO4VQH&-lQZCm;M*!Re@RRg}&|GwD()T1DYc9^2z*ChYN)ZZ<4KXV5( zpYK({#4GOl~8 z8REHfDk8U;nxO+hE6c0Qo)W?rfCbluyy)0c2{Oi;_r$HVMUOK+D97~R7ihDqL9>IL z4X6OO1D9k+jU%?z%6CB&qI;4ea&AIO_q&2r7dQ|NVHm8RaLJVI7I)qPnHn{EJf$0+ zdmBOAitZ{dCU7b_{6F~#a~S#=zM=~k?~!t&nrkYzH9YhmMe&0XdFj3G@PWj`=^*67 zGmE`Mehd)D5DKotxvH%(KbJr8yksxt6(f=^(_BTpI1#OlTgM9do4Qj4zxC}m>2$G6 zJqG!KUCcZRyl{leIdeKTZyHtUQO1A_Xbe0;MAFdZ6qzCZXSdqBl~c%Wuf z1xTel90nc6N*?^D1Q*a$f==pTG6P8Gm2oa$oaLiVo@}%FnB;Gu-+N4Us^TtE%kx%x z;l=a4OLSfPlmTr1G04$9G39#xJc5hN~@5n1El1{kFFC^inTz1$>m)vq&6o0XL zXO+o=368YSn%jJD3#?A*)J7z|J`M;@gNx(^xzMIygP41O+uu3xIC4K~ZE04`soL!^ zL5+a=5osMJFIne8LVEBc(~bd0y=Td`u-O{=J0tHwg3>h?GQ=Af3XdozIcdto6NSbE}mI>ri_R{eRaJU036L)RUtOPh=*>YR)!ACB3&f~Q*j>g((-w+$oG@|f?`7>2gRVTz}f&^bQ>O%x#dH<@+MdCrJlL z%@trah+u>tx#Fim#tRz4Mw>3QVYFLfu3BI34!`B3-fOWI7Y-D)eN4H~@sF9+4cfw_ z>UeB2Q62psAOjN_fYo-^@*04!f&t$K)6nRX{gaml z_RSFj^cF(ELslk0qDU%l4zme`2r-U7P9ogLl#mOo!nVc+)JPELn(mhXZ2#oadj(Nf zwC#u^Xw#EgIR^EE*~Y=@hYanIkuu?-T)?8wO%qDoLnoxnx=)V3f-VSaTmu`hY;R!6 zlr5}CCY~A&eAzcuJyHX(AZ?>~)*fZw$iCzoIx-X0PHaT#vJm_;EX%1-HN&9Z{Av=P&snMJ4ms*Lk#yG1=5 zm?3;h+8XUWLw5Tlhj#ZxfykzT6+qa>=E=g)|G=-jY<*mqT~pmBEd2?ofLBbBO0KN$ zsrzq+Bo=~?w0Wjd#cfVq7dG4{vc~XK{mPb)NRN6X+uC#g|9yZAJ5I|`Z58XGQE$|v zNV&JC(@cL^dP~UD9%0!7rewZDroPz($1XFJaIPkypIjBT@A@|tM8$TwMZAKKbHKFFuz`7Y*QA#XcTO)t_ z8ICdj3y#4J#OJZRKNo-xIgY+-%uM>wyY4XOt7b6aAw+4M0uCjcGM-6~o@VD5*s`W% z3^Oe1-w@NpZ*VtR#KSoQhU~9loh|?>t``W{)t&63vLK;*%I5qhX10(rhas#00A8q5 zIo#OMJ%l_`7RFbLAyC)XE@mQ+B4dNo`EP~uN=79#DzY-HogOy^t3*_21Myl|v^$V$ zl&JkPy$^^8e;;e+c<@}}m%Yu&W?QBI6sC-fsi+UXI$pdn1Br`-+ql6ODBqzNCsm!X zVVtY$;s+;T4%k%~Ds8~Lr&88-#ht`0iPlp6+-z~$K8SLV3v z)RyB1a+j~^g*wa8lk=k2W(e+xy=`+jq3gSz7zd5I=o>o58}5&cu~+i0o9QbX9s|}( z{}7OoiR7v47`w!;Vb9gaqClZcu22sC{u$Pn^xcb906>!Rv#U{}|>Z zZmvSz-^Au~Qg=Wr5p$*eo5-~f0Mf<3A@OTsG;mqqhd8z^InGRhfcpGfG$xC#+>j_Z z!Lph^B26yApx+|cGd=2+xC6$|v1dFs=ZuIBNvBYnwLKnD|7f`1Jm8a{P&I-8u$XNK zAbNBG3s|K4cgvFXN~fHrLK=d~X!2V_QLoilOuuuxqFXibcG0;S3l&;|a;@d3N#M|# zGl9caCaDr`2Ei$NkPn?~#90vX16g{qw{=#@Tso~^vG|mM9kKC$3XFMrXC)p{ugRMW z0D{RDKmS<6uM)IvaF%+~^{n*S)6YXrpVxt679eo<8(^K7L&JbH(cAeaK&B0_cBXjS zER1JROpo-sd?MdAbPSegw*QI-rJ`Xff9)aN#=)dLxg1nYJGZ=x}#62pd4b_khyBtZx0iFW?f6O{o}!#K0E{%YRm<<9*JmMMI@ zURdy=)8+WybiGG@8AA9|9@rK12k{|vfNwT=NQXe#S5dyRWa3P5*lFDcy6|8;5C^kK z-f|4-ACI)HoNC6pt%gMWQj>@7OnKqsX8ZJ^p0c`LSg=C^?~f20NYP-Hjg0kJ%?KM( zrYV-Ylj#qdMk|dRP*RY_5l8hVT^K2++1;i?95wRC0o6|*FZdjwZ9BF)cxb;sf1gUk z2LE20cIy8W97AFq8gVURN|3|uc`t3n1iPJVG8~@*7G}dw3sanG&P)KG)!zB&d_F*O zRW6XlnBvZi*_hu~a0C%a)}RTAT@RyRPI27Wh?)VUA8po8fz>Iqyp_?FEDD$1#|OL*Eu z5$Q9%rHzt#%g`B7n)u!Zdxj>3u0owwjR>)|n`Mi--eHTv^g;z`oc0Yea)M@OgZV;8 z)&{(k;QH&7!-d@a)QE^2n~}&av~wUYO;4vjCa{%|((@s_04W2ch03We#MVu_IsmOI z09LI<^<>Fd$_aE#gTtsRPz&10uDdFPN%8Zk4>c}{H*5o$CdC0Qoud70E&bNQsYOE_ zaXe`2;)S174}jwp=nQz=hY0~($$kW7+L9ip$t8eX0*+hTIMgOJS?!e_{Nv6967Xl%2``$jKqpVs@4nplt%-OHG`o%dV7&83*uysfzPT?+&UeO-D%X7jN6T*!OQs=K@a1f$k=!faNRo&Yr^U zLmNkUXbl6#ngcQ*554BiV66hue}Xd7QmdfMYj>uz*m6Dr3V<>io~`iXzf{gB;2znB zP2^@RMyLW*I`q=vHENf#Y!cqTDi?S^py|?e$1lb zNv_qie*b#9TEg_F1TE3R0YK1IGIWBPgELPywv1?gLZc_0XTL<>Bo;B@RR!TD`rS&i?KF(#5BA7 zISKo*O(p4%+H<>`VHxYA`bVJOMO2XY!DC~D<}-;32{N;)(p^kdnbow59}8uG33K)0 zzihdr!5vyj1I~gK;VgZV2kWKf9)z}`FOv4_;MWt~%$KpTRzHGv|DQJ3`funoLElA9 zBOlPJNqFMoKl3eDP#ojhm88M)+Et!QLd2@XOZDe+?>}QKeL!!2jq>#PE&PJqo5+mYFOZ#kwq}@x_|H5#9D`p_KW?giF6qsbaBip+)F0-l zGdc4v@-UatT$Ea0@q!ec^qYB6iu^YBwLrcBASL0w5`9p9E}n*@oY*XxH*l0O^JU8Y zNWNtK1;M)pwR$Rq{B)%TkJbuhEgaYfc0l+A(I- zSm$l68-}wY;QGL}t`Or^fe znnm6z_Es$r8*U;IcmX|p&#(m6*4Wr0waOqFwkX|oj`*@!@E2M^q)93jhL}G@&GdgN zpOj!)DCLL}At4R5GW8jNhf~ycM}2RkYrtl0Zb)1`4e0JT9eR?q^WCID=JTEovHQDJ zw*$XqMX02fi%zY`lRl`?DGFoXoOQXXWUWIvPLACNR@WQIs{Nr&2Bb+R44ZrGb-rx` zUm>^2Rocz(#9cQPo;rn_1p4E0@N>9|MCF#+h+CS2U-Ooq+qy9A8k5#xt(lh5%w2fWrDkILS0SL+=FHL9ZXMkU-+QCs`s6~GT-}x z-u~e;T{3C>u}F<+XO7~z7fk?_dd;&wT4d?3Z|>9(1HEYDODsakYmP=dtpg47S+pf$% z2f}zJ4}e$7`HA?rN;kNld-p1?9t=%d0_SDW9hb*R;IF9S>TRBu4#O5QTFAIxdM>vl zfO8yQZ5vfF zZ`+HqFkK3%=8lR{riCA18SP;eNvnCMX|VGFG!O|`7X<*3eDa~G92*4W>VyP)Xfxmj zlwEqhwQ>0awueOa09+}k$cYU-d8|E1aNwm#ziM7dz}o&QE@2Oy?&ccHSq&rHtNIhm zaaAd~n0EIdm`oEzKDaY-b)bDSkT?ES0eIC?aF8R8UHHh)P2CeAw{!`LW7@&cdisx6 z`*zJk>twrQX>L zGe2Az7(Q9<(K=O+mDQjBqy>6k1Cx~TQ%|)0e01=TK}Kfu<5l{D69U(tEGVB(Bm-mG zg@q~H5OuAoU$)fuu|Cjo8>7zF!jsDOZH@k!{=i?bEs$JjP3wZbOZO~~uJbpie3GJG z{XG8kV_%L)=XfB=mL%APb1+7J9qyI-zK=-I)6y-E0<=bgb2WnD4*caMyBl`z z)5rxU&Z%Sil{;BBxL%8eKscrDabyC++kZS`$%6rJMMkEw3rC&aWfoKnZx_*!kwd}O z%v^Ck7En%20TSu{1PH38J+0{iT^?+(Veay(FU_Yu15UhJL(-ua$BvA@Xo?sm@KDrl zZ$#(_9*ChgyN|5D${6yi9 z3=Fh=PCTaTJ9;FO3HIl<7q4H)S(XNM5+8W! zk?h`^godHpGo6ER6UpBj{g#UKU6w(bZCQIy+BU$LYO9PfuY~L}EtBGIz+XfL+Eo$= z2+3!)V;~LZeh1=p-PY^?UdGWZi^!TvsVdYj&f1cxjHLy#2JH%4SpgHunSKL20^AiL zEIiPpn92;k9`#@Re8AGuSadYV^0tjM1An)u*>#|saym}EAi%%+%Iz?7N>;J()H*0{ z?m&EYLfbRrw!2XTDcmlM- zaF5&0*v1*Q!w!x_tNYR-?QUoBw4l!c!|Xfq{SkqCrTI{ez$9AW!z8FW zl68#m9PC`k)V_^8ZdObMMv~*WYc7|hhgyC@(OqBD_XM3O^M{>k)Tq@fN5=4`X1ewz%WR$}_wYNIhiQy(j1kE%Q&{TE=r9 zn(b>%ST?hMp|K|ZAg+EvbB#@ZZ@|&&bwFq|Q8P+oE@NFZ?%i8aylvu(?au$2v}62% zNjq+7rg`zgj;EW&;6Cq3$<2{Zv;NWDJwG*wT56Cb$W{4Bd1(2@^mTEys@^niZ>scB z3Lk7dzvGU(wu;w5Znen?Wdi2{T7A8Dfes#sQ0x`;If#cgdLfGMzqS`=Cgu0%`QA7Z z+7ftOV?SmMhY#%=Lw!Q3j#%O6AUyh*Lv&C%KuSY8uO58se>(VpkUnOKCP52)!WZ{i zBOTtA6JQZ{@)jNbN&@caH@G;pW;9=N&D-1w-!7=ajT|U$3I64zpZYE9>gT&+k=#4C zk1hO>0qTuEu30ZJMsfU2{yZa(5DNGhUF)=1D5?ExQoe6NWAK+1A6E!$SVR2k0e~1o zCf6>d@~Uv}-<=2daBJ>DSRu?mDMdVWATcG`!@k>kB_Ya2Whh^HsaDjRazkZm*I~^{ zWcOoEW`%SA*=KgE5AyQ~{=JX-^LP;9#d3bCI%1on3`{lVf&mbKnMnF6;byftdGFEH zU7vEkDbO8nZv1m4I2v(UM{6ZMJLUkeYovc% z!PT~Do#dK05U3{9f1Eu2E4=Q< z-TD7~UvzbJHKp!N1R+fb+X>?rA_NPL(c+VYRexbG_R1e7brDhAqm;$P$ghn7Q6l6i zfVsalk^hs_AK-&o&L+K4za?6=hOmWkAJm#mwDGfMmdARwM~Q*6ro>%l{ono&@Ci79 z8rb>0wXv<`h+q{9Luzj?IMJzp&`AXG_VdHSA!+3m8;(WnLJ%NQdr&d4}9ZFMrm zcwi55%WrqTo|G~EQXYjR4KS)MEz6&ueZcM5yJ6W;-0ft`n|&$x7=8k4*m@a?&rVVa zo{6(!pK;UFCpWT^wW+tDqh_k-oHFp=ka;?dQp~MYs*8(2MLw_o)6KbBo$m8}4;ggN zGXm=+{Z=irZRgm9W}QCYP7fh%IuRnv(o_}PmS#v52qjEl8E*YIhY z^+|k##jg zZ`c{2Rt-bCT{xt9%0;2pcRfWjYEx@VGAmRekpd3*(g6Dr6h+PURD*|uEZg_-g=Va^ zK>ZeyrTeq1K51z$(x!IOE*>=8m?H|PYv2-mBGp=ml=R}co?g&>1BHm(5W7uHA$#$G zWX(ZkPEj^ridDJ$^ADXwML3kn$FEYRCJCAS9sUgj$E^J zKTAiK?2|hmJ(x3Ac62Fz5g+v$Q0vOgzbpICF8EvV)E`~&@jLUHXlhR!qA&r|a7mWx z8vxASEH=q{)h?GtL;28qk*n6t8kD64s{Lq$pX_NhmLFbhQ;OPXJpZuli~2siT2Pwe zW5ko|YQ;F>4(H#hu3HFhX~h}r>>o4u{l#aNXJ+Ts5f58Y6Jey8Iad(Q5WvXT_T^j* zvhHfVdYeg)d3`?7s|MB=#94`aWx@;W$teU^2L!J^ms|S+{V|9qy+q2L^uF%#0WYh2 z`U7EFwxk?XPv5Da+Gay9yD%5(Gpb*L=tsmBnrvTl57~?UVF5({O7{UB2l4R+)5&U{ z@>2$vEUWht$YFcjg*)u!>vA%LxU+ge?frflTR)qMQ#M-&ImyT6ztw6txw}2Efh=k~ zit6u@sag?1EfVyQCZfRPV$gaCH2T^!M5J)lw-`w`2YjH}zI~|6{qi4f5kS|?z8982 ztb!cgQ>Fl%3-gD&`3mAx+~U9}XsgSU>tSv9F3yKlRnxg^Z+=^ye@1ZOk~(Il{`L@Q z+w$`hPICEfAT6agsFKG)o}hgw|00>%Vo}S9i4hQGL=!BZGu4UdW)F}<6%qSlB()L8 z+h(?l(oCiAb$R-lVx3-K>UC?#zY<|Uu*8hI8egfkNzDlINsm1p>GG!VwBB~qMFoOI zZG6D&dWVS%mtQ{cp9Lrf_u8y{eFg@(tSOtD240?#Xs-VmEa7YxQgm%sg%+64{7vAt zza^J^)A#A5bX zoPD>=-tSWN_uWZAo@!<7vPf;4^W$&n_i9=CB)er}+m;f}%@YVJb|=S}*FY!~oB_@^ zsN#QV^@Y?ss(3+5Oy%6%wv<{-dBoYyQ83D(0SJi%Ik5 z!v!m6#%Bmxp)2^iu=m$}-Gg)^GD)sCpKQ4ubSnTgpxM(8P$%|hC_JB=+Ymq$SA6Q_ zZ6VBnC^p95+IecwkiV>qdpz0mMgVgg=O?!4@<)CIU!H@h)!QUjURWq^Zi+^Qx`B+`H+9b+NKdL8eu4`=m%J=m>x$DE0_fEGhhYhJ) zVlNKnU#LGFUk!v?xteI({l-DqTD(w$`q)vPu}f70m1AUobkcinG2wv`h*5RVP%aO$yA`n!oJF2kdaCH?#Q629M49S zR4(C2=@Z}_Wc_zXSelvzBEDGjIQAVuK0lhcWkrleG4`8)(0^R^J} zDxnL9n_b|(VGA2 z0H8}XXCO)oy?hL4@h91lHDW?wqPEi`JNt9gW)X2A_Urq%wRm5X^y+s1rOHO#JCKi) zU#M8a@ovr5Irowxv&9S{50=;<&rmiu^zEdn1oi(rQhS~C?&KcC{*o$kK?>&&{)y2j z6yH=7@+d7_3$uc)&nOy_4V{|gFr6Ru%n3L%gLT9inex;WeGL9BSyLA}*qQr5@hXi3 zubU&OR42`N^j)=eQFNs$_U=UTQ*N}UjD&M%vy~S=UUg%L9;>6#M}Q2Dzv{ol6sYp8 zda=e6@;v@nUej3Efpli<9rdQDxl8^g(lrb&t>^6))D2La)qgc-Sr z?Y3A0X&Q35UrAHEd}50KUboi`6Sf}*?bnoQJ0d4ip2+;C)^{TYbx(8sA`rr{CfDi- z+6{dR7`DTX-y@bXt7dcg@cj>KYa^;$FgiC`+LkMv#~n`elvd0P;>4s3hcsejG@NJf&4sF{*#sj zbYm6s+^2y-{o{Z!8uR(rIrO7q_e$*&am>Vr8+Ui@5H{61T)yz6iBQ2HKl!u_nXBGw z*?;AH$VTslQlYY0{6!o8o!%Wu7;b2s`l!1;>p9rRPWAH5YJ1)RKjwPO@;mgDzAEB% zo@VF#y`bOPs4X4~)`Z4?U%YR_$NzWH&gCus-uA_YFd+H8uPz4jNROhZVB9HGNUZ%( zzkxXft*U@`4_VAyXOdraGO(OgMkrn`2V5Rw`cwnJXvDp_ymq)k8e2ibEZ|L6Pd5;9 zi9=)?fu^Xr>UveI$(7Mn4*b``niCVx2bll``QrhA+x|BU27umv+n~CZMYP7&C%3G< zu~SyV&yyc}n2uilW987WSW&9x;|P)ea8j>Km|P55i_eN#bJnUFuFt1$Zpq2r^}Ysr`*;p?+0-pCvn>|6);4@?nir@wMw)w|Gc$r3+&GaX$xCXpr78mG3LQ^v*eO%AdTjwPhJAKO_Fu=2NZKk7_+ay} zC61wcGQ{)X6RUIC@bNgeZu76{vk}0;EbskYA%28#=btEaeqfFH?Bj=35W}@+aIdF0 zZ?_kMN5H`4jdH)6z8@3h&%Q%4#|f4Z7Uo0iHk?s?d-t-m%uG^7v6xI>h~u9Eo~ir4 zVz(b1%W{iOR-C4WM{hKTU4=l^#Y;MT5m3*C7yorF@HgP|e+~l>c-;R@a+&{^`WNuD zmluB&q#)tn8_bULs~!-9buh_I(GO6+2B5ns=69N#7ep;j@sO&d_UCN)r?-%w6|dCq zIPR1PV5kY0+4v7hxeou1y4E>Sh7>t0d`J_wL*96e*O=cAe4mLwao|yrl<6DB5%rxr zd*}yi`qJ|9S0f`HRdKP4fFQ3g;pl&xg14b!;fvSmS1gv{%9ylhfpFI+qZ^-7Te74E zACDtYIr`FW{<*VrzxRj#sLsUqeB&{~S@6X0t=6icId8VbUOgjo@b5V8NCHhwLv(e6 zy}|V;Fo(1BW1gJ?kYaoay=n=$Lvh%D`7C$`O_=*pGf4=&fO-C1|7+ex&6wCpV=i2T zz=|j3Y?8FsCJBrcd-qHbgs|0;J$I$IfNLX`gBz}eaV*b{+5Daf_<=f>amAXs%x6oE zkUjOe>;qQh3}z^!w0X4N}q60X-{2rpOz#_TH91VSMq2We$xH!#P6GL z|M&F$kCtI`gMEoN?2epohv>2n&KF+rw?_B8dG_EkJwk1hLkV<`qz}}Tw^%zlP1yH| zUAr0xV*V)q(}ybncb^mC&Z+@`AlR^$yypj&5^E2A$0YnwIbw1YGO?z9YvQ!hQMka} zBX}VqR^<$LU6UN}ASD+G#>m*gVonn$QDwqjDZUD-_`*>u+8eY)d%d z`V=E%?#^!OMZ@Y21TR@x)g%;_ga&c%gS&X$qEsWHz9Bk6Xw`~*P+S+edy?{;j)|NO zb0st3Z8mAaZyMIWuY;b`oS*J8m_)kh`z)6Cr62g7C$X)_G3#@+nb?;ZsG~U;i=GL8 z@5j}@wH-c@Cth+c^Vhf+_-(R1%^Ic&9?QKR$s@J($}ZQ|A8;psEOW=3)1n_Y>i;YJ z&U)%-aWQV^DBxp5)ra}X6Z=A(0?)|%*}|@>FCPN!W9+MTz$Q&;zW&REMHX80ygp-f z{!v{FSdl>FyX-HBP(hAtv^ZU_q17}n4VQg9tF;eRCzyfAW2ZF#?8z#3)GT@LI2&Yk z{<6KSBH$fI_x&)R3UAC4bVZhC?jt=+)REaL9jib-5s_Ih_na++KWx4p^~e6d~%lT z{hnjox)>;))#{RvKA$BH}6s^`;`1{fCh=Q%w|`iRsXJfE=&KYW;h)tB5@u z2*UZZ(LJbO_4#^TRSsVb?FLmyj1dl@Yh#A+yepvd@kJ$hZl894kD%a{-aa$37ovfw z_`9II*;Lg&)Xh;~x{G7@dFk()v_3+q_W>cCUx>{IPWx}(N^j&$uVqpSMJlSebj_K< zdWtkH2T7XK<#e_s^{I#!dm6Ur3qzIckzHVD4(#Y>IUKS6asJ|(K^wgKpbik`<~0s+ z3A<9S_2JS>*lpJ)K&V8`FV-`Uw-Q9v`bzmRnbn#_TmN$2*0&qLBsJpk!|gj7!0!)S(Wvy~ zr2V^+*4WG6QOjJwOVlERqbk+tcOP7W+?bPp`Tjz4m4-zoN!|$9+&hyDJ zfI9X!Q`OF*ocFD7FlHl`+V1puuk=Ij|q={+$G8J?_J%kNF1 zyzoK;mC*J7@-u)Q-BnR%9prDRVb9CP2UxmA)k3T%UiV9zQTK1`8hw8a`_|$RN#4QY z*lavZXI#BWzdkQVD_SgARD5+z?+)JYrC&161k zl~KE#-$a3w0~~}a>$#HJY^IBc;bd20k36vt(RZA%yLpq@# z6YzIBwWNlQ9tN`U?#i~XQoYHx;IB}=WDpo64NLA0tcUTR<@Y>nQkexJ%va&Zf+IP# zN?QJKXjpcr*JN=?O-6X8j;p>Iqf`N4_ehD(syor0zu>n&I7;_+(A<=O@1+_OmfUvZ z;XIr@b179jwK^-d+h{>rY_W+52G05a&XulQpBr{YJNz@j%})LfsHrwdJL;8My&L;r z{>!tSe@-i=DOc3?9B9%Hu-*0wz=Vq}A(`~X3|G`bPs)jhRQgSXrP`F$s08Gel&Oj6 zEAj86kGML+4$O9jo@P&ieC#FkTBpfEO;YVj>E8e*h)jKe zSlQe!o!vN;U=&Ot3xnP5(eqwF&H;v}^}?a;4~y(j=J_cn!wrHXk%?~WY7-X$;fpb| zP1O+Vqwf(kdp?KMl3iX0ZBL0-3Ny za?g^Y>X#Iu$yD7W{zZzsdpnztIvn&W65|^)tAG4!Hd{IV<2Hi=9koN6ps&jpkDZbe zJH=-BILVC-&?Wj5<@^*Rv%fBgS+To6hp!3s9{t;_>{=0-GHB>$AiHS32LStU9u%Y- zbT&8u~6=!IhFu08)bM*4)1k_pi9D2*?kbf}#eoRu-n}D_>^x9P&%3y(HOy_Y1?zx7uDB zJ+gOYlc^e-hzZLHKS#C1SfisXAZ_P9XzX`*Wmvbb?vY(3u8oF#@F&2W>yj6t`xp--->=QrB=x){OQl{V5Hw84e^B;0l()R2kfum zPGrss<*{C}ZF00tLL5R78`Xp7i;pzot$vu9mH#p`j;;H>EKg@^_8na8df+MVu#}pi z846knm42!!(JZS^Ee1&|9j)!D+ifpziNBhIczz28i?6=ePdvTS>KuOilr?a;@0D1@ z0*x0&Xu1GE|Ih$K)>eC^SzHl-evm&o(4hS5PfmrIUf4jcCksbLi_C0?583DRK#R@h zoxnDtU4vQg3P-(_zLRN#BH_@MyUX!OPK3H~7137(iUiK!LviU;pG>hWj1{8dEf%pmpZ&c4`_5BN5 z|0PU7kRNZRmXWze83^)E+*c!I+r(qJ^LSma2)wiP$BLF5y5tC;R@Y?7iHZbg=d*Qu;O;28 zq}FZ^T!1Z^x=z%eg}frv*Q-8Aip)#~R%UuuR((-3ezPav-!CPc`llHZ4yI}yuFSoM|;S*^g zwHn?Ynt#J>(*2?SU8qj-4O2m0N${6@LqoK4ePn#o;#QNBo7z8@k%br8tA!y!sZsq~ z7w?IO@cNru9Yq}!WAiUG_>6KL07`}X*Brr*1j-BB5xv;T3;ur$YK5GOf0l8Xd;UpW zBg>-b@69w-6kSM?G$QN03%qvB&LUL z>J~vW7vb`?gWy|th98$*JhR8$8#O*dVHl9ZrrhnFjSxBTh5+**)*z1#KljXx?Uhr0 zui^?L7HyLsza-oVfDP__v{+bPV;8(&^6HxVwhC^0NqIQdy3YZAn<40%3Cn#ilj|3% z!WOPVe(d@n+~q%RwF+?p1z%~xyJ-!dzT^+CATMI?@W9I+R@C&V*R)d1qr&ito~MsZ zP5$MD{-{R-rtZAI&_IE;-(P22Vrj!RW~PL3e-*>!A!KXZhu@>lA5+P34!~K_n7DGd zXe7nWb{O%|u;h+?F2zS{|H7r;g&fF5oE_W#9^hZ_i1me6+2u#M?HX=P20CWI|F`0D zCEyyLr6?V|Q3XVj(%>DmClcu((9Hh${|6a||A!O_wD!kfGgwTANxu-y#D%K6MCT|w zN;ifJ;)K(NRI&arLIj}JMbUhyl51unbUAFpkaTjy(#&_^_?=sL8Nq4rza~X)>3E8} zbR-MJpPaJXA64r~wS&~6nxD+K!XMMn0`>cvm>;9hgbni4d6u8+fSgUhvw$YIBFX6IQa4*3riDmd)=R-IQI_1UKNAP9#jmc zrB5XB=MOQB0Mv=u=B4n@oS;WP%i+*m0AxlkbZUmr&1SQU9pJ8M0Mc9dk)X+mD!eWH z4h>m@jGDB?44E!eCf}*A`Uw15%%qmHIOMS4Up+tF08LT!!p3mS^rSv@=W6N;jkqSA ztQ=TU`~`Y`qFgv2)AE_PAjmxLX_RIneW>&IU|1XojWFHW$Y3^ia8z zQ&l&)m?-|pF5*2nL>N`b->2fJ@7`uw!BWu&qyDgUTRf5l-$-RjfEHlR%dVa+ieLv- zL>P=ynf5TGC%Emv{B?ZR!Mm`o)l%FZsiO?=dw#h3M)dDWQCke+zO`xzxs2crZ;dL};7c<@Ix;U5p#Whz0ESh%HljS^RKN$_KnP;?AuIlYQW-O>8gH!uxX$kxHA&lQXFfO*>EN7JM^lbb>H z0sU}`O6K5oJSGMg!5>tvV2V()+c_f#$hKw~i{Dk?>xP6zyf~V5H}z06#Eby_#Q3hi z`uqCfoZ*;d)0e2<&jWu;U2TA)xGrn^vYv_h-uN)q`i<|XVXN8srwZa=A6Yt|dOj;n z0o>>=pVA|&<2T}BVEp+U>8G@ejc9s9w*C_3i6TEgVeB*)W!1sRYWm}5)iK#zdIb#DP^rtGfoUmM$`IPnSAw$gaRTHT^oOP`~_ z*s;23Si#7o6R(aT=Xc-DtHqagPp(B53G`Q0ls=f^irdOkXC6&2&n)AFB>ab3{E6?9 zW}56{TJf`;U7U}&I!O^VA&0_tLwb@)pNyhh@Vl^t*s2M~JM}TOGAZI+VH3-cNl)*7 z9{R|n1}$ScM6Q>d!&=YIS5)Xx51OL#Y0H(zwH!$O|{&~ zuNLojDy@nAm)Of zNxGev<6Cv&D;HW0Q+%3o2oHg^IdSWfihzOR*S%U zhaN>ANul^{_Q4Vin8?Q&whjdCjyOSO0b{9*B)Fm&xYx&{5*IAAZGk(ZF-WN^^L#~@ zOG{9hCv#6cc--SzhZ%;1tdqQwoA#~mZqUck9)s%>auvt3%)E*qeMPW?!6lNg30?DL z(}ZbH9VPlO>ssEdZ3ezv#e}S~w}Y)eu8+rr9}pY}3H*#dggWGtZ{IaId0g~bV8k++ zo%aT_nLKC9zIJh-2lX3WOzrdK;!K6-!2}sN%Zh;5?M@yAx>fR3jdb5u?*0h3_RB5Q@sUPRMCpFJ_BQ1oF6D^vOp?>3B+T!J{gChJZ35 znMUVj`ijAgc$NSvv}Zi?M?-ay9Rf&VSS!3H;Y>r8)aYVLeHxf&6dfI-7oCE>2j@Fy znDPW-)R?yqVL#7`wbd&^S1-8L(1XS|B&;_lG<8{)X~poHSRzR-H=+2mbElLNUcnnK zCFc6_t@)n(!S-Tv(Ppg(NUzjf^eljxgABY94mR}O&G4uyz*Jr~n{JwvWHDx)e{5QD zJmr!DUqcMCRb`#-pVoArB*+^p@_h2}HBmLLS4- zgWsJEbGYGSt1A8`rc3rBER@X&4UX8EX9JuHseLhTH1iAqRX5v--o4n$wx-+KKtEk#x@{&)h! zB{14A`{|jDLPO<)+tDGoT9&x8n*S4TDuT$EV3bf(rp`OE=w zh7zYouCcU)VJ+%hxxpigNY?i1gbwm_0(m74f!AdpdW*Ql#Bs?qVp~%Va==4s!$A7R z4#|xRtN$eRHI@>MvMy`LtFe$2J><~j?cyNwkR;IK?0aRfC zF^el669?!7Yt^KFZBNaRXz3s;S)*;O^n~Kq&ZL|IdwBix8U1>^s}|>YLXOI;VXnBW zKuVr7WPVnf5#nhNxDiX=&|pnmWEk|j{$<$2WNX-*P$G{ouu$g4l+e1*q&Pd6$#i~j zx~1;^+M3jqM9XDga_nd_XNG^KWeMK3zo2=J$FPgAWwaKefXD&nEtoZZdfF}0N zut?rP{Cdz%#eebaF1}6uKnwES87J9%W^o3iEUaz70l+m~=n4)ft*z{^sgGOQpZD^B zkD-HeKSvKZhO##ztz}pFF>U)iFiT}ED!GFGu`8bC;hmbyyy+aj-1@3`gSP4eW)P44 ztaF5X@@zK2Jj9N#DGH_kl~~Y);_oF_^!Y;KLhVJ_%}IKy=3-B98)@@pS)ytEost-= zbHmV$Hk#61IQh19+HkJUsPQ#OJ)Qk50WR1B?Uh1$eI0%4TUl2$JfCZs?{ThC8V|*^ z8BYwWb=-jrhob2&!!YkW4KJ);S}!$eo>%rpwgb^;1Fq4E5f4`<6j>~#qidXR-1=?+ zCJxn5EL41sHWVdFJ>Qs;&C#%?KxgS6h)bWrrc6eh;~r>?uu@Mji}N#|cv|&o=l3ih zR=D@CZQ;9i&nX6WAbKQ?Kw)1X(H=yJ)E3SFzYJ}Va!QR?l@ z)LLvq_1TFNUd1>2<^o-r!y%s0FIYSdo}0XbxKPT}j@+WOGcIxYL;~b?RLGmQ(7#hw z9|>y)H00ULhfp80qpzK1uiW{3BEEalgx7Vf)p?eGg?5epu+!j$dLCbERt2|!_0o>4 zEDNR$5i=m8N%gnYSTzO}t0|$k?FA643iRyr1r6laQjyst>$RGo{>nt7mk;3(FPBfh zF*lwYo~S#H@yNBs&2f7b3lrN^W`Z3#TwKuA&cRcEgJm+ytY5vJIs7Am|#7!3a8WaX)fpJiO=j?^vqt1B@urP=24 zOT>J0V3N2_d}5r{c`Ql&M^Sr!us`akHuVa}sb$}E@nLEJ)?RKcz~@%TNMquJ@(!~kVRCuqnYt`fWG%Gu z)KUMxd*#5SHnC$b(n!riP6IT0AWyX;Pk6fT7O9jp`SyP)LE305YPOR!SUB-M0n{o| zI!ZTcI;A)pU;+18D&rpssnnQ_c8;)xg4Q@Ir@kGe0G0`h8>Sn3ka}Pc(2H7N@tGtl zwjwZFCP7??g4cJlwXH6WFey`)4Q1+kQ*!H$g*UOMlXxED%w_M1>1HRFLErNssSBhT z!?^@*f(RQD-lp>Qb2(YB#OcwpQ)Xx;Tc_CGBuf+h8pOXiOe{JD9^VN!kUpR1aEGm3 zCL)3sTSs`UyDu90qz)S5QYKr`VKE|4cwfcBk{!CGxCduo+)q9*y%CWnwicU zL0p8@RrRz=8w94luiJY7I2d)XiIgjaW>c)WEk|eZE)GNNIg^E@fte7;bbSKS+y)`K zl0_uJ>fbZr6B+Al^4ArRRIV&In$n|M$1R_2C!XnX3hp3+kjD&l3GPOBJ#Fk!nZ~mp zh;!0H(KAs-TU|SRVwXN7Q1!;mVx?JYsVreuWSL8M#7R{)eNMjd?0JSW`9m`$Ly7Dl zl+OwMTeHzr{wl9ARWZucB7}JkV{;AQORdVR{xKo| zG&o}&w=kods93f%(D!U zUCY#wC_VW?7Pc4!wj0h+uT1WJ^Ab{3MN2AQunhX#GC)6*2>4e!5XR%@S)9kytbi3( z;oc^ddODpezg!6yI(Cj^o8gFf^S*5lnvxj{Tx>x`u$E!oXm1&ueaRej(2_t5u`pWz za|Wd`KFoC0F&@YQ(2h({LQtrR*VV}tUW9;&*O~en9Vo(-+;pHyEGm^-Zl8n3E`8q3 z2j@A@ZgqZUB2&qufSWA=tW;Eb3fNk3NqA-QC;{1-M64_)5|88Ey5Ez1Qo#cI%Me&h z7?=*Q)NR9Iq2|aCs6S4ZDq83G<+f&{Pl%{2ee0@ z2X#h23MQgCeZYPVu-lQgB+>O^sDtG5Rg1w^+rgS7(F+E6 z5l~|F+o0Y+SjP zdJkCtV{iykcV2#nVsJz| zm)z^Z#-t7b6pTzPNIKTcs7cdCLdvqLj3bp&_o3CFm0$jIGzZ;6u~ddn>t>+czKSs}I&sXyD;~6CA}^?Ns=s7#)mFgno_S$CerCTZZql%_C$7wh4&z5}JZ z4LzSR2MVFw*Mg_zww~~+N4iJbk{?am5)xa7aUkq+T4&fy>rNEa4J^3bOeXaa=UOe9 zZ=8n_xby=K=)4X#Cfu5lKcNLQE+Add8eH1*KSlcmEeVySfDZD*7lNUKzHpD|E~?OU zgrkORM(8+*N(%(yW~VAX1!qObtZX#B_=v{R4)H7Y9TFm$xxV?nJ*pY%giu@}#_YO8 zIb)!GvL~H%uD+ZpO$gT~U7fr$8E{0;ycNU=R)^63$7O!$x?{oe1ogK6D?M>Rc)e7} zmbM$-c6w@VAfsxl;(y1Fw`I~cE@Ub9xw!cAsUhZ39;g}4CsxAzS6~84bDaW*r)n?aT%^TC7urd1Z^Vtf!h(@4JU# zO$%Be-PZ_5!Hj0N8EPLaF_J(hzqk(FfFf_=(TtXrPIl@K9Zb^e;`3a|XUiWmRO<=FI}`>SvE{LwD|xG`;K>*b$U(Jg;%i*C}}e{Poe%SUuO z%F<^F!k3j_N^4>;!aQBr&o2eO{m%nnuibZCVWd5`nIUhTu0Lir-$XEt>~_tnCzDn>Be!It%GkJKvV$m^9vC-~{s zYq_2^T6JYjQ7BX`Hev6MQ@YI5`}gAn844M0HwW!P?)w_J{PPOL-(O)ph08VHqt`h(wf*X}+Dt5suANmRin_o3H*RdZ)n?_=gbT;HnZ zH(k@~Di`Qxor6BP>Qa|ui?hLK zo>$SSzJ!lgR=Hy6uYUdpp8iV`&tN`(Jp_XFnjd|aY5P22)kOnkEz6VHnd(!W5myJ- zP)or)0XT5U`=eG;g6k#bXp~Mpb|Hg+-Vlws1eYdPM?YO*ci%1-vHwgeZid``Y>H=I_FMOvR$rg8{xH5o0lz+n zyXP#j3Oi)0b9eup4ns#5^-5*!H{Y0D<-LB@f?;W9SiJ!~ZVA)e z3H^CLVQ<$j5lC5A2yg(dOkeYAAt5YIuqOGBO?2)Ha`k?-+xo?6OHksbA$I+ zB2KJ9H;x7Zv~ASxh&81LQ^*@~$2rI3m$V3#Dl;LZPKB#iBhD{d4eKr$tf=d>pN4-} zS0=wDhw;7Ej)}w1yxA0jw)weFb`JleBb}~0G|tmG>nFNSZX#F0*1G)Btadx0U`^&9 zOe-IS9*ZR{sd~m{VL@oK_EHh#W6tv<)uaQvg7dJ(%*uVpixE(}zFA25Kh}8eml^c8 zJZh1ajX50^GfO7p6Uq?6RJd9!9}Nv(2MLQbhHXn@*w-~9^X`;CF7 zb+&J@sj0 zHMO}iqv#Y$X~)FJ??)z0BFn|Mm(^RZA0V$Ev6h)LI_R?Y?NQ_dB`dvPqgOY;qT*sx zpYB(EgE9rcE4+n?zlOs3EiZ^tY1ZLY2Mp3^xHV7jc(nB<_F_R_EHK@k1u{wJ)0Y!o z9rGx}Pb&!ai|$Kq6V$$!m@Gs3qcz2>%aZ}Khzlvjw6MQ!m{xYv;*u#MC1dTtZ!ZLm zdaB$MhL-fn3^_5W(E zz0!`v+2RuY4amMm!$z%h$N%lMG?kkzeEdJ=A<1=z3`%L8-{T0SKEF~Yxw&}8tW1K^&WWSzmqG%Mo(0R; zC>?w&c7j=(3+t|T+RAO4z9!rGE=To7-5Q5GyZ4O~{dFVVJFib3BOMCCj`?jiBg>9w z2KIxr+FLr|LyVBd>rg}VtHZNu&x}47!^itV4<`HZF;<-3JhVx33lTdZNK1nZ^*eY8cSt1AqRzWO5tKl^uXPT%UM$Ti**EQq;xU*Tb=mFndNkDpUy(aTjh+;1BE;x#@99|&^Oo?9|%d~ z6;hLFLi+BkY>MJ9D`{IeulIy# zDR!=tap|(?Rf3Mk9*Yb(!DF45rSDYa5q)!3!>uZ&eTBmFL}Ayf^to9T@5g4a_)ua51K*QS|-84&Z$&A}KRQk{4Ei#3$5Hr`3VOnv5M zY4aGgl|zh$GImpryQR3;EJ+ljdufNh4TVM zNj(Cg=xKCH=)n}BKbdE69*rhx>MP=ED8uBL*|6?>*gHi9wP^v^>khZ~oN`fTLp^rpCgg_t=RJGwdJmrrnJO`-pJy4rd zN^1O?;~no+7u;l1g)6;eZA7ncBt{%!jvtL)P!t&~obuq_PjZRq6c%df3cm zAF)ta|D$w=#1r^B+a5@90}>@v*c<=xw&};Q!dJcdp$5 z=g&ETdU}=RXJzsJcL&G^e2mXqEn)5|I-uWOepI7Xf1Ce4W;KG86M3iTjMI@1@t95x z#to=w<=~h%)M47_@Jw}bQcYR%U%g)7&c9&NXpxmvS0=*fU~2PO*-%!})E>q>Qq~mL zvTTLv&J+|TgAa(ZRWntdX)$a<04=nI&c*ccz0rsv?`IV=j!azrOFu@DQVC>SpB+fb z3a2~V7^r$SxHI0|j45s^@4Pk3AgQGCO%Mzc*&g7CabqUkH%5vzvAhs?8+dvz1V&8g3 zp7R-E@SarN>`QIN>vAx>;mSUlR!n&TRsUt7w8Z+dx!n8xh%NQzPJbSE#T zz#^p{jFwH)4J36ZnBIVv(F)A;i5Va`)Xt9mKj9o8>?Z0-!Dh3)c5y+ zf%z9O=K@WZ_zt5TeLYtZAE=@q2h@yf@~bE#3kZOoUjyM zUZ$dTZF2dYcw(jTl{jCN;h$mP8&DYbk<+HSN>+|oE%fb*O2leOYDly z6lTt=`5gMNpoKVDmR@Du*X3JpD;+$aQmpEb$`3POIdt9`?$m<>f^#}2moD`?++be} zo;ViB;CGlqS;e@TWc*j>&Gv3{&!+X?Gf*!+=ri(wbsZaiBniQW$1tgTva@5d|0gv2 z!*idE@%n9JuOcH#F@Kkvs2LkOrz|)GzD+wI3Z(D8dfhoE!e1?I9_-;fxU9O=Bge5P zO#~+3BhD=#gnybr3}f;6ZmTwkKOXgP@Hsp2+|QGJTN!DVkazjf8K-7A!9&h7EtKlN zGg)As3CZ#`-bRXVFt8okRfeCp3US05;{lUVN%_-6D`j;+cS5M2@fFP~VqMm3y2Of? zwre$l0NN?q$LTH6N<2n_yxO6!sMUgK#!tf&{Ih~R^328&(%5_~#oJKKX5_W@gkEH~ zE?&+osS_DLKk-b{%Y58kg%`&yM41p22H0Is%LK%e8+ddUEqMvQaJzXD4KYb3YDwSC z>gz$4qQ?x7$whro;TMJ`vZoVg+x;kf&%qjPc9v+Ss;Z?Q$J*KQ!fX~-8v4e@j<@w! z7Hi>Xb?%`^Bc;XhkHmEvL6K)O@?;<1Ha_V@=XIUQwO}^CK8pVODpj{z&uA(`$;Te~ zzJUh6ZyOyM7(d!jS#epeI};+HM^{}=8{utADBtIGMu3M z1>UWG?+D+1p$(AA6BaofWeZI+Ho=(TY&ah5Fy47f8Nu^5*~Q6D8w3^(+5%VY_CLXU zsv8@0<<>YUCTntLXks`wY#lao*;#tzX_J{SH8Z@(4&baR$yvIY>*YnxRQ}w#?SYxM zsIk?M(;)?=3b92La27FBKaq>8!Ww-IbfQiR^+QaM%E)8m@Hu+~rNaJqA9mqrxIV&o zfCj*x$;AW9r*tLG9EblPq^1F4Xd1{j&7eBSm1cgml%4l44IFD<>3}c#YJe=>eJ0R= zoD)zF5qitY-)#|f=_kO(J!~4u)2)u($z?Ze^kZmo{1YqkysBW+2-$s2qvE1)UH9{` z2TZ-nstrS#@BQQr5Gy5HURSHI^0!%Yf}y?sd#oa18?_* z$PS(foLN{1DReU7hiqn!Nv_SB)Z20HK$gIaU94?KKT-b5f^Yb8{l1|XW6IR=L?dus zG`ES0b&=;;0=oAA)^XGeVueB^CVsTAzJ}8!@$Ie3^f?i|wrIKdM+Qe&`p=Y!;;Iy^ z{#>_bv!xSzwCL8-VGxJ?>DFK{uzD^8QPM|NfLUd&wCh!NXyUKXO=W*l!kK(YxE7>3 zclwpl#0sws+pJ{nm1b}3BnykyswkVPHtjrdbM$U37~+v#^w1WXfbo0m)POxxm>y&w z>6^2p0g{{?vGR;!{cT1BKTY@&c9(NYV@5;a0(jf#Mf0zwR! zganngv6W2$*@-Pkgg~OQ$r>rj5(3eL5DiOIAeaP*20~0ilKEr%V4r!P4>R-5Tr+cB z(~qV7=eM5UIp@C5eXRTpP_RVEgE79*RmIXaZvh6{$UGOVE<3epL_{RbRHi0@PwtnZ z-n-ThXOF(%iy9`P^!4XOmwyqXr{rqdRl(Dc*kd!#C9N_EO~pD=zLiJ`d0x@ z2rr!-7~_|!gyW0SoOjBsh*26VeON6ySpTV2w}|)X0my(F?;hy3TceI7Qk%^*Q?nxplw!HrxUsVJ*I-ujpmI`kGTW48Hw?32uWj zm%y_zw8hLZ?cCZ3XYw_vncYtBTX-oJjeN2<KVizTrYDL=axpQ>gsp!fb7}0uK_#wOq_sc;xdB&CmD&ew7Id)=Ep!km> zKRpNx!V9Y?;m{njIm2FfISM%zMJp*{8cfX^Bb|e0FM9a4!@6zTM`HqK*U;R?(Rl+C zU#c`_fbnb5)!g1gBAxJ#u2Tx~q`dksbC&6~O3=|}3c&I}vhsHPH?`ax> zY6#4LseXJm@W4$9w@vq4dABL@!eEmZ?|wNr@AKUdMu*0HYqWJTV&GqW(PyaY+BW zaI$H_H}bwmeQp9*lK2NPW6;z%73|%g-Qt09HD!k}yn=&SFX)*AlZc7wAJp=*^?6HQ z+Kxc$xdBjKpZwXx24M*caP03eo#s=wi+&;yU;XaJ)Isqv3!`O?dcj8iTa+|$x+KNP*oI|I+qVu z4=T4{m@GXY*Wct1llK zws@y1!^}>LYXUL7_rG5uflfJ-N9v@U8Nbd*xP<}*~t|ToWj5+LlhF6W~Km7kYAz7p~46UOC~mWqjHr=d+N z&wu$2D>)088S)?ha?k$P14;iemG~(u`aghh1$B|;=JGwH#DC=%fe(pspK%OxL#ApT zgnD5i-B0?8shUQ#eEa|;0{_bEpIk_4$=trETCt+J<8J!j*c#qoA>gvkkssOe7fQxe z-2K-=We`_{YTl6rf9x@(Z%L<(t0jV#_aE^4V4Pc|#M$oXIse>cNevvhK4B6E`IzGZ z0vV8LD@V78RcZ)WM@Q=bluLD{Hs~hW17^bGI=1LWq<>>^-1y%=|H`URvmEEEzmhVb z&%YHdBU*(ZAN(3SdMnk!U1I_BJR%x^%uOYZYNpZ<+B&BtzAH;_WjCyUDZW!a~mcO@FbNaI%9d+F|Q-s-Lk!ZI2DSU;H@&z1$bmf1WGnVle zo~rWw91phXRmCORuC5PVqmZzHDz=*sy*z_j@r zK$RZ-yws-5Z|;A8>DRNT46Mv#X68RO9*ANbwR56M0b1lkpX z?=`Cq)%pY+RpWQvSaT<^CTu zP8smEe;I>c4L)7DIRNqA+N(dGs2f04TTm!3_Tz zIX+<_1w06tV7`Lz{tZc|8YI$nBh#ky>yaArH&X$>Fvn4Vc!JpTZvEf12GTDJXDDiA zs0LWxyJcwzJNvQ!G>N@Mo!{gp^MCn@Rpigj8qn2$-(KzH>fjc!yBc_F zGW_S-q6xYzYaK{wk#bBxOGvFUnD>H`m1z^a7DbZ5JfI7i6W1Y(r-3U&`yAH3x$bMU z!Neg@u{-vJz41nHtd#_?FzgPD2JqGFg+NG>-WDj^Jf2BY;9M5nup_6KYG(X{weAin zKOZFH^TCy~V)srkS*zIG_nfS5gb!8$@hTXB~i$0hX27=L?+PS}`XW z*+Z6?98(Dl)|tL?3SSpbENFZ<_Ijo!X^ZMiETo0oKo7A(a%%|O~Xnp;nTrvevx-H{k1OLuF7= zMBa5@*KIeiZoF1mLe$0$5jtIt>;y zD$%)8#w6&PAB&7ABW}1M?A=~<_>XW-mT$4cdc)?zH2y9N&h{&aNl5Kk`eODNAdd z%_4=zH`LM+P5osJ7IhJ(RrqG0nHTe*mHJyIE?k zqe5np58`&)LQB+N=a!eN0v7Ch6V~cxQmxUWN_}%mCPnYsVVE@Ykn!j}ONXbU&(pv$ z4**=|W)8-?78ij9meYrS z&V=oy^6NIw;S6}H_D648^c{QiCj4E?QCmopIgJKEWi-t=jM;{1@*?#4>Nj}MRUnmU z2@UqGTpWUZl@~PLIQ4MQxt?q#K`b>ZA@5aM53HuT3P_NECn_}VU&8~se3UkeS@pVidIY66r}PId1YhCZJsW*sQY7 ze_Hi2b{zxhNp3d!p?@ih68th(RtC|lr8s*5x$*7<1(@p;q;~R>{N%8R8t!lwj9QV8 zweTNcZZ4zWNfbLi_u6MlZmK>yP_y4-E5OU`0#nBB+bUqJ5s(N&0?%6C`bD!2GM%6F zF$d4?MnO0x7*0b+-vG^gpQLYE^|AC}MgQ5FJ8ofAb=XO<7?mfdP5(xzjp2g5MxHR2 z(ljPrb~D#V$e@1VyCMPiR&BicQRzKu6)H>lP7W)2G+H^usY2%0c1eP_tyQ-Ox3JY= zivfBXo4hPn1%5UY&WCs9PZ_h-Mxpyun|%}~+6M7l^j_rg{qdoDFu{Q=fKJ=mQ7Wy6Z!URB78?KxMby22| zKyYWbXP-gDuGUu z?w&CC<}9_ixulZc?ya^@Sqk8(;kvQBaiHSSvGl{U8A@+ApgGPzAT0xOM52k5yf``d z7~AJs{<2E(nNm$de(})9chRQK1?{~mE4tm&UG7$NBNz-rTAM*9X&i zw!asflT(ew7wAh$m$n8DPc1^3jo}*YXr@kH;W3UCO^&~0IeZ+GdpO=s1sU54I02r> zFHxJ*j9Sb zmds-W@bQr2l2WQ8JWMPVxnfx(ngipHS4~Y&yYR521WwrNs5OmF>{sesQpA#Q&bTp- zWW(GcA2)e3p1GY)_Krt2b_3o%i1M%KCj)ppD)mhoGn-@2)E%D7mwf~{&=Ic+Go_RL zP2gIKO8zu0^<2pH)lH`oD@2+t?1$tXyxWI*yk%JIs8x0w-)ZqrPCb`Gh8r6XlAVS# zf;i`fz8Y9Sc9$*m6n_bC^|~LYa-(qF1WP+X&|wjd{n9x$a1_0Rbi%10NTA zXh6m=I5c1Aw3$Gni87N%=!mbVb{{+lp!k- zYw{3LQo^f#ycKrnT0Jvt?P>NdWmj;Mod5Yy=Z^Eq_LCg%0Xte9y}Q_ijr2=6jvx9@ zvmSOAkX=a@ZI4g66n&N4Xgwi&XE}Sh#EBPbf`NjXb(ALW_xq=WaXia^n{vHb&a=fv zh@sQ;C6QxOm#F!42e!eN(^;XKZBp^Ma~jAPPGI4p+!F94!T7Z2O`tO6UXjU-yUl&x z1}VV#wh7LYy*(Xzs5bC@c>Mk2*rNUAUhh(1h(Ef*tlt=UH=hso(B&H5V1+i&)*$utD+*}pT@%Hfa zDPER3vpT%6JfJ%$)T2?u8+bPK(MNNPzui)Cng33={;2U*Ik%~=wTL2G$vEek2JnXd z-M6EeFd2)DXOkYgF^r9!+KpbutmxYQE%B<+)CVvzp(a6PBM;7k58NflP>Ti(My-kU zMjKAmnq0a)+~H&JZT%gjl}36kpPc-A-iPP?nWkiC(a_6NmciR;v$*)Pg^Tn;9{=Kq zd|rIV6GUk!2h2bdMRGOQfbl$RxC(m8V6sov=YlP)v&EDIlMG5gvUkob|4BVIRuG3- zrpNXY?h0m|Ars;`rWaZwf|eX{9kMfk2Y0DXAXG;Z-HKV6&`ZIGI&!S735@<2uW9cA z>SUjjkmxj(+cch4?YBt|*qpZ!6Mx^Le4&{}jDZV3*#|c%23ikwlj6m~>DB7t@A;nj zAb@q?ooE|HpoXAGAWUrYb*6Lw!|WZ2jwhz3_yJ>qzQjzjr6Fo| zIi^X9^fVE12Bk8aaeT|I*{*#3*KqZ<>fyR#r|X{RNncB$nR@gh7Sc#tJwWfsUy{!>Z#IW6_E-oe7a^!M--h(bzo4Y7`J{1noI;rIh(3b=u&M_YFQl_ z(G2ZEOe$P~0+gD3#`7=Kb!2Hf5tf*HNJz^LoZQL=Zk=X}OyYP6G^X@;jkhFeXU$&% zrt}{n)E$~3Gvg~t8yL8fbv8hH;yW04S5C{Syyi`YBPTBb$!>Y_Li%K0Q$n}B_sy$Z zayalA=|SioW4zo13U3}y?3Vq+n>n2WIC|dybo6fOZsJuDJLkWinV2s_CnWrQR`=V} zsG?ph4e`QdTa;o3@WTJ$91hCt=5s@7yRKR6e9{JUhvn{H{6O(Bt6n(}7}f!7E_Q(l z{(o|o!azJ<>S91wO~N59UdnQ*ucA&&9-pTc|CQ!TP!k0}JPX;Qoln2dSGW+EIBMcY zPBwT>X^AkJJ}v!R5Crh)?K`#fz>in%gU0B;RHNhbp)p*jzLo2t6_>n{cCj*=XSWbT zT@-Iv1Z7H^-bm(Af_6SpcL%=~MXFROP7!n+0;QnVNAjZMNJat5g?nCoKEmDV{2@ISn- zcR#Y5H_aGdC#nf3+0P(TGZB+0wuQovR1B?zkSG|IybsoWIX8pJ$^3lYfTugDK|BuA zuXmWKKc$7qnky8=jKSvi#lomS`<*+}l3ewNt%$crWX8Y*7kYY*n zpOhYi6g!$tZ}P20D}u+L+5`OWNr>D&`RfCNE62;(<7I4Tby?TJQ97tLX zXO8Q6kuplw|MaHn9w9Ysuj|#{nwFLC7C^Rs_5LV-bb5DdJOfJdoI89h2%6|7>gJl$ zWxn}}xh8*@R`2$*N0+`W{-^5!j6Y2OQfXVhn|{#lG?|Dg~SU#q114p>zk9zP|tyto6Beuga#wC_Q!^?m&xC zsh4^&eELwAJeS9N$&t41nU-60n|M6vOWc||gx}xvbHe`Tqy#So>sDYQ%2OA=leg|= zxhO$<){>Oi_A$C5uXlWnh^B!A?d*)3G4#9Vq~jbJ=5&OoZuXx_V{V#_E&sRtD1DHJ zNX3ld^$kkfcIxYkc@3j^+@s&33oW4ha!;+n1QvEn}x z!wgJ(G$kq3{+x$(F23!5wn8lv<5~c2&?y5)02L3~AB-uhcdYUX$Zv|Ol!(Fk1;SYQ z0k^`{s(fYe-egg|`mh(W4V=R`zYn4QQ{Cd@8WflmfSR=+0x^^wD0o7T$hrl7Xd*&F z5|WdD1!{;NC1Q0AhAt$36;yQ~-qleV$gfml5cf#c1JY~}D#E+SdiJ3iEg!tos@F+2 z4J*3%yJdCCyoQfWc6inJy);l^gIep+I3aJK`%F9ZXc&9Y7b20S62AbAhgjh_hSHTX zBj|F_2}p+3w0HM}$6>n^2UmamkC`mLnOgPcw+DCuypFHP%J111tENUMD2M}oma2*q z3Lc#quT7;-nW}sx#muY*o8cfZvJ(w5KpJ-%O#%Pf%|RH-AhSlH3MXWy6Mt-+zfo$A z)J7PAEF-Op{PcYr%l7w^X2ORNZ02?eXe^#1aD>m`{i4~Dpx2HQW2Zj{efxkiW@{l( zx%{>uDb48P45HNG$ZM-z!~>m{6Pbnjkk~6Hy2(93MNMU%gcs0!qucLSL-hI_?uztm z%gCvfCQT)Dqw6KmG6{2gM>#2+rXbeBik$eJb2g-!i7cg`FK-9>LV{+|Z%%B)d1^0p z{n&kSZEgdM$HgDatuN7(r4m*g2V*k3HoJB&7GLh+%8#qjObcj`B@~Q7ugN4&0oR>F zAHAn*3f-Tp_9NIt%KSK-w7l8VuU6;YWXh@0zUya~^Sm_q7xq7@#c>X$U;Y)Y5XZu9+$PV{VB+U zl&*c@6`4OrFb2p-YpZtk9n)PI1C5kRPLJD?An1fJFoo8CtA0Fdo`3>}WLz{ypVW)I z=M-+?VuHSvTGmJfC?#Gp4xH~+Uuc2g#9GQ77-1&J??{HWw3@(SUW1i9y>5Wjsr@~O z`ukq|?;fg?-7Qb)dS&_A=QMsDm?+wM+eHwk>$!z}w;J%GW`VM{XjqRO!ixixDc z7~dJ0f#4w8CVsZC6bh=6EftGn_i4t)9eK^t0HU3z-RGEBe%437Q`LG>->g$Y)N{Bf z(#uwc6!1z;LiK-AS-y7ITc-DIwOvi_WtBfixtugJtjip?x~s@Yx+dD9a>1zlIOcFo z*WmLX*lZVlvj|_lMDy4Ykzt5{Jnj0}NkP*`13>7)E0v-vAtcW!p$&S*&MonAXdvy?{rZtm>%Ekm!aTg#e1@vRo*X^HV5eMiclTsbycB+NShIWo17vw8yA;J`Z_M7=eO-Ea@)(H zfD$Onmo~)rkdNQ3Wf|CXG&|YsuL!^OD8P2io18k#~V$0hbJS zH9Zdkr56h0%rzxW(_Vot8bC+|1e$)?k&elkO`JVGX-jOO)Vl(;mm}bT#L>LInta*> zM3q}z0rw34(J*ZC5Ux>rm~qzAy%5hd^q(Aw0+W@wz$US=N^-)k4}?{ZDuh>o$Tg=K z#@p^ST^qY4no0t<`DmW@J!{%IDJB%LAJnNc>q#EC=0qlv1Yz%nOy-w0_u*@uLZ{S^ zszkWPG(9)@|OFe61n__LqWh8Y!j*@$4WC9 z5{LG%>35XE3_XU>9u?sb<_}^~NQO`MhZgdfRg0+yl=!BJZqwgIL7%8q7}`RhN{{oC z7Hvl7_}k{ir6LZax(E9XT2K4vjC~zaQXE~2Q}R;7vu!}pcE9AbgfKaTpymEwCG?J; zR(&i;G_XSbJQ1lv&-h-M6+Gg$w3a!Yl5!hjdo~OrxXy$_BQG^|Uj5|W7uBK6FQ)|q z(5=;Q4hD*~q~D&Mj^=H+T*=NJq923v@l?tOD4XnfaCRUUlu~^SD0BRr;947MoGXJ9 zayv3BWTaQObH%6Pivj-VzV88?kTii#6Xw+Cl8cc*@td*AhJZ_T|S&`8Sxz zc8|bn4un=-)|eX3?XTYNMi~QG@98mY^Vv1%(bsos-q`LO^O;0^h%nA9R23*49tE|H zCtSC0I(2AQWv{6h`m8W+JlEPQxcl+N;?j}oUTd`6iR#cudX-iJORfKdTJ5kLnOcFS zG4Z#w+axbKV&sDPyn}sKN3!I2Aji%{K2gvQDjiqM*PDR|B!jbOLXOklz6cQNW~e|) zFTKN2s5z;edXXT!YA0pQkXfS4*$w1+a+LmRoFm&sMwT=fIX-fUg*+D!KIXhO47p#G z=Nw8M(d>6k68Q^B$kNzA#(5|dgb!r@;Ca&!+Cw%iu`VJU$v+t3XYArhvq`JJ12kxX z6Y1Q(z>cT#Gu`J@f!({#BIb|#i%nA?aSs7tYc7?=1%pPoj-{9mChJvmhHTIhpXfDB zEb)w_F%al215p8uaWHs~yAo(cgS)PDTeJj4=fyUH!7hAOONc=~`gkHs>whrC(re6m zq~R2tntL4&7ds#|YhG9VtP+RWO=r~lk|OwFkiHs!V72=?g3u|Mr-|PY38zM7u z;F@DoU&?GunIXd{=!13)B+#^eBiYG&0lte?9jbEOK{NU8(o5$p#Pu~lj;0siVZCwD zs4{cfhWy|JB@MkToU-(WMRfd)Be+pdz1Jl%lP})1GDHu|Mk@4yqemDBM zY--G!yTdOPNr_l%B= zQ6P7;CDkOfJEokoBZp_-J?hyp)Jj0t&~2k<=>4s%GWEOHQD%|WrQo8j;Ap(>Q z>6dsM4j_W?4XhYD1rrKh3UFxC6!K1|U{A79I85Lcti_V3om={G-=Ka@&i!DWI=Fhy z!*5toYb(ra*LdJd;BLi5ejO2oxq1waAg`#UPdV>Hm6XbxY)Nk6bp-HvV_mNDPd?A_ zATy|pgy+y#+oz;})BDHuY<~%d-lOJaS9_brWCitr3#PKjTHMv}XE5e9S`b5r!4y@f+2T+G6Dj^q_90p+%zISHjsm}V#RZFt9n zd{}#?lUNe@9<>irU%r*2V;ab8!{-LO5jC`~ox%3DcZ{w+GDTvkq$LDz##tz0Xq-~d zn!6NOX|8bvbrw`*$9nEdLsKnCtWMkMxC^SbCbNBd^`iA5uH);PrZP;bTPL!x>pUP9 zh>m0c`lL;F*<}U~&iq`>-=)A)p{BI{Ynj`dOP}o_xrq!yVEcms#W769^f6^I>rwJj zi3+A~=+3^h#b4!yw=;IzK~t>%WE&f5Gm8^Bgix>>O&2t}g>gGOCNLMrc9Vz#T(-z< zNuy>dV6suEK}~eEw}O4T1po$}*jnm-emN@lA$#1<1Q}$En%#gdEy}wSD_VVOmng@2 zIWbQFDfR{g)YL&1qk{h3RHy_RFn? zo5EN$ae;>^!2Vn?p8&7y3SWIkQLvPAAiLtEB@w;9lnkZBue>(9Agx zL%vvHz(W~h>@=Op#WYsL;H}x%NPb8mj=tHMF;OuI(+k%K25d*d_C+|3?Pj6T`>lgV z`FY?jdvU-he~9ks&3KzhUPz^l0$Zq)3v|WOzHpFSDZEr++EPaFVJ_aMH%yB$y_8s~ z|IlIGF1l&EgdC z=YrMI@z%QROF9Ta9(f?=o=R7AwdceNSSI}So-Ne&o%*0| zwz7!Hpy!8?yp)*-a^wv{HwtgiKcQDCK&w_Pgx&zDdu5JpX<^%1eIzDL35owub>*z$ z2Eg;y=weMTZF7J9oBA7B(Tv5B#0yi_;@2l~53Wc*i2zvtGaTEaTbICB-g#txyO(~8 zgC+rzjzNeeV%pa~o;Oefzp{JbS3V%WKwtKQ;#&aX9Rjgrlf#2F47-~)ruwlfPjS`) zH&Qisxu~^*mz_BB3I`iTjV1cMwT)uHn*A591~~WsQ3C&^hyDLUzUu#S=H34W!LR?8 z73&Jyl_TfT@o(B7I(fZ;K>H@XBLN?fIIX5V@P;^!NpuQxh)&pnIp144*El!NdVXm7 zi3*qiU>Sy=7}8?(=Ojwo@~RaFW7cV_5QJc+IZy{(2(yy7Kr|a+?@LtFk9}Z(1*GlX zq}%thHGsC{81u!v4osS|(}~(Iw3`FK679o4)q7Xe$NR%yGSBNOX5B9c9t36XxNDbn z5}@pH760H}tPVAM^7NWA6FU6jsLEHmDzy0m3Gv;MQ-Gax>WLTXB`P{B6W64#TQ{l+ zgleDbPb$A38o9D7=WALf@G0P13v6uw!_w7JS$HH8$Y zTXkPlPpz;rT!V31`O+XV$0-g z&F!l@(bSfMkEC`4VbK+F-aLO@OkSAgCy6(z{d3{ELg#pW7OFGQU`Uy3Q-bR3#qC_w zW;f>%L~YxWxgC_a^`<0z$Ko>436P%7h>cns2@7lCr&gOh|E8I@9=A12Rq%mL9OcBb zu}91_W~6OjDC>)2c#i_xTjh2iTX7{|@tbj{$SeYkP=3>?ePFsg)8Y0(G7_jx-2=N* zf7YWSxDZO9j;);NYkoCO*TdMDH=A5Af(>VZ%`Wwku22@=^A5V6OChBHkUtTw`VNeD zJ3*m2i?>7Yp{Z9$Ej-yCS_NsIk^K*5IKUj-LwsxWlcLFp%B#*qEI;1qZ=7nL)}|;r zWL!?(H*szCbx_Irz4t{xrunV-H399(mqxD3$r1i?b;(#gwbXXlqB*a{ICq=t^_>*Q zuHrOUPziMh?ouhvZ1e3$6E(}?(+|2z7en}fEL&cY(wsIM?QK$Z2P8dCdYM!rU-V6Q z8F~Dnix>#_ld46k>Q~a-WV#*-W`a~Pn7%ZZ`9mkD`!^hS`$4@AuoD+nogTF+YRWU| zlJNSPOdi~5tSx=LNqB@_3WU+m%GL%1I$uqivACPD?MPu=iTud&5ZA-2)@&aW4+f7shhC=D4Yf^Zg$9G@Sv^{_OU7EiSC+sz&6HEu;}7?A;qR4Ast$z5w58 z=`G+0)NVln>fT?*2aCVj>we_6wrJ(!`GJZ@78DleOAUx`SN?hF4C|czuF5+-M^#g= zn-Q>SA0RpSKFnYe5CRxhVBhwAL8ZDW3!9^t>8)6`bKMQ*$o|(EF-6wArl-6${a83v z%mOm;Yj;fr^yt1#QvkW02v*oW*ZkS;2+P1pSkZ;!>9^Hp(BLtOCDKIb7XWNC_Y7{h zJoWKb&V}nykNu+Ow-}FD@E(9h0zOL?X`;V)b9r}B(#%jRj$SIPqz=@eFJIL0p`r4b zDp}_0*0g2I;m~kvX|mnOSY8wK!A>d4vp-UWeOyfY{bpax=#*RGjN*Rb<9wC{py2Bd z%6*oQeuta`;4$g6Wfhp_X5jw&r__vBif=SpqhXtX@@3tpy(BE`<$PL|LR7jeUL*67 zPXZ%2cIj?uhm+)uM=(u%eYV4>l=pN9%~_nFuf;qn(_8-4 zgYB-QWU zGkg9gpL@AI$Bq&lupF~HLuUCUlfjdnH1BVku%(6=N0@}Bkk&K*44;fa3#d%+6wYUU zX#cpDQR=*-`eRB%2Yd6YnMCl(qn8R6t;5*e|6V12QZzH{qpuZh)%+eM z_Sjk?zv`(EAf8~hVCYI5-pfR@gH|i(xPABQ$#s2qO@hL4Vq|uMMYdw4QNQ*y$0W2O z0N_A#ezcqf%wc>8xoJ!F`Gj0u#mI(H_n=wS_53nowVyVEWCgS%buz#E%S^rS9CcE& zEoC->zuywc!j6MW)=1&%gxEub`N8Aq|2%LT`xh-HzA^f9y{qfCyV>JUz^#ibTJK*XJd*oA@y57mCm#v76>Uo4biD)aiT_{dv`d-j}9Q>z$E0H1>r(K9Tk5O z^XHATonki&{EyQcUS$GwtnzZ{=QQaTRWrYj?O8XSh5O>zaN5f6-UcQjK52|fIsd9e zod1d|nO4Q=xat22RMEL-1zX7MS%_4ey1C#M)2qtcP3scYeX#q~mT-{kcRF6}iO`!g< zTzYY=<)kG+BTtLe0_CvS`wj`Gr7J=oCQiN7gIV1K9q|*arp#o|ysL79cz*K7J_5zF z5FsdUaOoh)Zt_Q672U!eBo`b9hVgl-2Acq>&@$7`V*sbTQ5@J>kv%c(?s}G%noELD zr!33-s>##~^teEwcr*^{1ZZ zr|9`ovWSHe5Hh1`c;dOa-AMe7~ z)qeNrC4j~wuBGm*Dk4$lK!_6vgFY3AepYk^*pqTVFY)!rV&5e@UXt|x97Q{v?p}u<#|K4e`<*k>$7ZOfLxHvZ)e0;okApzii^z@8H}fpQ+8Bz@0DLh4h`Za_I@Nri4n zeh|$B{uW1@e_6kgu*)@teb=ZRi|9_#Z|}P5`(0G>10x>j4>Zi;%K0 z9wU;Lo0h!T)ZR_#%82W$$DS{i)(ox>>mN01zpbR=?85O0E~36xR<*khXUMi7ax~dZ zQH)By3&R7G+tIMg0!9;&JQL!)NS;G8zc%D>wxm-@hMC3fFS;(678qAZbr zlY`HGRAUk_L`F}EAD8WzoI$2P8s({PKMFu}zloZB&j{F#ry@O+gV8X|)T`t@=&%HQ z;z-tAqmjFN@tJOzN^f-HMi-?bV>|Ci9+*77<>hZQ z6$6SKwR&JeZ8yTkUd&l~RLpEO4cA!RnhAo=d)BCSchlRXr2~W$`P$p8R*15m;CQLh zMxRPsymS~)Vl{y9+Pw5#kj4Ot9~s7wmh_1D_LT#S%#i(?*GtZfXONJXcDN#xq%#@a z9$l_y*pV534+@AP>h;Rgaaq|le)6OP{0mUdCYflpv`ZpM$96(VxjTl*(wYQ?S^IbS zO*Fi_pQ+#^w*MNuJ!7s)VJfn4Con?S%z2p5>UWt;t_{kC2UU&7dd`NavcV@>1SDXc z9e0xesfvKf?iPil`Szn%ke580V2K=d5dGd(S+ie;4TMWM%)rT|kc@25!R5c&)PTE1-i5)lNIosz-OMJgcq~87sND0A>c7BaP~em zQaF1n>Cd8$b4En8U8TwQ{WGp6Q?fW>n%%z0bCA*QH>O0A9cT;*r~*CV+J)2WTHlNv zI7D&&q5beZIHzt$cyNOWER>PYJSyoWJQxV<5nW(B;)wzIk$Vmkm198HgCHbUNNVEK zy)l5;VACG_d4t>S*W%de)qR}lmpjn93e{2mWjudE;n6NI&;VXC7Fa>xkgBmYU$}^p z$!TUN^sLq$qe5_i@{akHlMFuza5fcxv_6`><;Q#v(#v49DQBbnb{#((pIk?t4!Kl0%+)_Ma z@g61Dx|@$D{I4$L^2p=RSJ8Rlu$PgM??=Pi|H5IOnJ8!=qxd;XN9N+|Ap& z=5wMD;HV}W^~PN6JZdCNf0XUum_8q@aM7IYZ!e!Y(_?2eWtO67F0!w=MnRq`B3u@& z$H*^bIV+q_whqRua5O#*+%{}y_qq44&c28+qHWhO=K367*5~QGO{74rf6S_P7d%Tf zf982&;Of4m$11%0&0DkcI@DW|=fkOg`PndeeQ;L-hg8(Bj>`;^+%VL`33dH$|wvR~FSF^Jj`WaQzt#4a>~BXrv4mITYm@2pcYU@=}D0eS4s@ zewqm;!HJ*v;bH<@_$~Wj$V*gpA($I8q55gGQW%lV^Mr`n%J%_BVj-ai3F0z1C%Bcay znW0ge$1lG>ys#47B2v<5IK5()%>_S9Eg8F82*ey#W1?Gm#QKeJ&9+FpexUc%j;Z$3 z_$lB}pwo6%DkgX1`C*0~y?zK`NM47x`f(m>$Z4woY&P7J6c_xd&c&VI%kMp@;TVMm zfTF#@vvbAD?H9iXU&|}`V3^lzNIIN&7+ILmau2L(Wp!$f_!)Olp{_xNH>)s1gQR9W z@IHTL1kCqgd7qNhrp@wjctQbC(H_^JzayI($BJ${yPQAOLC{Z@gCYwXJ8|dg(d*Y& zuDP5W-=6m&)^phWNxFg~kFiV5VoGkw-EKsw8vQs^05zp4aEPi5YpEJfg9$6 zf$3ijAqXw(WHP(+K=nhNSTCINaJI?YIOb5P7}fD7jxA~N;FnM2I=+1s^OV_rAPp#b zu_HCk#v>neQ%a%m4zEu|K2ur1=A$cx@x0l~q@r9?u;Sz31=C%ZGJv_;CIU2-a1!Bc zbl4VP+K-XyAL(p!t;>?Bp0ecf@^Am?U-wTvk7jf)9-cZ9n&JA~I-tK_^1GQ-eQl4>s@4SS720HH-|_p@3p6le-sMArAqvvAGWtRh(8eu8 znJ+|UDKa(R(a&Vh{61ws-44N^_r(C$|8Z?;rL1((Q8ZWDHJ<#lb^5S$FW8OPT+ej`<0o+39Nw{Pb@3A@ImP@F}bp(wow(2dO3YD-kZl&9}qeQ zRT->!+h+qUr0+r1NFnj_5pp{tg;ArB=qA19;t^OJWDE`)cl55q~|yv2fvE z-bOS^Rv_O_HHh9@6XWI(?=;&$#9uV;Efd{;LL#vY#lcJ5@oE8mcopi2AF0-_XN-H+ z$8!XP1k@H!)gp9!FG+1IJdP3E;u<^|;W(XdN70+1Y%>Ts)k16Kg15JNv&+^agJunR zUV1`G(z^f{Cl0f6+l=}=5T+&co_Pe82l-FRy;Y}Ony|V_aDEUrx}yKXZd$`uH8qlr z3lfVJt3qjgtb4^OvIFxmcDQ_!i^ql%9^I(`k#w+hbGb+GaEg=>a4$s*Ioh5yakgD-2Jn<{uQ^wHy=e&kKUR#}Shec<0(?nSR0V&3;@(!JE&TM%~ z=q$Xul06RG{#pg#eNe(1n9 zzLQi>xbFj`>%4#ptWQfM`Q4nDTjR+;V?0;cUgh|DP;TguTp2l@ep?dZP{OL&&lkvR zju)Z{Hd^d9x^1KvhBg-AWgZ_AkA(5o=d!r4l}uD&Vt>jbv?W&t6|EOuZJg5Nw0Plx z9L)TZxL_!_Z-}DiIR-iPXKN2$41KgA@6bJ(_?H{XX18b3x0(j!Qn)SK3l$vuh@lxv-4`*F2NFw8 zwveHx4#~aLfM~=&Uq(QD%3CL)>s$oCa#UsDhLxdT78J^Ey&rC7{1L7yZ&iGQIM!{?0$=MsGoNr48!m*- zo0)9louw}mJdM2o#SK>H_{znygi66oR>F`|A^PCvnTuZ~4}kC+r{&3=yszi~n}2vR zYeGfNj`+etaOwOg|FApj4D@JtozFn8yxQDho^?f>+(I%8TY`7$LdON2_Lf&I;CcU7 z#mWCqB4a_W=6_3{ng15p>3{0L<~3=6_5~l_!08$>alWBJu-5-L>D^ZR1W@`vZ1Aa+ z=RzL1rN3!j9LH3vO=Bf8M^t(6`Q(Z0Arnf__E_sG?;&Q=2wuwg&bb$Q!VF9y<1(vP zw<8%UNJ}vJt0e*el$`@wB1CHe*)Y{d!_Jl|T`xCL@KHe(0&l0uLT?2iA?>5jv_CDu z7@6qiD~ql?|G{v{hGphcj%T`$A`E=qe1g3&%f3@>-=;aHa!lC+G#kKAG|99cM~KQU zbmMH=;Bs6M2f}QSUiWm>A&(%x<=nHpazK}6)#Ao?K zeBWF4yZ3(feje4*zeBSo5@=zsFy5m&qWvRIiWJfmJAsDjo+O1q^3!?-1D;MbbYN$= zS4#UWp+y2FOT4j(BzpbC+x4s>v$As>n46e|3zU-$G)rQiS)2K%LgGPzRimxq8(z4C z7bt8oq#4Z(9Xa4Wdgt-0(Wj4jFP64bwTTcEekec$U-R2+$nN%**B+*dKQv$tWMBr-{C+FFJBVwdml6fnb5Jxa_74uw;&m;+3mcnz?acY) zdT&K>0l!^UoavXjzn@v2OjGhO&(@DGNqwd2oQg(zk?n#!>zn4f5V=U{;65oe>{WGB zv!q}IwPb>Y(ZZX$XrX4yUF^jc_%#)LuL*Q(o)R3i@QV*L{kjV(M#Y7q%0X1UCU>bzu$Sk{CSDO*sN&nUUkRrjbiV}8qXB4jepWy(st@QBk z1!5Bu*!2KPUNwIX>KUf;gwSHpm93UAu1L=zs0NYh>rib?Bqp3)m19G7nHU?3f?=?NSH`)-C=jiNeDQ8UAVj^`>85=&*k(1 z9^Z&RbY9WR1%$Wh$Xt`!-&2Ad8Q}=HyQ`&BXTlK&#uen`jb1pzW0Q5x&YIKYT@AD< z>TY!6n{f?hDHJX++4EkG8RkKQkNBjUMc1sh|$lQ zSjvN(U@gVl?WOz0$@7cGczGiYvNpaGzx(jxNH2(g96mTI-aEaX(;>N1tsK4dqYn3X zCmP_d%<8vLQX6*|AgswlG-+HrID%}CxlX#O=0|ZY6L2&)cXjd<4z{*>%3rS{!ND&}q+Tb--4Gt%t%KgWU6fI-znK@ssp_RD zcnJ^d!^D`=v&I68fDZzbb2Ag-5(5zcG0cOjaG#1t;t;K`UtRj7BL-*i;X?A_#%eG6 zQpStpwak=#igz!Q1CYD61n7ZaJl=fkml0(a8*qNuy`IrfoXXt4Ji@-xg5!v8ZC|GH zg@XaKE$tUFddOjPB}6kI*iTo2)xY7KsfsyJ?Ne{;d}+;Gw{)UKA^C9ZXo^nwqkbBp z7gdrJ@*H|OHN=#=$vbW~gIIPE8t^VneKuhn7F7{+ket^^HgEDJ!>_PbCek^!7 z%W)*0f9+vjiIppE^UP1GefG(2t3We(oGGhW((J+<$>pU>Jk$bg`p9u}(Kq1|7RG{- z?IMJkPfZCLg}3@XV6ao6?aN1I({LOuxS-vGu>^T_XxH zthV()_3!r3!^xUes@C-?>b6l4ebL2_G~An??FOQgQDs%8Ge=h0B3%s?(~xs8=0ISq z3BAhTXygmGcZsvu%xQ-*FQhLk%PbSW@?$0~`kBjdqc+t02*JwrSq09Y-j)mW*$%?? z<^tDB%sp=7;?P(31t)EY7##$bwt-eFU*)l+pRCOId4dEMae7U!I;Yid=r-( zC=zJWlP%dtAL+EI2E+<*x-*y4H)O_?SYZ0Llw~Ke=O=<17PlLcoQ_zj=ezEb<;as9I%*5IC~%!;KS6S_kfZjX*v zhW?q1$RVrRjUL%7y279^V+|DViw6z#;lrb5;-@jCx`*j#dUQ@}J6%#B+)qbqaw&!t z!Y>nZF!b%_>AyRSoKu(1(6`-&a73jlKBITG0A}# z5~Vp045vc8C(%YJB!$mK&>+$CE_7$dYyzU#HAwI?I*VFjo-fCRmf9$H@pv!5e?h$GMi?6_TX^f%$AfNSa1Z29=)YCW>it|^yvsfDs@BB#pL zfpfSJFs1LGw7#U|M}(r->8mj|wM*L8zr4^QpbKL<@uoegoYqEu2@aeH2fba~REdY= zH2ZNzRS8S#A+!@AJ6|Bm2xHvc$&Y7SN39bP`klq$ns@F{gjbiDu0-e%OYe|vfT0mTWJI>-UlHqLwRE$Wbf5h~NWF7h z{&zUr4AO0RX<5Lnw*#V!Yx-x)7!IUPTKO~vnGEaStru{LNE)Jr6|g314Ke0J-TbT4`H?=cON+U2W-T=D z%zl^6=wZp>Vpm!}Os9CCJybtirXW|o0CzU|0t7#@1M@NcI1|&DT=!3LR1z)j_|cwJ zP$yd#c)QYM;{?Mk0pSx0xr_>x-;@_Q=mSwlZA~_!g-=oF7hIlWl|;CZzb2vxGa;O~ zdbnBnLAi|TyK`yPqnPav1(|{}D-*OSZrniN60ut4xd3&TYxT*{Osr-1p2T!1fFg^f zv`0xbn@4C0a_53=n#1_~=hgk>M5SgP?$+>!(h3^YS(O`nFj?QS>SH_nXwr4*)wa+( z`r^D1%OSI_G$(2PI@GHqm|Mm2wxAK$&?*3N`R2mG`OR@(C2x>ntOyRT_o8k~7* z3SGgl+Xr-?zQ*B?w^TqnZ!2qx$3vKK7;T%U8qEWu0}A{DcBQ-u_-I|GVjPcQ)I6@X zK@zaHI~u;f^I5g4^`HTdG;h{I89fSiZ?!%Wl0`3|eYmSYrR`=pzQW#!l?VJybfb!`T*Qr;&p7kI7-E6Q zNL<&KvfZ<1FX4$WGtU9VO# zHTdpqKfbo0UDNYrB!*w<3KPUYu|-7#a_^BL264R0@UHQHMflK51~F(G-C0$==R#cWmiz;yvjk_(8q z#!-U^(B(K{?oH`>$AKjQWEpZhTf$MM1%jF(Beuu@tc?%?6dG|1P()Zs7e zv9+ANBX?$~a-$l!$RTZ#P?h1TMpH1!Hl@RyWqB51+rpg}@}@T5#M<9e2o+n7=0s&k zR;-_R=4Xo38-eDAJoliCn{(#I-J8VC8w@9s2kze`58cX=|0H?nlK5O>8!l<7)mzO)WBe{8WSca%eSBwdjz!zx? z4(mPGe_j0be{N8|Q+$Xlr8JbtiWj7g68oew;V9W$@Q;k0HCgJ!D=yr8!LL)ijy;f= zzp}{u8zrncY$1;Z{JQmPh4VEH8sQp{mKaJ^Ny*7n!wZ|FUkJKr>d=wO14+Z6WKzlB<7~;-kr-yx9{ph4 zz(vV#HN&jlv(=>42uW{Q|Kzf^B0*gBxr}OFk?yO_$tDav#1ZG{5Fhq^UZk<8$4+;W zZeE<7SEGu0HlsU2>SZSsh`bCfqD=y%j|K5yRdXfKg$)5@)gJId)iERfqO!JMd;v=( zgaRy>EAHm4)#3M)(+1a)pX^v03*!AoQmr~<2r)}Iy|!REBwJti3S+I(QZ%e4dcP`U;g4IcNU#t6=y*!1-!s+?ie zIipYDnOrx!b3QUR!MinpJcvV8gC42pk2;JBu2Aqenc4Y)p&gH%x{7|l+LoiHQEhp*NY^2igs1e~ zW^(s>XxhF>Np)h?_q7T;GmO{paFJ4#&-Q?l0~Qx5OtZe8XIgL7vyrFq>#IB+mvj@% z&b{2TS$hH1m=mG2uk_G}S+K4@+b&x%R*#E5KrkT~^|X9SIJE5TXWX67`!1xpx#8J; z#`6WY+{H@@q(CGkO}V|4gn^L2*z~1-ELKQfAWM^N4OP;J;;Re`rioO0UGLFnpFTYU z&EPPkp;mmJdL2c4F6uG*_D>bNQNyqhZ;$>~ z7iq$vQ^rIp=PIKNy7F$`K?7ZH!F*|K#-i$50eB2Ux4r}u)O#BI$xXW|?n|P|ZLWef zO#^M5K; zBb?+sZSQNKzM{m~`v$UAQ8c`w@4t}*} z=G3S{U^%lnA=rV{y{x$C?&&+9e;d3zs2K1EY<2kr69V7n)N!vWKtpDuiIho<)p zcngkErj19Sf@%uiUNswSUHD}pE&E3GDSt|gh5KodS-SYZvNGToJMcpmt_oRrl+~iV z0t84kMl0~b$I~kO_@(FwBk#xqA)#Yq+KGAR0AoEoOSSVlC680m-c2Y@CWO&@&)T_< z+?X1(icm(j6dkij9fa-vhI-29C@J{IC_zVk5GZj|C(I$Zt8vY za@|%1$F``c^Fc{qUaq)gS6X(aBOKjx!}AHtw>)Cp5NtxO46?>PU;++0c{w}}NomMK z{Zl~pDoj=Sl=W&(el8RPL6TTMxjM#7TiY&Z-CivmTh-A#%j=J=XThSdTjQn z$=8;PN^x20WX8_-9=#z5{CHM7P<4S^Nx>A$ab?5l>S5BX!N|uxcA}{%p58{{JXg@rC24UtEL9gd5!y1!=2~kb>`kr*kj@ZAx&f==IR*wTYg_T=8 zrbNj@`x=qRDWAe!UGIZBvzI@KMcSxoU*eVz+Y_h$=u!3cNb4S;+HW18Pg|dJol%?g zZ}DMY5k{DiQi}{9N`^xtu9h?$Zdb(EcK5tVNH;BKkN00`ah&`+Ujr$aSCBw2Y6{;7 z(SK0q4@pPZx$8$UETVdJwb9T0O8U5C&EUfM+5v-18hOCh%58Z1azt;|gzy@Fm6giT z3nv&%7Espps+;-lCn)R_#+%?OG=foXy9XxGnl&drp?$N}&#peTb=fgT)V9ei)l6ST zO6A3avnI5Bn;BPm(-I4{P}GIUv*4MLlgwzGp)KlkHwJINZ`LG+q1^68bOM)QMgc&G z0dd=6MEOkO)wxLq{f*MCx8$jJ5w6Lr+4p;&l|QaNFnXwcX8y^3irrM9*Q;_7h9&7B_{ za-KguoN;m~aFla%Neg9o8}Q%B^66F!CSd<}A&lIlg-h+~e7!E1hkvUjEgLKM|60%B zKL^(RwPV92O0aR>%|}4&RaG0+b+{IK7NUUqM7a($QTAR z91Z;Pl~U`r#_@{qq`94z^W@1kQyk znb_6WY&^?(%VHSPb@hiVO}vSo1M4n4+w;v~eKp}@nup3s@}6SSSZmY1gFLQPZ%Ccc zmX?hP)!ThPNH$Whx+LQj&c;b>1v8pmw_12k#rgq{XRf7InHHQC!bg99oo!?(X?2D= zZ3dMCegm!+;{%=(%;w!_Z}z8dezWmbODGE&cB4a_I!!c(Wt8KS$)V2auufw{9ij>d zwDYqT>x6+~5v2dL1;zh#YUBloJYnglq=Skt+H3cs|EVb?wCfT>TCZ$VOf%vQFNv>f zQn?t9*=X04b`{^1^rcLkr}&qQ7|hEW#GmUJQthGRkc{!3Nn*>hKybM&oiLwyG0g)U z5Xl^nAkIOp8rIy^XjpWq^79_A(2 z2Td2*K9KRAf*IeQouq8GwHOH@O%2e^FHSb>8*-a~iyn2flt!Cfr#X>*C<2MMx$t5^ z=g1DBL4m!d_}U|IWbupbbBBKNx;bXiv+=;-Adgu0R^{M4jMKtWe`CD$@KimsCWu)ovkB>(yfW9Z_5^%LOS@il zxS%~egpth_%|ki#Ds+}a;d3_0-D*}<^X=yja5kw&XXdyjI&< zpVgnEL;sv z8$ozMwu)$aU+rhs5xp)uEN%SU-J(*p5Z2uT^+){g3r_dv(x{4_hrf)7LE;{uZl&1S z3X6~wk6e^@ef)GmNSudH!IHgw*+1w8&^(=(;y%7+Qny3I4xma zDXu}sRk6JM4XFb!Dd^Oml_{^jZuLyp?E$!rxj}X)+Cy^T5Jjt?t4e>orSkp0@m5qD z4$mw;5Rhv2SLKdaWFYKHgkkh`3h5lwce;m5oNCzZ+deSC)n?25x9$bhH!y(3*|iPaw(Qciu!?1~&qK0d@; z`zrNSz?b9_mG_K0DF=5oY%^q|LMFmDrm?DhAScGZ;@il~K@6AyNJtDM;9G)^Vwi`p z_nTTOYzjZ@+3sC$M|!5hG`m)df;1v7RlMHMZ68(Vx@18C=Jo<5`c2%eh1`3!{x0w$ zFJBrxg!G!i!P+jwQ$+`o%=99wrV0x2c-;?b9vQou`^Q3hw+!0|Z~#xX z`oX;b(i*=qo^r>e7_8-WlBy~v01`KT)EEdo`)f)mayJXKqS66yQ?F2v9F;kup2#Vk z_)h~j*(gnb+E@;1DE4UMUkCZRGomn>d&A8c(14oWtcNd_tmv{9KZ3JJ$Z5*qxBF00 zaLzdi;80c>Ml&9Sj;E=kGi^BI{f&lIVIE#)E_K z;~C!zuA1Q(h^5in=53?hOY2kur%VH48=krP8g!k*n%PmqwL9yY(v9BcD?T*3Gogr! zE87lbGZoPjQK|NQa6lSo>O47+t7hM4!FY;+t7W81bJqA7RVN!05Zrfv?;eXga+Lf; z{p{4XVehu}PpxK6yGvNXQ#z2&5c2pM)Z^K!*qO@Pfqu{|Oq)@SRyqO@cKYT$Azx)T ze+c`qZ?;>l0{vm!1$PtZ1Xz*0-w@iR+Iq@N9nV(GO!l0Q?UxCRN6WA51G<@KUlW4u z_n}^gBE{uQHIY9Bs*l&|s1uFO5K_t}_#Ye@3gd>ri_*>dvB6kHZwg|`Jui3b@S#Lp zrY+=4P=?Xk%nZy5N~!qHS|d%(Z!}g|v8tHMl8xV8Lp>iL}&96-&fMYN>BRj@t zXMdBf|8ubBp!mK~g3SOSlHnu#YmPDa28EQUT@Q1h2rv#!LqJ&|wZ6o_*R!%LLn0{p zxK!IBijC7{D7H~P z8*PU2gO*B~UX%m;2{{Mgr$T}ve0Davg8xFAfRo?VuFN+idaVHz-7}vP-C90K`np9a ze6ylQZ$e9;M51dVqMMwDn7$@yBlj+)F=2+|#sx=vCYZAI%UM{zPZF0Kl@YyXCj+a#%6d5yB!s2bd?LXQ5iTc)4!rzx!H=R z>kb7HmgxytAG{V=EBXsWfFI9rc$8-*ur^a+2P6dvZ|irV2S(MaRH^Nd>nbdP=zt8E z5mTzrr4ohE(1EhoG#kx3P2!@Ta!(T30yHC!1eXW-{dgHN)7Fw^=cm?Oa*8>y@m=%i ziM?vwx)!x5O??tH1#{WbDUG8S5PE*VzDrk}&e)d?nF&>6=Sq@3!pa&rzh6om$8!Up z1Dmy2p(yLZR!kKS?t?X`D;5sh%tZDA&v57?_jD>GBjC;%X{bw*e!@sfO6#*7QH{el z58ITfoP$LP{*Snf%IyHX7W0#sodt?}i(>4bgmMGB0vlVu>SGw`z)3V#pw${J z;4?GYf|*1iVxTzaa(s#Qmm|iuf`H)N4RiF_313^eKjyKS!2`fmES=~em%F~LeiDsRIV%PRswMiH=Z%NbeR88FR+0Z+<$oB@}8!vAi z?u=}EVLnyQ>6Lg+cr#WSWPoZCPuY>A7k90H-*|C56jqy((4w+ET!H1f^_^f^Ezx`5 z2DiWHVV=KP%%D-PG1dbc@{bZHk*6rRyyU8c7q+8yiwW73%&TFiJ8)Ul- zqk4J@iK@&s9vPyG591JkU>;EL(r$=bqhIwjGy`Rd)$bfhGlW!$&4?wrX#TYpE5Q#* zQ=MRZvP6V+X(_3_G90Mh_>X4PAKq(>297~QaK-c(A4mkDl7&jfqD?ng<2dIBfX569 zNEdbgI5#4lf|Ca+JWV;KDgS-D+R+Fz-b2FK>^TcV*e>gkK8p-2dQTZPYa8A#HU$j5DG>)V`Z0B$MD|O)aS_@Q9B!*1Tvg7)y`hl4)4K)?Ksq@F+Xwh02u&=I@3km4av2W7eg5>84fYBtt>)Jg$)M1>`YY-}0&Sq@B44x% z@ce_%4^;o4d~3SneL{@F)fMYU?(L8_wlDJ`c86?Sdqyu0+owj9hjv)?=iaEd#Lczr zspJUAyI^AP2-lL6PxCQV|KtvwHXZ>zqp}a(VBrLTtZw2UEn)M9FUKTP_8I!+$9pnC z*PmjZzSPOP z+9me2HuRw`8gw@GA^WrS=a=o@mG<1rRNiCkF2Aqh&N}3JYIn%a!4n|st4+*8gU-Yj zlP%OUgV#5?eMYQk8ogIy5WYuqNs_RcLmW6duA7G$8=)IoHeHHi;Sy>oQPdLYvOpFG#VFlF!`k29#^qN;h*}+ zWHEi|>6ISzqCUDk!XzfbNhW$DTgxA|1}G|s&{7D^9^5Fmg|o6qedP9ICXuu`69%|X zZ##yo$=eLm-G1Q=E7iVLDAcRXy$FdXbG46Z$&57k2p8>iNHH15zx+dL6a|D7=KquV z;vr!lOh!g2pjSwEWG3Hbq-p=Z#<{$ZZ~v9r(+FR?er|T7{E?N^f3{*DSkFH-)Oq2* zd;`=a%Qs=U_sNqE?E|Si{7oL2`)$fX7aRBf$1-ur+Q$K7(oh`T~J5d@(}cW)6BfBo3_T5;!5GHT!@SEeM} z5axpTZW|X1flbeYU$Z0Zceh`{cSM{pLxWmsLxmilr@4x;D~|0LJE_E3c?@Vk;zh}) z?&Lnf=Oe#R3_IeDv!DLT3~niy-wT+O1+x^A48~E4FkabedQ5Np4D|N;`y7SLP?vhC zSPeUhZNGi-L5X%_qT5DjSLKb2tC#5EhFi67xLdSLGWqh?cq_xbnEiV=h(LLmhGi+ z=4WsC_$5~VbQ#Hgr*xF?LaX4aWM>yq!m9w4yTd-#^S?jWd%-=ph0uFIAcm@5R|sWw zano17T|2kEu!Os7u;iyz0PLzD=TxD!*NzruC2@o-$Lo1<*l6r*^nnBlQhZl&a-+ta{8M7C!YSc zYS=Cm?btT|{32W&}zxx3%@_1GBAgZ^bGb zxjYAQg~HhFWA{V9?7EXcx}>RRI0A216n2Y_nykFWCsgdR0$S(${{!Q=r+R(Nprwt* z%VUL}t6s)pb|#-xqD+}?CmBK||7dPsyQ5)jsVKDe0@=%-GJ3r* zC#J)Bv_RHF0X{!eXoJu{V`FaZc53`_1^4pI(WYn4HGdk5O8X4tv{+1-%}rk+ydBZs z?e@#aF7m4PJHEVwFUeTxafNkxS)(JUbo#c!KVGQ7Os}^y8oIRH`5Lg^HsRa*1q9kv zd06|vz!~)iT^VoUpLP*j=6v%36|KFK;XJ2^1ONWwEhS2IQh+~_cx~MIr8x9HGfOOq zA#-2(h55SDF7e%g*8A-a{E!LsFEVIP-n7hkgF&k`1K8=@m&P@Lf*8NxwB#W0| zYi*7uHC049h1s|YySR?xWI!tx%c0*>c(5x{A?C5;_-XaLCzH0}uY6YjnWZX!nb{y~ zS&_cI%d23_W3~=Zn+0>&%klW7c7yyLd;cs{u-*gn4{ve+LC^~2IAC`h1bp_KU?=R+cg25S%$x9T7W7BdlF=#tlLX>-*+xvd%0xn?Nw! z%{Pi{_V+;Md^3+9lWilU9d^W8eP6^yPa#bI+mHSm0jU3+>hynrjDb#|PMI3eHw~h1 zazg{>geL~Z+-ahDA#ECVc6&Q-I`II7BLVG6b5XJ$CF#wF^JjrYSah_2cfWFlSk`&; zhBwdj(hi^Dkhb~0cZ_hLL+6-QYFrGU?VIx}e84e$N+-$q@*Et*9SfFe-nahac6#NI zC2-TnWd&CHZi)MCzB}RgqJ>?qx;@#UeJW@(^wvz(XQ93K{EFn_a~GxwxUB06%axNU_LnM1(^j~2 z@x44t`E&f0d6%uk3I#shyN~84m~l)0{Qk{|AHO->(MBf?Sv~dHtQmTbjQgXb9iRVs zzVy0bu3&HVUH{ErzRjGtV<9>M7dt|~_Bj)=d|I}84Rdeigyub3FAt7nNzLQF`8#;S zMN0tO&D#+<%d++$COYm=sJROhj13a=J^TrZd( zDEEhH`|9z{QT=~~X8)Is$-D0!^bZdvi%Rff&K5Nc;B3Nt1>)W&400Cl9zaSm1TsdV zI=qx~GMhPsXp?bzhFJrVWAd!u2y};%ntrFY>$mx-Sg_`@;PB3SnQEG}QN!(o9#dwL z8uY))Anw;k)}f!bDCdJ3M^kxY!;hsudF_8f1|s58lV9eA&LnChv9IjmTTMm?H9eF( zuEm!rne!Nhm5c|dHQ(CW1=7?O7dt1gVfQFL!X_;iEB}rWd3Hm=t91{-(Czs%6D@xh&~*w&dpc z%fIv>ggcMq@7;gm{9fb3xpNw?e&2Y$Ti(h;(Iw)aO|#GIKH#QRv;@V|XiVFS69z*f zT?d{IksY<)>anKfId5HKFHg;;Y5M#44?F6I-uNH%+Pc-XDc!EjJhCH<*e@lqv68?& z!HD!KL0a=bLqKsKO}A@AIBWYV6wUqWNtIu+#4*|l4E5L;^(wa}yz6qJDT5`fyqlIffIuIt-?L_j}1LS)$?o z1Pqbcda)rNkCBeFzY?ZY{k%iThGm=8$o4Deh>C96U?kLT^^M*y>>feAsT2{_kZ)3a z6{*-6Cp2^P9_pGJJ>&va)y>1cXngfT?&l>--oonlSb`@@FO7CGl;l66`^U>=FMnEY zHFoXxY?~u3@vK$@{J3q^%!~bb%ZnOOO?C%kPFS#BagFj@lgg)9qwubnhEs-KEo|+W z#L-`4z+(zpl6Qb1bBf{ny;_!@xrcUxk^ zJ;L&W%c%`5dZotD9`PJYIE{Yvs6M~^h0Z9ccdz1-C6(yKM^rk&s6YYIg^J#m5@q-) z!&w7OecqU@ye@s$x^alF-snmc{1dgGGFcZ%3NhC$Pqboi7vd z&9u>*48%hx@Z$IXbx3DSip{&$ki|#?zKVrLSCyV@-|KvT3$b5AK18WVpOHUxv0QOB z<+%GVOP1&ve48_BGIG1?(d7MFQN|n1;zt#QYy7-E)3` o`McAi<7 z8SfQ5A_xM3_L^L}a2*8V6#;>`V+8ntp9H;#PzDZMi0j7ZLB%~1^S}pQ7lW$?AW&(X z(DofZ;PW1@OScdp5Tu#&kE_))&lv>TeP?pPz{=l#k!_w=ehay@cTRrUMP^k98z#rg z6K=fL5tbk-t~nnWdj683a76r&mNDLyH}X^X1+!)&eZfbcpYF{*l6=EJaF2n-46mv3kQWJIneU>1{(4es zYj>v}{d)R*F&yVTLmW$=0cJ80-ubwhcWD7 z^v-}k>(?JtEl)RLcbL0~_1!IWhzfA?sxP}Vbp5gRCx9KYk#%0AcD@ZiU*MDfP`o2> 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 >x7AN=_~q!F-q>?*pTdn$fk%jN zl33M3J~*Mw*^`3w5i6;ZP18aCnZ2m|1Pwk5EVod#FTp7QTWwZgaz7}U{c7Jz-`~R* zY(dO0;1J&(Nle00ghr&HOU$D`>$V8o7sth{+=y)GyL`B%1`WkuMnVc}a*%-?|D5E~ zN;%>DBHS^iV#TwPp&DcN2G%!<{IgWDlPfuQx9%a$A1!UM6F9JvExK|%LCf8kE?={Ce~OO#&)WsNtx+b|Z% z4ld!zCZDbCw_=$lEnR`G1FJ#N>)mtju+vXREQm-r1e2On2{|!R8DK5*c_4TA+TBfV zz%67RZOU`%<65errw{8&rCXpLSG6D4_2}!i<+@EpR=EX$7h}3_bY5+>(VD<{ zpMz#crJHF02cOeUt-Xe6WW3RI?D|5IRq%QBi0)Q<0Ckgh68*rpNI;vBC9H=Y%X;8;X*5sA^qGvMJ%){8lNCz{#}#-=rY+VhtdN-&$JU)^8#Nhkn{$dDvZz!!%9AG;HXYY9q|5=V;$Y2;^J992*Ccbzivx57$0f=7Qo}43AiYy(dsD#Dl%fCr{ z-38S?vmG8^-E+s&G0%9S#}DbXYvq%1qh?sZl#wiZ_jkEy)2+8R^gOmNXJ0Vk(iJ1} zr;Bvx%RxU)yQ7|j>lxh)prglx=%npihq;7j+$5~Tb;>f_!(bTTZU})v34yPspASX_ zZ{*`Xz^eTwVWE$;>+a2$i_S=l#4&L$r6RQpMl6~igR?X>62I{Irth-hLe<|miOFvy zcv4bG>Ze8oK&DRojncrfP~K-$+oZ53fS3bxYA4W0Y9w|`^K}L% zNlP2OTr#Ygnd6V?A)S1&(|0@IfD^79DBT($B8Lg)b&H=xL9!gFKh${;uUXWktQ&|#Q7 z4i&yWP!Y%B-X6y*v7GpC%j{FJo=}+^J*~iY^O65IDs^=o5UO0aFizOL^88tB?dozOlhbl|pIH&Oq z^VHsw_3`@=W}-D1-8Jj1Rek>^6lX=XgYSW#>P8KEArS3*wDJzea3<-vOZYs1M=Q^) z-NzNg-d)$A&2l#Ho)Ms>X}Bdd-^2VeI>_F>8>X?{^KEH(T|&+7Z`}>lVUxD4!S6%m z!p!QU%{9io)n%S~P z*tuffc0@!`C7K+(^Zp&jbDX=uU6FJ;N4D@yq$VFtI1kplaGbuLOJoYD)_Z5;GLODy zj7J(S>@84i3(!YV1D73jp3ig}J$Qi{c(Ro^2VXHLc@4M(tS><|GKn)fO0Mi=g{Gx} zHr6SLf977m8r9m-q-`GIM+q!?Ehu2B(-)c#)bx)zEAc&Lh_4ma49d<=5)HyV2~5cS zqvFV|ZSn5ic|Nfv^FZT^3lnN>iZeTLOvFMXjG$B>Bvz$mVa6Qd%P=Mt{8!+??c)Fc zW;)^Hnf3qWu3V`Jw#wHe2jAPap+xA2 zU=0sO^vLoLw``2O2s>6}XpxfCPuvrN|Nfy|rPS>g$WX^*w{gD??(z5*U_5Zxjj+Hy zoDz-0r`gl2jvU{oaRy}wqbL-s6Kx|)InQHqrrtmmgcfmsJgv1HEVUi(UC|tLo|zf{ zIZw~K$7V#G&IC}VUJnw04G)34?=w03iP4>-)PF`(edcGNv3&&rCV~x5!1#)Y z?C^T_`31W+RW9e`Mglu*7r{iJmVNE^HK8w(b2lg`FG;S{fMuI~dkqPitI+2EZd|3D~$ylHbt>zKX7d53XvD#_=%(kuA6e%yRa< zr$o9?7wRsCe%WFmF<@CWUmf*9F(OS9c@OaW#%BWR6#Yk?W@ua!MFR{#JF!PyVO(=S zpRD!Sv1Td0zaA2lO{hd#BS8BtgF|bkH4syAY;eCBTRS~4m_cyQsWF+wCU=D$;Nf8; zhw;swJ)^+o0=AbuYG+&E)idh`iR9t35a{*O-F(-5cJ`&RuO^q7&MREG^X=ayDs#WE zoyuNslp^O)II$jv=Yplxl9-2&A9ue~K;7f&xPQmXma+6S>!J)rfmZE?$2WItEqs`pXB?u?-3rR4uERKMNJI#Tc@$)aK!t;TeAbrYTeLM*s$J!&AssdsO_{1hzjm?!$qB@!L>p4`@HniDZ|rq_D= zaq~YiH3GV%Va4G^u01Mo1NgGWa!4NE@p2LIH_Ue%z=b1n>bCOHg!IYs(0a>>_i(+V zmGi?>W~lTw8&xsqEb4;glI~`f=f-KdM5q1+;4WN&YP+uzB=Qc8i;Qw%FwPNSW!_Kp zb8EvQc4rXE#7ejpFs{=3ycCv`#Hg&z6t?!ijH{?S?Ef*Y5;2|l>-Ja<fGE<>Kjd}wOKMuj5z>*4b-5qq-`mJg$!NOB!N(&0WDMGXltU%SIOLu@<{)iy2t>Q z#T+a|cRJaX(}}?pknnv`MEo%GssvFRGr&}1Ue-G_aHvx6EcIrPZZ!DJc)CbD9RU~x z4Puw(EeA8S?;jOk0=V73bXaSk2`!on7Y^f{Gtd`Z3sX zXXvBtJ@jMvdF(IkA+ZFR7qcmfwJ)0#cXjN+iai}lBbV`cH}d&PeeU}4>j(_J$+oDP z`zX%|8EtCIsu`AN-fTK$*RM{yN5P7Z&`j{?B_v|=c*`%*V@QneNBG(GpoqcF8s`o5 zChD!KEBHYxj|OnRun%p8wAw>lrrT8g;^zSoMnJ3DfU5#t%uNy|oNsjne?URmvub`< zUiH478L7h4=T~?o`W~bIE^E&D;YFoTSDkoGX1JAw{a@gIOZ21;~zgBeR-sE&K1?;sM;ZVq@I2DtW;iQiRaX*jsKZl2) zfgA9@kHeB(#!zYB=I_p*&)I|f-$P&4!(kMNz@7^JFx4$QM4s6#y}3PEQ0o?HB8JCK z;^$8$%M#c$+b>pG-qUB5ZMZ)@&_wgTSbycrjQ*9sKloA>eEhQ8^0c+znK-NH^OM%W z7vVEXz^1u|^Dq7~da8!p&}&)d_l~(Y@-1LI(PGaS5ZylH9e(YD>`AY_@u8ly3P-3< z{n6yT%bPL&yBwO2Vg6C3Dep7!bJy;o7!&c$oX*B*kjwJ96?+H5m%ain$iFlz+biBr zCUa{)@4rDsSR%?r8s1P3PxtA9;B?N}aU5gw@Jb~U+!2_+am$1g?SK?={vCQ)iLXw}i`lcw6t)NWPw2mDJUW&DG@;Y6MOYXTyIm-wvyrCQ~7>pIKGE!)S6 zqvbc)(6Cd~(}pY>B=uXApWw6UU9&%%Vgd$y&hCoumT)GX-5h@~PSa2A8Jk7RxIH_! zSwKGdFSC-)p>Ej^m@K`z02oJ|oK1W?)C9uRNHOC&eNUj2Vc%Ee+Tb%)e}Q&iShShz zvZfunwsgo%9~9_gLu$^bb)S59lIwRrg)8XXj?STajo;>lUBqcef7ZI`({1rD`P$4f z_K$kirK#7o%Wz&g@97WOfFL<@$HKTV@lsZ35Urzh1%&>xxX*$OW_2rpb9t z@vQV4-6fQ?pWDd&k1^jpNjpFB42`er1{H^v(Csn?Uh?A_pjDPo3u9=agf8W4q{%J) z_Cw1(kR*JSU_AH;kLb!Aew<5b>=8tX1dBMOD=6T5fd+z{81USW8_r&ehGNYvo|PJ5 zyKC1VA?{nZR#92Qx~kLtwGUImH@nW)L;+g1?NQ1{)WnS;=B;hCdZy&lH5(c!h3&vTg4ZQb#+m-{wc<9kE`(({4`dVyE9u`PqYl&EU>D z;8|n1_2op1(2yCR7?Y}vJl+oSUTHoY9WsuT%)uO(gw-MPy548)%A`TGlHZMS37=cyEy@gO%Pea{Ud5gGyjO%kVgsE>LLa2bOJz`*Bh{q^-dOtK5GJhFxBq?{mi9) z^Ih*`a5siXs;uy3C-7p^ml5_+X`#q$sF~+W=HR2_HZM=F@-zwprF*XLYG#1vG02!D z9PrLLPbLux@*B(gnEb7q%VtuXm1S@_hFsUv6P|(_khuB2(Pp)TLi4ICF!!8A$W`?9;6i1Xt=TIV3@NeV@spyv>|DMX%cREzOz2Dw+5Y5T8wi+eeHC7apQ>`bfqCBMQEjMS6pE}z{bV3!>r+=iltnnvjozdkPDl~#{t z9(AgF>V5>!@qZ6Ffvwa(Lr&8F9CD`8MbW*sZQ)@u<)U*Gwr@IppN`3wox6dUbrZhi zvusSa(y(!S3obkzV;U!>RsVSsnpKCpF9d&VT1ENv<#ka1yk2T+O%>M3Ufn3;y)fDtO*dT>pgb)#)Hgq?8T9sv(@P4zg2E17Nh<_aOOcK!1vf~%-Hs3 zofkhGJN}7MZhUK8m{-65>vRQOrq6G!;?88NAb3h109*gpUjq&`;S&mS|CNz00AKpI z40D?K@qbKifyMdM1M6o8qM7@(FAoMX_S04NbRcd5TZ&oR0SQ49UTIZMJYT)*=%;Op z^EdMk`j6B#Z+N90_&w~a9mtH_H+)~iDb1;>SuX3j**;W9*ycavbGehy0Hf*J9`|1skw-u1)8z3LQ zeqB6aAA!i3L~#rJ(ic#7)RSdn1~3QPF-O>ek3s?#g$^Bhz@HFp;dWmXa%1Qt=c7Ok zXBB)1!(FYgSPtHhRcSWvSneG*p!Wp#Z|gnMVyTd6kPMHP2Mpgp-{9Yu?fk0jIVFa*ZLo( z(_b_~+8hjcWBRCvR0n|CFfJIHq7*=yO9SAE;{kkgo__+G;dNzl!Nfq?hMGcoxn_Tg zJH-abr7$5S3(k?+a8~rJ@V5y45|0Km;thlPy>3(N_Q$ax}@dqac zi}hu-d;pl~B=IllnX|VRQjElnPZ{SEuQa%32!)D58Qh~p*e8oPP<;g&Ez>EsDJbh2 zFjCf{Pdo+XpPI?{Xxk3-5;WWo45ni_yw@L>I9&kvN6cmY4V=SxTnT{IV7=e26X0?G zf>kE#hb}hlirNTkC%J|*+LWv#vT>z?-Cpp>`$pSVlv|7ZD;3pU^0pWdp*gSlMQ2ln z7h;!3d=%k};VNwe?mJF;nP3@uh<1St5C~&v1FnVAYs)t%`LTtl2d#1oh`xvl@mPG6 zODqY*LA@rybBj>Hau?IQ^)umfMQ>d-fX#8>XuRP-XRp?G*3tzlSxzHG+$z*dHMq!1 z9jZRRPt5>(1giWCT!e6wGsYhXhFvUd0mPw!CL(VXxTy3S}7#p9(?POFgD;!>u)~f z)-11(4>Pc9CTFS-o(p!}HJi;qoqbwWTrtDYP|Pq_q4myfV=0cwTN`@HXL5;@1#_7U z-hpAP@cYRObI@e6S9uiBF+ZLILxht}^^)5D{#-yZ!!yCtksf zzW4A5eR@cVBL{&A-XgppVGBP(6jWjmu<}!&XZ^r?<97MzxJq>IkVMiv1CR{&q0$SK zXj;1&V1=k$z(rW3t}5P?)>>I(HET#KJ|5bNzv0}JV2 zyjZ%#XeBxETSglBZiJhnqs*HGfT7-?){MAvZ0k@@F{P#&C8>7LLTspCwSp@EH@MqH zuJfic0$VaKbXnY?RiL4dEVFN@`bSE<;lWbD&O${4nZ^X}Es=$9D-gFuvxm;yvo3}j#6<@l~k04 zEbz(9(J-;e*k#U{`d{1TteG@EGlMaMHCFPSH28dftIS^Tu;KDZ>RqOd!WcVd#6vfP+{9YjEWEOE zQI5E-;?X5NB+?%0^pYU)A-02h{-iS>_ZhXAZXkIBa3?7o#!+9Na70`<%2jdP?3nVg za9`BX&T7parGAm*_6(#5JLmi&Q^JTUutQj-(JXbsw$t0tlLkwmXj36Iz&|i4#N9!Q_iW%H78b=p=*10LxYg`{3l1_71IwY5$5lp8Hw zg0$y2WfmCUXwhB0c+Ga8#M}Lh?GnSD;D;x^wz^564EC?Q%U%lE=}}vb;Y$K(bhn@n zQ~9XoVUw{b(tW$!lP7KHrTt*1YU@eB$#}Op_Q7@6ggS3)b5WD@a8mF{vuPohbb|QxD<-A5sXtwhuRp`l)YecGaH8`jG{#B0v zEc!w|)^;^ziH|QqzbDNKK~(*4uEvpnSqHXRywlny9$)F?}ruIhOm zrGqWhYMnV~3*K(|T*P{*9Io9dw!dyu=7LJ^oR!0nUnd1pIwsV2mNf&2B1#7vBda2v z@g=ElIMS3Rc`%Nc;}pudShHeSchINp5Vl>VxF&{J9i9xNZi83HLCaz!Zq&!p_1cF4 z?QtH5c(XiUF$g%`|A9ASyQTKXBwDv-+w%2HL5vRFU5Yo-`~|2rjXvMC{5# z`={eBQ|hc!CDzWIPWhtGz((=za}gY*S_s!B#O{_7UtKi?7f^a{6ClpA+%N zN-;sIH2RzZ2Bqr0+=itN1z$)P=Sh?t%ls|uWR_@oX^S#GA(;oCZ%znU+6E)A0S`Mi zw}4xCG~(~6K*uRQ+v88yZYt9khM0!%wT-0@0o9oOKa?|Zq5q_uNos#oY&tVI7q2mx zDWhm5+M=|CrwmL7Ogvfum>jx26kN?&RlXLk~$S{)UzucL|`#8*Ou{Gn#aqv>(` z!kZLR^bPX6W*-2bq6h(ODx{KFWixy+(|m;$DXeN#h~ZC?o3jb8=QS_0f` z7?uubg`S;z4LMX#uXW*11=u<>{tRNXf+ebRk-8oRp3tt>F}^}~O_iRzA-w7IMILrh z8cECjbGU39`)9Q~IkN>u2xF~lLYrn{)&lAEVAhSbV7opoUVceUWW)Raq@T^W<#SNA zgQbb-mlx)Kn~e?g3F-(4>5@z)b}j6)?CmZ+FCqCg2tUS&_E{SXOppbg0^1%gqB-C2 zZkaysWEtk|Hhk{+3*$wA4i{-dg7)u$fT$F*cYyr_y}h$Ly870DaEv8ROJQt(5jr=v zOS|h7M1d?Utth9P^=0vNPuQ0wZOx3UPF2+Ju@0J_G6@oH^_lwNCT16K7@5|GID@yK z2qsI;dGeIUwcFORzgwtNG=3=jl5NI-(*r0k>t%{4S{JBNQ9h(lm^6ksu z`-cAwi8hL&OBcVc{Z401C&*NQ`SVwO*?(uEUG9DuP_K>_merkgTb1- zqixRxmAw#r><#`y{^eG-P+4@F+9_w`zjTrNLJ z8WC91_9$xtI_ZpXbcCwV8ZX7#Z)U_K5F3~5IGsXFDQ;a?KU;WhT9x{h(#ta@imU_f zr#oH$Ubw0RpQk6>L$MjL4eQyvCw}b@DiuN;K>!W$gj>z-U9;#&dWza3&4=o`o{F+1 zNk1`kQz<_wPYZczZY|aqti!BxtOja6CgQp<^j?z3QO|#XX))VkK=!qjqRaavvV8w2+T%yeW zM@))Yba>~9vh+A;;I_p-$h6;8fFu6ro8&F{@&}+z+maLBbWZ;?C1~F?0DuA(rU16? zow<0olA6d#!Rmrg!v@jdvkl^S%RuHZ_R+oABdbuY1*oF9sYitw(7H%bDb&$a?}i@h zRw0+B7;Yw|Tf@YhF%(jbWz;d#+T8Yq+iTYLsi7E%Px9V8GUx~}pa-ibP9oLV>N70B zzv(H7VYrA?%mBZ-U~{gGLGjKt5w!0Q7He(F;P%hc3&CJ1z3{ygjTJyQJ2+J*7^M9Y zB*%2N`c_#c5XNRfy*)yMr_G&mg!OYIyEc#L3v;Ccvs^R1iDMd{L;Sa6wll{G)0W=D zRhdUWEN)*=tEj&hW3>js*Z^04^Bn+4jRUpw3K%c|1C(S>zd|VG%}q{3!Rn>V#mshp z$S0mb#F(ir@Tz(XEZJT;>Z7au5R?#dmiZBTxIovew#9`@&x1@F?v*_AV$iXR+~Rtn z@Z2v#DENr1dLkXux67=@tz1`yTNZ%mjCOm2lx4UPtSYqq%!IFIfy&s{QWL5kTPaK5 zI9d@cku;Yo=asws@<@T>YD*n2Np!Pcbimr|ZU9LhCPFTZVPb?=Y1Es$5cZx|XS_@Y zjFG_GnLWkq)ahI9S1*2?j7)ve{DapAXiTzrH*1MYRb2LAXcIl%Q^#UZ61mT0#{SeE zJJQ8}a6ydc^Ke00Fgn8ZDQNt)8Itky#I~+?fPQ0>z>u&L=W{bd( zUJWG)ZG!I4@9Fa&LZw)x)?p<`3WYjZ-=KrXx%>R`^HptcTuUB<&D0W8Q!5O`jrBro7xuHE*G@;zr{s3pch)fo zUFLJX!l|e)inY@CoSRFo)Toypii}E_fE(sa}5w`J{{gU9O~YIwuO9f=?f(OmZ+k(+VtU)u>y|BJ6-E*?I%--7-{J6>^U- z7v?3%pd3@xn9(JrgWAa>oJz3`7Iwq=2o0{S7PwVt74&rZphi z4X-1#9~Xdku6K>l{$H4C+m}6(as#ZhEh<7um7thuH1LYfqv_P{t|R3#;`hjevk4(N zvh~=8#BGa;s?TA-v!WN_C7zPmAJaq3MCF_8|#1 z6YaodVKPqtG+15L+z zTCMKk(k9&tjNB_~5bYghONbi}=;!>)u5JUFhJ|8%UBpQL=8`_Q!K;%5HralZ@7Whv z@!V5d(V0cbV=x$z&%I)zVtzv-a_`y$JAz=CyG5+kAi!$>@YYm@Z=8}X_KexHHg~O$ z0s5IXr{j7{LoAE40t1SROT((=#|x440Y^K_)h?z-q#Cv!VIF4pQcdjZ(eu09L<~2k z%a*y+{dzw~$6ddRd(ofGJqD{c)w86q&RibW^*Kjs@>ku~x-T%q(y`*L_;B^))iui~eUM zGut?)xPb(F`dBOF3%(vx#cM#Q<5POgmy-@BfOR-vU7EJ8-H-`7K)CxB8gR`LE-O!4 zC*Y3lJULcAuy1|}3DCKdtip+tuI$Xw1#w#L$G4t520X)?=ElpLh=a5EJd5N_R*W8T z?88dWtb%YXmsLNmZ(0X7xWdLkM(n<0SM>X>wX>IF_5UCy%ums$1>|r{-2#+E9kr^qiSwCbYn*#gS(Gdp+ zb7K2>E)xuZFD60*Hey|WP|a7VIIfx()0V#7%lc`g~P=21T)HxZa@DsX8-nPKK!tS*J%Et`i7}Q9me1gAmi~im`B(MpUJ2YCU^seuw50usNMO?7BB3s zY>C);|6pa(-(t=DDCsS*G5+LHAZx=nV6n!#%Hg?!jT|H zP+G96oY+BKKgpO}Pc_?^miPyh{1O1XJ84fY zK ziE2rsopw=W;(X}#4>?3&uD(Vb*BYeh!p(xTE}p?rn+G<4wS^|jonrtolPYRZ4OQog zk z)dQodrO=FB1KApUw*2JX>6q-O8MX8{ixSigeoNwg#8DmHD?q1RqlthW#E z2>02nKZ(Yb%X^V3t|m1%EUlD99}(Fo8fpI83p&WnyJGWupd+#9E1UnvWSpQ=7{BI^ zc}BFZVvjcz10LtA$x9?X+veF*ebz-@ZWcujJ59Xu->lfUkwlt7%&FMO`p;7|19pex z{7d3Rc;_}(iUVUwqYYz|1@FruHbA~ch;ODFb7p$QXvD`0B@ogC%yivPoV!u=KwHFx(Z zy0lQfFg{KHU!Ngi5>1bnRdyPfRr`n+I7m68U~@=ecBioNot(}uxSkB(#lmZ2;DmNl z&?R@Foo8r~+AP$O9NFy}r|J0hSLd*ORiUYzz9lf*q@seV;hgF9c=>i6>W7S7ZXtqn zYf&11A+&P$cdqAJI4AimXLwJr$XIyHk+GH{X_aYvQ~9lTzif~{v^5@AZ?)=)L173x z&0RqX|8FU(tj)bYz&Nj&LtvatuGPp1$ir#+ismHhMHCoEz2Yo@y_{xrP}wX6+IwK* zbkjFbj=1gHS1vz}{EA*M3zZgY4&jdMDX)Ix|pradtkV^g+tfKi!>SOAQv3{;775gS%OgsY$OL86s|Eo zcfKQGurD-sWO>fQ#Vg=T(|7GBjo^Xz^PLWE-=M&De`;uX$AcA551Y6}IYs{{&nJH` z_x~oe-jM0tO8~w=zgf~XzH^EU>kKxCl{MelE^5LQ5fNF7+3@Jydwt5z1SpKc6S(`~ zSHM$9?Lcs4^Oq!C?6?5T#%(&j@~4yV*_|Bz&3j0z=}m1)u;P!ldGltRA`lTJ>965T zEqm`kit$`GfRP-WiG+&v4}lehylv9l^G>(Weau1I0@@yn`tJFR*T^ybPXQImZdjTy z+idscmVbLROu08UTnp3De1`-b?GgEH z)Bu)E?)1Ae?fygi6{D&5BY+!_vLuncD8sqc+rXn5`{cCr?bIg)b&HG3zCzS&3oFn? zhrRAH2a*2L;UI?}&9hqx)$qr)YF)n1T$PLNd>Hbr7f5-vQi4?!~ zTy>C2m{8j(ni206KTOBaUr>fm~j(Wt`89mYcoY_q{i{{Ab!tn zK&)LhmRd029iu#lgWFCWzeoayJPwJnN*2&zu)%V;jIazv5=U^dt-;~L@vo>GG_q&k{!f}B-sk**m z_Ysi3Uk1(JI`c3Z^amdWxR0iL)i?7ZEO1da48}f0lBp~o9(%bdvT1YiT4hbQu8sA2 zoJF?=iTbg80X=yU?0oKXjyGDToTaMDYEt~uw{Cp>uLcQ+H-9+;7iY%=tlc*&7Iv5O zc5F}QRIEeY@#yMbBC%F=Wic&?Afk!~Yd%|TbJpUO+ja6DVmbQ);ZH2%d(`>{BJ^~{ z+z@Z)UXSvebWdsrTUoo@uDh#gBRSAd#ru;Kmv`@rM*FtsLOF|v-kSwx^Tcru_0gkC zm9D{LaFRJ-r#Na`i3^gV!v)vSsdni=m2ZMn$MyWS?wU0B`3@*MFUVPnf@ko?HIZ22 z%9l63{X1qkDgSnRL)Uk;s-5zRvP&VgrT15}FkpPVYZF;bpzEAVzb0@&Sp4=T&ZlHh zDiB*gpS?dF8QaeJid$OxkwLfsbp2}1fPhY8u3bJkmTB8c!^sgdKk6{d(mBnFEjRXTah4$L(yiy8|e{1Yfp3hK);6tIlts1tyvORPBQ8~ z5os9T{A7(XLH-zO_H-Hip(o4FKSHE$J6-x+KLOJ2@>A`Kasmt{>u$UmsuCu&SnZM3 zEfLNbUn{TO6dcQ>6Sj@8ZG+e$K{|^NsK z>C>+x+_ht9!&#?R1+M;R3WAgGmx&HC!}a8w-wwQhAhJrc;5zV1A63ImB3e7Swxz`S zRbaAPL=2g+vRnQYVD6HkW*LIyY38nToH_6=;?L$7^g#IvpB~vs2x2~8^P{>70Fxye z^1*kpyR8##7hKH!^FpEc1^-4I@H$`N8vs=d=uzGTq|5hX1;Yw7HF8&|FPXbuv0;JG z-S3`un3|_n3TeLbfhF>C6C(v-cOLXoJ@G$%wr5LT9X#xiHp=(lZj$S3 zPgz8^762@uML4fchrY)!;aE|!WaP-=^HpEY<(JOM7ZHL&+BSQAwWkUSIP44q zHXy%1P~z_7dQ(8Z_f}UJ=M0{tIQL2nd7-~R#qa-O?Y*O#+QM&95fM2kD4^636%bGf zBGMtDsI(*40U<<+qSB<-BvKS<(v&Cyp@;|wp-3;G7ePYr5IUi^&;m*Bj-K-??~VK3 zxaGeL1|(tawb!2WoAaBWZ|t@%lHOYivw4RqJtX>?0*p2Aze&_HlF-X6JA%JpGltm8 zX>)xyBr(?4DHim?1^?JK<@j%*F`JkD%0)L}0~?=tOD0lk{m1oD9J@g<262B}0p&{V ztMAnSL!C`(jJM?pA>n-^!0pwWL)jJb`l{o>%6s9xl*_RRuB8>A6ROE?c_Qd>x=J8X zq^&b1BK=jJQV`jouV#YC&CIbVL@6dIegM{{ZQHg)RWxZ!^NuQ}uq22OWGg!?ZqcS@ z28raGH?{vcbR;U}OGtgNb=!=b(kAT+@^Dq?ru0HI=YBFo&-W`N7gQ>2N2-o96G?9Qe-S03M|=c{U&bzeDoK;luuOBrY-Z2dpEZex zLuQ>P+~fE6Ufu#$n$Lw3!>)e#`qdkjeJv^ydILJOe5)IA@pn{Zv}ScPxa`Hs6AXq( zBIN>8?l&d;dZcA@Ly?0?26w#;QkGCU7%sh~yVELp)jPo2=kk<`4Tq#sq-&}kqn5Y} zvx9lvU!<&(j85%d)vK^I^Bd?K3$IBW?lF_|SZ3ZSwOw3tW=bhJOh8HAoog+aZtjpY zIo5vx!#-iHGo;ApP7ImBuopkE|E{}46>lXlEq5Qhuz*cFPZR-6k5+=-^YDo(X0^t`P9|LT?Wk%YgyPAGz=T<7dBL z42YEeDMToq{QV+V``?c|`}>7O1OT-BVCV*7AFTlgU0?IS!M6>G`>jFvJFE8ocoV|M z6+@)1_`UJ1yJ%A|ePzaR2C+}Lk@9(Wb>}_ubM!DWIb_pJm#y3(ob2!+(*yfr7 z7CRPTOT6UmnDGv@K#CQjc4>e2BIZ{O+&w&2*>tJ@#|=TNwALC9E3a8<5U3@$a~Vuo z?9wP&PupHB*;aKs#nkJu%(l$C;NZhHwpx+S7m%1^cx=M=Ki9N|Gg;{G4;3ytedmgS zM7n&TceY%5f~-D{sbgYH+E$YMW3^&#Zn-(OG0`E>@doa?v6e3{!E#vGp3T8@FR)3v z;GD-iM3csfVj+oDoUzlUB|oyGj)S@a;#&n0gO^FQhu~Y5;eq?_TZ{DDV+aqaAt{1E zVOu*zQn`*D!S=o+O5n+MamJQ7x!vp_&6{L?()DHJld$4DxRz5}L!5kc#b5myNI!Sb z5Pzt7hk}~}=E%FcGV*f=5v3q+dQp@-#fJ+Bsxysn?*+dHA~(KnoKQ;~8RzuY-pUDY z6(+k15^~D=Z;o92ngCnEb;cLvUIPZ&d#TQ~zFzgEH%Y_xU*n4M zQ)_+4s57DTu#MKBxk4A;sYN1cF9=4Pw}>Cw?f&#)|Cb}obMMzGZTy2w{aOGKy?b^J zU^xVfmhIuygM-sbv~u4Q^|J{cM4t|gbLQzJ{^UP|eZkkOs(44e1pJ$*uK{@m6TC`6 z^DDVw6&DOglS>yp{z|--6r;>0U{uS0z!dUQg5 zjeTG5dd8)y+itzy_H~?%wjj?m2vJB(u@Ihw$qPA+6ISU3a@nsi(liRLAuLlXFDS`h zgAL6C;fST+-Ea=BD-BGgTvz8KkHi0Pb!Gsz*LzGaAf{5*As#+%w+0LyTALp0Q{YuU z+zk|juQ@I??{H9Lum%rHi=Yf3E%v#sXqf|GS&xUFggW0kWo;8)Aa zM@`9AYL%lV`MqM|&7>)N03!v5M|)1lNA-TOlYCk&z|ER{8kO6p>H+l;q+a9jyxV>e;goaO?6i^xe=m+5TAEB>Kf?@Q(Vvu6QN|bx#Z=>_}b`YvAstNAEnmgH1cr>4YP|EQZ}8ki9B?cV+0<+8*V<(FymiWlTatc zYQynO=#|(aM^@rDwgsBh`P(?E0TXyFbS}ysmg^!RZZYv{Ow0`=&{|*@oQYNJG}OK5 zE-F%UHug7N&fFSmEbw(*;1g5SD^tE%^xwJi;5-iHiB1;fE+>omS*u05DQ6+Vo;Y?y zre>P=iL}L z?mLIk`Qq8T^(L~wtvfG71!7gr_Z|)p?{4!~WCx_wM^8sMzTC2xy+I^hblN-*8pDc4 zTi?CvswaKJez$MXkk6(+%MRL?FAdq-<8xn50=&Ec%#UNyK-w#6qC3V+ffFOzg1 zG;p?MN4|kDdM~; z{Ur1Jsnn9!FQwc)O2=7Ufn~L0EGu~n`a-00Q+{FVEb=eZ?uy;MUxHQ@x?D#k2%Sj1 ztG*F3%#}kN*74Liq$+dXg28fg7gEf*FRk9&A{gsIfV@6a1z~<<#V?aMX=ko0nDSfJ zWGAn!R7$o!sMo}3Cv|gh*t&a%$$9YXY(c%l^IMtto==8BvwqS&Ha_=yc1wisAP3@( zgxU@-Y-_*%xa)0U2;D7vz;h1{X$SUK7RUHx#{O~R{VHBJ#=YvyAgOC%43dg~+yO+bDdwSyfIvz^>r(o-Qkv(w+@4>Z6S|dRV9EoK9%ks zT-v~0=m(MF8`}5p#M*V^1c_n?qb$c<(v!5HQUH>FSXtiu>W-Oq?#@TtcJ6k{LP$Zx z{7`OagxPO*<$Hl)hy%&g$BCy_Y@m0>pG&rvdX|tpf_FMC^iJu(ThLqa*`*qwx+G3X zpJb)B7l8+K4@PXn4vqD5H(dmao!&|!C_)Sugw&4KpEN~{Ye(!y5bFg&>It+s&Z?w) zY{!-JOu4;l2JW=wwHmj43LqG@u*qNh8d?k-mk#JdYd-z;AxRqxA3>!C;rj1kPAPYG;-bPJ*`K?HpWl|6;+uWrIq}+wN!- z0wsYER~4wa)8Zt!wh&n7!$HqDaAS=Vn1C|yNLGBEgS|HA)W^fP2df!9TFAm>R(CG; zSu$Uv5#97@%ZEcA3~uSNi@Q3c>czx$q~Q?$Etn8}4->CU>xfXM=vewf$DPt5xFlLY zl>2lR@8IyIxEe6Bvd=#3t=UuT5r`+7s`g+}9V+cIr5Y7n8C|+!VQh#Vq$K1xI zeI!gb14)8qqLE5dF$<(5!{S)C3d=C?k15_MvGi=M&C0awzw+C29>aQ#qphtl?g%3a z#RqR%5LIbQxaaD_-;qtN&%#UFpj7_d+AJODr`57-okNaBlK)dWxY%&GXV2XgS!8~> z`dg2eV#0D-C?GULj`ILV8d&L@7-1Yst|KW0G z#41~&WY_XZg{6%)pTCfWhR6D?J?JLaOTbTcn$PY%l|C7~AMs{q^^oszIp~P;I3XK(0h@QXYQJmrwo*)EL;ZTJGHf{HbA88D|pO z3++LA9GIcs1n~b&1WQLD?&=vu+T+~8#fX<~$dOgCjtA1}9p|vh`0}E5NW)aSY{R}{ z2=D&$ML>0i03e@tt{Xwwx<#^E4F@PFzyy6g@IdR#LAbzT2H zX)lW6;p!j4FMJ6Pd?y-PJJ6{xc3LdbA?EsRUF!e`u3YDV5ux8lT~P^!g>NPpb>eQ5+LPzRvRt8`mvI* zeRwkt+4tQGw+!n0T(~#}{+^DD+SXcDNTm&HspbWlyY{Np3A-rC!=Y1;iXt~li48jY zo<)Z3X;qF9fB&-_a5D%gH@WW9P=?5+*1Pd8CVr|?iNgo%Vb%+p`7@F3&lT(4g2yE< zgLVn8jl-iwmmJj0R4`$6Z|7c?R-4ZvyIKaoZG@d;1kv^}$D^yTvCvE_{a}SvukBYr zessi%#Nez20oateU0!jq@6%snHn!D$g|O~esBK?G|2D_IhV9BT>Y@#cjLAO#L;A9X zka8O5aPtR6Zrg29YF-3_JZGY;4M=UP;hpA>!Kvjj@WTfiJIhfmGmJulT7GCN3+(S* z4UE=L(%KCe$9bWf)#A3=i|s^n z{VbqFzjDfb5B+5?D&D#IC0w53@@)CwV6Iqr8AwOpn>r1roC%gE?<&M^MH(%_1z9bB z(@uWSl}@Ecyp2i2_MJv~$t%rA3BuC-Y`Z@byGjHcr=bc+Eper?^#FOx5VUG56xaM* z+n_Q>#+k_cqZBca?PFc^CR!inJsmM!pmqWFfOVT=InFU$O#WjkLwaUk>e;*R37bHR zXN`nPkyG$708Mv0!Qws8G{ihq+{~AXJol^#I-WWdpAF>M%bAmH;v4&S9?b=yg&z-Z zt%u#Bv`Qz6vD&qd(P^}!mW_|}R<;-8`Sr^eG&k!xHYj6Xe%ZHun*z-eMwI!RW6?!z zC10}#eYAb@W3o-A%HFtzXW92Z=zs526~VvgqRBaBLo;rVF&AmT3(9a4`o%3zSQBm0fzbvwtml$r-P~r z4VxIU^Odhfvcmg3wF@4GxXGoEGn+Q2fsFcs!J|HWX*m!oH0 z3pziZvGvgR+1w{6>GLvEqX-61)@HTJz?o?6O;5pBd_rt`^X50Xg@+;S1%+9zQ%vRK zdEc&x&ra_9G*%91N>fx!Sl|PT)~|%^_Jo1Kgtr$5Y>xZ<8gA%Hv__L;;m&pv=C)(D z37pLz4s?T{p`?g-TJ%(a-65*>Dmpuua?j>O;k(`O?FAdK_hOuG`aWW+rJ|hA!*xo| zvAA0UHapy+ob%k4JjO(}OpR#)CgGOLO&7HHH`uqHp?)hU26CBA&@FkPW?KuKKK_); z@)%JJJ7y*t!`>`G+@nRnGGlJLTfH|1im=|dRkuaA%2Y`Z-fu4F>R%s1mL5yOLYS3H z{~1LOl9_dS^F5e}9E5d#$*d7fkGfEmH*)-JF&bq$fe zXjsm{ncx7cAYG~TRXirc2{On?)epMYF>(Em>}>tPbNmLeqjs|VmqTT>y*FBBn7Lzb$-Y2NXirqR zbTuyuU*!Og&*)yU7b#mmjE^h`$_i7Q&>nS^U1!&j>*J_<`uiyzU7!b4;OZo-BMv9P zO#3#?fTykr#H)0TVcKXi_mp#5^4!eELI(nY8!DpA+)N<%CPhvo9NGWS?S9Gk$H$Qp zkj0@g>djAs$0j5gB6R1(XLQeA&=`Ha5wyxa3R`QB_Pw;5#M~TL$HIDwIjp&vh@i8e#5@sx)(e(w0&|os#wx3}YNx;JWV%Nr-Cqkb4&xGU_-cDk zRT%*vtI+_Lhl$;J397ieLtD|F<1YCH3~~^D)owF1-EVh7dpmF%1TjKyb3wf=I~qzu zd*3<$8TJ}jCb>_hlje3A;N3^}W5;Yd_H+fmy~FNiQMxD)WX^r$ILeh`TTupGG90TL zNRxKzvC-+rQwq1Jt7o+U%AUC6NexS-Uxw(rP9+#%wwvw1Zf4zQoGD%vLVa%rk_p4M zVZCo~B1*evnZzHh!cg6tee-q+-}taiNYzZNQ00nY5Y6T79sk8$RnjF>ilH<)T-lA10TmEe zJxa1LfPno_(JrTvA`!(7+Eu{gQ!O1b*)$}RV>-2R zKDl;xLF6`obXNRE0cgZoKxba1dwS3ZJm}Rb`WxB18fo3jLF^oNXunvOg&uou>oc`n za?me9If~SbM@|#pJ3Y<}4q~wMl_^_nCc2UI@_< z9m}lYP?5}pkbR{WR;u3jS7)a#BXiE;f|G~Mym1;^e!Ha+OZLB6zkwHBMIVdog}Tjl zpZi>$$Vc_hsx@w?#=dUi``8_4jh~7udOJfxUfKUUOD4yDRNx_UMZtbW+T{xlTA%{! zhyW$3pkJ8fv;biL_WQ?P`SAS*?*}f)q_rEj=$?_(i|y3CGx_EgZu6(7SdISe+z3L? zhcB(*zlu7wH6C&s8@{k%gDgXh;LSP)`39EZ@$SE#KNoUdh-03Tu$_#+(^`)wKEQzM z`QXBsLB*C&5tOM^+~Tpl9H)V8C!U71tD%**zu)gSUxrvs>)Z2QL@`a}M`6zi1q0gj z8fPh(L-E*xdNWg)Bf1ji`sdP|&~IfA&me{??7ytl@>Jr*N0cb)F2%4wCh22kxaH)g6$^iY;#t#QZRP zNWW+6SIX=gtV4{l{BxjfXG&ICH8Ecj-wP(m4l|Q623y)Wlr8}-R&o{$35Pj1ep}h* z4}gR(Kd!Kxw%=gOMeH8~6RK*=!)1`7=_|B{E4{G+=HV>c7v0F-Fu&!fFsFgo_^ot2 z-te1`zv;43?6#;|u`Xgdgm<~ew!%z%OT+4|nA_6To64jJL>w>mTk8et(^d3PC4M$- z2jU$Sv6LF2Ob}TkPUXnYn-#PRL?GZ{Vn(W8%ANI1PcL0;Kkb@Q9@Fw}sZXv?;Ki*U zZ>l0jW-KMCI(hH>VXbog+ zquYkuNym^$&a#R-@Xam0%i)XDwo$^C&9e4!;q#HMo{M9gum7?7w_X!Q}hzTTzVZrXQk+f zGl$}Xn}So7I1WQ{gY;xm!E}#U`a2joHAgFsz?zGbA+OgNy@vLpWlVV+uf#&*E;+fX zz=fV}`%3WzIV3}&3clUv9yw2@?RG@a9PXjAU?p%;-$#9}!R&qC=O;R0!&>?qk8nL( ztdn!l6ssSxKp-_q8tqH(FkC(zjyE#p07A*i=2eDn5)e{&+Gp)Sflf7B9oKoEQakm_f_x(Zyo=8NZI+{4Q;!;Ssw4CX2cE?Rq!TUZj zzkQ$vI`zCsy3vQo@oNX*{%+EW1J-upR&93S$vMfmQ}>6%fb8tQH)A1<6jYM5eP+Po zoHNsC&So@2j?z8Dc1Bm?bs&0q=CGA|%efmHD=F16&5-1!#;~Lw(a7@&?=NaAY+AL; znJgciN}Z$xTi6Sp-ddlNy7KgX1=zMuwJ=eCO4I{n`dD>+rt3(#u;I^VIRyibmBz0M zH-Xg9o2WN0McsF>Hv)lNPg&&(cUD;$mB(X(1$?82qm?;2621p~@n^0ow(oV~*m=>K zv3ep}hzl!6ylSL6SZebWD_-p1`qtY?HlV)9{8d}uUi3)U!zV@J7zl5ocX)BWo1xtV z2`FzQBB{Gbc?Uj;ed-nYJ85E{O*34rN;~ zeiN8oof6~LvoqSIjEFWJayAy99YxM|HbRB7r#d0Lp3;cTN)IxiCCBKE=_u>I>j!Qw zat3&+L?TINOw1+m`bDSv=bJ8VDL*~J@>%b_*VBrHuJmbm@U(=JkXVVjic^#W{KA^v zXT5YC3PM6M- zvSJBSOG8k(0OC`Fw(YV#Dft=UYGR>A&`xUD!SM+lMk(P0FhDY=>+d<6&#yYC zQyw}YI@79lm*`gN(GMw-8lZ4)ky3IG&0p^P(~E70V0i*c8?>Y^8rCBH{s^GiZdAgb4%g>wd}E`v%~)S z)adTX+9!W#^vPO3pz6fn)6u`x=W~I~QGaCU>8}{}gJ4M-$8I7$z9$YA;K_*|J3&Y9 z#u!%iwF|6!G|RzgqQYno^e?Ot_d&4SDgg@@d0KyZbYKfs7$hVZy{RxDW;!Wsm(09J zGVJbb-#-f9B9yG#u&Y$=`oRW{(om|j9u&yUF2M-+0_kG^NVvBE@y%E_Qh887=X;T8 zK>C^)gjeTjIXkmhD-_>(qyCs{3^~)l^81m~pO={CQ^RQk)=q{CV7!LHP+2&VKrFkawc( zKl=Bg9&^P&g5fEl>A0zAUv}*xxtLO63W@ia8D9_L>LKUGT!#lmM;j?P3C|oCpj~gx z71*~xZBBUb*UaG-K4NY3<@J!~l#9tTdz}f|9XC`6qW8k?eAcq8SHKCRJI28wJ{8fA zH!qh~ZS{I0>n@w_-U8wG9)41`+T|~6JiCMa(mji^=%2|ChPJ2;GB1^n;P2o7ULDnI z9Q8JZ6XuILj3~celqx8l+x@HQT;uLQ%f%f__Da&K_4nk&`8ok6+ezvX9}7`aP0aZ! zgy+{2pLR|FU-KGpH(gz`IrK+5HeCbgHJEn9LOjcN*_7yG9AHo+{&o&b+f9$4eV_bo z_g0nsvF}UtT}+oIqUPqny;{eb=74P>YLq(tw{AF>g;;aqOE)$?t7lfeJGZ3R3ZgAt zz0cQAEw(-sP%>*<)<^}Ekl9iA2ayE+50~oFWB{d+g=Yx7INMW z?L(A#ropQ2V0_GLQgBf}nkSYF>-r_roY zR#)EpTMQ}cqizn=f!piWu@5EdX8QpUX1??<9o*%BJ2@2x;qZh{#U#Oya>59>_lZupY6>l6#>++2Rj&$ryD-5bqZJC^#k_4@%dNa`)#W8YPhLQy|9^}uk4agj35 z2I*-s&ZjbUm~eaNZ^lg_f?@CX(>y%VVqh_^`FI}CTN0)} S1TxsaFeNI?NvhOw` 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 diff --git a/llpc/lower/LowerAdvancedBlend.cpp b/llpc/lower/LowerAdvancedBlend.cpp index e06f675fe1..6e937329dc 100644 --- a/llpc/lower/LowerAdvancedBlend.cpp +++ b/llpc/lower/LowerAdvancedBlend.cpp @@ -29,13 +29,13 @@ *********************************************************************************************************************** */ #include "LowerAdvancedBlend.h" -#include "GfxRuntimeContext.h" #include "SPIRVInternal.h" #include "compilerutils/CompilerUtils.h" #include "llpcContext.h" #include "llpcSpirvLowerInternalLibraryIntrinsicUtil.h" #include "vkgcDefs.h" #include "lgc/Builder.h" +#include "lgc/RuntimeContext.h" #define DEBUG_TYPE "Lower-advanced-blend" @@ -85,30 +85,23 @@ void LowerAdvancedBlend::processFsOutputs(Module &module) { if (global.getType()->getAddressSpace() == SPIRAS_Uniform && global.getName().ends_with(AdvancedBlendIsMsaaName)) isMsaaUniform = &global; } - // Prepare arguments of AmdAdvancedBlend(inColor, imageDescMsLow, imageDescMsHigh, imageDescLow, imageDescHigh, - // fmaskDescLow, fmaskDescHigh, mode, isMsaa) from shaderLibrary + // Prepare arguments of AmdAdvancedBlend(inColor, imageDescMs, imageDesc, fmaskDesc, mode, isMsaa) from shaderLibrary m_builder->SetInsertPointPastAllocas(m_entryPoint); // Get the parameters and store them into the allocated parameter points - Type *descType = FixedVectorType::get(m_builder->getInt32Ty(), 8); unsigned bindings[2] = {m_binding, m_binding + 1}; - Value *imageDescLow[2] = {}; - Value *imageDescHigh[2] = {}; + Value *imageDesc[2] = {}; for (unsigned id = 0; id < 2; ++id) { unsigned descSet = PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorResource); - Value *imageDescPtr = m_builder->CreateGetDescPtr(ResourceNodeType::DescriptorResource, - ResourceNodeType::DescriptorResource, descSet, bindings[id]); - Value *imageDesc = m_builder->CreateLoad(descType, imageDescPtr); - imageDescLow[id] = m_builder->CreateShuffleVector(imageDesc, ArrayRef{0, 1, 2, 3}); - imageDescHigh[id] = m_builder->CreateShuffleVector(imageDesc, ArrayRef{4, 5, 6, 7}); + imageDesc[id] = m_builder->CreateGetDescPtr(ResourceNodeType::DescriptorResource, + ResourceNodeType::DescriptorResource, descSet, bindings[id]); + imageDesc[id] = m_builder->CreatePtrToInt(imageDesc[id], m_builder->getInt64Ty()); } unsigned descSet = PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorFmask); - Value *fmaskDescPtr = m_builder->CreateGetDescPtr(ResourceNodeType::DescriptorFmask, - ResourceNodeType::DescriptorFmask, descSet, m_binding); - Value *fmaskDesc = m_builder->CreateLoad(descType, fmaskDescPtr); - Value *fmaskDescLow = m_builder->CreateShuffleVector(fmaskDesc, ArrayRef{0, 1, 2, 3}); - Value *fmaskDescHigh = m_builder->CreateShuffleVector(fmaskDesc, ArrayRef{4, 5, 6, 7}); + Value *fmaskDesc = m_builder->CreateGetDescPtr(ResourceNodeType::DescriptorFmask, ResourceNodeType::DescriptorFmask, + descSet, m_binding); + fmaskDesc = m_builder->CreatePtrToInt(fmaskDesc, m_builder->getInt64Ty()); assert(modeUniform && isMsaaUniform); modeUniform = m_builder->CreateLoad(m_builder->getInt32Ty(), modeUniform); @@ -132,8 +125,7 @@ void LowerAdvancedBlend::processFsOutputs(Module &module) { Value *blendColor = inliner .inlineCall(*m_builder, advancedBlendFunc, - {srcVal, imageDescLow[0], imageDescHigh[0], imageDescLow[1], imageDescHigh[1], - fmaskDescLow, fmaskDescHigh, modeUniform, isMsaaUniform}) + {srcVal, imageDesc[0], imageDesc[1], fmaskDesc, modeUniform, isMsaaUniform}) .returnValue; storeInst->setOperand(0, blendColor); diff --git a/llpc/lower/LowerGLCompatibility.cpp b/llpc/lower/LowerGLCompatibility.cpp index 62c82a0697..aeae5b78fe 100644 --- a/llpc/lower/LowerGLCompatibility.cpp +++ b/llpc/lower/LowerGLCompatibility.cpp @@ -773,19 +773,16 @@ void LowerGLCompatibility::emulateDrawPixels() { auto vec2Type = FixedVectorType::get(floatType, 2); auto vec4Type = FixedVectorType::get(floatType, 4); auto ivec2Type = FixedVectorType::get(int32Type, 2); - auto ivec8Type = FixedVectorType::get(int32Type, 8); if (m_patchTexCoord == nullptr) { createPatchTexCoord(); } Value *patchTexcoord = m_builder->CreateLoad(vec2Type, m_patchTexCoord); Value *texcoord = m_builder->CreateFPToUI(patchTexcoord, ivec2Type); - auto imageDesc = m_builder->CreateGetDescPtr( + auto imageDescPtr = m_builder->CreateGetDescPtr( lgc::ResourceNodeType::DescriptorResource, lgc::ResourceNodeType::DescriptorResource, PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorResource), Vkgc::InternalBinding::PixelOpInternalBinding); - auto descriptor = m_builder->CreateLoad(ivec8Type, imageDesc); - descriptor->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(*m_context, {})); - Value *texel = m_builder->CreateImageLoad(vec4Type, Dim2D, 0, descriptor, texcoord, nullptr); + Value *texel = m_builder->CreateImageLoad(vec4Type, Dim2D, 0, imageDescPtr, texcoord, nullptr); // Write Color if (buildInfo->glState.drawPixelsType == Vkgc::DrawPixelsTypeColor) { @@ -868,7 +865,6 @@ void LowerGLCompatibility::emulateBitmap() { auto int32Type = m_builder->getInt32Ty(); auto vec2Type = FixedVectorType::get(floatType, 2); auto ivec2Type = FixedVectorType::get(int32Type, 2); - auto ivec8Type = FixedVectorType::get(int32Type, 8); if (!m_patchTexCoord) { createPatchTexCoord(); } @@ -882,13 +878,11 @@ void LowerGLCompatibility::emulateBitmap() { } mask = m_builder->CreateShl(ConstantInt::get(ivec2Type, 1), mask); Value *texCoordSrc = m_builder->CreateLShr(constInt0x3, texcoord); - auto imageDesc = m_builder->CreateGetDescPtr( + auto imageDescPtr = m_builder->CreateGetDescPtr( lgc::ResourceNodeType::DescriptorResource, lgc::ResourceNodeType::DescriptorResource, PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorResource), Vkgc::InternalBinding::PixelOpInternalBinding); - auto descriptor = m_builder->CreateLoad(ivec8Type, imageDesc); - descriptor->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(*m_context, {})); - Value *texel = m_builder->CreateImageLoad(ivec2Type, Dim2D, 0, descriptor, texCoordSrc, nullptr); + Value *texel = m_builder->CreateImageLoad(ivec2Type, Dim2D, 0, imageDescPtr, texCoordSrc, nullptr); Value *val = m_builder->CreateAnd(mask, texel); val = m_builder->CreateExtractElement(val, ConstantInt::get(int32Type, 0)); auto cmp = m_builder->CreateICmpEQ(val, ConstantInt::get(int32Type, 0)); diff --git a/llpc/lower/ProcessGfxRuntimeLibrary.cpp b/llpc/lower/ProcessGfxRuntimeLibrary.cpp index 378a8e749e..3dac36e0a2 100644 --- a/llpc/lower/ProcessGfxRuntimeLibrary.cpp +++ b/llpc/lower/ProcessGfxRuntimeLibrary.cpp @@ -113,37 +113,35 @@ void ProcessGfxRuntimeLibrary::processLibraryFunction(Function *&func) { // ===================================================================================================================== // Create texel load void ProcessGfxRuntimeLibrary::createTexelLoad(Function *func) { - // Arguments: imageDescLow, imageDescHigh, icoord, lod - constexpr unsigned argCount = 4; - Type *int4Ty = FixedVectorType::get(m_builder->getInt32Ty(), 4); + // Arguments: imageDesc, icoord, lod + constexpr unsigned argCount = 3; Type *int2Ty = FixedVectorType::get(m_builder->getInt32Ty(), 2); - Type *argTypes[] = {int4Ty, int4Ty, int2Ty, m_builder->getInt32Ty()}; + Type *argTypes[] = {m_builder->getInt64Ty(), int2Ty, m_builder->getInt32Ty()}; std::array loadArgs; for (unsigned i = 0; i < argCount; ++i) loadArgs[i] = m_builder->CreateLoad(argTypes[i], func->getArg(i)); unsigned imageFlag = Builder::ImageFlagInvariant | Builder::ImageFlagNotAliased; - auto imageDesc = m_builder->CreateShuffleVector(loadArgs[0], loadArgs[1], ArrayRef{0, 1, 2, 3, 4, 5, 6, 7}); - auto imageLoad = - m_builder->CreateImageLoad(func->getReturnType(), Builder::Dim2D, imageFlag, imageDesc, loadArgs[2], loadArgs[3]); + loadArgs[0] = m_builder->CreateIntToPtr(loadArgs[0], PointerType::get(m_builder->getContext(), ADDR_SPACE_CONST)); + auto imageLoad = m_builder->CreateImageLoad(func->getReturnType(), Builder::Dim2D, imageFlag, loadArgs[0], + loadArgs[1], loadArgs[2]); m_builder->CreateRet(imageLoad); } // ===================================================================================================================== // Create texel load with fmask void ProcessGfxRuntimeLibrary::createTexelLoadFmask(Function *func) { - // Argument: imageDescLow, imageDescHigh, fmaskDescLow, fmaskDescHigh, icoord, lod - constexpr unsigned argCount = 6; - Type *int4Ty = FixedVectorType::get(m_builder->getInt32Ty(), 4); + // Argument: imageDescMs, fmaskDesc, icoord, lod + constexpr unsigned argCount = 4; Type *int2Ty = FixedVectorType::get(m_builder->getInt32Ty(), 2); - Type *argTypes[] = {int4Ty, int4Ty, int4Ty, int4Ty, int2Ty, m_builder->getInt32Ty()}; + Type *argTypes[] = {m_builder->getInt64Ty(), m_builder->getInt64Ty(), int2Ty, m_builder->getInt32Ty()}; std::array loadArgs; for (unsigned i = 0; i < argCount; ++i) loadArgs[i] = m_builder->CreateLoad(argTypes[i], func->getArg(i)); unsigned imageFlag = Builder::ImageFlagInvariant | Builder::ImageFlagNotAliased; - auto imageDesc = m_builder->CreateShuffleVector(loadArgs[0], loadArgs[1], ArrayRef{0, 1, 2, 3, 4, 5, 6, 7}); - auto fmaskDesc = m_builder->CreateShuffleVector(loadArgs[2], loadArgs[3], ArrayRef{0, 1, 2, 3, 4, 5, 6, 7}); - auto imageLoad = m_builder->CreateImageLoadWithFmask(func->getReturnType(), Builder::Dim2DMsaa, imageFlag, imageDesc, - fmaskDesc, loadArgs[4], loadArgs[5]); + loadArgs[0] = m_builder->CreateIntToPtr(loadArgs[0], PointerType::get(m_builder->getContext(), ADDR_SPACE_CONST)); + loadArgs[1] = m_builder->CreateIntToPtr(loadArgs[1], PointerType::get(m_builder->getContext(), ADDR_SPACE_CONST)); + auto imageLoad = m_builder->CreateImageLoadWithFmask(func->getReturnType(), Builder::Dim2DMsaa, imageFlag, + loadArgs[0], loadArgs[1], loadArgs[2], loadArgs[3]); m_builder->CreateRet(imageLoad); } diff --git a/llpc/lower/llpcSpirvLowerGlobal.cpp b/llpc/lower/llpcSpirvLowerGlobal.cpp index ef982d0525..bc3233c22d 100644 --- a/llpc/lower/llpcSpirvLowerGlobal.cpp +++ b/llpc/lower/llpcSpirvLowerGlobal.cpp @@ -30,6 +30,7 @@ */ #include "llpcSpirvLowerGlobal.h" #include "SPIRVInternal.h" +#include "compilerutils/CompilerUtils.h" #include "continuations/ContinuationsUtil.h" #include "llpcContext.h" #include "llpcDebug.h" @@ -188,8 +189,7 @@ static_assert(lgc::ShadingRateHorizontal4Pixels == "Shading rate flag mismatch"); // ===================================================================================================================== -SpirvLowerGlobal::SpirvLowerGlobal() - : m_lowerInputInPlace(false), m_lowerOutputInPlace(false), m_lastVertexProcessingStage(ShaderStageInvalid) { +SpirvLowerGlobal::SpirvLowerGlobal() : m_lastVertexProcessingStage(ShaderStageInvalid) { } // ===================================================================================================================== @@ -204,8 +204,39 @@ PreservedAnalyses SpirvLowerGlobal::run(Module &module, ModuleAnalysisManager &a changeRtFunctionSignature(); + // Special handling of explicit interpolation (InterpolateAt* instructions) in fragment shaders -- get those out of + // the way. + if (m_shaderStage == ShaderStageFragment) + handleCallInst(false, true); + + // Preparations for output lowering + m_unifiedReturn = nullptr; + + if (m_shaderStage == ShaderStageGeometry) { + // Collect "emit" calls + handleCallInst(true, false); + } else if (m_shaderStage < ShaderStageGfxCount) { + ensureUnifiedReturn(); + } + + // Preparations for XFB handling + auto shaderStageMask = m_context->getShaderStageMask(); + m_lastVertexProcessingStage = ShaderStageInvalid; + + if (m_shaderStage < ShaderStageFragment) { + if (shaderStageMask & ShaderStageGeometryBit) + m_lastVertexProcessingStage = ShaderStageGeometry; + else if (shaderStageMask & ShaderStageTessEvalBit) + m_lastVertexProcessingStage = ShaderStageTessEval; + else if (shaderStageMask & ShaderStageVertexBit) + m_lastVertexProcessingStage = ShaderStageVertex; + + if (m_shaderStage == m_lastVertexProcessingStage) + buildApiXfbMap(); + } + // First pass over globals - for (GlobalVariable &global : m_module->globals()) { + for (GlobalVariable &global : llvm::make_early_inc_range(m_module->globals())) { auto addrSpace = global.getType()->getAddressSpace(); if (addrSpace == SPIRAS_Private || addrSpace == SPIRAS_Input || addrSpace == SPIRAS_Output) { @@ -213,12 +244,11 @@ PreservedAnalyses SpirvLowerGlobal::run(Module &module, ModuleAnalysisManager &a // used yet for inputs/outputs.) convertUsersOfConstantsToInstructions(&global); - if (addrSpace == SPIRAS_Private) + if (addrSpace == SPIRAS_Private) { mapGlobalVariableToProxy(&global); - else if (addrSpace == SPIRAS_Input) - mapInputToProxy(&global); - else if (addrSpace == SPIRAS_Output) - mapOutputToProxy(&global); + } else { + lowerInOut(&global); + } } else if (addrSpace == SPIRAS_Local) { // Prefix all LDS variables to avoid downstream conflicts when linking shaders together if (global.hasName()) { @@ -227,30 +257,17 @@ PreservedAnalyses SpirvLowerGlobal::run(Module &module, ModuleAnalysisManager &a } } - // Remove global variables that were already fully replaced - for (auto globalVar : m_globalsToErase) { - globalVar->dropAllReferences(); - globalVar->eraseFromParent(); - } - m_globalsToErase.clear(); - - // Do lowering operations - if (m_lowerInputInPlace && m_lowerOutputInPlace) { - // Both input and output have to be lowered in-place (without proxy variables) - lowerInOutInPlace(); // Just one lowering operation is sufficient - } else { - // Either input or output has to be lowered in-place, not both - if (m_lowerInputInPlace) - lowerInOutInPlace(); - else - lowerInput(); - - if (m_lowerOutputInPlace) - lowerInOutInPlace(); - else - lowerOutput(); + // Now that outputs have been lowered, replace the Emit(Stream)Vertex calls with builder code. + for (auto emitCall : m_emitCalls) { + unsigned emitStreamId = + emitCall->arg_size() != 0 ? cast(emitCall->getArgOperand(0))->getZExtValue() : 0; + m_builder->SetInsertPoint(emitCall); + m_builder->CreateEmitVertex(emitStreamId); + emitCall->eraseFromParent(); } + m_emitCalls.clear(); + // Do further lowering operations if (m_shaderStage == ShaderStageVertex) lowerEdgeFlag(); @@ -294,8 +311,8 @@ void SpirvLowerGlobal::lowerEdgeFlag() { } // ===================================================================================================================== -// Handle "return" instructions. -ReturnInst *SpirvLowerGlobal::ensureUnifiedReturn() { +// Ensure that there is exactly one "ret" instruction. This is used for writing output variables for many shader types. +void SpirvLowerGlobal::ensureUnifiedReturn() { SmallVector retInsts; for (BasicBlock &block : *m_entryPoint) { @@ -303,8 +320,10 @@ ReturnInst *SpirvLowerGlobal::ensureUnifiedReturn() { retInsts.push_back(retInst); } - if (retInsts.size() == 1) - return retInsts[0]; + if (retInsts.size() == 1) { + m_unifiedReturn = retInsts[0]; + return; + } // There are more than 2 returns; create a unified return block. // @@ -319,7 +338,7 @@ ReturnInst *SpirvLowerGlobal::ensureUnifiedReturn() { } m_builder->SetInsertPoint(retBlock); - return m_builder->CreateRetVoid(); + m_unifiedReturn = m_builder->CreateRetVoid(); } // ===================================================================================================================== @@ -335,7 +354,7 @@ void SpirvLowerGlobal::handleCallInst(bool checkEmitCall, bool checkInterpCall) // We get all users before iterating because the iterator can be invalidated // by interpolateInputElement SmallVector users(function.users()); - for (User *user : users) { + for (User *user : make_early_inc_range(users)) { assert(isa(user) && "We should only have CallInst instructions here."); CallInst *callInst = cast(user); if (checkEmitCall) { @@ -348,6 +367,8 @@ void SpirvLowerGlobal::handleCallInst(bool checkEmitCall, bool checkInterpCall) mangledName.starts_with(gSPIRVName::InterpolateAtSample) || mangledName.starts_with(gSPIRVName::InterpolateAtOffset) || mangledName.starts_with(gSPIRVName::InterpolateAtVertexAMD)) { + m_builder->SetInsertPoint(callInst); + // Translate interpolation functions to LLPC intrinsic calls auto loadSrc = callInst->getArgOperand(0); unsigned interpLoc = InterpLocUnknown; @@ -375,7 +396,7 @@ void SpirvLowerGlobal::handleCallInst(bool checkEmitCall, bool checkInterpCall) GlobalVariable *gv = nullptr; SmallVector indexOperands; - if (auto getElemPtr = dyn_cast(loadSrc)) { + if (auto getElemPtr = dyn_cast(loadSrc)) { // The interpolant is an element of the input for (auto &index : getElemPtr->indices()) indexOperands.push_back(m_builder->CreateZExtOrTrunc(index, m_builder->getInt32Ty())); @@ -383,7 +404,9 @@ void SpirvLowerGlobal::handleCallInst(bool checkEmitCall, bool checkInterpCall) } else { gv = cast(loadSrc); } - interpolateInputElement(interpLoc, auxInterpValue, *callInst, gv, indexOperands); + Value *result = interpolateInputElement(callInst->getType(), interpLoc, auxInterpValue, gv, indexOperands); + callInst->replaceAllUsesWith(result); + callInst->eraseFromParent(); } } } @@ -430,162 +453,6 @@ static bool hasPrimitiveIdx(const Constant &metaVal) { return static_cast(inOutMeta.PerPrimitive); } -// ===================================================================================================================== -// Handle a single "load" instruction loading a global. -// -// @param inOut : Global Variable instruction -// @param indexOperands : Indices of GEP instruction -// @param loadInst : Load instruction -void SpirvLowerGlobal::handleLoadInstGEP(GlobalVariable *inOut, ArrayRef indexOperands, LoadInst &loadInst) { - - assert((indexOperands.empty() || cast(indexOperands.front())->isZero()) && "Non-zero GEP first index\n"); - if (!indexOperands.empty()) - indexOperands = indexOperands.drop_front(); - - m_builder->SetInsertPoint(&loadInst); - - Value *vertexIdx = nullptr; - auto inOutTy = inOut->getValueType(); - - auto addrSpace = inOut->getType()->getPointerAddressSpace(); - - MDNode *metaNode = inOut->getMetadata(gSPIRVMD::InOut); - assert(metaNode); - auto inOutMetaVal = mdconst::dyn_extract(metaNode->getOperand(0)); - - // If the input/output is arrayed, the outermost index might be used for vertex indexing - if (inOutTy->isArrayTy() && hasVertexIdx(*inOutMetaVal)) { - if (!indexOperands.empty()) { - vertexIdx = indexOperands.front(); - indexOperands = indexOperands.drop_front(); - } else if (inOutTy != loadInst.getType()) { - vertexIdx = m_builder->getInt32(0); - } - inOutTy = inOutTy->getArrayElementType(); - inOutMetaVal = cast(inOutMetaVal->getOperand(1)); - } - - Value *loadValue = loadInOutMember(inOutTy, loadInst.getType(), addrSpace, indexOperands, 0, inOutMetaVal, nullptr, - vertexIdx, InterpLocUnknown, nullptr, false); - - m_loadInsts.insert(&loadInst); - loadInst.replaceAllUsesWith(loadValue); -} - -// ===================================================================================================================== -// Handle "load" instructions. -void SpirvLowerGlobal::handleLoadInst() { - auto shouldHandle = [&](const unsigned addrSpace) { - if (addrSpace != SPIRAS_Input && addrSpace != SPIRAS_Output) - return false; - // Skip if "load" instructions are not expected to be handled - const bool isTcsInput = (m_shaderStage == ShaderStageTessControl && addrSpace == SPIRAS_Input); - const bool isTcsOutput = (m_shaderStage == ShaderStageTessControl && addrSpace == SPIRAS_Output); - const bool isTesInput = (m_shaderStage == ShaderStageTessEval && addrSpace == SPIRAS_Input); - const bool isMeshInput = (m_shaderStage == ShaderStageMesh && addrSpace == SPIRAS_Input); - - return isTcsInput || isTcsOutput || isTesInput || isMeshInput; - }; - - for (GlobalVariable &global : m_module->globals()) { - const unsigned addrSpace = global.getType()->getPointerAddressSpace(); - if (!shouldHandle(addrSpace)) - continue; - for (User *user : global.users()) { - if (LoadInst *loadInst = dyn_cast(user)) { - handleLoadInstGEP(&global, {}, *loadInst); - } else if (GetElementPtrInst *gep = dyn_cast(user)) { - // The user is a GEP - // We look for load instructions in the GEP users - for (User *gepUser : gep->users()) { - // We shouldn't have any chained GEPs here, they are coalesced by the LowerAccessChain pass. - assert(!isa(gepUser)); - if (LoadInst *loadInst = dyn_cast(gepUser)) { - SmallVector indexOperands; - for (auto &index : gep->indices()) - indexOperands.push_back(m_builder->CreateZExtOrTrunc(index, m_builder->getInt32Ty())); - handleLoadInstGEP(&global, indexOperands, *loadInst); - } - } - } - } - } -} - -// ===================================================================================================================== -// Handle a single "store" instruction storing a global. -// -// @param output : Global Variable instruction -// @param indexOperands : Indices of GEP instruction -// @param storeInst : Store instruction -void SpirvLowerGlobal::handleStoreInstGEP(GlobalVariable *output, ArrayRef indexOperands, - StoreInst &storeInst) { - assert((indexOperands.empty() || cast(indexOperands.front())->isZero()) && "Non-zero GEP first index\n"); - // drop first element - if (!indexOperands.empty()) - indexOperands = indexOperands.drop_front(); - - m_builder->SetInsertPoint(&storeInst); - - Value *storeValue = storeInst.getOperand(0); - Value *vertexOrPrimitiveIdx = nullptr; - auto outputTy = output->getValueType(); - - MDNode *metaNode = output->getMetadata(gSPIRVMD::InOut); - assert(metaNode); - auto outputMetaVal = mdconst::dyn_extract(metaNode->getOperand(0)); - // If the output is arrayed, the outermost index might be used for vertex or primitive indexing - if (outputTy->isArrayTy() && (hasVertexIdx(*outputMetaVal) || hasPrimitiveIdx(*outputMetaVal))) { - if (!indexOperands.empty()) { - vertexOrPrimitiveIdx = indexOperands.front(); - indexOperands = indexOperands.drop_front(); - } else if (outputTy != storeInst.getValueOperand()->getType()) { - vertexOrPrimitiveIdx = m_builder->getInt32(0); - } - outputTy = outputTy->getArrayElementType(); - outputMetaVal = cast(outputMetaVal->getOperand(1)); - } - - storeOutputMember(outputTy, storeInst.getValueOperand()->getType(), storeValue, indexOperands, 0, outputMetaVal, - nullptr, vertexOrPrimitiveIdx); - - m_storeInsts.insert(&storeInst); -} - -// ===================================================================================================================== -// Visits "store" instructions. -void SpirvLowerGlobal::handleStoreInst() { - auto shouldHandle = [&](const unsigned addrSpace) { - const bool isTcsOutput = (m_shaderStage == ShaderStageTessControl && addrSpace == SPIRAS_Output); - const bool isMeshOutput = (m_shaderStage == ShaderStageMesh && addrSpace == SPIRAS_Output); - return isTcsOutput || isMeshOutput; - }; - - for (GlobalVariable &global : m_module->globals()) { - const unsigned addrSpace = global.getType()->getPointerAddressSpace(); - if (!shouldHandle(addrSpace)) - continue; - for (User *user : global.users()) { - if (StoreInst *storeInst = dyn_cast(user)) { - handleStoreInstGEP(&global, {}, *storeInst); - } else if (GetElementPtrInst *gep = dyn_cast(user)) { - // The user is a GEP - // We look for store instructions in the GEP users - for (User *gepUser : gep->users()) { - // We shouldn't have any chained GEPs here, they are coalesced by the LowerAccessChain pass. - assert(!isa(gepUser)); - if (StoreInst *storeInst = dyn_cast(gepUser)) { - SmallVector indexOperands; - for (auto &index : gep->indices()) - indexOperands.push_back(m_builder->CreateZExtOrTrunc(index, m_builder->getInt32Ty())); - handleStoreInstGEP(&global, indexOperands, *storeInst); - } - } - } - } - } -} - // ===================================================================================================================== // Maps the specified global variable to proxy variable. // @@ -618,326 +485,158 @@ void SpirvLowerGlobal::mapGlobalVariableToProxy(GlobalVariable *globalVar) { }); } - m_globalsToErase.push_back(globalVar); -} - -// ===================================================================================================================== -// Maps the specified input to proxy variable. -// -// @param input : Input to be mapped -void SpirvLowerGlobal::mapInputToProxy(GlobalVariable *input) { - // NOTE: For tessellation shader, we do not map inputs to real proxy variables. Instead, we directly - // replace "load" instructions with import calls in the lowering operation. - if (m_shaderStage == ShaderStageTessControl || m_shaderStage == ShaderStageTessEval) { - m_inputProxyMap[input] = nullptr; - m_lowerInputInPlace = true; - return; - } - - m_builder->SetInsertPointPastAllocas(m_entryPoint); - - const auto &dataLayout = m_module->getDataLayout(); - Type *inputTy = input->getValueType(); - if (inputTy->isPointerTy()) - inputTy = m_builder->getInt64Ty(); - - MDNode *metaNode = input->getMetadata(gSPIRVMD::InOut); - assert(metaNode); - - auto meta = mdconst::dyn_extract(metaNode->getOperand(0)); - Value *proxy = m_builder->CreateAlloca(inputTy, dataLayout.getAllocaAddrSpace(), nullptr, - Twine(LlpcName::InputProxyPrefix) + input->getName()); - - // Import input to proxy variable - auto inputValue = addCallInstForInOutImport(inputTy, SPIRAS_Input, meta, nullptr, 0, nullptr, nullptr, - InterpLocUnknown, nullptr, false); - - m_builder->CreateStore(inputValue, proxy); - - m_inputProxyMap[input] = proxy; + globalVar->dropAllReferences(); + globalVar->eraseFromParent(); } // ===================================================================================================================== -// Maps the specified output to proxy variable. +// Lowers an input or output global variable. // -// @param output : Output to be mapped -void SpirvLowerGlobal::mapOutputToProxy(GlobalVariable *output) { - m_builder->SetInsertPointPastAllocas(m_entryPoint); - - // NOTE: For tessellation control shader, task shader, or mesh shader, we do not map outputs to real proxy variables. - // Instead, we directly replace "store" instructions with export calls in the lowering operation. - if (m_shaderStage == ShaderStageTessControl || m_shaderStage == ShaderStageTask || m_shaderStage == ShaderStageMesh) { - if (output->hasInitializer()) { - auto initializer = output->getInitializer(); - m_builder->CreateStore(initializer, output); - } - m_outputProxyMap.emplace_back(output, nullptr); - m_lowerOutputInPlace = true; - return; - } - - const auto &dataLayout = m_module->getDataLayout(); - Type *outputTy = output->getValueType(); - if (outputTy->isPointerTy()) - outputTy = m_builder->getInt64Ty(); - - auto proxy = m_builder->CreateAlloca(outputTy, dataLayout.getAllocaAddrSpace(), nullptr, - Twine(LlpcName::OutputProxyPrefix) + output->getName()); - - if (output->hasInitializer()) { - auto initializer = output->getInitializer(); - m_builder->CreateStore(initializer, proxy); - } - - m_outputProxyMap.emplace_back(output, proxy); -} - -// ===================================================================================================================== -// Does lowering operations for SPIR-V inputs, replaces inputs with proxy variables. -void SpirvLowerGlobal::lowerInput() { - if (m_inputProxyMap.empty()) { - // Skip lowering if there is no input - return; - } - - // NOTE: For tessellation shader, we invoke handling of "load"/"store" instructions and replace all those - // instructions with import/export calls in-place. - assert(m_shaderStage != ShaderStageTessControl && m_shaderStage != ShaderStageTessEval); - - // NOTE: For fragment shader, we have to handle interpolation functions first since input interpolants must be - // lowered in-place. - if (m_shaderStage == ShaderStageFragment) { - // Invoke handling of interpolation calls - handleCallInst(false, true); - - // Remove interpolation calls, they must have been replaced with LLPC intrinsics - std::unordered_set getElemInsts; - for (auto interpCall : m_interpCalls) { - GetElementPtrInst *getElemPtr = dyn_cast(interpCall->getArgOperand(0)); - if (getElemPtr) - getElemInsts.insert(getElemPtr); - - assert(interpCall->use_empty()); - interpCall->dropAllReferences(); - interpCall->eraseFromParent(); - } +// @param globalVar : the global variable to be lowered +void SpirvLowerGlobal::lowerInOut(llvm::GlobalVariable *globalVar) { + assert(globalVar->getAddressSpace() == SPIRAS_Input || globalVar->getAddressSpace() == SPIRAS_Output); + const bool isInput = globalVar->getAddressSpace() == SPIRAS_Input; - for (auto getElemPtr : getElemInsts) { - if (getElemPtr->use_empty()) { - getElemPtr->dropAllReferences(); - getElemPtr->eraseFromParent(); - } - } - } - - for (auto inputMap : m_inputProxyMap) { - auto input = cast(inputMap.first); - auto proxy = inputMap.second; - - for (auto user = input->user_begin(), end = input->user_end(); user != end; ++user) { - // NOTE: "Getelementptr" and "bitcast" will propagate the address space of pointer value (input variable) - // to the element pointer value (destination). We have to clear the address space of this element pointer - // value. The original pointer value has been lowered and therefore the address space is invalid now. - Instruction *inst = dyn_cast(*user); - if (inst) { - Type *instTy = inst->getType(); - if (isa(instTy) && instTy->getPointerAddressSpace() == SPIRAS_Input) { - assert(isa(inst) || isa(inst)); - Type *newInstTy = PointerType::get(*m_context, SPIRAS_Private); - inst->mutateType(newInstTy); - } - } - } - - handleVolatileInput(input, proxy); - - input->mutateType(proxy->getType()); // To clear address space for pointer to make replacement valid - input->replaceAllUsesWith(proxy); - input->eraseFromParent(); - } -} - -// ===================================================================================================================== -// Does lowering operations for SPIR-V outputs, replaces outputs with proxy variables. -void SpirvLowerGlobal::lowerOutput() { - if (m_outputProxyMap.empty() && m_shaderStage != ShaderStageGeometry) { - // Skip lowering if there is no output for non-geometry shader - return; + // Apply output initializer, if any + if (!isInput && globalVar->hasInitializer()) { + m_builder->SetInsertPointPastAllocas(m_entryPoint); + auto initializer = globalVar->getInitializer(); + m_builder->CreateStore(initializer, globalVar); } - // Collect "emit" calls - if (m_shaderStage == ShaderStageGeometry) - handleCallInst(true, false); - - // Create unified return block in which to place all the outputs from proxy variables - ReturnInst *retInst = ensureUnifiedReturn(); - - // NOTE: For tessellation control shader, we invoke handling of "load"/"store" instructions and replace all those - // instructions with import/export calls in-place. - assert(m_shaderStage != ShaderStageTessControl); + const bool mapToProxy = isInput ? (m_shaderStage != ShaderStageTessControl && m_shaderStage != ShaderStageTessEval) + : (m_shaderStage != ShaderStageTessControl && m_shaderStage != ShaderStageTask && + m_shaderStage != ShaderStageMesh); - // Set the last vertex processing stage - auto shaderStageMask = m_context->getShaderStageMask(); - m_lastVertexProcessingStage = ShaderStageInvalid; - if (shaderStageMask & ShaderStageGeometryBit) - m_lastVertexProcessingStage = ShaderStageGeometry; - else if (shaderStageMask & ShaderStageTessEvalBit) - m_lastVertexProcessingStage = ShaderStageTessEval; - else if (shaderStageMask & ShaderStageVertexBit) - m_lastVertexProcessingStage = ShaderStageVertex; - - buildApiXfbMap(); - - // Export output from the proxy variable prior to "return" instruction or "emit" calls - for (auto outputMap : m_outputProxyMap) { - auto output = cast(outputMap.first); - auto proxy = outputMap.second; - auto proxyTy = proxy->getAllocatedType(); - - MDNode *metaNode = output->getMetadata(gSPIRVMD::InOut); + if (mapToProxy) { + const auto &dataLayout = m_module->getDataLayout(); + Type *ty = globalVar->getValueType(); + if (ty->isPointerTy()) + ty = m_builder->getInt64Ty(); + MDNode *metaNode = globalVar->getMetadata(gSPIRVMD::InOut); assert(metaNode); - auto meta = mdconst::dyn_extract(metaNode->getOperand(0)); - if (m_shaderStage == ShaderStageVertex || m_shaderStage == ShaderStageTessEval || - m_shaderStage == ShaderStageFragment) { - m_builder->SetInsertPoint(retInst); - Value *outputValue = m_builder->CreateLoad(proxyTy, proxy); - addCallInstForOutputExport(outputValue, meta, nullptr, 0, 0, 0, nullptr, nullptr, InvalidValue); - } else if (m_shaderStage == ShaderStageGeometry) { - for (auto emitCall : m_emitCalls) { - unsigned emitStreamId = 0; - - m_builder->SetInsertPoint(emitCall); - - auto mangledName = emitCall->getCalledFunction()->getName(); - if (mangledName.starts_with(gSPIRVName::EmitStreamVertex)) - emitStreamId = cast(emitCall->getOperand(0))->getZExtValue(); - else - assert(mangledName.starts_with(gSPIRVName::EmitVertex)); + m_builder->SetInsertPointPastAllocas(m_entryPoint); + Value *proxy = m_builder->CreateAlloca(ty, dataLayout.getAllocaAddrSpace(), nullptr, + Twine(LlpcName::InputProxyPrefix) + globalVar->getName()); - Value *outputValue = m_builder->CreateLoad(proxyTy, proxy); - addCallInstForOutputExport(outputValue, meta, nullptr, 0, 0, 0, nullptr, nullptr, emitStreamId); - } - } - } + if (isInput) { + // Import input to proxy variable + auto inputValue = addCallInstForInOutImport(ty, SPIRAS_Input, meta, nullptr, 0, nullptr, nullptr, + InterpLocUnknown, nullptr, false); - // Replace the Emit(Stream)Vertex calls with builder code. - for (auto emitCall : m_emitCalls) { - unsigned emitStreamId = - emitCall->arg_size() != 0 ? cast(emitCall->getArgOperand(0))->getZExtValue() : 0; - m_builder->SetInsertPoint(emitCall); - m_builder->CreateEmitVertex(emitStreamId); - emitCall->eraseFromParent(); - } + m_builder->CreateStore(inputValue, proxy); - // NOTE: "Getelementptr" will propagate the address space of pointer value (output variable) - // to the element pointer value (destination). We have to clear the address space of this element pointer - // value. The original pointer value has been lowered and therefore the address space is invalid now. - for (auto outputMap : m_outputProxyMap) { - auto output = cast(outputMap.first); + handleVolatileInput(globalVar, proxy); + } else { + // Export the output at shader end or vertex emit + if (m_shaderStage == ShaderStageVertex || m_shaderStage == ShaderStageTessEval || + m_shaderStage == ShaderStageFragment) { + m_builder->SetInsertPoint(m_unifiedReturn); + Value *outputValue = m_builder->CreateLoad(ty, proxy); + addCallInstForOutputExport(outputValue, meta, nullptr, 0, 0, 0, nullptr, nullptr, InvalidValue); + } else { + assert(m_shaderStage == ShaderStageGeometry); - SmallVector propagationWorklist; - propagationWorklist.push_back(output); + for (auto emitCall : m_emitCalls) { + unsigned emitStreamId = 0; - while (!propagationWorklist.empty()) { - Value *current = propagationWorklist.pop_back_val(); + m_builder->SetInsertPoint(emitCall); - for (User *user : current->users()) { - Instruction *inst = dyn_cast(user); - if (inst) { - Type *instTy = inst->getType(); - if (isa(instTy) && instTy->getPointerAddressSpace() == SPIRAS_Output) { - assert(isa(inst)); - Type *newInstTy = PointerType::get(*m_context, SPIRAS_Private); - inst->mutateType(newInstTy); + auto mangledName = emitCall->getCalledFunction()->getName(); + if (mangledName.starts_with(gSPIRVName::EmitStreamVertex)) + emitStreamId = cast(emitCall->getOperand(0))->getZExtValue(); + else + assert(mangledName.starts_with(gSPIRVName::EmitVertex)); - propagationWorklist.push_back(user); - } + Value *outputValue = m_builder->CreateLoad(ty, proxy); + addCallInstForOutputExport(outputValue, meta, nullptr, 0, 0, 0, nullptr, nullptr, emitStreamId); } } } - auto proxy = outputMap.second; - output->mutateType(proxy->getType()); // To clear address space for pointer to make replacement valid - output->replaceAllUsesWith(proxy); - output->eraseFromParent(); + SmallVector toErase; + CompilerUtils::replaceAllPointerUses(m_builder, globalVar, proxy, toErase); + for (auto inst : toErase) + inst->eraseFromParent(); + } else { + // In-place lowering. + SmallVector indexStack; + lowerInOutUsersInPlace(globalVar, globalVar, indexStack); } + + assert(globalVar->use_empty()); + globalVar->eraseFromParent(); } // ===================================================================================================================== -// Does inplace lowering operations for SPIR-V inputs/outputs, replaces "load" instructions with import calls and -// "store" instructions with export calls. -void SpirvLowerGlobal::lowerInOutInPlace() { - assert(m_shaderStage == ShaderStageTessControl || m_shaderStage == ShaderStageTessEval || - m_shaderStage == ShaderStageMesh); - - // Invoke handling of "load" and "store" instruction - handleLoadInst(); - if (m_shaderStage == ShaderStageTessControl || m_shaderStage == ShaderStageMesh) - handleStoreInst(); - - DenseSet getElemInsts; - - // Remove unnecessary "load" instructions - for (auto loadInst : m_loadInsts) { - GetElementPtrInst *const getElemPtr = dyn_cast(loadInst->getPointerOperand()); - if (getElemPtr) - getElemInsts.insert(getElemPtr); - - assert(loadInst->use_empty()); - loadInst->dropAllReferences(); - loadInst->eraseFromParent(); - } - - m_loadInsts.clear(); - - // Remove unnecessary "store" instructions - for (auto storeInst : m_storeInsts) { - GetElementPtrInst *const getElemPtr = dyn_cast(storeInst->getPointerOperand()); - if (getElemPtr) - getElemInsts.insert(getElemPtr); - - assert(storeInst->use_empty()); - storeInst->dropAllReferences(); - storeInst->eraseFromParent(); - } - - m_storeInsts.clear(); - - // Remove unnecessary "getelementptr" instructions - while (!getElemInsts.empty()) { - GetElementPtrInst *const getElemPtr = *getElemInsts.begin(); - getElemInsts.erase(getElemPtr); - - // If the GEP still has any uses, skip processing it. - if (!getElemPtr->use_empty()) - continue; - - // If the GEP is GEPing into another GEP, record that GEP as something we need to visit too. - if (GetElementPtrInst *const otherGetElemInst = dyn_cast(getElemPtr->getPointerOperand())) - getElemInsts.insert(otherGetElemInst); - - getElemPtr->dropAllReferences(); - getElemPtr->eraseFromParent(); - } +// Recursively lower all users of `current`, which can be traced back to `globalVar` via the given GEP indices, +// to in-place import/export ops. +// +// This makes the assumption that GEPs have not been type-punned (though 0 indices may have been dropped). +void SpirvLowerGlobal::lowerInOutUsersInPlace(llvm::GlobalVariable *globalVar, llvm::Value *current, + SmallVectorImpl &indexStack) { + for (User *user : llvm::make_early_inc_range(current->users())) { + Instruction *inst = cast(user); + + if (auto *gep = dyn_cast(inst)) { + // We currently expect that GEPs are only used on the global variable directly, with the global variable's type. + // The SpirvLowerAccessChain pass ensures this. + // + // TODO: As LLVM is moving away from GEPs towards ptradds, we need a better solution, probably by adding our + // own "structured GEP" operation. + assert(current == globalVar && gep->getSourceElementType() == globalVar->getValueType()); + assert(cast(gep->idx_begin()[0])->isNullValue()); + + for (unsigned i = 1, e = gep->getNumIndices(); i < e; ++i) + indexStack.push_back(m_builder->CreateZExtOrTrunc(gep->idx_begin()[i], m_builder->getInt32Ty())); + + lowerInOutUsersInPlace(globalVar, gep, indexStack); + + indexStack.clear(); + } else if (isa(inst) || isa(inst)) { + auto *loadInst = dyn_cast(inst); + auto *storeInst = dyn_cast(inst); + + m_builder->SetInsertPoint(inst); + + Value *vertexOrPrimitiveIdx = nullptr; + auto inOutTy = globalVar->getValueType(); + auto accessTy = loadInst ? loadInst->getType() : storeInst->getValueOperand()->getType(); + auto addrSpace = globalVar->getAddressSpace(); + + MDNode *metaNode = globalVar->getMetadata(gSPIRVMD::InOut); + assert(metaNode); + auto inOutMetaVal = mdconst::dyn_extract(metaNode->getOperand(0)); + + auto indexOperands = ArrayRef(indexStack); + + // If the input/output is arrayed, the outermost index might be used for vertex indexing + if (inOutTy->isArrayTy() && (hasVertexIdx(*inOutMetaVal) || hasPrimitiveIdx(*inOutMetaVal))) { + if (!indexOperands.empty()) { + vertexOrPrimitiveIdx = indexOperands.front(); + indexOperands = indexOperands.drop_front(); + } else if (inOutTy != accessTy) { + vertexOrPrimitiveIdx = m_builder->getInt32(0); + } + inOutTy = inOutTy->getArrayElementType(); + inOutMetaVal = cast(inOutMetaVal->getOperand(1)); + } - // Remove inputs if they are lowered in-place - if (m_lowerInputInPlace) { - for (auto inputMap : m_inputProxyMap) { - auto input = cast(inputMap.first); - assert(input->use_empty()); - input->eraseFromParent(); + if (loadInst) { + Value *loadValue = loadInOutMember(inOutTy, accessTy, addrSpace, indexOperands, 0, inOutMetaVal, nullptr, + vertexOrPrimitiveIdx, InterpLocUnknown, nullptr, false); + loadInst->replaceAllUsesWith(loadValue); + } else { + Value *storeValue = storeInst->getOperand(0); + storeOutputMember(inOutTy, accessTy, storeValue, indexOperands, 0, inOutMetaVal, nullptr, vertexOrPrimitiveIdx); + } + } else { + llvm_unreachable("unhandled user of input/output variable"); } - } - // Remove outputs if they are lowered in-place - if (m_lowerOutputInPlace) { - for (auto outputMap : m_outputProxyMap) { - auto output = cast(outputMap.first); - assert(output->use_empty()); - output->eraseFromParent(); - } + inst->eraseFromParent(); } } @@ -1129,7 +828,6 @@ Value *SpirvLowerGlobal::addCallInstForInOutImport(Type *inOutTy, unsigned addrS vertexIdx, interpLoc, auxInterpValue, isPerVertexDimension); } inOutValue = m_builder->CreateInsertValue(inOutValue, elem, {idx}); - // clang-format on } } } @@ -1176,7 +874,7 @@ Value *SpirvLowerGlobal::addCallInstForInOutImport(Type *inOutTy, unsigned addrS if (addrSpace == SPIRAS_Input) { // In the case where the command has no baseVertex parameter, force the value of gl_BaseVertex to zero if (builtIn == lgc::BuiltInBaseVertex && - m_context->getPipelineContext()->getPipelineOptions()->disableBaseVertex) + m_context->getPipelineContext()->getPipelineOptions()->getGlState().disableBaseVertex) inOutValue = m_builder->getInt32(0); else inOutValue = m_builder->CreateReadBuiltInInput(builtIn, inOutInfo, vertexIdx, elemIdx); @@ -2297,6 +1995,7 @@ void SpirvLowerGlobal::lowerUniformConstants() { // ===================================================================================================================== // Interpolates an element of the input. // +// @param returnTy : the return type of the interpolation // @param interpLoc : Interpolation location, valid for fragment shader (use "InterpLocUnknown" as don't-care value) // @param auxInterpValue : Auxiliary value of interpolation (valid for fragment shader): - Sample ID for // "InterpLocSample" - Offset from the center of the pixel for "InterpLocCenter" - Vertex no. (0 ~ 2) for @@ -2304,12 +2003,10 @@ void SpirvLowerGlobal::lowerUniformConstants() { // @param callInst : "Call" instruction // @param indexOperands : indices of GEP instruction // @param gv : Global Variable instruction -void SpirvLowerGlobal::interpolateInputElement(unsigned interpLoc, Value *auxInterpValue, CallInst &callInst, - GlobalVariable *gv, ArrayRef indexOperands) { +Value *SpirvLowerGlobal::interpolateInputElement(Type *returnTy, unsigned interpLoc, Value *auxInterpValue, + GlobalVariable *gv, ArrayRef indexOperands) { assert((indexOperands.empty() || cast(indexOperands.front())->isZero()) && "Non-zero GEP first index\n"); - m_builder->SetInsertPoint(&callInst); - auto inputTy = gv->getValueType(); MDNode *metaNode = gv->getMetadata(gSPIRVMD::InOut); @@ -2328,36 +2025,26 @@ void SpirvLowerGlobal::interpolateInputElement(unsigned interpLoc, Value *auxInt if (hasAllConstantIndices(indexOperands)) { if (!indexOperands.empty()) indexOperands = indexOperands.drop_front(); - auto loadValue = loadInOutMember(inputTy, callInst.getFunctionType()->getReturnType(), SPIRAS_Input, indexOperands, - 0, inputMeta, nullptr, nullptr, interpLoc, auxInterpValue, false); - - m_interpCalls.insert(&callInst); - callInst.replaceAllUsesWith(loadValue); - } else { - // Interpolant an element via dynamic index by extending interpolant to each element - // - // Regardless of where we do the interpolation, the alloca for the temporary must be inserted in the function entry - // block for efficient code generation, so we don't use the builder for it. - auto interpPtr = new AllocaInst(inputTy, m_module->getDataLayout().getAllocaAddrSpace(), Twine(), - &*(m_entryPoint->begin()->getFirstInsertionPt())); - // Load all possibly accessed values - auto loadValue = loadDynamicIndexedMembers(inputTy, SPIRAS_Input, ArrayRef(indexOperands).drop_front(), inputMeta, - nullptr, interpLoc, auxInterpValue, false); - - m_builder->CreateStore(loadValue, interpPtr); - - auto interpElemPtr = m_builder->CreateGEP(inputTy, interpPtr, indexOperands); - auto interpElemTy = GetElementPtrInst::getIndexedType(inputTy, indexOperands); - - // Only get the value that the original getElemPtr points to - auto interpElemValue = m_builder->CreateLoad(interpElemTy, interpElemPtr); - callInst.replaceAllUsesWith(interpElemValue); - - if (callInst.user_empty()) { - callInst.dropAllReferences(); - callInst.eraseFromParent(); - } + return loadInOutMember(inputTy, returnTy, SPIRAS_Input, indexOperands, 0, inputMeta, nullptr, nullptr, interpLoc, + auxInterpValue, false); } + + // Interpolate an element via dynamic index by extending interpolant to each element + // + // Regardless of where we do the interpolation, the alloca for the temporary must be inserted in the function entry + // block for efficient code generation, so we don't use the builder for it. + auto interpPtr = m_builder->CreateAllocaAtFuncEntry(inputTy); + // Load all possibly accessed values + auto loadValue = loadDynamicIndexedMembers(inputTy, SPIRAS_Input, ArrayRef(indexOperands).drop_front(), inputMeta, + nullptr, interpLoc, auxInterpValue, false); + + m_builder->CreateStore(loadValue, interpPtr); + + auto interpElemPtr = m_builder->CreateGEP(inputTy, interpPtr, indexOperands); + auto interpElemTy = GetElementPtrInst::getIndexedType(inputTy, indexOperands); + + // Only get the value that the original getElemPtr points to + return m_builder->CreateLoad(interpElemTy, interpElemPtr); } // ===================================================================================================================== @@ -2613,21 +2300,23 @@ void SpirvLowerGlobal::changeRtFunctionSignature() { } } + SmallVector globalsToErase; + if (hitAttributeVar && m_entryPoint->arg_size() == 2) { assert(!rayTracingContext->isContinuationsMode() || m_shaderStage != ShaderStageRayTracingIntersect); convertUsersOfConstantsToInstructions(hitAttributeVar); hitAttributeVar->replaceAllUsesWith(m_entryPoint->getArg(1)); - m_globalsToErase.push_back(hitAttributeVar); + globalsToErase.push_back(hitAttributeVar); } if (incomingPayloadVar) { convertUsersOfConstantsToInstructions(incomingPayloadVar); incomingPayloadVar->replaceAllUsesWith(m_entryPoint->getArg(0)); - m_globalsToErase.push_back(incomingPayloadVar); + globalsToErase.push_back(incomingPayloadVar); } else if (incomingCallableDataVar) { convertUsersOfConstantsToInstructions(incomingCallableDataVar); incomingCallableDataVar->replaceAllUsesWith(m_entryPoint->getArg(0)); - m_globalsToErase.push_back(incomingCallableDataVar); + globalsToErase.push_back(incomingCallableDataVar); } if (rayTracingContext->isContinuationsMode()) { @@ -2647,11 +2336,10 @@ void SpirvLowerGlobal::changeRtFunctionSignature() { contFuncTy.writeMetadata(newFunc); } - for (auto globalVar : m_globalsToErase) { + for (auto globalVar : globalsToErase) { globalVar->dropAllReferences(); globalVar->eraseFromParent(); } - m_globalsToErase.clear(); } } // namespace Llpc diff --git a/llpc/lower/llpcSpirvLowerGlobal.h b/llpc/lower/llpcSpirvLowerGlobal.h index 1ca6cd6ade..700f9c870b 100644 --- a/llpc/lower/llpcSpirvLowerGlobal.h +++ b/llpc/lower/llpcSpirvLowerGlobal.h @@ -62,14 +62,12 @@ class SpirvLowerGlobal : public SpirvLower, public llvm::PassInfoMixin &indexStack); - llvm::ReturnInst *ensureUnifiedReturn(); + void ensureUnifiedReturn(); - void lowerInput(); - void lowerOutput(); - void lowerInOutInPlace(); void lowerBufferBlock(); void lowerTaskPayload(); void lowerPushConsts(); @@ -105,30 +103,17 @@ class SpirvLowerGlobal : public SpirvLower, public llvm::PassInfoMixin indexOperands, unsigned maxLocOffset, llvm::Constant *outputMeta, llvm::Value *locOffset, llvm::Value *vertexOrPrimitiveIdx); - void interpolateInputElement(unsigned interpLoc, llvm::Value *interpInfo, llvm::CallInst &callInst, - GlobalVariable *gv, ArrayRef indexOperands); + llvm::Value *interpolateInputElement(llvm::Type *returnTy, unsigned interpLoc, llvm::Value *interpInfo, + GlobalVariable *gv, ArrayRef indexOperands); void buildApiXfbMap(); void addCallInstForXfbOutput(const ShaderInOutMetadata &outputMeta, Value *outputValue, unsigned xfbBufferAdjust, unsigned xfbOffsetAdjust, unsigned locOffset, lgc::InOutInfo outputInfo); - llvm::SmallVector m_globalsToErase; - std::unordered_map m_inputProxyMap; // Proxy map for lowering inputs - - // NOTE: Here we use list to store pairs of output proxy mappings. This is because we want output patching to be - // "ordered" (resulting LLVM IR for the patching always be consistent). - std::list> m_outputProxyMap; // Proxy list for lowering outputs - - bool m_lowerInputInPlace; // Whether to lower input inplace - bool m_lowerOutputInPlace; // Whether to lower output inplace - - std::unordered_set m_emitCalls; // "Call" instructions to emit vertex (geometry shader) - std::unordered_set m_loadInsts; // "Load" instructions to be removed - std::unordered_set m_storeInsts; // "Store" instructions to be removed - std::unordered_set m_interpCalls; // "Call" instruction to do input interpolation - // (fragment shader) - ShaderStage m_lastVertexProcessingStage; // The last vertex processing stage + llvm::ReturnInst *m_unifiedReturn = nullptr; + std::unordered_set m_emitCalls; // "Call" instructions to emit vertex (geometry shader) + ShaderStage m_lastVertexProcessingStage; // The last vertex processing stage llvm::DenseMap m_builtInXfbMap; // Map built-in to XFB output info specified by API interface llvm::DenseMap diff --git a/llpc/lower/llpcSpirvLowerInternalLibraryIntrinsicUtil.cpp b/llpc/lower/llpcSpirvLowerInternalLibraryIntrinsicUtil.cpp index c8c644855c..65a0bcef1e 100644 --- a/llpc/lower/llpcSpirvLowerInternalLibraryIntrinsicUtil.cpp +++ b/llpc/lower/llpcSpirvLowerInternalLibraryIntrinsicUtil.cpp @@ -175,13 +175,13 @@ static void createAtomic(Function *func, Builder *builder, bool is64, bool isCmp // Create GEP to get the byte address with byte offset gpuAddrAsPtr = builder->CreateGEP(builder->getInt8Ty(), gpuAddrAsPtr, offset); Value *atomicValue = nullptr; + SyncScope::ID scope = func->getContext().getOrInsertSyncScopeID("agent"); if (!isCmpXchg) { assert(binOp != AtomicRMWInst::BAD_BINOP); - atomicValue = builder->CreateAtomicRMW(binOp, gpuAddrAsPtr, value, MaybeAlign(), AtomicOrdering::Monotonic, - SyncScope::System); + atomicValue = builder->CreateAtomicRMW(binOp, gpuAddrAsPtr, value, MaybeAlign(), AtomicOrdering::Monotonic, scope); } else { atomicValue = builder->CreateAtomicCmpXchg(gpuAddrAsPtr, compare, value, MaybeAlign(), AtomicOrdering::Monotonic, - AtomicOrdering::Monotonic, SyncScope::System); + AtomicOrdering::Monotonic, scope); atomicValue = builder->CreateExtractValue(atomicValue, 0); } builder->CreateRet(atomicValue); diff --git a/llpc/lower/llpcSpirvLowerTranslator.cpp b/llpc/lower/llpcSpirvLowerTranslator.cpp index 575f1ed0ac..9c61f90cd4 100644 --- a/llpc/lower/llpcSpirvLowerTranslator.cpp +++ b/llpc/lower/llpcSpirvLowerTranslator.cpp @@ -101,7 +101,8 @@ void SpirvLowerTranslator::translateSpirvToLlvm(const PipelineShaderInfo *shader for (const auto &range : descriptorRangeValues) { if (range.type == ResourceMappingNodeType::DescriptorYCbCrSampler) { uint32_t rangeSet = range.set; - if (context->getPipelineContext()->getPipelineOptions()->replaceSetWithResourceType && range.set == 0) { + if (context->getPipelineContext()->getPipelineOptions()->getGlState().replaceSetWithResourceType && + range.set == 0) { rangeSet = PipelineContext::getGlResourceNodeSetFromType(range.type); } convertingSamplers.push_back( diff --git a/llpc/test/lit.cfg.py b/llpc/test/lit.cfg.py index d545648727..896718f119 100644 --- a/llpc/test/lit.cfg.py +++ b/llpc/test/lit.cfg.py @@ -66,6 +66,9 @@ if 'Undefined' in config.xgl_sanitizers: config.available_features.add('ubsan') +if config.llpc_is_standalone != 'ON': + config.available_features.add('gpurt') + llvm_config.use_default_substitutions() config.substitutions.append(('%PATH%', config.environment['PATH'])) diff --git a/llpc/test/lit.site.cfg.py.in b/llpc/test/lit.site.cfg.py.in index c80a3bc6a4..31bd7a41b8 100644 --- a/llpc/test/lit.site.cfg.py.in +++ b/llpc/test/lit.site.cfg.py.in @@ -15,6 +15,7 @@ config.gfxip = "@AMDLLPC_DEFAULT_TARGET@" # Propagate CMake options used in lit feature tests. config.llvm_assertions = "@LLVM_ENABLE_ASSERTIONS@" config.xgl_sanitizers = "@XGL_USE_SANITIZER@" +config.llpc_is_standalone = "@LLPC_IS_STANDALONE@" for d in "@LIT_DEFINITIONS@".split(";"): def_split = d.split("=") diff --git a/llpc/test/shaderdb/core/ObjNonUniform_TestTexutreLoadStoreInt64.spvasm b/llpc/test/shaderdb/core/ObjNonUniform_TestTexutreLoadStoreInt64.spvasm index f1f8eecaea..7eaa31a17b 100644 --- a/llpc/test/shaderdb/core/ObjNonUniform_TestTexutreLoadStoreInt64.spvasm +++ b/llpc/test/shaderdb/core/ObjNonUniform_TestTexutreLoadStoreInt64.spvasm @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by tool/update_llpc_test_checks.py ; BEGIN_SHADERTEST -; RUN: amdllpc --print-after=llpc-spirv-lower-translator -o - 2>&1 %s | FileCheck -check-prefixes=SHADERTEST %s +; RUN: amdllpc --print-after=llpc-spirv-lower-translator -filetype=asm -o - 2>&1 %s | FileCheck -check-prefixes=SHADERTEST %s ; #version 450 ; #extension GL_EXT_nonuniform_qualifier : require ; #extension GL_ARB_gpu_shader_int64 : require @@ -88,7 +88,7 @@ OpFunctionEnd ; SHADERTEST-LABEL: @main( ; SHADERTEST-NEXT: .entry: -; SHADERTEST-NEXT: [[TMP0:%.*]] = alloca { [3 x <8 x i32>], { <4 x i32>, i32 } }, align 32, addrspace(5) +; SHADERTEST-NEXT: [[TMP0:%.*]] = alloca { [3 x ptr addrspace(4)], { ptr addrspace(4), i32 } }, align 8, addrspace(5) ; SHADERTEST-NEXT: [[_12:%.*]] = alloca i64, align 8, addrspace(5) ; SHADERTEST-NEXT: [[TMP1:%.*]] = call ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 7) ; SHADERTEST-NEXT: [[TMP2:%.*]] = call i32 (...) @lgc.create.get.desc.stride.i32(i32 1, i32 1, i64 0, i32 7) @@ -127,20 +127,21 @@ ; SHADERTEST-NEXT: [[TMP31:%.*]] = extractvalue { { ptr addrspace(4), i32, i32, i32 }, { ptr addrspace(4), i32, i32 } } [[TMP30]], 1 ; SHADERTEST-NEXT: [[TMP32:%.*]] = extractvalue { ptr addrspace(4), i32, i32 } [[TMP31]], 2 ; SHADERTEST-NEXT: [[TMP33:%.*]] = extractvalue { ptr addrspace(4), i32, i32 } [[TMP31]], 0 -; SHADERTEST-NEXT: [[TMP34:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP33]], align 16, !invariant.load !4 -; SHADERTEST-NEXT: [[TMP35:%.*]] = insertvalue { <4 x i32>, i32 } poison, <4 x i32> [[TMP34]], 0 -; SHADERTEST-NEXT: [[TMP36:%.*]] = insertvalue { <4 x i32>, i32 } [[TMP35]], i32 [[TMP32]], 1 -; SHADERTEST-NEXT: [[TMP37:%.*]] = extractvalue { { ptr addrspace(4), i32, i32, i32 }, { ptr addrspace(4), i32, i32 } } [[TMP30]], 0 -; SHADERTEST-NEXT: [[TMP38:%.*]] = extractvalue { ptr addrspace(4), i32, i32, i32 } [[TMP37]], 0 -; SHADERTEST-NEXT: [[TMP39:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP38]], align 32, !invariant.load !4 -; SHADERTEST-NEXT: [[TMP40:%.*]] = insertvalue [3 x <8 x i32>] poison, <8 x i32> [[TMP39]], 0 -; SHADERTEST-NEXT: [[TMP41:%.*]] = insertvalue { [3 x <8 x i32>], { <4 x i32>, i32 } } poison, [3 x <8 x i32>] [[TMP40]], 0 -; SHADERTEST-NEXT: [[TMP42:%.*]] = insertvalue { [3 x <8 x i32>], { <4 x i32>, i32 } } [[TMP41]], { <4 x i32>, i32 } [[TMP36]], 1 -; SHADERTEST-NEXT: call void @"spirv.NonUniform.s[a3v8i32,s[v4i32,i32]]"({ [3 x <8 x i32>], { <4 x i32>, i32 } } [[TMP42]]) -; SHADERTEST-NEXT: store { [3 x <8 x i32>], { <4 x i32>, i32 } } [[TMP42]], ptr addrspace(5) [[TMP0]], align 32 -; SHADERTEST-NEXT: [[TMP43:%.*]] = load { [3 x <8 x i32>], { <4 x i32>, i32 } }, ptr addrspace(5) [[TMP0]], align 32 -; SHADERTEST-NEXT: [[TMP44:%.*]] = extractvalue { [3 x <8 x i32>], { <4 x i32>, i32 } } [[TMP43]], 1 -; SHADERTEST-NEXT: [[TMP45:%.*]] = extractvalue { [3 x <8 x i32>], { <4 x i32>, i32 } } [[TMP43]], 0 -; SHADERTEST-NEXT: [[TMP46:%.*]] = extractvalue [3 x <8 x i32>] [[TMP45]], 0 -; SHADERTEST-NEXT: [[TMP47:%.*]] = extractvalue { <4 x i32>, i32 } [[TMP44]], 0 -; SHADERTEST-NEXT: [[TMP48:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> [[TMP46]], <4 x i32> [[TMP47]], i32 1, <2 x float> zeroinitializer) +; SHADERTEST-NEXT: [[TMP34:%.*]] = insertvalue { ptr addrspace(4), i32 } poison, ptr addrspace(4) [[TMP33]], 0 +; SHADERTEST-NEXT: [[TMP35:%.*]] = insertvalue { ptr addrspace(4), i32 } [[TMP34]], i32 [[TMP32]], 1 +; SHADERTEST-NEXT: [[TMP36:%.*]] = extractvalue { { ptr addrspace(4), i32, i32, i32 }, { ptr addrspace(4), i32, i32 } } [[TMP30]], 0 +; SHADERTEST-NEXT: [[TMP37:%.*]] = extractvalue { ptr addrspace(4), i32, i32, i32 } [[TMP36]], 0 +; SHADERTEST-NEXT: [[TMP38:%.*]] = insertvalue [3 x ptr addrspace(4)] poison, ptr addrspace(4) [[TMP37]], 0 +; SHADERTEST-NEXT: [[TMP39:%.*]] = insertvalue { [3 x ptr addrspace(4)], { ptr addrspace(4), i32 } } poison, [3 x ptr addrspace(4)] [[TMP38]], 0 +; SHADERTEST-NEXT: [[TMP40:%.*]] = insertvalue { [3 x ptr addrspace(4)], { ptr addrspace(4), i32 } } [[TMP39]], { ptr addrspace(4), i32 } [[TMP35]], 1 +; SHADERTEST-NEXT: call void @"spirv.NonUniform.s[a3p4,s[p4,i32]]"({ [3 x ptr addrspace(4)], { ptr addrspace(4), i32 } } [[TMP40]]) +; SHADERTEST-NEXT: store { [3 x ptr addrspace(4)], { ptr addrspace(4), i32 } } [[TMP40]], ptr addrspace(5) [[TMP0]], align 8 +; SHADERTEST-NEXT: [[TMP41:%.*]] = load { [3 x ptr addrspace(4)], { ptr addrspace(4), i32 } }, ptr addrspace(5) [[TMP0]], align 8 +; SHADERTEST-NEXT: [[TMP42:%.*]] = extractvalue { [3 x ptr addrspace(4)], { ptr addrspace(4), i32 } } [[TMP41]], 1 +; SHADERTEST-NEXT: [[TMP43:%.*]] = extractvalue { [3 x ptr addrspace(4)], { ptr addrspace(4), i32 } } [[TMP41]], 0 +; SHADERTEST-NEXT: [[TMP44:%.*]] = extractvalue [3 x ptr addrspace(4)] [[TMP43]], 0 +; SHADERTEST-NEXT: [[TMP45:%.*]] = extractvalue { ptr addrspace(4), i32 } [[TMP42]], 0 +; SHADERTEST-NEXT: [[TMP46:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) [[TMP44]], ptr addrspace(4) [[TMP45]], i32 1, <2 x float> zeroinitializer) +; SHADERTEST-NEXT: store <4 x float> [[TMP46]], ptr addrspace(65) @_3, align 16 +; SHADERTEST-NEXT: ret void +; diff --git a/llpc/test/shaderdb/core/OpAccessChain_TestBlockVectorExtract_lit.frag b/llpc/test/shaderdb/core/OpAccessChain_TestBlockVectorExtract_lit.frag index 0e28ffad56..f7005d4991 100644 --- a/llpc/test/shaderdb/core/OpAccessChain_TestBlockVectorExtract_lit.frag +++ b/llpc/test/shaderdb/core/OpAccessChain_TestBlockVectorExtract_lit.frag @@ -40,11 +40,11 @@ void main() ; SHADERTEST: %[[COLUMN1:.*]] = type <{ [3 x float], [4 x i8] }> ; SHADERTEST: %[[COLUMN2:.*]] = type <{ [4 x double] }> -; SHADERTEST: getelementptr inbounds (<{ [3 x float], [4 x i8], [2 x %[[COLUMN1]]] }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 0, i32 1 +; SHADERTEST: getelementptr {{(inbounds )?}}(<{ [3 x float], [4 x i8], [2 x %[[COLUMN1]]] }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 0, i32 1 ; SHADERTEST: getelementptr <{ [3 x float], [4 x i8], [2 x %[[COLUMN1]]] }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 2, i32 1, i32 0, i32 %{{[0-9]*}} ; SHADERTEST: getelementptr <{ [3 x float], [4 x i8], [2 x %[[COLUMN1]]] }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 2, i32 %{{[0-9]*}}, i32 0, i32 1 ; SHADERTEST: getelementptr <{ [4 x double], [4 x %[[COLUMN2]]] }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 0, i32 %{{[0-9]*}} -; SHADERTEST: getelementptr inbounds (<{ [4 x double], [4 x %[[COLUMN2]]] }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 1, i32 2, i32 0, i32 3 +; SHADERTEST: getelementptr {{(inbounds )?}}(<{ [4 x double], [4 x %[[COLUMN2]]] }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 1, i32 2, i32 0, i32 3 ; SHADERTEST: getelementptr <{ [4 x double], [4 x %[[COLUMN2]]] }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 1, i32 %{{[0-9]*}}, i32 0, i32 %{{[0-9]*}} ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/core/OpAtomicXXX_TestImageDimension_lit.comp b/llpc/test/shaderdb/core/OpAtomicXXX_TestImageDimension_lit.comp index 1e2d98cc1c..2d46dfd421 100644 --- a/llpc/test/shaderdb/core/OpAtomicXXX_TestImageDimension_lit.comp +++ b/llpc/test/shaderdb/core/OpAtomicXXX_TestImageDimension_lit.comp @@ -124,94 +124,94 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 0, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 2, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 9, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 3, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 0, i32 0, i32 0, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 4, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 5, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 8, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 6, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 7, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 0, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 2, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 9, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 3, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 0, i32 0, i32 0, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 4, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 5, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 8, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 6, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 7, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 0, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 2, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 9, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 3, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 0, i32 0, i32 0, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 4, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 5, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 8, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 6, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 7, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 0, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 2, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 9, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 3, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 0, i32 0, i32 0, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 4, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 5, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 8, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 6, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 7, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 0, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 2, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 9, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 3, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 0, i32 0, i32 0, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 4, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 5, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 8, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 6, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 7, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 0, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 2, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 9, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 3, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 0, i32 0, i32 0, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 4, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 5, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 8, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 6, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 7, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 0, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 2, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 9, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 3, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 0, i32 0, i32 0, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 4, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 5, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 8, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 6, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 7, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 0, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9, i32 3) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9, i32 3) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 2, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9, i32 3) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 9, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9, i32 3) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 3, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 0, i32 0, i32 0, <4 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 4, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 5, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 8, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 6, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 7, i32 0, i32 0, <8 x i32> +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 0, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 2, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 9, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 3, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 10, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 4, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 5, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 8, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 6, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 7, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 0, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 2, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 9, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 3, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 10, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 4, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 5, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 8, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 6, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 7, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 0, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 2, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 9, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 3, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 10, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 4, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 5, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 8, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 6, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 7, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 0, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 2, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 9, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 3, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 10, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 4, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 5, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 8, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 6, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 7, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 0, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 2, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 9, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 3, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 10, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 4, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 5, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 8, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 6, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 7, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 0, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 2, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 9, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 3, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 10, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 4, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 5, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 8, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 6, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 7, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 0, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 2, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 9, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 3, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 10, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 4, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 5, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 8, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 6, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 7, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <4 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 0, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 7, i32 9, i32 3) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9, i32 3) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 2, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <3 x i32> , i32 9, i32 3) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 9, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9, i32 3) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 3, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 10, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 4, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 5, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 8, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 6, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 7, i32 0, i32 0, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call i32 @llvm.amdgcn.image.atomic.add.1d.i32.i16(i32 9, i16 7, <8 x i32> %{{.*}}, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpAtomicXXX_TestImageMemoryQualifier_lit.comp b/llpc/test/shaderdb/core/OpAtomicXXX_TestImageMemoryQualifier_lit.comp index 8b2876bf51..3892925122 100644 --- a/llpc/test/shaderdb/core/OpAtomicXXX_TestImageMemoryQualifier_lit.comp +++ b/llpc/test/shaderdb/core/OpAtomicXXX_TestImageMemoryQualifier_lit.comp @@ -16,9 +16,9 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call i32 @llvm.amdgcn.image.atomic.add.2d.i32.i16(i32 9, i16 5, i16 5, <8 x i32> %{{.*}}, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpAtomicXXX_TestImage_lit.comp b/llpc/test/shaderdb/core/OpAtomicXXX_TestImage_lit.comp index 9241040a7e..c64f1c2cdb 100644 --- a/llpc/test/shaderdb/core/OpAtomicXXX_TestImage_lit.comp +++ b/llpc/test/shaderdb/core/OpAtomicXXX_TestImage_lit.comp @@ -46,23 +46,23 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 1, i32 0, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 5, i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 7, i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn float (...) @lgc.create.image.atomic.f32(i32 0, i32 1, i32 0, i32 0, <8 x i32> +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 1, i32 0, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> , i32 9) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 5, i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 7, i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn float (...) @lgc.create.image.atomic.f32(i32 0, i32 1, i32 0, i32 0, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call i32 @llvm.amdgcn.image.atomic.add.2d.i32.i16(i32 9, i16 7, i16 7, <8 x i32> %{{.*}}, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpAtomicXXX_TestImage_lit.frag b/llpc/test/shaderdb/core/OpAtomicXXX_TestImage_lit.frag index 2ee55dcbf6..81b0a25cc1 100644 --- a/llpc/test/shaderdb/core/OpAtomicXXX_TestImage_lit.frag +++ b/llpc/test/shaderdb/core/OpAtomicXXX_TestImage_lit.frag @@ -48,23 +48,23 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 0, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 1, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 1, i32 128, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 6, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 0, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 0, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 0, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 0, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 3, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 5, i32 0, i32 0, i32 0, <4 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 7, i32 0, i32 128, i32 0, <4 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 7, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 3, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 3, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 3, i32 0, i32 0, <8 x i32> -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 3, i32 0, i32 0, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn float (...) @lgc.create.image.atomic.f32(i32 0, i32 9, i32 0, i32 0, <8 x i32> +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 0, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 4, i32 1, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 6, i32 1, i32 128, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 6, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 0, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 0, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 0, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 0, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 3, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 5, i32 10, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 7, i32 10, i32 128, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 8, i32 7, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 9, i32 3, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 10, i32 3, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 0, i32 3, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.compare.swap.i32(i32 3, i32 0, i32 0, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn float (...) @lgc.create.image.atomic.f32(i32 0, i32 9, i32 0, i32 0, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call i32 @llvm.amdgcn.image.atomic.add.1d.i32.i16(i32 %{{.*}}, i16 1, <8 x i32> %{{.*}}, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpFMul_TestOperandIsZero.spvasm b/llpc/test/shaderdb/core/OpFMul_TestOperandIsZero.spvasm index ff8682c708..fd43a195b7 100644 --- a/llpc/test/shaderdb/core/OpFMul_TestOperandIsZero.spvasm +++ b/llpc/test/shaderdb/core/OpFMul_TestOperandIsZero.spvasm @@ -32,6 +32,8 @@ OpDecorate %22 FPFastMathMode NotInf OpDecorate %32 FPFastMathMode NotInf OpDecorate %38 FPFastMathMode NotInf + OpDecorate %33 NoContraction + OpDecorate %39 NoContraction %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 diff --git a/llpc/test/shaderdb/core/OpFOrdEqual_TestVec3_lit.frag b/llpc/test/shaderdb/core/OpFOrdEqual_TestVec3_lit.frag index 110b133f0d..b7e84aefe6 100644 --- a/llpc/test/shaderdb/core/OpFOrdEqual_TestVec3_lit.frag +++ b/llpc/test/shaderdb/core/OpFOrdEqual_TestVec3_lit.frag @@ -20,7 +20,7 @@ void main() // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // CHECK-NEXT: [[TMP2:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP0]], align 16 -// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ [[]3 x float], [[]4 x i8], [[]3 x float] }>}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 2}} +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr {{(inbounds i8|<{ [[]3 x float], [[]4 x i8], [[]3 x float] }>)|i8}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 2}} // CHECK-NEXT: [[TMP4:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP3]], align 16 // CHECK-NEXT: [[TMP5:%.*]] = extractelement <3 x float> [[TMP2]], i64 0 // CHECK-NEXT: [[TMP6:%.*]] = extractelement <3 x float> [[TMP4]], i64 0 diff --git a/llpc/test/shaderdb/core/OpFOrdNotEqual_TestVec3_lit.frag b/llpc/test/shaderdb/core/OpFOrdNotEqual_TestVec3_lit.frag index 05b9e49a03..0732bda8cb 100644 --- a/llpc/test/shaderdb/core/OpFOrdNotEqual_TestVec3_lit.frag +++ b/llpc/test/shaderdb/core/OpFOrdNotEqual_TestVec3_lit.frag @@ -20,7 +20,7 @@ void main() // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // CHECK-NEXT: [[TMP2:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP0]], align 16 -// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ [[]3 x float], [[]4 x i8], [[]3 x float] }>}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 2}} +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ [[]3 x float], [[]4 x i8], [[]3 x float] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 2}} // CHECK-NEXT: [[TMP4:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP3]], align 16 // CHECK-NEXT: [[TMP5:%.*]] = extractelement <3 x float> [[TMP2]], i64 0 // CHECK-NEXT: [[TMP6:%.*]] = extractelement <3 x float> [[TMP4]], i64 0 diff --git a/llpc/test/shaderdb/core/OpIEqual_TestIvec2_lit.frag b/llpc/test/shaderdb/core/OpIEqual_TestIvec2_lit.frag index 01adb95c6a..1ce6abbbbc 100644 --- a/llpc/test/shaderdb/core/OpIEqual_TestIvec2_lit.frag +++ b/llpc/test/shaderdb/core/OpIEqual_TestIvec2_lit.frag @@ -20,7 +20,7 @@ void main() // SHADERTEST-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // SHADERTEST-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // SHADERTEST-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr addrspace(7) [[TMP0]], align 8 -// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ [[]2 x i32], [[]2 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} +// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ [[]2 x i32], [[]2 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} // SHADERTEST-NEXT: [[TMP4:%.*]] = load <2 x i32>, ptr addrspace(7) [[TMP3]], align 8 // SHADERTEST-NEXT: [[TMP5:%.*]] = extractelement <2 x i32> [[TMP2]], i64 0 // SHADERTEST-NEXT: [[TMP6:%.*]] = extractelement <2 x i32> [[TMP4]], i64 0 diff --git a/llpc/test/shaderdb/core/OpINotEqual_TestIvec2_lit.frag b/llpc/test/shaderdb/core/OpINotEqual_TestIvec2_lit.frag index d58cc30b47..3fedb0e70d 100644 --- a/llpc/test/shaderdb/core/OpINotEqual_TestIvec2_lit.frag +++ b/llpc/test/shaderdb/core/OpINotEqual_TestIvec2_lit.frag @@ -20,7 +20,7 @@ void main() // SHADERTEST-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // SHADERTEST-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // SHADERTEST-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr addrspace(7) [[TMP0]], align 8 -// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ [[]2 x i32], [[]2 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} +// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ [[]2 x i32], [[]2 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} // SHADERTEST-NEXT: [[TMP4:%.*]] = load <2 x i32>, ptr addrspace(7) [[TMP3]], align 8 // SHADERTEST-NEXT: [[TMP5:%.*]] = extractelement <2 x i32> [[TMP2]], i64 0 // SHADERTEST-NEXT: [[TMP6:%.*]] = extractelement <2 x i32> [[TMP4]], i64 0 diff --git a/llpc/test/shaderdb/core/OpImageDrefGather_TestBasic_lit.frag b/llpc/test/shaderdb/core/OpImageDrefGather_TestBasic_lit.frag index 151dde1a3a..380040dcfa 100644 --- a/llpc/test/shaderdb/core/OpImageDrefGather_TestBasic_lit.frag +++ b/llpc/test/shaderdb/core/OpImageDrefGather_TestBasic_lit.frag @@ -17,9 +17,7 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: [[IMAGEPTR:%[0-9A-Za-z_.-]+]] = call {{.*}} @lgc.create.get.desc.ptr.p4{{.*}}(i32 1, i32 1, i64 0, i32 0 ; SHADERTEST: [[SAMPLERPTR:%[0-9A-Za-z_.-]+]] = call {{.*}} @lgc.create.get.desc.ptr.p4{{.*}}(i32 2, i32 2, i64 0, i32 0 -; SHADERTEST: [[SAMPLER:%[0-9A-Za-z_.-]+]] = load <4 x i32>, {{<4 x i32> addrspace\(4\)\*|ptr addrspace\(4\)}} [[SAMPLERPTR]] -; SHADERTEST: [[IMAGE:%[0-9A-Za-z_.-]+]] = load <8 x i32>, {{<8 x i32> addrspace\(4\)\*|ptr addrspace\(4\)}} [[IMAGEPTR]] -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> {{.*}}@lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x i32> [[IMAGE]], <4 x i32> [[SAMPLER]],{{.*}},{{.*}} float 2.000000e+00 +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> {{.*}}@lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) [[IMAGEPTR]], ptr addrspace(4) [[SAMPLERPTR]],{{.*}},{{.*}} float 2.000000e+00 ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.c.lz.2d.v4f32.f32(i32 1, float 2.000000e+00, diff --git a/llpc/test/shaderdb/core/OpImageDrefGather_TestTextureGatherOffset_lit.frag b/llpc/test/shaderdb/core/OpImageDrefGather_TestTextureGatherOffset_lit.frag index b6e0067e9d..42c07e1bba 100644 --- a/llpc/test/shaderdb/core/OpImageDrefGather_TestTextureGatherOffset_lit.frag +++ b/llpc/test/shaderdb/core/OpImageDrefGather_TestTextureGatherOffset_lit.frag @@ -27,9 +27,9 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0) ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 0) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 384, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 9, i32 512, <8 x i32> +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 384, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 9, i32 512, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.c.lz.o.2d.v4f32.f32(i32 1, i32 257, float 0x3FECCCCCC0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageDrefGather_TestTextureGather_lit.frag b/llpc/test/shaderdb/core/OpImageDrefGather_TestTextureGather_lit.frag index 77074845cf..d5f32f94b5 100644 --- a/llpc/test/shaderdb/core/OpImageDrefGather_TestTextureGather_lit.frag +++ b/llpc/test/shaderdb/core/OpImageDrefGather_TestTextureGather_lit.frag @@ -1,3 +1,4 @@ + #version 450 layout(set = 0, binding = 0) uniform sampler2DShadow samp2DShadow; @@ -33,7 +34,7 @@ void main() ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 2, i32 2, i64 0, i32 0) ; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, {{.*}}, i32 545, <2 x float> , float 0.000000e+00, float 0x3FECCCCCC0000000) ; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 384, {{.*}}, i32 545, <3 x float> , float 0.000000e+00, float 0x3FE99999A0000000) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 9, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 545, <2 x float> , float 0.000000e+00, float 0x3FE6666660000000) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 9, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 545, <2 x float> , float 0.000000e+00, float 0x3FE6666660000000) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.c.lz.2d.v4f32.f32(i32 1, float 0x3FECCCCCC0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageExplicitLod_TestDrefLodOffset_lit.frag b/llpc/test/shaderdb/core/OpImageExplicitLod_TestDrefLodOffset_lit.frag index 2ccb975b3a..5e243f4bcd 100644 --- a/llpc/test/shaderdb/core/OpImageExplicitLod_TestDrefLodOffset_lit.frag +++ b/llpc/test/shaderdb/core/OpImageExplicitLod_TestDrefLodOffset_lit.frag @@ -17,7 +17,7 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 0 -; SHADERTEST: call reassoc nnan nsz arcp contract afn float (...) @lgc.create.image.sample.f32(i32 1, i32 512, <8 x i32>{{.*}}, i32 801,{{.*}}, float 1.000000e+00, <2 x i32> , +; SHADERTEST: call reassoc nnan nsz arcp contract afn float (...) @lgc.create.image.sample.f32(i32 1, i32 512, ptr addrspace(4){{.*}}, i32 801,{{.*}}, float 1.000000e+00, <2 x i32> , ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} float @llvm.amdgcn.image.sample.c.l.o.2d.f32.f32(i32 1, i32 770,{{.*}},{{.*}},{{.*}}, float 1.000000e+00,{{.*}},{{.*}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageFetch_TestBuffer_lit.comp b/llpc/test/shaderdb/core/OpImageFetch_TestBuffer_lit.comp index aa8f65b773..c97da7dea4 100644 --- a/llpc/test/shaderdb/core/OpImageFetch_TestBuffer_lit.comp +++ b/llpc/test/shaderdb/core/OpImageFetch_TestBuffer_lit.comp @@ -19,7 +19,7 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 4, i32 4, i64 0, i32 0 -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 1536, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 3) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 10, i32 1536, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 3) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.struct.buffer.load.format.v4f32({{.*}}, i32 3, i32 0, i32 0, i32 0), !invariant.load diff --git a/llpc/test/shaderdb/core/OpImageFetch_TestTexelFetch_lit.frag b/llpc/test/shaderdb/core/OpImageFetch_TestTexelFetch_lit.frag index 78d7897576..4dbca71ce8 100644 --- a/llpc/test/shaderdb/core/OpImageFetch_TestTexelFetch_lit.frag +++ b/llpc/test/shaderdb/core/OpImageFetch_TestTexelFetch_lit.frag @@ -36,7 +36,7 @@ void main() ; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 1536, {{.*}}, i32 2, i32 2) ; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 128, {{.*}}, <2 x i32> , i32 8) ; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 9, i32 1536, {{.*}}, <2 x i32> ) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 1536, {{.*}}, i32 5) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 10, i32 1536, {{.*}}, i32 5) ; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.with.fmask.v4f32(i32 6, i32 128, {{.*}}, {{.*}}, <2 x i32> , i32 4) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results diff --git a/llpc/test/shaderdb/core/OpImageGather_TestConstOffsets_lit.frag b/llpc/test/shaderdb/core/OpImageGather_TestConstOffsets_lit.frag index ac7612a0e2..428160ad38 100644 --- a/llpc/test/shaderdb/core/OpImageGather_TestConstOffsets_lit.frag +++ b/llpc/test/shaderdb/core/OpImageGather_TestConstOffsets_lit.frag @@ -18,7 +18,7 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 0 -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x {{.*}}, i32 2, float 0.000000e+00, [4 x <2 x i32>] [<2 x i32> , <2 x i32> , <2 x i32> , <2 x i32> ]) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x {{.*}}, i32 2, float 0.000000e+00, [4 x <2 x i32>] [<2 x i32> , <2 x i32> , <2 x i32> , <2 x i32> ]) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.lz.o.2d.v4f32.f32(i32 4, i32 513,{{.*}},{{.*}},{{.*}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageGather_TestDrefConstOffsets_lit.frag b/llpc/test/shaderdb/core/OpImageGather_TestDrefConstOffsets_lit.frag index 09f96ac2b3..6d1959e231 100644 --- a/llpc/test/shaderdb/core/OpImageGather_TestDrefConstOffsets_lit.frag +++ b/llpc/test/shaderdb/core/OpImageGather_TestDrefConstOffsets_lit.frag @@ -18,7 +18,7 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 0 -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 801, <2 x {{.*}}, float 0.000000e+00, [4 x <2 x i32>] [<2 x i32> , <2 x i32> , <2 x i32> , <2 x i32> ], float 1.000000e+00) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 801, <2 x {{.*}}, float 0.000000e+00, [4 x <2 x i32>] [<2 x i32> , <2 x i32> , <2 x i32> , <2 x i32> ], float 1.000000e+00) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.c.lz.o.2d.v4f32.f32(i32 1, i32 513, float 1.000000e+00,{{.*}},{{.*}},{{.*}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageGather_TestIntegerSampler.frag b/llpc/test/shaderdb/core/OpImageGather_TestIntegerSampler.frag index 97be87bb57..2eb83e3bf0 100644 --- a/llpc/test/shaderdb/core/OpImageGather_TestIntegerSampler.frag +++ b/llpc/test/shaderdb/core/OpImageGather_TestIntegerSampler.frag @@ -25,12 +25,12 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 1 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 0 -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 516, <8 x {{.*}}, <4 x {{.*}}, i32 37, <2 x float> , i32 0, float 0.000000e+00) -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 516, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, <2 x i32> ) -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 516, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, [4 x <2 x i32>] [<2 x i32> , <2 x i32> , <2 x i32> , <2 x i32> ]) -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 37, <2 x float> , i32 0, float 0.000000e+00) -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, <2 x i32> ) -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, [4 x <2 x i32>] [<2 x i32> , <2 x i32> , <2 x i32> , <2 x i32> ]) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 516, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <2 x float> , i32 0, float 0.000000e+00) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 516, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, <2 x i32> ) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 516, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, [4 x <2 x i32>] [<2 x i32> , <2 x i32> , <2 x i32> , <2 x i32> ]) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <2 x float> , i32 0, float 0.000000e+00) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, <2 x i32> ) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.gather.v4i32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, [4 x <2 x i32>] [<2 x i32> , <2 x i32> , <2 x i32> , <2 x i32> ]) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call <4 x float> @llvm.amdgcn.image.gather4.lz.2d.v4f32.f16(i32 1, half 0xH0000, half 0xH3C00, <8 x i32> %{{.*}}, <4 x i32> %{{.*}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageGather_TestOffset_lit.frag b/llpc/test/shaderdb/core/OpImageGather_TestOffset_lit.frag index 52fe89de91..6509cb2964 100644 --- a/llpc/test/shaderdb/core/OpImageGather_TestOffset_lit.frag +++ b/llpc/test/shaderdb/core/OpImageGather_TestOffset_lit.frag @@ -18,7 +18,7 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 0 -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x {{.*}}, i32 2, float 0.000000e+00, <2 x {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x {{.*}}, i32 2, float 0.000000e+00, <2 x {{.*}}) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.lz.o.2d.v4f32.f32(i32 4,{{.*}},{{.*}},{{.*}},{{.*}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageGather_TestTextureGatherBiasLod_lit.frag b/llpc/test/shaderdb/core/OpImageGather_TestTextureGatherBiasLod_lit.frag index 7c7805cc3f..9ed1e5cc97 100644 --- a/llpc/test/shaderdb/core/OpImageGather_TestTextureGatherBiasLod_lit.frag +++ b/llpc/test/shaderdb/core/OpImageGather_TestTextureGatherBiasLod_lit.frag @@ -61,22 +61,22 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 1 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 2, i32 2, i64 0, i32 0 -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 69, <2 x {{.*}}, i32 0, {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 69, <3 x {{.*}}, i32 1, {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 3, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 69, <3 x {{.*}}, i32 2, {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 8, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 69, <4 x {{.*}}, i32 3, {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 325, <2 x {{.*}}, i32 0, {{.*}}, <2 x i32> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 325, <3 x {{.*}}, i32 1, {{.*}}, <2 x i32> ) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 325, <2 x {{.*}}, i32 0, {{.*}}, [4 x <2 x i32>] [<2 x i32> zeroinitializer, <2 x i32> , <2 x i32> , <2 x i32> ]) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 325, <3 x {{.*}}, i32 1, {{.*}}, [4 x <2 x i32>] [<2 x i32> zeroinitializer, <2 x i32> , <2 x i32> , <2 x i32> ]) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 37, <2 x {{.*}}, i32 0, {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 37, <3 x {{.*}}, i32 1, {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 3, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 37, <3 x {{.*}}, i32 2, {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 8, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 37, <4 x {{.*}}, i32 3, {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x {{.*}}, i32 0, {{.*}}, <2 x i32> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <3 x {{.*}}, i32 1, {{.*}}, <2 x i32> ) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x {{.*}}, i32 0, {{.*}}, [4 x <2 x i32>] [<2 x i32> zeroinitializer, <2 x i32> , <2 x i32> , <2 x i32> ]) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <3 x {{.*}}, i32 1, {{.*}}, [4 x <2 x i32>] [<2 x i32> zeroinitializer, <2 x i32> , <2 x i32> , <2 x i32> ]) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 69, <2 x {{.*}}, i32 0, {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 69, <3 x {{.*}}, i32 1, {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 3, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 69, <3 x {{.*}}, i32 2, {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 8, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 69, <4 x {{.*}}, i32 3, {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 325, <2 x {{.*}}, i32 0, {{.*}}, <2 x i32> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 325, <3 x {{.*}}, i32 1, {{.*}}, <2 x i32> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 325, <2 x {{.*}}, i32 0, {{.*}}, [4 x <2 x i32>] [<2 x i32> zeroinitializer, <2 x i32> , <2 x i32> , <2 x i32> ]) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 325, <3 x {{.*}}, i32 1, {{.*}}, [4 x <2 x i32>] [<2 x i32> zeroinitializer, <2 x i32> , <2 x i32> , <2 x i32> ]) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <2 x {{.*}}, i32 0, {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <3 x {{.*}}, i32 1, {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 3, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <3 x {{.*}}, i32 2, {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 8, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <4 x {{.*}}, i32 3, {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x {{.*}}, i32 0, {{.*}}, <2 x i32> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <3 x {{.*}}, i32 1, {{.*}}, <2 x i32> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x {{.*}}, i32 0, {{.*}}, [4 x <2 x i32>] [<2 x i32> zeroinitializer, <2 x i32> , <2 x i32> , <2 x i32> ]) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <3 x {{.*}}, i32 1, {{.*}}, [4 x <2 x i32>] [<2 x i32> zeroinitializer, <2 x i32> , <2 x i32> , <2 x i32> ]) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.b.2d.v4f32.f32.f32(i32 1,{{.*}},{{.*}},{{.*}},{{.*}},{{.*}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageGather_TestTextureGatherOffset_lit.frag b/llpc/test/shaderdb/core/OpImageGather_TestTextureGatherOffset_lit.frag index 584be47256..d05255542d 100644 --- a/llpc/test/shaderdb/core/OpImageGather_TestTextureGatherOffset_lit.frag +++ b/llpc/test/shaderdb/core/OpImageGather_TestTextureGatherOffset_lit.frag @@ -31,9 +31,9 @@ void main() ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 2, i32 2, i64 1, i32 0) ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 1, i32 1, i64 0, i32 0) ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 2, i32 2, i64 0, i32 0) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x float> , i32 2, float 0.000000e+00, <2 x {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 384, <8 x {{.*}}, <4 x {{.*}}, i32 293, <3 x float> , i32 3, float 0.000000e+00, <2 x {{.*}}) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 9, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, <2 x i32> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x float> , i32 2, float 0.000000e+00, <2 x {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 384, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <3 x float> , i32 3, float 0.000000e+00, <2 x {{.*}}) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 9, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 293, <2 x float> , i32 0, float 0.000000e+00, <2 x i32> ) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.lz.o.2d.v4f32.f32(i32 4,{{.*}}, float 0x3FB99999A0000000, float 0x3FB99999A0000000,{{.*}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageGather_TestTextureGather_lit.frag b/llpc/test/shaderdb/core/OpImageGather_TestTextureGather_lit.frag index 5134dadc01..2bdc97e82b 100644 --- a/llpc/test/shaderdb/core/OpImageGather_TestTextureGather_lit.frag +++ b/llpc/test/shaderdb/core/OpImageGather_TestTextureGather_lit.frag @@ -30,9 +30,9 @@ void main() ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 2, i32 2, i64 1, i32 0) ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 1, i32 1, i64 0, i32 0) ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 2, i32 2, i64 0, i32 0) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 37, <2 x float> , i32 2, float 0.000000e+00) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 384, <8 x {{.*}}, <4 x {{.*}}, i32 37, <3 x float> , i32 3, float 0.000000e+00) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 9, i32 512, <8 x {{.*}}, <4 x {{.*}}, i32 37, <2 x float> , i32 0, float 0.000000e+00) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 1, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <2 x float> , i32 2, float 0.000000e+00) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 5, i32 384, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <3 x float> , i32 3, float 0.000000e+00) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.gather.v4f32(i32 9, i32 512, ptr addrspace(4) {{.*}}, ptr addrspace(4) {{.*}}, i32 37, <2 x float> , i32 0, float 0.000000e+00) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.gather4.lz.2d.v4f32.f32(i32 4, float 0x3FB99999A0000000, float 0x3FB99999A0000000, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageQueryLevels_TestTextureQueryLevels_lit.frag b/llpc/test/shaderdb/core/OpImageQueryLevels_TestTextureQueryLevels_lit.frag index 403ee311ff..9ca1f9f322 100644 --- a/llpc/test/shaderdb/core/OpImageQueryLevels_TestTextureQueryLevels_lit.frag +++ b/llpc/test/shaderdb/core/OpImageQueryLevels_TestTextureQueryLevels_lit.frag @@ -30,10 +30,10 @@ void main() ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 1, i32 1, i64 0, i32 1) ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 1, i32 1, i64 1, i32 0) ; SHADERTEST: ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4{{.*}}(i32 1, i32 1, i64 0, i32 0) -; SHADERTEST: call i32 (...) @lgc.create.image.query.levels.i32(i32 0, i32 512, <8 x {{.*}}) -; SHADERTEST: call i32 (...) @lgc.create.image.query.levels.i32(i32 1, i32 128, <8 x {{.*}}) -; SHADERTEST: call i32 (...) @lgc.create.image.query.levels.i32(i32 1, i32 512, <8 x {{.*}}) -; SHADERTEST: call i32 (...) @lgc.create.image.query.levels.i32(i32 8, i32 128, <8 x {{.*}}) +; SHADERTEST: call i32 (...) @lgc.create.image.query.levels.i32(i32 0, i32 512, ptr addrspace(4) {{.*}}) +; SHADERTEST: call i32 (...) @lgc.create.image.query.levels.i32(i32 1, i32 128, ptr addrspace(4) {{.*}}) +; SHADERTEST: call i32 (...) @lgc.create.image.query.levels.i32(i32 1, i32 512, ptr addrspace(4) {{.*}}) +; SHADERTEST: call i32 (...) @lgc.create.image.query.levels.i32(i32 8, i32 128, ptr addrspace(4) {{.*}}) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/core/OpImageQuerySize_TestBasic_lit.frag b/llpc/test/shaderdb/core/OpImageQuerySize_TestBasic_lit.frag index 483ef81f1d..45ed00b62b 100644 --- a/llpc/test/shaderdb/core/OpImageQuerySize_TestBasic_lit.frag +++ b/llpc/test/shaderdb/core/OpImageQuerySize_TestBasic_lit.frag @@ -106,7 +106,7 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v2i32(i32 9, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v2i32(i32 4, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v3i32(i32 5, i32 512, {{.*}}, i32 0) -; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 0, i32 512, {{.*}}, i32 0) +; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 10, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v2i32(i32 6, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v3i32(i32 7, i32 512, {{.*}}, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageQuerySize_TestImageSize_lit.frag b/llpc/test/shaderdb/core/OpImageQuerySize_TestImageSize_lit.frag index 9a00841e7e..f9b18ff291 100644 --- a/llpc/test/shaderdb/core/OpImageQuerySize_TestImageSize_lit.frag +++ b/llpc/test/shaderdb/core/OpImageQuerySize_TestImageSize_lit.frag @@ -36,7 +36,7 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 0, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v2i32(i32 9, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v2i32(i32 6, i32 512, {{.*}}, i32 0) -; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 0, i32 128, {{.*}}, i32 0) +; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 10, i32 128, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v3i32(i32 8, i32 128, {{.*}}, i32 0) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results diff --git a/llpc/test/shaderdb/core/OpImageQuerySize_TestImage_lit.comp b/llpc/test/shaderdb/core/OpImageQuerySize_TestImage_lit.comp index fd99503fae..aaa04cdc47 100644 --- a/llpc/test/shaderdb/core/OpImageQuerySize_TestImage_lit.comp +++ b/llpc/test/shaderdb/core/OpImageQuerySize_TestImage_lit.comp @@ -60,7 +60,7 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v3i32(i32 8, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v2i32(i32 6, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v3i32(i32 7, i32 512, {{.*}}, i32 0) -; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 0, i32 512, {{.*}}, i32 0) +; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 10, i32 512, {{.*}}, i32 0) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/core/OpImageQuerySize_TestTextureSize_lit.frag b/llpc/test/shaderdb/core/OpImageQuerySize_TestTextureSize_lit.frag index 6c0b3a9485..dbc8973fd0 100644 --- a/llpc/test/shaderdb/core/OpImageQuerySize_TestTextureSize_lit.frag +++ b/llpc/test/shaderdb/core/OpImageQuerySize_TestTextureSize_lit.frag @@ -29,7 +29,7 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 1) ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v2i32(i32 9, i32 512, {{.*}}, i32 0) -; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 0, i32 128, {{.*}}, i32 0) +; SHADERTEST: call {{.*}} @lgc.create.image.query.size.i32(i32 10, i32 128, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v2i32(i32 6, i32 512, {{.*}}, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.query.size.v3i32(i32 7, i32 128, {{.*}}, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageRead_TestBuffer_lit.comp b/llpc/test/shaderdb/core/OpImageRead_TestBuffer_lit.comp index 8c2bdc89ad..048f86a7ab 100644 --- a/llpc/test/shaderdb/core/OpImageRead_TestBuffer_lit.comp +++ b/llpc/test/shaderdb/core/OpImageRead_TestBuffer_lit.comp @@ -19,7 +19,7 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 4, i32 4, i64 0, i32 0 -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 512, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 3) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 10, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 3) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.struct.buffer.load.format.v4f32({{.*}}, i32 3, i32 0, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageRead_TestImageLoad_lit.frag b/llpc/test/shaderdb/core/OpImageRead_TestImageLoad_lit.frag index 3f38b36347..0674a80145 100644 --- a/llpc/test/shaderdb/core/OpImageRead_TestImageLoad_lit.frag +++ b/llpc/test/shaderdb/core/OpImageRead_TestImageLoad_lit.frag @@ -35,7 +35,7 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0) ; SHADERTEST: call {{.*}} @lgc.create.image.load.v4f32(i32 0, i32 512, {{.*}}, i32 1) ; SHADERTEST: call {{.*}} @lgc.create.image.load.v4f32(i32 9, i32 512, {{.*}}, <2 x i32> ) -; SHADERTEST: call {{.*}} @lgc.create.image.load.v4f32(i32 0, i32 128, {{.*}}, i32 4) +; SHADERTEST: call {{.*}} @lgc.create.image.load.v4f32(i32 10, i32 128, {{.*}}, i32 4) ; SHADERTEST: call {{.*}} @lgc.create.image.load.v4f32(i32 8, i32 128, {{.*}}, <4 x i32> ) ; SHADERTEST: call {{.*}} @lgc.create.image.load.v4f32(i32 6, i32 512, {{.*}}, <3 x i32> ) diff --git a/llpc/test/shaderdb/core/OpImageRead_TestMemoryQualifier_lit.comp b/llpc/test/shaderdb/core/OpImageRead_TestMemoryQualifier_lit.comp index 226e84d136..edba3359b8 100644 --- a/llpc/test/shaderdb/core/OpImageRead_TestMemoryQualifier_lit.comp +++ b/llpc/test/shaderdb/core/OpImageRead_TestMemoryQualifier_lit.comp @@ -27,10 +27,10 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 2 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 1 ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0 -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> ) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> ) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 513, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> ) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 515, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <2 x i32> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 513, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 515, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, <2 x i32> ) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.load.2d.v4f32.i16(i32 15, i16 1, i16 1, <8 x i32> %{{.*}}, i32 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageSampleExplicitLod_TestTextureGradClamp_lit.frag b/llpc/test/shaderdb/core/OpImageSampleExplicitLod_TestTextureGradClamp_lit.frag index 9257edf333..b7666b14b1 100644 --- a/llpc/test/shaderdb/core/OpImageSampleExplicitLod_TestTextureGradClamp_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleExplicitLod_TestTextureGradClamp_lit.frag @@ -53,12 +53,12 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.sample.v4f32(i32 2, i32 512, {{.*}}, {{.*}}, i32 409, <3 x float> , <3 x float> , <3 x float> , {{.*}}, <3 x i32> ) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results -; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.2d.v4f32.f32.f32({{.*}}, float 1.000000e+00, float 1.000000e+00, float 0x3FF19999A0000000, float 0x3FF19999A0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.2d.v4f32.f32.f32({{.*}}, float 1.000000e+00, float 1.000000e+00, float 0x3FF19999A0000000, float 0x3FF19999A0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.3d.v4f32.f32.f32({{.*}}, float 0x3FF3333340000000, float 0x3FF3333340000000, float 0x3FF3333340000000, float 0x3FF4CCCCC0000000, float 0x3FF4CCCCC0000000, float 0x3FF4CCCCC0000000, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FC99999A0000000, {{.*}}) ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.2d.v4f32.f32.f32({{.*}}, i32 514, float 1.000000e+00, float 1.000000e+00, float 0x3FF19999A0000000, float 0x3FF19999A0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.3d.v4f32.f32.f32({{.*}}, i32 197379, float 0x3FF3333340000000, float 0x3FF3333340000000, float 0x3FF3333340000000, float 0x3FF4CCCCC0000000, float 0x3FF4CCCCC0000000, float 0x3FF4CCCCC0000000, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FC99999A0000000, {{.*}}) diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestArrayDirectAccess_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestArrayDirectAccess_lit.frag index 64da83e7c7..e42cb57358 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestArrayDirectAccess_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestArrayDirectAccess_lit.frag @@ -14,7 +14,7 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> ) ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestBasic_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestBasic_lit.frag index 69a0938216..79b46e8c01 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestBasic_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestBasic_lit.frag @@ -13,7 +13,7 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestIntegerSampler_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestIntegerSampler_lit.frag index 5bddde6b7a..780f8fc1eb 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestIntegerSampler_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestIntegerSampler_lit.frag @@ -16,8 +16,8 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.sample.v4i32(i32 1, i32 516, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> ) -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.sample.v4i32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> ) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.sample.v4i32(i32 1, i32 516, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> ) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.sample.v4i32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> ) ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 1) diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestMultiDimArrayDirectAccess_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestMultiDimArrayDirectAccess_lit.frag index d772429a42..af4dec00a8 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestMultiDimArrayDirectAccess_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestMultiDimArrayDirectAccess_lit.frag @@ -14,7 +14,7 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> ) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 0, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> ) ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0) diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestSeparate_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestSeparate_lit.frag index eb6fe23a80..60923e7b20 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestSeparate_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestSeparate_lit.frag @@ -14,7 +14,7 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 1) diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureBiasClamp_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureBiasClamp_lit.frag index e141adff10..a132ad6d38 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureBiasClamp_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureBiasClamp_lit.frag @@ -74,31 +74,31 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.sample.v4f32(i32 8, i32 512, {{.*}}, {{.*}}, i32 193, <4 x float> %{{[0-9]*}}, float 2.000000e+00, {{.*}}) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results -; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.1d.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.1d.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.2d.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.2d.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.3d.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.3d.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubesc(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubetc(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubema(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubeid(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.cube.v4f32.f32.f32({{.*}}, float 2.000000e+00, {{.*}}) -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.1darray.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.1darray.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.2darray.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.2darray.v4f32.f32.f32({{.*}}, float 2.000000e+00, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.b.cl.cube.v4f32.f32.f32({{.*}}, float 2.000000e+00, {{.*}}) ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureClamp_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureClamp_lit.frag index 002bcc9bf2..e48d5ec2f5 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureClamp_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureClamp_lit.frag @@ -74,30 +74,30 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.sample.v4f32(i32 8, i32 512, {{.*}}, {{.*}}, i32 129, <4 x float> %{{[0-9]*}}, {{.*}}) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.1d.v4f32.f32({{.*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.1d.v4f32.f32({{.*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.2d.v4f32.f32({{.*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.2d.v4f32.f32({{.*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.3d.v4f32.f32({{.*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.3d.v4f32.f32({{.*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubesc(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubetc(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubema(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubeid(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.cube.v4f32.f32 -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.1darray.v4f32.f32({{.*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.1darray.v4f32.f32({{.*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.2darray.v4f32.f32({{.*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.2darray.v4f32.f32({{.*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.cube.v4f32.f32 ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureGradClamp_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureGradClamp_lit.frag index add49732f6..6a83db23d5 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureGradClamp_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureGradClamp_lit.frag @@ -76,31 +76,31 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.sample.v4f32(i32 8, i32 512, {{.*}}, {{.*}}, i32 153, <4 x float> %{{[0-9]*}}, <3 x float> %{{[0-9]*}}, <3 x float> %{{[0-9]*}}, {{.*}}) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results -; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.1d.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.1d.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.2d.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.2d.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.3d.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.3d.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubesc(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubetc(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubema(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} float @llvm.amdgcn.cubeid(float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}) ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.cube.v4f32.f32.f32 -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.1darray.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.1darray.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.2darray.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.2darray.v4f32.f32.f32({{.*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[0-9]*}}, float %{{[.i0-9]*}}, float %{{[.i0-9]*}}, float %{{[0-9]*}}, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.cube.v4f32.f32.f32 ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureGradOffsetClamp_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureGradOffsetClamp_lit.frag index 149360a1f3..b13c902967 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureGradOffsetClamp_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureGradOffsetClamp_lit.frag @@ -61,21 +61,21 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.sample.v4f32(i32 5, i32 512, {{.*}}, {{.*}}, i32 409, <3 x float> , <2 x float> , <2 x float> , {{.*}}, <2 x i32> ) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results -; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{.*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{.*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.1d.v4f32.f32.f32({{.*}}, i32 2, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{.*}} +; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.1d.v4f32.f32.f32({{.*}}, i32 2, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{.*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.2d.v4f32.f32.f32({{.*}}, i32 514, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{.*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.2d.v4f32.f32.f32({{.*}}, i32 514, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{.*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.3d.v4f32.f32.f32({{.*}}, i32 131586, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FD3333340000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{.*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.3d.v4f32.f32.f32({{.*}}, i32 131586, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FD3333340000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{.*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.1darray.v4f32.f32.f32({{.*}}, i32 2, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, float 0.000000e+00, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{.*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.1darray.v4f32.f32.f32({{.*}}, i32 2, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, float 0.000000e+00, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{.*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{.*}} ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.d.cl.o.2darray.v4f32.f32.f32({{.*}}, i32 514, float 0x3FC99999A0000000, float 0x3FC99999A0000000, float 0x3FD3333340000000, float 0x3FD3333340000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, float 0.000000e+00, {{.*}}) ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureOffsetClamp_lit.frag b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureOffsetClamp_lit.frag index 761e8f8e83..5e7dd16029 100644 --- a/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureOffsetClamp_lit.frag +++ b/llpc/test/shaderdb/core/OpImageSampleImplicitLod_TestTextureOffsetClamp_lit.frag @@ -61,21 +61,21 @@ void main() ; SHADERTEST: call {{.*}} @lgc.create.image.sample.v4f32(i32 5, i32 512, {{.*}}, {{.*}}, i32 385, <3 x float> , {{.*}}, <2 x i32> ) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results -; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane -; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.1d.v4f32.f32({{.*}}, i32 2, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call i32 @llvm.amdgcn.readfirstlane +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.1d.v4f32.f32({{.*}}, i32 2, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.2d.v4f32.f32({{.*}}, i32 514, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.2d.v4f32.f32({{.*}}, i32 514, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.3d.v4f32.f32({{.*}}, i32 131586, float 0x3FB99999A0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.3d.v4f32.f32({{.*}}, i32 131586, float 0x3FB99999A0000000, float 0x3FB99999A0000000, float 0x3FB99999A0000000, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} -; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.1darray.v4f32.f32({{.*}}, i32 2, float 0x3FB99999A0000000, float 0.000000e+00, {{.*}}) ; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.1darray.v4f32.f32({{.*}}, i32 2, float 0x3FB99999A0000000, float 0.000000e+00, {{.*}}) ; SHADERTEST: load <8 x i32>, ptr addrspace(4) %{{[0-9]*}} +; SHADERTEST: load <4 x i32>, ptr addrspace(4) %{{[0-9]*}} ; SHADERTEST: call {{.*}} <4 x float> @llvm.amdgcn.image.sample.cl.o.2darray.v4f32.f32({{.*}}, i32 514, float 0x3FB99999A0000000, float 0x3FB99999A0000000, float 0.000000e+00, {{.*}}) ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/core/OpLogicalNotEqual_TestGeneral_lit.frag b/llpc/test/shaderdb/core/OpLogicalNotEqual_TestGeneral_lit.frag index 8868c4c22e..8f5321288a 100644 --- a/llpc/test/shaderdb/core/OpLogicalNotEqual_TestGeneral_lit.frag +++ b/llpc/test/shaderdb/core/OpLogicalNotEqual_TestGeneral_lit.frag @@ -30,10 +30,10 @@ void main() // SHADERTEST-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 2) // SHADERTEST-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // SHADERTEST-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(7) [[TMP0]], align 4 -// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr addrspace(7) [[TMP0]], i32 8 +// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr {{(inbounds )?}}i8, ptr addrspace(7) [[TMP0]], i32 8 // SHADERTEST-NEXT: [[TMP4:%.*]] = load i32, ptr addrspace(7) [[TMP3]], align 4 // SHADERTEST-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP2]], [[TMP4]] -// SHADERTEST-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr addrspace(7) [[TMP0]], i32 12 +// SHADERTEST-NEXT: [[TMP6:%.*]] = getelementptr {{(inbounds )?}}i8, ptr addrspace(7) [[TMP0]], i32 12 // SHADERTEST-NEXT: [[TMP7:%.*]] = load i32, ptr addrspace(7) [[TMP6]], align 4 // SHADERTEST-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP2]], [[TMP7]] // SHADERTEST-NEXT: [[TMP9:%.*]] = and i1 [[TMP8]], [[TMP5]] diff --git a/llpc/test/shaderdb/core/OpSLessThanEqual_TestSignedAndUnsigned_lit.frag b/llpc/test/shaderdb/core/OpSLessThanEqual_TestSignedAndUnsigned_lit.frag index 7956d7e89c..21dfa067ef 100644 --- a/llpc/test/shaderdb/core/OpSLessThanEqual_TestSignedAndUnsigned_lit.frag +++ b/llpc/test/shaderdb/core/OpSLessThanEqual_TestSignedAndUnsigned_lit.frag @@ -25,7 +25,7 @@ void main() // SHADERTEST-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // SHADERTEST-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // SHADERTEST-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr addrspace(7) [[TMP0]], align 8 -// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ [[]2 x i32], [[]2 x i32], [[]2 x i32], [[]2 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} +// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ [[]2 x i32], [[]2 x i32], [[]2 x i32], [[]2 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} // SHADERTEST-NEXT: [[TMP4:%.*]] = load <2 x i32>, ptr addrspace(7) [[TMP3]], align 8 // SHADERTEST-NEXT: [[TMP5:%.*]] = extractelement <2 x i32> [[TMP2]], i64 0 // SHADERTEST-NEXT: [[TMP6:%.*]] = extractelement <2 x i32> [[TMP4]], i64 0 diff --git a/llpc/test/shaderdb/core/OpSLessThan_TestSignedAndUnsigned_lit.frag b/llpc/test/shaderdb/core/OpSLessThan_TestSignedAndUnsigned_lit.frag index 2bb60ce1df..357603eba2 100644 --- a/llpc/test/shaderdb/core/OpSLessThan_TestSignedAndUnsigned_lit.frag +++ b/llpc/test/shaderdb/core/OpSLessThan_TestSignedAndUnsigned_lit.frag @@ -25,7 +25,7 @@ void main() // SHADERTEST-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // SHADERTEST-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // SHADERTEST-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr addrspace(7) [[TMP0]], align 8 -// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ [[]2 x i32], [[]2 x i32], [[]2 x i32], [[]2 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} +// SHADERTEST-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ [[]2 x i32], [[]2 x i32], [[]2 x i32], [[]2 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} // SHADERTEST-NEXT: [[TMP4:%.*]] = load <2 x i32>, ptr addrspace(7) [[TMP3]], align 8 // SHADERTEST-NEXT: [[TMP5:%.*]] = extractelement <2 x i32> [[TMP2]], i64 0 // SHADERTEST-NEXT: [[TMP6:%.*]] = extractelement <2 x i32> [[TMP4]], i64 0 diff --git a/llpc/test/shaderdb/core/TestXfbStateMetadata.vert b/llpc/test/shaderdb/core/TestXfbStateMetadata.vert index 25b03a1630..c0a28c5490 100644 --- a/llpc/test/shaderdb/core/TestXfbStateMetadata.vert +++ b/llpc/test/shaderdb/core/TestXfbStateMetadata.vert @@ -29,8 +29,8 @@ void main() // //. // CHECK: attributes #[[ATTR0]] = { nounwind "denormal-fp-math-f32"="preserve-sign" } -// CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind willreturn memory(read) } -// CHECK: attributes #[[ATTR2:[0-9]+]] = { nounwind } +// CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind } +// CHECK: attributes #[[ATTR2:[0-9]+]] = { nounwind willreturn memory(read) } //. // CHECK: [[META1]] = !{i32 1} // CHECK: [[META6]] = !{i32 0} diff --git a/llpc/test/shaderdb/extensions/ExtMultiView_TestSubpassLoad_lit.pipe b/llpc/test/shaderdb/extensions/ExtMultiView_TestSubpassLoad_lit.pipe index 660dfcb827..54bf3513dc 100644 --- a/llpc/test/shaderdb/extensions/ExtMultiView_TestSubpassLoad_lit.pipe +++ b/llpc/test/shaderdb/extensions/ExtMultiView_TestSubpassLoad_lit.pipe @@ -3,7 +3,7 @@ ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 608, <8 x i32> +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 608, ptr addrspace(4) ; SHADERTEST: AMDLLPC SUCCESS ; END_SHADERTEST diff --git a/llpc/test/shaderdb/extensions/OpExtInst_TestFmaDouble_lit.frag b/llpc/test/shaderdb/extensions/OpExtInst_TestFmaDouble_lit.frag index 07064eab48..ad76b1641c 100644 --- a/llpc/test/shaderdb/extensions/OpExtInst_TestFmaDouble_lit.frag +++ b/llpc/test/shaderdb/extensions/OpExtInst_TestFmaDouble_lit.frag @@ -23,16 +23,16 @@ void main() // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // CHECK-NEXT: [[TMP2:%.*]] = load double, ptr addrspace(7) [[TMP0]], align 8 -// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} // CHECK-NEXT: [[TMP4:%.*]] = load double, ptr addrspace(7) [[TMP3]], align 8 -// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds {{i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 2}} +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr {{inbounds i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 2}} // CHECK-NEXT: [[TMP6:%.*]] = load double, ptr addrspace(7) [[TMP5]], align 8 // CHECK-NEXT: [[TMP7:%.*]] = call reassoc nnan nsz arcp contract double (...) @lgc.create.fma.f64(double [[TMP2]], double [[TMP4]], double [[TMP6]]) -// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds {{i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 4}} +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr {{inbounds i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 4}} // CHECK-NEXT: [[TMP9:%.*]] = load <3 x double>, ptr addrspace(7) [[TMP8]], align 32 -// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds {{i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>}}, ptr addrspace(7) [[TMP0]], i32 {{64|0, i32 6}} +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr {{inbounds i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{64|0, i32 6}} // CHECK-NEXT: [[TMP11:%.*]] = load <3 x double>, ptr addrspace(7) [[TMP10]], align 32 -// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds {{i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>}}, ptr addrspace(7) [[TMP0]], i32 {{96|0, i32 8}} +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr {{inbounds i8|<{ double, double, double, [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x double] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{96|0, i32 8}} // CHECK-NEXT: [[TMP13:%.*]] = load <3 x double>, ptr addrspace(7) [[TMP12]], align 32 // CHECK-NEXT: [[TMP14:%.*]] = call reassoc nnan nsz arcp contract <3 x double> (...) @lgc.create.fma.v3f64(<3 x double> [[TMP9]], <3 x double> [[TMP11]], <3 x double> [[TMP13]]) // CHECK-NEXT: [[D3_0_0_VEC_EXTRACT:%.*]] = extractelement <3 x double> [[TMP14]], i64 0 diff --git a/llpc/test/shaderdb/extensions/OpExtInst_TestFmaFloat_lit.frag b/llpc/test/shaderdb/extensions/OpExtInst_TestFmaFloat_lit.frag index 015a965534..653bdff986 100644 --- a/llpc/test/shaderdb/extensions/OpExtInst_TestFmaFloat_lit.frag +++ b/llpc/test/shaderdb/extensions/OpExtInst_TestFmaFloat_lit.frag @@ -23,16 +23,16 @@ void main() // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // CHECK-NEXT: [[TMP2:%.*]] = load float, ptr addrspace(7) [[TMP0]], align 4 -// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>}}, ptr addrspace(7) [[TMP0]], i32 {{4|0, i32 1}} +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{4|0, i32 1}} // CHECK-NEXT: [[TMP4:%.*]] = load float, ptr addrspace(7) [[TMP3]], align 4 -// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds {{i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 2}} +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr {{inbounds i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 2}} // CHECK-NEXT: [[TMP6:%.*]] = load float, ptr addrspace(7) [[TMP5]], align 4 // CHECK-NEXT: [[TMP7:%.*]] = call reassoc nnan nsz arcp contract afn float (...) @lgc.create.fma.f32(float [[TMP2]], float [[TMP4]], float [[TMP6]]) -// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds {{i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 4}} +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr {{inbounds i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 4}} // CHECK-NEXT: [[TMP9:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP8]], align 16 -// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds {{i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 6}} +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr {{inbounds i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 6}} // CHECK-NEXT: [[TMP11:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP10]], align 16 -// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds {{i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>}}, ptr addrspace(7) [[TMP0]], i32 {{48|0, i32 8}} +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr {{inbounds i8|<{ float, float, float, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{48|0, i32 8}} // CHECK-NEXT: [[TMP13:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP12]], align 16 // CHECK-NEXT: [[TMP14:%.*]] = call reassoc nnan nsz arcp contract afn <3 x float> (...) @lgc.create.fma.v3f32(<3 x float> [[TMP9]], <3 x float> [[TMP11]], <3 x float> [[TMP13]]) // CHECK-NEXT: [[F3_0_0_VEC_EXTRACT:%.*]] = extractelement <3 x float> [[TMP14]], i64 0 diff --git a/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectDouble_lit.frag b/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectDouble_lit.frag index 4cc9302d98..3674cbd309 100644 --- a/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectDouble_lit.frag +++ b/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectDouble_lit.frag @@ -28,17 +28,17 @@ void main() // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // CHECK-NEXT: [[TMP2:%.*]] = load double, ptr addrspace(7) [[TMP0]], align 8 -// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 1}} // CHECK-NEXT: [[TMP4:%.*]] = load double, ptr addrspace(7) [[TMP3]], align 8 -// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds {{i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 2}} +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr {{inbounds i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 2}} // CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr addrspace(7) [[TMP5]], align 4 // CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[TMP6]], 0 // CHECK-NEXT: [[TMP7:%.*]] = select reassoc nnan nsz arcp contract i1 [[DOTNOT]], double [[TMP2]], double [[TMP4]] -// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds {{i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 4}} +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr {{inbounds i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 4}} // CHECK-NEXT: [[TMP9:%.*]] = load <3 x double>, ptr addrspace(7) [[TMP8]], align 32 -// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds {{i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{64|0, i32 6}} +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr {{inbounds i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{64|0, i32 6}} // CHECK-NEXT: [[TMP11:%.*]] = load <3 x double>, ptr addrspace(7) [[TMP10]], align 32 -// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds {{i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{96|0, i32 8}} +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr {{inbounds i8|<{ double, double, i32, [[]12 x i8], [[]3 x double], [[]8 x i8], [[]3 x double], [[]8 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{96|0, i32 8}} // CHECK-NEXT: [[TMP13:%.*]] = load <3 x i32>, ptr addrspace(7) [[TMP12]], align 16 // CHECK-NEXT: [[TMP14:%.*]] = extractelement <3 x i32> [[TMP13]], i64 1 // CHECK-NEXT: [[DOTNOT2:%.*]] = icmp eq i32 [[TMP14]], 0 diff --git a/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectFloat_lit.frag b/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectFloat_lit.frag index 6889ff741e..f003075a6d 100644 --- a/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectFloat_lit.frag +++ b/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectFloat_lit.frag @@ -28,17 +28,17 @@ void main() // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // CHECK-NEXT: [[TMP2:%.*]] = load float, ptr addrspace(7) [[TMP0]], align 4 -// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{4|0, i32 1}} +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{4|0, i32 1}} // CHECK-NEXT: [[TMP4:%.*]] = load float, ptr addrspace(7) [[TMP3]], align 4 -// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds {{i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 2}} +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr {{inbounds i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 2}} // CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr addrspace(7) [[TMP5]], align 4 // CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[TMP6]], 0 // CHECK-NEXT: [[TMP7:%.*]] = select reassoc nnan nsz arcp contract afn i1 [[DOTNOT]], float [[TMP2]], float [[TMP4]] -// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds {{i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 4}} +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr {{inbounds i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 4}} // CHECK-NEXT: [[TMP9:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP8]], align 16 -// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds {{i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 6}} +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr {{inbounds i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 6}} // CHECK-NEXT: [[TMP11:%.*]] = load <3 x float>, ptr addrspace(7) [[TMP10]], align 16 -// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds {{i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{48|0, i32 8}} +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr {{inbounds i8|<{ float, float, i32, [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x float], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{48|0, i32 8}} // CHECK-NEXT: [[TMP13:%.*]] = load <3 x i32>, ptr addrspace(7) [[TMP12]], align 16 // CHECK-NEXT: [[TMP14:%.*]] = extractelement <3 x i32> [[TMP13]], i64 1 // CHECK-NEXT: [[DOTNOT2:%.*]] = icmp eq i32 [[TMP14]], 0 diff --git a/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectInt_lit.frag b/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectInt_lit.frag index 8108e0fbf5..03a4d7b21e 100644 --- a/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectInt_lit.frag +++ b/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectInt_lit.frag @@ -28,17 +28,17 @@ void main() // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(7) [[TMP0]], align 4 -// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{4|0, i32 1}} +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{4|0, i32 1}} // CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr addrspace(7) [[TMP3]], align 4 -// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 2}} +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 2}} // CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr addrspace(7) [[TMP5]], align 4 // CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[TMP6]], 0 // CHECK-NEXT: [[TMP7:%.*]] = select i1 [[DOTNOT]], i32 [[TMP2]], i32 [[TMP4]] -// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 4}} +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 4}} // CHECK-NEXT: [[TMP9:%.*]] = load <3 x i32>, ptr addrspace(7) [[TMP8]], align 16 -// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 6}} +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 6}} // CHECK-NEXT: [[TMP11:%.*]] = load <3 x i32>, ptr addrspace(7) [[TMP10]], align 16 -// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{48|0, i32 8}} +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{48|0, i32 8}} // CHECK-NEXT: [[TMP13:%.*]] = load <3 x i32>, ptr addrspace(7) [[TMP12]], align 16 // CHECK-NEXT: [[TMP14:%.*]] = extractelement <3 x i32> [[TMP13]], i64 1 // CHECK-NEXT: [[DOTNOT2:%.*]] = icmp eq i32 [[TMP14]], 0 diff --git a/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectUint_lit.frag b/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectUint_lit.frag index 461ebc24c6..fb95138864 100644 --- a/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectUint_lit.frag +++ b/llpc/test/shaderdb/extensions/OpExtInst_TestMixSelectUint_lit.frag @@ -28,17 +28,17 @@ void main() // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 0) // CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) // CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(7) [[TMP0]], align 4 -// CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{4|0, i32 1}} +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{4|0, i32 1}} // CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr addrspace(7) [[TMP3]], align 4 -// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 2}} +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{8|0, i32 2}} // CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr addrspace(7) [[TMP5]], align 4 // CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[TMP6]], 0 // CHECK-NEXT: [[TMP7:%.*]] = select i1 [[DOTNOT]], i32 [[TMP2]], i32 [[TMP4]] -// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 4}} +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{16|0, i32 4}} // CHECK-NEXT: [[TMP9:%.*]] = load <3 x i32>, ptr addrspace(7) [[TMP8]], align 16 -// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 6}} +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{32|0, i32 6}} // CHECK-NEXT: [[TMP11:%.*]] = load <3 x i32>, ptr addrspace(7) [[TMP10]], align 16 -// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds {{i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>}}, ptr addrspace(7) [[TMP0]], i32 {{48|0, i32 8}} +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr {{inbounds i8|<{ i32, i32, i32, [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32], [[]4 x i8], [[]3 x i32] }>|i8}}, ptr addrspace(7) [[TMP0]], i32 {{48|0, i32 8}} // CHECK-NEXT: [[TMP13:%.*]] = load <3 x i32>, ptr addrspace(7) [[TMP12]], align 16 // CHECK-NEXT: [[TMP14:%.*]] = extractelement <3 x i32> [[TMP13]], i64 1 // CHECK-NEXT: [[DOTNOT2:%.*]] = icmp eq i32 [[TMP14]], 0 diff --git a/llpc/test/shaderdb/extensions/OpExtInst_TestTanhFloat_lit.frag b/llpc/test/shaderdb/extensions/OpExtInst_TestTanhFloat_lit.frag index 5968ac8f47..f81e8478f0 100644 --- a/llpc/test/shaderdb/extensions/OpExtInst_TestTanhFloat_lit.frag +++ b/llpc/test/shaderdb/extensions/OpExtInst_TestTanhFloat_lit.frag @@ -14,13 +14,13 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results ; SHADERTEST: = call reassoc nnan nsz arcp contract afn float (...) @lgc.create.tanh.f32(float ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results -; SHADERTEST: %{{[0-9]*}} = fmul reassoc nnan nsz arcp contract afn float %{{.*}}, 0x3FF7154760000000 -; SHADERTEST: %{{[0-9]*}} = {{fsub|fneg}} reassoc nnan nsz arcp contract afn float {{(-0.000000e+00, )?}}%{{.*}} +; SHADERTEST: %{{[0-9]*}} = call reassoc nnan nsz arcp contract afn float @llvm.fabs.f32(float %{{[0-9]*}}) +; SHADERTEST: %{{[0-9]*}} = fmul reassoc nnan nsz arcp contract afn float %{{.*}}, 0xC007154760000000 ; SHADERTEST: %{{[0-9]*}} = call reassoc nnan nsz arcp contract afn float @llvm.exp2.f32(float %{{.*}}) -; SHADERTEST: %{{[0-9]*}} = call reassoc nnan nsz arcp contract afn float @llvm.exp2.f32(float %{{.*}}) -; SHADERTEST: %{{[0-9]*}} = fsub reassoc nnan nsz arcp contract afn float %{{.*}}, %{{.*}} -; SHADERTEST: %{{[0-9]*}} = fadd reassoc nnan nsz arcp contract afn float %{{.*}}, %{{.*}} -; SHADERTEST: %{{[0-9]*}} = call reassoc nnan nsz arcp contract afn float @llvm.amdgcn.fdiv.fast(float %{{.*}}, float %{{.*}}) +; SHADERTEST: %{{[0-9]*}} = fadd reassoc nnan nsz arcp contract afn float %{{.*}}, 1.000000e+00 +; SHADERTEST: %{{[0-9]*}} = call reassoc nnan nsz arcp contract afn float @llvm.amdgcn.fdiv.fast(float 2.000000e+00, float %{{.*}}) +; SHADERTEST: %{{[0-9]*}} = fsub reassoc nnan nsz arcp contract afn float 1.000000e+00, %{{.*}} +; SHADERTEST: %{{[0-9]*}} = call reassoc nnan nsz arcp contract afn float @llvm.copysign.f32(float %{{.*}}, float %{{.*}}) ; SHADERTEST: AMDLLPC SUCCESS */ // END_SHADERTEST diff --git a/llpc/test/shaderdb/extensions/OpExtInst_TestTanh_lit.frag b/llpc/test/shaderdb/extensions/OpExtInst_TestTanh_lit.frag index 79ee280562..4ab214d410 100644 --- a/llpc/test/shaderdb/extensions/OpExtInst_TestTanh_lit.frag +++ b/llpc/test/shaderdb/extensions/OpExtInst_TestTanh_lit.frag @@ -23,20 +23,20 @@ void main() ; SHADERTEST: = call reassoc nnan nsz arcp contract afn float (...) @lgc.create.tanh.f32(float ; SHADERTEST: = call reassoc nnan nsz arcp contract afn <3 x float> (...) @lgc.create.tanh.v3f32(<3 x float> ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results -; SHADERTEST: %{{.*}} = fmul reassoc nnan nsz arcp contract afn float %{{.*}}, 0x3FF7154760000000 -; SHADERTEST: %{{.*}} = {{fsub|fneg}} reassoc nnan nsz arcp contract afn float {{(-0.000000e+00, )?}}%{{.*}} +; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.fabs.f32(float %{{[0-9]*}}) +; SHADERTEST: %{{.*}} = fmul reassoc nnan nsz arcp contract afn float %{{.*}}, 0xC007154760000000 ; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.exp2.f32(float %{{.*}}) +; SHADERTEST: %{{.*}} = fadd reassoc nnan nsz arcp contract afn float %{{.*}}, 1.000000e+00 +; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.amdgcn.fdiv.fast(float 2.000000e+00, float %{{.*}}) +; SHADERTEST: %{{.*}} = fsub reassoc nnan nsz arcp contract afn float 1.000000e+00, %{{.*}} +; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.copysign.f32(float %{{.*}}, float %{{.*}}) +; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.fabs.f32(float %{{[0-9]*}}) +; SHADERTEST: %{{.*}} = fmul reassoc nnan nsz arcp contract afn float %{{.*}}, 0xC007154760000000 ; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.exp2.f32(float %{{.*}}) -; SHADERTEST: %{{.*}} = fsub reassoc nnan nsz arcp contract afn float %{{.*}}, %{{.*}} -; SHADERTEST: %{{.*}} = fadd reassoc nnan nsz arcp contract afn float %{{.*}}, %{{.*}} -; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.amdgcn.fdiv.fast(float %{{.*}}, float %{{.*}}) -; SHADERTEST: %{{.*}} = fmul reassoc nnan nsz arcp contract afn float %{{.*}}, 0x3FF7154760000000 -; SHADERTEST: %{{.*}} = {{fsub|fneg}} reassoc nnan nsz arcp contract afn float {{(-0.000000e+00, )?}}%{{.*}} -; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.exp2.f32(float %{{.*}}) -; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.exp2.f32(float %{{.*}}) -; SHADERTEST: %{{.*}} = fsub reassoc nnan nsz arcp contract afn float %{{.*}}, %{{.*}} -; SHADERTEST: %{{.*}} = fadd reassoc nnan nsz arcp contract afn float %{{.*}}, %{{.*}} -; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.amdgcn.fdiv.fast(float %{{.*}}, float %{{.*}}) +; SHADERTEST: %{{.*}} = fadd reassoc nnan nsz arcp contract afn float %{{.*}}, 1.000000e+00 +; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.amdgcn.fdiv.fast(float 2.000000e+00, float %{{.*}}) +; SHADERTEST: %{{.*}} = fsub reassoc nnan nsz arcp contract afn float 1.000000e+00, %{{.*}} +; SHADERTEST: %{{.*}} = call reassoc nnan nsz arcp contract afn float @llvm.copysign.f32(float %{{.*}}, float %{{.*}}) ; SHADERTEST: AMDLLPC SUCCESS */ // END_SHADERTEST diff --git a/llpc/test/shaderdb/general/ImgDescLoad.comp b/llpc/test/shaderdb/general/ImgDescLoad.comp index ccc4431815..3abbe69a02 100644 --- a/llpc/test/shaderdb/general/ImgDescLoad.comp +++ b/llpc/test/shaderdb/general/ImgDescLoad.comp @@ -4,11 +4,22 @@ /* ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s -; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results -; SHADERTEST: [[SMP_DESC:%[0-9]*]] = load <4 x i32>, ptr addrspace(4) %{{[0-9]*}}, align 16, !invariant.load -; SHADERTEST: [[IMG_DESC:%[0-9]*]] = load <8 x i32>, ptr addrspace(4) %{{[0-9]*}}, align 32, !invariant.load -; SHADERTEST: lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> [[IMG_DESC]], <4 x i32> [[SMP_DESC]], i32 33, <2 x float> zeroinitializer, float 0.000000e+00) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline before-patching results +; SHADERTEST: [[IMG_DESC:%[0-9]*]] = load <8 x i32>, ptr addrspace(4) %{{[0-9]*}}, align 32, !invariant.load +; SHADERTEST: [[SMP_DESC:%[0-9]*]] = load <4 x i32>, ptr addrspace(4) %{{[0-9]*}}, align 16, !invariant.load +; SHADERTEST: %{{[0-9]*}} = extractelement <4 x i32> [[SMP_DESC]], i64 0 +; SHADERTEST: %{{[0-9]*}} = call i32 @llvm.amdgcn.readfirstlane(i32 %{{[0-9]*}}) +; SHADERTEST: %{{[0-9]*}} = insertelement <4 x i32> poison, i32 %{{[0-9]*}}, i64 0 +; SHADERTEST: %{{[0-9]*}} = extractelement <4 x i32> [[SMP_DESC]], i64 1 +; SHADERTEST: %{{[0-9]*}} = call i32 @llvm.amdgcn.readfirstlane(i32 %{{[0-9]*}}) +; SHADERTEST: %{{[0-9]*}} = insertelement <4 x i32> %{{[0-9]*}}, i32 %{{[0-9]*}}, i64 1 +; SHADERTEST: %{{[0-9]*}} = extractelement <4 x i32> [[SMP_DESC]], i64 2 +; SHADERTEST: %{{[0-9]*}} = call i32 @llvm.amdgcn.readfirstlane(i32 %{{[0-9]*}}) +; SHADERTEST: %{{[0-9]*}} = insertelement <4 x i32> %{{[0-9]*}}, i32 %{{[0-9]*}}, i64 2 +; SHADERTEST: %{{[0-9]*}} = extractelement <4 x i32> [[SMP_DESC]], i64 3 +; SHADERTEST: %{{[0-9]*}} = call i32 @llvm.amdgcn.readfirstlane(i32 %{{[0-9]*}}) +; SHADERTEST: [[NEW_SMP_DESC:%[0-9]*]] = insertelement <4 x i32> %{{[0-9]*}}, i32 %{{[0-9]*}}, i64 3 +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.l.2d.v4f32.f32(i32 15, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, <8 x i32> [[IMG_DESC]], <4 x i32> [[NEW_SMP_DESC]], i1 false, i32 0, i32 0) */ // END_SHADERTEST diff --git a/llpc/test/shaderdb/general/PipelineCs_DebugPrintf.pipe b/llpc/test/shaderdb/general/PipelineCs_DebugPrintf.pipe index ee39f82720..d4a15e421b 100644 --- a/llpc/test/shaderdb/general/PipelineCs_DebugPrintf.pipe +++ b/llpc/test/shaderdb/general/PipelineCs_DebugPrintf.pipe @@ -24,10 +24,9 @@ userDataNode[0].next[0].set = 0xFFFFFFFF userDataNode[0].next[0].binding = 6 ; CHECK-LABEL: @lgc.shader.CS.main( ; CHECK-NEXT: .entry: -; CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 4294967295, i32 6, i32 0, i32 2) -; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i32> (...) @lgc.create.read.builtin.input.v3i32(i32 28, i32 0, i32 poison, i32 poison) -; CHECK-NEXT: [[__LLPC_INPUT_PROXY_GL_GLOBALINVOCATIONID_0_VEC_EXTRACT:%.*]] = extractelement <3 x i32> [[TMP1]], i64 0 -; CHECK-NEXT: call void (...) @lgc.debug.printf(ptr addrspace(7) [[TMP0]], ptr addrspace(4) @str, i32 [[__LLPC_INPUT_PROXY_GL_GLOBALINVOCATIONID_0_VEC_EXTRACT]]) -; CHECK-NEXT: call void (...) @lgc.debug.printf(ptr addrspace(7) [[TMP0]], ptr addrspace(4) @str.1, double 1.000000e+00, double 1.000000e+00) +; CHECK-NEXT: [[TMP0:%.*]] = call <3 x i32> (...) @lgc.create.read.builtin.input.v3i32(i32 28, i32 0, i32 poison, i32 poison) +; CHECK-NEXT: [[__LLPC_INPUT_PROXY_GL_GLOBALINVOCATIONID_0_VEC_EXTRACT:%.*]] = extractelement <3 x i32> [[TMP0]], i64 0 +; CHECK-NEXT: call void (...) @lgc.debug.printf(ptr nonnull @[[GLOB0:[0-9]+]], i32 [[__LLPC_INPUT_PROXY_GL_GLOBALINVOCATIONID_0_VEC_EXTRACT]]) +; CHECK-NEXT: call void (...) @lgc.debug.printf(ptr nonnull @[[GLOB1:[0-9]+]], double 1.000000e+00, double 1.000000e+00) ; CHECK-NEXT: ret void ; diff --git a/llpc/test/shaderdb/general/PipelineRays_TestLgcRtTraceRayOp.pipe b/llpc/test/shaderdb/general/PipelineRays_TestLgcRtTraceRayOp.pipe index 7ed6a30f8d..d432d16530 100644 --- a/llpc/test/shaderdb/general/PipelineRays_TestLgcRtTraceRayOp.pipe +++ b/llpc/test/shaderdb/general/PipelineRays_TestLgcRtTraceRayOp.pipe @@ -1,6 +1,7 @@ ; Check lgc.rt.trace.ray dialect is being generated. ; BEGIN_SHADERTEST +; REQUIRES: gpurt ; RUN: amdllpc --print-after=llpc-spirv-lower-translator -gfxip 10.3 -o /dev/null 2>&1 %s | FileCheck -check-prefixes=SHADERTEST %s ; SHADERTEST-LABEL: @main( ; SHADERTEST: call void (...) @lgc.rt.trace.ray(i64 %{{[0-9]+}}, i32 0, i32 %{{[0-9]+}}, i32 0, i32 0, i32 0, <3 x float> %{{[0-9]+}}, float %{{[0-9]+}}, <3 x float> %{{[0-9]+}}, float %{{[0-9]+}}, ptr addrspace(5) @RayPayloadKHR0, [1 x i32] [i32 16]) diff --git a/llpc/test/shaderdb/general/WorkaroundStorageImageFormats.pipe b/llpc/test/shaderdb/general/WorkaroundStorageImageFormats.pipe index 0ee38a19af..2854fdab17 100644 --- a/llpc/test/shaderdb/general/WorkaroundStorageImageFormats.pipe +++ b/llpc/test/shaderdb/general/WorkaroundStorageImageFormats.pipe @@ -28,7 +28,6 @@ userDataNode[0].next[0].binding = 0 ; CHECK-NEXT: .entry: ; CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(4) (...) @lgc.create.get.desc.ptr.p4(i32 1, i32 1, i64 0, i32 0) ; CHECK-NEXT: [[TMP1:%.*]] = call i32 (...) @lgc.create.get.desc.stride.i32(i32 1, i32 1, i64 0, i32 0) -; CHECK-NEXT: [[TMP2:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP0]], align 32 -; CHECK-NEXT: call void (...) @lgc.create.image.store(<4 x float> , i32 1, i32 512, <8 x i32> [[TMP2]], <2 x i32> ) +; CHECK-NEXT: call void (...) @lgc.create.image.store(<4 x float> , i32 1, i32 512, ptr addrspace(4) [[TMP0]], <2 x i32> ) ; CHECK-NEXT: ret void ; diff --git a/llpc/test/shaderdb/gfx10/PipelineVsFs_TestVsOutMiscSideBusEna.pipe b/llpc/test/shaderdb/gfx10/PipelineVsFs_TestVsOutMiscSideBusEna.pipe index 074a293e19..4e89bd1ffd 100644 --- a/llpc/test/shaderdb/gfx10/PipelineVsFs_TestVsOutMiscSideBusEna.pipe +++ b/llpc/test/shaderdb/gfx10/PipelineVsFs_TestVsOutMiscSideBusEna.pipe @@ -64,7 +64,6 @@ entryPoint = main ; SHADERTEST-NEXT: .pa_cl_clip_cntl: ; SHADERTEST-NEXT: .dx_linear_attr_clip_ena: true ; SHADERTEST-NEXT: .rasterization_kill: false -; SHADERTEST-NEXT: .vs_out_misc_side_bus_ena: true ; SHADERTEST-NEXT: .vte_vport_provoke_disable: false ; SHADERTEST-NEXT: .pa_cl_vs_out_cntl: ; SHADERTEST-NEXT: .clip_dist_ena_0: true @@ -84,6 +83,7 @@ entryPoint = main ; SHADERTEST-NEXT: .cull_dist_ena_6: false ; SHADERTEST-NEXT: .cull_dist_ena_7: false ; SHADERTEST-NEXT: .vs_out_cc_dist0_vec_ena: true +; SHADERTEST-NEXT: .vs_out_misc_side_bus_ena: true ; SHADERTEST-NEXT: .pa_cl_vte_cntl: ; SHADERTEST-NEXT: .vtx_w0_fmt: true ; SHADERTEST-NEXT: .x_offset_ena: true @@ -193,7 +193,8 @@ entryPoint = main ; SHADERTEST-NEXT: .entry_point: _amdgpu_ps_main ; SHADERTEST-NEXT: .float_mode: 0xc0 ; SHADERTEST-NEXT: .ieee_mode: false -; SHADERTEST: .mem_ordered: true +; SHADERTEST-NEXT: .lds_size: 0 +; SHADERTEST-NEXT: .mem_ordered: true ; SHADERTEST-NEXT: .scratch_en: false ; SHADERTEST-NEXT: .scratch_memory_size: 0 ; SHADERTEST-NEXT: .sgpr_count: 0x2 @@ -246,7 +247,8 @@ entryPoint = main ; SHADERTEST-NEXT: .entry_point: _amdgpu_vs_main ; SHADERTEST-NEXT: .float_mode: 0xc0 ; SHADERTEST-NEXT: .ieee_mode: false -; SHADERTEST: .mem_ordered: true +; SHADERTEST-NEXT: .lds_size: 0 +; SHADERTEST-NEXT: .mem_ordered: true ; SHADERTEST-NEXT: .scratch_en: false ; SHADERTEST-NEXT: .scratch_memory_size: 0 ; SHADERTEST-NEXT: .sgpr_count: 0x3 diff --git a/llpc/test/shaderdb/gfx11/AttributePrecedesPos.pipe b/llpc/test/shaderdb/gfx11/AttributePrecedesPos.pipe index 7aa05e7a74..243b999907 100644 --- a/llpc/test/shaderdb/gfx11/AttributePrecedesPos.pipe +++ b/llpc/test/shaderdb/gfx11/AttributePrecedesPos.pipe @@ -3,7 +3,7 @@ ; RUN: amdllpc %gfxip %s -v | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: @_amdgpu_gs_main( ; SHADERTEST: call void @llvm.amdgcn.struct.buffer.store.v4f32(<4 x float> %{{.*}}, <4 x i32> %{{.*}}, i32 %{{.*}}, i32 0, i32 %{{.*}}, i32 3) -; SHADERTEST: fence release +; SHADERTEST: fence syncscope("agent") release ; SHADERTEST: call void @llvm.amdgcn.exp.f32(i32 12, i32 15, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, i1 false, i1 false) ; SHADERTEST: call void @llvm.amdgcn.exp.f32(i32 13, i32 1, float 1.000000e+00, float poison, float poison, float poison, i1 true, i1 false) ; SHADERTEST-LABEL: _amdgpu_gs_main: diff --git a/llpc/test/shaderdb/gfx11/cooperativeMatrix/array-of-matrices.comp b/llpc/test/shaderdb/gfx11/cooperativeMatrix/array-of-matrices.comp index 4ca900bf0d..6aad9398cd 100644 --- a/llpc/test/shaderdb/gfx11/cooperativeMatrix/array-of-matrices.comp +++ b/llpc/test/shaderdb/gfx11/cooperativeMatrix/array-of-matrices.comp @@ -35,7 +35,7 @@ void main() { // CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(4) (...) @lgc.create.load.push.constants.ptr.p4() // CHECK-NEXT: [[TMP1:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 0, i32 0, i32 0, i32 2) // CHECK-NEXT: [[LOAD:%.*]] = call <8 x float> (...) @lgc.cooperative.matrix.load__v8f32(ptr addrspace(7) [[TMP1]], i32 32, i1 true, i32 1, i32 0, i32 0, i32 16) -// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr addrspace(7) [[TMP1]], i32 512 +// CHECK-NEXT: [[TMP2:%.*]] = getelementptr {{(inbounds )?}}i8, ptr addrspace(7) [[TMP1]], i32 512 // CHECK-NEXT: [[LOAD2:%.*]] = call <8 x float> (...) @lgc.cooperative.matrix.load__v8f32(ptr addrspace(7) [[TMP2]], i32 32, i1 true, i32 1, i32 0, i32 0, i32 16) // CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr addrspace(4) [[TMP0]], align 4 // CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP3]], 2 @@ -49,13 +49,13 @@ void main() { // CHECK: 10: // CHECK-NEXT: [[TMP11:%.*]] = phi i32 [ 0, [[DOTENTRY:%.*]] ], [ [[TMP9]], [[TMP5]] ] // CHECK-NEXT: store i32 [[TMP11]], ptr addrspace(7) [[TMP1]], align 4 -// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds i8, ptr addrspace(4) [[TMP0]], i64 4 +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr {{(inbounds )?}}i8, ptr addrspace(4) [[TMP0]], i64 4 // CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr addrspace(4) [[TMP12]], align 4 // CHECK-NEXT: [[TMP14:%.*]] = icmp ult i32 [[TMP13]], 2 // CHECK-NEXT: [[TMP15:%.*]] = icmp eq i32 [[TMP13]], 1 // CHECK-NEXT: [[TMP16:%.*]] = select i1 [[TMP15]], <8 x float> [[LOAD2]], <8 x float> [[LOAD]] // CHECK-NEXT: [[TMP17:%.*]] = select i1 [[TMP14]], <8 x float> [[TMP16]], <8 x float> zeroinitializer -// CHECK-NEXT: [[TMP18:%.*]] = getelementptr inbounds i8, ptr addrspace(7) [[TMP1]], i32 1024 +// CHECK-NEXT: [[TMP18:%.*]] = getelementptr {{(inbounds )?}}i8, ptr addrspace(7) [[TMP1]], i32 1024 // CHECK-NEXT: call void (...) @lgc.cooperative.matrix.store(ptr addrspace(7) [[TMP18]], i32 64, i1 true, i32 1, i32 0, i32 0, i32 16, <8 x float> [[TMP17]]) // CHECK-NEXT: ret void // diff --git a/llpc/test/shaderdb/graphics_library/PipelineVsFs_TestGraphicsLibrary.pipe b/llpc/test/shaderdb/graphics_library/PipelineVsFs_TestGraphicsLibrary.pipe index 685133b765..584652edee 100644 --- a/llpc/test/shaderdb/graphics_library/PipelineVsFs_TestGraphicsLibrary.pipe +++ b/llpc/test/shaderdb/graphics_library/PipelineVsFs_TestGraphicsLibrary.pipe @@ -20,7 +20,7 @@ colorExport=PipelineLibCes_TestColorExport.pipe ; SHADERTEST-NEXT: [[VERTEXINDEX:%.*]] = add i32 [[TMP3]], [[TMP4]] ; SHADERTEST-NEXT: [[DOTFR:%.*]] = freeze i32 [[VERTEXINDEX]] ; SHADERTEST-NEXT: [[TMP5:%.*]] = icmp slt i32 [[DOTFR]], 3 -; SHADERTEST-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr addrspace(7) [[TMP0]], i32 4 +; SHADERTEST-NEXT: [[TMP6:%.*]] = getelementptr {{(inbounds )?}}i8, ptr addrspace(7) [[TMP0]], i32 4 ; SHADERTEST-NEXT: [[DOT0_IN:%.*]] = select i1 [[TMP5]], ptr addrspace(7) [[TMP0]], ptr addrspace(7) [[TMP6]] ; SHADERTEST-NEXT: [[DOT0:%.*]] = load float, ptr addrspace(7) [[DOT0_IN]], align 4 ; SHADERTEST-NEXT: [[TMP7:%.*]] = insertelement <4 x float> [[TMP2]], float 1.000000e+00, i64 3 @@ -34,16 +34,16 @@ colorExport=PipelineLibCes_TestColorExport.pipe ; SHADERTEST-NEXT: .entry: ; SHADERTEST-NEXT: [[TMP0:%.*]] = call ptr addrspace(7) @lgc.load.buffer.desc(i64 1, i32 1, i32 0, i32 0) ; SHADERTEST-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p7(i64 -1, ptr addrspace(7) [[TMP0]]) -; SHADERTEST-NEXT: [[FRAGCOORD:%.*]] = call <4 x float> @lgc.input.import.builtin.FragCoord.v4f32.i32(i32 15) #[[ATTR3]] +; SHADERTEST-NEXT: [[FRAGCOORD:%.*]] = call <4 x float> @lgc.input.import.builtin.FragCoord.v4f32.i32(i32 15) #[[ATTR4]] ; SHADERTEST-NEXT: [[__LLPC_INPUT_PROXY_GL_FRAGCOORD_4_VEC_EXTRACT:%.*]] = extractelement <4 x float> [[FRAGCOORD]], i64 1 ; SHADERTEST-NEXT: [[TMP2:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[__LLPC_INPUT_PROXY_GL_FRAGCOORD_4_VEC_EXTRACT]], -5.000000e-01 ; SHADERTEST-NEXT: [[TMP3:%.*]] = fptosi float [[TMP2]] to i32 ; SHADERTEST-NEXT: [[DOTFR:%.*]] = freeze i32 [[TMP3]] ; SHADERTEST-NEXT: [[TMP4:%.*]] = icmp slt i32 [[DOTFR]], 8 -; SHADERTEST-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr addrspace(7) [[TMP0]], i32 16 +; SHADERTEST-NEXT: [[TMP5:%.*]] = getelementptr {{(inbounds )?}}i8, ptr addrspace(7) [[TMP0]], i32 16 ; SHADERTEST-NEXT: [[DOT0_IN:%.*]] = select i1 [[TMP4]], ptr addrspace(7) [[TMP0]], ptr addrspace(7) [[TMP5]] ; SHADERTEST-NEXT: [[DOT0:%.*]] = load <4 x float>, ptr addrspace(7) [[DOT0_IN]], align 16 -; SHADERTEST-NEXT: call void @lgc.output.export.generic.i32.i32.v4f32(i32 0, i32 0, <4 x float> [[DOT0]]) #[[ATTR4]] +; SHADERTEST-NEXT: call void @lgc.output.export.generic.i32.i32.v4f32(i32 0, i32 0, <4 x float> [[DOT0]]) #[[ATTR3]] ; SHADERTEST-NEXT: ret void ; ; diff --git a/llpc/test/shaderdb/object/ObjFragMask_TestFragFetch_lit.frag b/llpc/test/shaderdb/object/ObjFragMask_TestFragFetch_lit.frag index 0eeac24367..dda5e3a2bf 100644 --- a/llpc/test/shaderdb/object/ObjFragMask_TestFragFetch_lit.frag +++ b/llpc/test/shaderdb/object/ObjFragMask_TestFragFetch_lit.frag @@ -32,11 +32,11 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 6, i32 512, <8 x i32> -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 2, i32 512, <8 x i32> -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 7, i32 512, <8 x i32> -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 1, i32 544, <8 x i32> -; SHADERTEST: call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 6, i32 544, <8 x i32> +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 6, i32 512, ptr addrspace(4) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 2, i32 512, ptr addrspace(4) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 7, i32 512, ptr addrspace(4) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 1, i32 544, ptr addrspace(4) +; SHADERTEST: call <4 x i32> (...) @lgc.create.image.load.v4i32(i32 6, i32 544, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.load.2dmsaa.v4f32.i16 ; SHADERTEST: call i32 @llvm.amdgcn.image.load.3d.i32.i16(i32 1, i16 2, i16 3, i16 1, <8 x i32> %{{.*}}, i32 0, i32 0) diff --git a/llpc/test/shaderdb/object/ObjImage_TestCubeAtomicAdd_lit.comp b/llpc/test/shaderdb/object/ObjImage_TestCubeAtomicAdd_lit.comp index 17520b8f99..365fc5f536 100644 --- a/llpc/test/shaderdb/object/ObjImage_TestCubeAtomicAdd_lit.comp +++ b/llpc/test/shaderdb/object/ObjImage_TestCubeAtomicAdd_lit.comp @@ -16,10 +16,10 @@ void main (void) /* ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 8, i32 0, i32 0, <8 x i32> +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 8, i32 0, i32 0, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC.*}} SPIR-V lowering results -; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 8, i32 0, i32 0, <8 x i32> +; SHADERTEST: call i32 (...) @lgc.create.image.atomic.i32(i32 2, i32 8, i32 0, i32 0, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC}} final pipeline module info ; SHADERTEST: call i32 @llvm.amdgcn.image.atomic.add.cube.i32.i32 diff --git a/llpc/test/shaderdb/object/ObjImage_TestMemoryQualifier_lit.frag b/llpc/test/shaderdb/object/ObjImage_TestMemoryQualifier_lit.frag index d8be3affa1..921561a6de 100644 --- a/llpc/test/shaderdb/object/ObjImage_TestMemoryQualifier_lit.frag +++ b/llpc/test/shaderdb/object/ObjImage_TestMemoryQualifier_lit.frag @@ -16,13 +16,13 @@ void main() /* ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 513, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, <8 x i32> -; SHADERTEST: call void (...) @lgc.create.image.store(<4 x float> %{{[^,]*}}, i32 9, i32 515, <8 x i32> +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 513, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, ptr addrspace(4) +; SHADERTEST: call void (...) @lgc.create.image.store(<4 x float> %{{[^,]*}}, i32 9, i32 515, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC.*}} SPIR-V lowering results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 513, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, <8 x i32> -; SHADERTEST: call void (...) @lgc.create.image.store(<4 x float> %{{[^,]*}}, i32 9, i32 515, <8 x i32> +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 0, i32 513, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, ptr addrspace(4) +; SHADERTEST: call void (...) @lgc.create.image.store(<4 x float> %{{[^,]*}}, i32 9, i32 515, ptr addrspace(4) ; SHADERTEST: AMDLLPC SUCCESS */ // END_SHADERTEST diff --git a/llpc/test/shaderdb/object/ObjResource_TestAlias_lit.frag b/llpc/test/shaderdb/object/ObjResource_TestAlias_lit.frag index c2d76316b4..37f246212a 100644 --- a/llpc/test/shaderdb/object/ObjResource_TestAlias_lit.frag +++ b/llpc/test/shaderdb/object/ObjResource_TestAlias_lit.frag @@ -39,16 +39,15 @@ void main() /* ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, <8 x i32> +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC.*}} SPIR-V lowering results ; SHADERTEST: call {{.*}} {{.*}}@lgc.load.buffer.desc{{.*}}(i64 0, i32 1,{{.*}} -; SHADERTEST: load <4 x float> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, <8 x i32> +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.load.v4f32(i32 1, i32 512, ptr addrspace(4) ; SHADERTEST: AMDLLPC SUCCESS diff --git a/llpc/test/shaderdb/object/ObjSampler_TestLargeId_lit.frag b/llpc/test/shaderdb/object/ObjSampler_TestLargeId_lit.frag index 39a9031568..d04cd7195d 100644 --- a/llpc/test/shaderdb/object/ObjSampler_TestLargeId_lit.frag +++ b/llpc/test/shaderdb/object/ObjSampler_TestLargeId_lit.frag @@ -46,23 +46,23 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC.*}} SPIR-V lowering results -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) -; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, <8 x i32> %{{[-0-9A-Za0z_.]+}}, <4 x i32> %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) +; SHADERTEST: call reassoc nnan nsz arcp contract afn <4 x float> (...) @lgc.create.image.sample.v4f32(i32 1, i32 512, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, ptr addrspace(4) %{{[-0-9A-Za0z_.]+}}, i32 1, <2 x float> zeroinitializer) ; SHADERTEST: AMDLLPC SUCCESS */ diff --git a/llpc/test/shaderdb/object/ObjSampler_TestSeparateSamplerShadow_lit.frag b/llpc/test/shaderdb/object/ObjSampler_TestSeparateSamplerShadow_lit.frag index 4636798b25..92b381dded 100644 --- a/llpc/test/shaderdb/object/ObjSampler_TestSeparateSamplerShadow_lit.frag +++ b/llpc/test/shaderdb/object/ObjSampler_TestSeparateSamplerShadow_lit.frag @@ -14,7 +14,7 @@ void main() /* ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: call reassoc nnan nsz arcp contract afn float (...) @lgc.create.image.sample.f32(i32 1, i32 512, <8 x i32> +; SHADERTEST: call reassoc nnan nsz arcp contract afn float (...) @lgc.create.image.sample.f32(i32 1, i32 512, ptr addrspace(4) ; SHADERTEST-LABEL: {{^// LLPC}} pipeline patching results ; SHADERTEST: call {{.*}} float @llvm.amdgcn.image.sample.c.lz.2d.f32.f16(i32 1, float 0.000000e+00, half 0xH0000, half 0xH0000, <8 x i32> %{{.*}}, <4 x i32> %{{.*}}, i1 false, i32 0, i32 0) diff --git a/llpc/test/shaderdb/object/ObjSharedVariable_TestArrayCopy_lit.comp b/llpc/test/shaderdb/object/ObjSharedVariable_TestArrayCopy_lit.comp index 2fac95aef8..f311930853 100644 --- a/llpc/test/shaderdb/object/ObjSharedVariable_TestArrayCopy_lit.comp +++ b/llpc/test/shaderdb/object/ObjSharedVariable_TestArrayCopy_lit.comp @@ -30,8 +30,8 @@ void main() ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results ; SHADERTEST: @[[LDS:[^ ]*]] = addrspace(3) global { i32, [16 x i32] } -; SHADERTEST: store i32 %{{[0-9]*}}, ptr addrspace(3) getelementptr inbounds ({ i32, [16 x i32] }, ptr addrspace(3) @[[LDS]], i32 0, i32 1, i32 {{[0-9]*}}) -; SHADERTEST: %{{[0-9]*}} = load i32, ptr addrspace(3) getelementptr inbounds ({ i32, [16 x i32] }, ptr addrspace(3) @[[LDS]], i32 0, i32 1, i32 {{[0-9]*}}) +; SHADERTEST: store i32 %{{[0-9]*}}, ptr addrspace(3) getelementptr {{(inbounds )?}}({ i32, [16 x i32] }, ptr addrspace(3) @[[LDS]], i32 0, i32 1, i32 {{[0-9]*}}) +; SHADERTEST: %{{[0-9]*}} = load i32, ptr addrspace(3) getelementptr {{(inbounds )?}}({ i32, [16 x i32] }, ptr addrspace(3) @[[LDS]], i32 0, i32 1, i32 {{[0-9]*}}) ; SHADERTEST: %{{[0-9]*}} = getelementptr { i32, [16 x i32] }, ptr addrspace(3) @[[LDS]], i32 0, i32 1, i32 %{{[0-9]*}} ; SHADERTEST: %{{[0-9]*}} = load i32, ptr addrspace(3) %{{[0-9]*}} diff --git a/llpc/test/shaderdb/object/ObjSharedVariable_TestArray_lit.comp b/llpc/test/shaderdb/object/ObjSharedVariable_TestArray_lit.comp index bddcfcbd43..2623ea3276 100644 --- a/llpc/test/shaderdb/object/ObjSharedVariable_TestArray_lit.comp +++ b/llpc/test/shaderdb/object/ObjSharedVariable_TestArray_lit.comp @@ -22,8 +22,8 @@ void main() ; SHADERTEST: @[[LDS:[^ ]*]] = addrspace(3) global [16 x i32] poison ; SHADERTEST: %{{[0-9]*}} = getelementptr [16 x i32], ptr addrspace(3) @[[LDS]], i32 0, i32 %{{[0-9]*}} ; SHADERTEST: store i32 %{{[0-9]*}}, ptr addrspace(3) %{{[0-9]*}} -; SHADERTEST: store i32 %{{[0-9]*}}, ptr addrspace(3) getelementptr inbounds ([16 x i32], ptr addrspace(3) @[[LDS]], i32 0, i32 3) -; SHADERTEST: %{{[0-9]*}} = load i32, ptr addrspace(3) getelementptr inbounds ([16 x i32], ptr addrspace(3) @[[LDS]], i32 0, i32 4) +; SHADERTEST: store i32 %{{[0-9]*}}, ptr addrspace(3) getelementptr {{(inbounds )?}}([16 x i32], ptr addrspace(3) @[[LDS]], i32 0, i32 3) +; SHADERTEST: %{{[0-9]*}} = load i32, ptr addrspace(3) getelementptr {{(inbounds )?}}([16 x i32], ptr addrspace(3) @[[LDS]], i32 0, i32 4) ; SHADERTEST: AMDLLPC SUCCESS */ diff --git a/llpc/test/shaderdb/object/ObjStorageBlock_TestMultiLevelAccessChain_lit.vert b/llpc/test/shaderdb/object/ObjStorageBlock_TestMultiLevelAccessChain_lit.vert index 35540f4a9a..788af1911b 100644 --- a/llpc/test/shaderdb/object/ObjStorageBlock_TestMultiLevelAccessChain_lit.vert +++ b/llpc/test/shaderdb/object/ObjStorageBlock_TestMultiLevelAccessChain_lit.vert @@ -26,7 +26,7 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results ; SHADERTEST: getelementptr { <4 x float> }, ptr addrspace({{.*}}) %{{[a-z0-9]*}}, i32 0, i32 0 -; SHADERTEST: getelementptr inbounds (<{ [3 x float], [4 x i8], <{ [4 x float] }> }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 2 +; SHADERTEST: getelementptr {{(inbounds )?}}(<{ [3 x float], [4 x i8], <{ [4 x float] }> }>, ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 2 ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: store <4 x float> , diff --git a/llpc/test/shaderdb/object/ObjUniformBlock_TestDirectIndex_lit.frag b/llpc/test/shaderdb/object/ObjUniformBlock_TestDirectIndex_lit.frag index ba1b71735e..3b21275d95 100644 --- a/llpc/test/shaderdb/object/ObjUniformBlock_TestDirectIndex_lit.frag +++ b/llpc/test/shaderdb/object/ObjUniformBlock_TestDirectIndex_lit.frag @@ -17,7 +17,7 @@ void main() /* ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: getelementptr inbounds ([4 x <{ [4 x float], [10 x [4 x float]] }>], ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 3, i32 1, i32 5 +; SHADERTEST: getelementptr {{(inbounds )?}}([4 x <{ [4 x float], [10 x [4 x float]] }>], ptr addrspace({{.*}}) @{{.*}}, i32 0, i32 3, i32 1, i32 5 ; SHADERTEST-LABEL: {{^// LLPC}} SPIR-V lowering results ; SHADERTEST: call {{.*}} {{.*}}@lgc.load.buffer.desc(i64 1, i32 0, i32 0 diff --git a/llpc/test/shaderdb/object/ObjUniformBlock_TestLoadMatrixArray_lit.vert b/llpc/test/shaderdb/object/ObjUniformBlock_TestLoadMatrixArray_lit.vert index 6aeaafdcdb..cda46c22b6 100644 --- a/llpc/test/shaderdb/object/ObjUniformBlock_TestLoadMatrixArray_lit.vert +++ b/llpc/test/shaderdb/object/ObjUniformBlock_TestLoadMatrixArray_lit.vert @@ -20,14 +20,14 @@ void main() ; RUN: amdllpc -v %gfxip %s | FileCheck -check-prefix=SHADERTEST %s ; SHADERTEST-LABEL: {{^// LLPC}} SPIRV-to-LLVM translation results -; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr inbounds (<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2), align 16 -; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr ([4 x %llpc.matrix.column], ptr addrspace(7) getelementptr inbounds (<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2), i32 0, i32 1, i32 0), align 16 -; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr ([4 x %llpc.matrix.column], ptr addrspace(7) getelementptr inbounds (<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2), i32 0, i32 2, i32 0), align 16 -; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr ([4 x %llpc.matrix.column], ptr addrspace(7) getelementptr inbounds (<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2), i32 0, i32 3, i32 0), align 16 -; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr inbounds (<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2, i32 1), align 16 -; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr inbounds (<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2, i32 1, i32 1, i32 0), align 16 -; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr inbounds (<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2, i32 1, i32 2, i32 0), align 16 -; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr inbounds (<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2, i32 1, i32 3, i32 0), align 16 +; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr {{(inbounds )?}}(<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2), align 16 +; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr ([4 x %llpc.matrix.column], ptr addrspace(7) getelementptr {{(inbounds )?}}(<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2), i32 0, i32 1, i32 0), align 16 +; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr ([4 x %llpc.matrix.column], ptr addrspace(7) getelementptr {{(inbounds )?}}(<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2), i32 0, i32 2, i32 0), align 16 +; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr ([4 x %llpc.matrix.column], ptr addrspace(7) getelementptr {{(inbounds )?}}(<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2), i32 0, i32 3, i32 0), align 16 +; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr {{(inbounds )?}}(<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2, i32 1), align 16 +; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr {{(inbounds )?}}(<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2, i32 1, i32 1, i32 0), align 16 +; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr {{(inbounds )?}}(<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2, i32 1, i32 2, i32 0), align 16 +; SHADERTEST: %{{[0-9]*}} = load <4 x float>, ptr addrspace(7) getelementptr {{(inbounds )?}}(<{ i32, [12 x i8], [2 x [4 x %{{[a-z.]*}}]] }>, ptr addrspace(7) @{{[a-z0-9]+}}, i32 0, i32 2, i32 1, i32 3, i32 0), align 16 ; SHADERTEST: AMDLLPC SUCCESS */ diff --git a/llpc/test/shaderdb/ray_tracing/lit.local.cfg b/llpc/test/shaderdb/ray_tracing/lit.local.cfg index c839f74489..995b0dc96b 100644 --- a/llpc/test/shaderdb/ray_tracing/lit.local.cfg +++ b/llpc/test/shaderdb/ray_tracing/lit.local.cfg @@ -1,3 +1,5 @@ +if "gpurt" not in config.available_features: + config.unsupported = True # overwrite %gfxip in config.substitutions config.gfxip = '-gfxip=10.3' diff --git a/llpc/test/shaderdb/relocatable_shaders/PipelineVsFs_EnableColorExport.pipe b/llpc/test/shaderdb/relocatable_shaders/PipelineVsFs_EnableColorExport.pipe index 76845b01dc..b08b250318 100644 --- a/llpc/test/shaderdb/relocatable_shaders/PipelineVsFs_EnableColorExport.pipe +++ b/llpc/test/shaderdb/relocatable_shaders/PipelineVsFs_EnableColorExport.pipe @@ -71,79 +71,62 @@ attribute[0].binding = 0 attribute[0].format = VK_FORMAT_R32G32B32A32_SFLOAT attribute[0].offset = 0 -; -; SHADERTEST-LABEL: @_amdgpu_ps_main( +; SHADERTEST-LABEL: @lgc.shader.VS.main( ; SHADERTEST-NEXT: .entry: -; SHADERTEST-NEXT: [[PERSPINTERPCENTER_I1:%.*]] = extractelement <2 x float> [[PERSPINTERPCENTER:%.*]], i64 1 -; SHADERTEST-NEXT: [[PERSPINTERPCENTER_I0:%.*]] = extractelement <2 x float> [[PERSPINTERPCENTER]], i64 0 -; SHADERTEST-NEXT: [[TMP11:%.*]] = call i64 @llvm.amdgcn.s.getpc() -; SHADERTEST-NEXT: [[TMP16:%.*]] = call float @llvm.amdgcn.interp.p1(float [[PERSPINTERPCENTER_I0]], i32 immarg 0, i32 immarg 0, i32 [[PRIMMASK:%.*]]) -; SHADERTEST-NEXT: [[TMP17:%.*]] = call float @llvm.amdgcn.interp.p2(float [[TMP16]], float [[PERSPINTERPCENTER_I1]], i32 immarg 0, i32 immarg 0, i32 [[PRIMMASK]]) -; SHADERTEST-NEXT: [[TMP18:%.*]] = call float @llvm.amdgcn.interp.p1(float [[PERSPINTERPCENTER_I0]], i32 immarg 1, i32 immarg 0, i32 [[PRIMMASK]]) -; SHADERTEST-NEXT: [[TMP19:%.*]] = call float @llvm.amdgcn.interp.p2(float [[TMP18]], float [[PERSPINTERPCENTER_I1]], i32 immarg 1, i32 immarg 0, i32 [[PRIMMASK]]) -; SHADERTEST-NEXT: [[TMP12:%.*]] = and i64 [[TMP11]], -4294967296 -; SHADERTEST-NEXT: [[TMP13:%.*]] = zext i32 [[DESCTABLE0:%.*]] to i64 -; SHADERTEST-NEXT: [[TMP14:%.*]] = or {{(disjoint )?}}i64 [[TMP12]], [[TMP13]] -; SHADERTEST-NEXT: [[TMP15:%.*]] = inttoptr i64 [[TMP14]] to ptr addrspace(4) -; SHADERTEST-NEXT: [[DOTI0:%.*]] = fptosi float [[TMP17]] to i32 -; SHADERTEST-NEXT: [[DOTI1:%.*]] = fptosi float [[TMP19]] to i32 -; SHADERTEST-NEXT: [[TMP20:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP15]], align 32, !invariant.load !{{.*}} -; SHADERTEST-NEXT: [[TMP21:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP15]], align 16, !invariant.load !{{.*}} -; SHADERTEST-NEXT: [[DOTI01:%.*]] = sitofp i32 [[DOTI0]] to float -; SHADERTEST-NEXT: [[DOTI12:%.*]] = sitofp i32 [[DOTI1]] to float -; SHADERTEST-NEXT: [[TMP23:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float [[DOTI01]], float [[DOTI12]], <8 x i32> [[TMP20]], <4 x i32> [[TMP21]], i1 false, i32 0, i32 0) -; SHADERTEST-NEXT: [[TMP25:%.*]] = zext i32 [[COLOREXPADDR:%.*]] to i64 -; SHADERTEST-NEXT: [[TMP26:%.*]] = or {{(disjoint )?}}i64 [[TMP12]], [[TMP25]] -; SHADERTEST-NEXT: [[TMP27:%.*]] = inttoptr i64 [[TMP26]] to ptr addrspace(4) -; SHADERTEST-NEXT: call amdgpu_gfx addrspace(4) void [[TMP27]](<4 x float> [[TMP23]], i32 inreg 0) #[[ATTR1:[0-9]+]] -; SHADERTEST-NEXT: unreachable +; SHADERTEST-NEXT: [[TMP0:%.*]] = call <2 x float> @lgc.input.import.generic__v2f32(i1 false, i32 0, i32 0, i32 0, i32 poison) +; SHADERTEST-NEXT: call void @lgc.output.export.generic.i32.i32.v2f32(i32 0, i32 0, <2 x float> [[TMP0]]) #[[ATTR1:[0-9]+]] +; SHADERTEST-NEXT: ret void +; ; ; -; SHADERTEST-LABEL: amdgpu_ps_main: -; SHADERTEST: s_getpc_b64 s[6:7] -; SHADERTEST-NEXT: s_mov_b32 s6, s0 -; SHADERTEST-NEXT: s_mov_b32 s32, 0 -; SHADERTEST-NEXT: s_load_dwordx2 s[6:7], s[6:7], 0x0 -; SHADERTEST-NEXT: s_waitcnt lgkmcnt(0) -; SHADERTEST-NEXT: s_and_b32 s7, s7, 0xffff -; SHADERTEST-NEXT: s_add_u32 s6, s6, s4 -; SHADERTEST-NEXT: s_addc_u32 s7, s7, 0 -; SHADERTEST-NEXT: s_setreg_b32 hwreg(HW_REG_FLAT_SCR_LO), s6 -; SHADERTEST-NEXT: s_setreg_b32 hwreg(HW_REG_FLAT_SCR_HI), s7 -; SHADERTEST-NEXT: s_wqm_b64 exec, exec -; SHADERTEST-NEXT: s_getpc_b64 s[16:17] -; SHADERTEST-NEXT: s_mov_b32 s0, s1 -; SHADERTEST-NEXT: s_mov_b32 m0, s3 -; SHADERTEST-NEXT: s_mov_b32 s1, s17 -; SHADERTEST-NEXT: v_interp_p1_f32_e32 v2, v0, attr0.x -; SHADERTEST-NEXT: v_interp_p1_f32_e32 v0, v0, attr0.y -; SHADERTEST-NEXT: s_clause 0x1 -; SHADERTEST-NEXT: s_load_dwordx8 s[4:11], s[0:1], 0x0 -; SHADERTEST-NEXT: s_load_dwordx4 s[12:15], s[0:1], 0x0 -; SHADERTEST-NEXT: s_mov_b32 s3, s17 -; SHADERTEST-NEXT: v_interp_p2_f32_e32 v2, v1, attr0.x -; SHADERTEST-NEXT: v_interp_p2_f32_e32 v0, v1, attr0.y -; SHADERTEST-NEXT: v_cvt_i32_f32_e32 v1, v2 -; SHADERTEST-NEXT: v_cvt_i32_f32_e32 v2, v0 -; SHADERTEST-NEXT: v_cvt_f32_i32_e32 v0, v1 -; SHADERTEST-NEXT: v_cvt_f32_i32_e32 v1, v2 -; SHADERTEST-NEXT: s_waitcnt lgkmcnt(0) -; SHADERTEST-NEXT: image_sample v[0:3], v[0:1], s[4:11], s[12:15] dmask:0xf dim:SQ_RSRC_IMG_2D -; SHADERTEST-NEXT: s_mov_b32 s4, 0 -; SHADERTEST-NEXT: s_swappc_b64 s[30:31], s[2:3] +; SHADERTEST-LABEL: @lgc.shader.FS.main( +; SHADERTEST-NEXT: .entry: +; SHADERTEST-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.s.getpc() +; SHADERTEST-NEXT: [[TMP1:%.*]] = bitcast i64 [[TMP0]] to <2 x i32> +; SHADERTEST-NEXT: [[TMP2:%.*]] = call i64 @llvm.amdgcn.s.getpc() +; SHADERTEST-NEXT: [[TMP3:%.*]] = bitcast i64 [[TMP2]] to <2 x i32> +; SHADERTEST-NEXT: [[INTERPPERSPCENTER:%.*]] = call <2 x float> @lgc.input.import.builtin.InterpPerspCenter.v2f32.i32(i32 268435457) #[[ATTR5:[0-9]+]] +; SHADERTEST-NEXT: [[TMP4:%.*]] = call <2 x float> (...) @lgc.input.import.interpolated__v2f32(i1 false, i32 0, i32 0, i32 0, i32 poison, i32 0, <2 x float> [[INTERPPERSPCENTER]]) +; SHADERTEST-NEXT: [[TMP5:%.*]] = call i32 @lgc.load.user.data__i32(i32 44) +; SHADERTEST-NEXT: [[TMP6:%.*]] = insertelement <2 x i32> [[TMP3]], i32 [[TMP5]], i64 0 +; SHADERTEST-NEXT: [[TMP7:%.*]] = bitcast <2 x i32> [[TMP6]] to i64 +; SHADERTEST-NEXT: [[TMP8:%.*]] = inttoptr i64 [[TMP7]] to ptr addrspace(4) +; SHADERTEST-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP8]], i32 0 +; SHADERTEST-NEXT: [[TMP10:%.*]] = call i32 @lgc.load.user.data__i32(i32 44) +; SHADERTEST-NEXT: [[TMP11:%.*]] = insertelement <2 x i32> [[TMP1]], i32 [[TMP10]], i64 0 +; SHADERTEST-NEXT: [[TMP12:%.*]] = bitcast <2 x i32> [[TMP11]] to i64 +; SHADERTEST-NEXT: [[TMP13:%.*]] = inttoptr i64 [[TMP12]] to ptr addrspace(4) +; SHADERTEST-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(4) [[TMP13]], i32 0 +; SHADERTEST-NEXT: [[TMP15:%.*]] = fptosi <2 x float> [[TMP4]] to <2 x i32> +; SHADERTEST-NEXT: [[TMP16:%.*]] = sitofp <2 x i32> [[TMP15]] to <2 x float> +; SHADERTEST-NEXT: [[TMP17:%.*]] = load <8 x i32>, ptr addrspace(4) [[TMP14]], align 32, !invariant.load !11 +; SHADERTEST-NEXT: [[TMP18:%.*]] = load <4 x i32>, ptr addrspace(4) [[TMP9]], align 16, !invariant.load !11 +; SHADERTEST-NEXT: [[TMP19:%.*]] = extractelement <2 x float> [[TMP16]], i64 0 +; SHADERTEST-NEXT: [[TMP20:%.*]] = extractelement <2 x float> [[TMP16]], i64 1 +; SHADERTEST-NEXT: [[TMP21:%.*]] = extractelement <4 x i32> [[TMP18]], i64 0 +; SHADERTEST-NEXT: [[TMP22:%.*]] = call i32 @llvm.amdgcn.readfirstlane(i32 [[TMP21]]) +; SHADERTEST-NEXT: [[TMP23:%.*]] = insertelement <4 x i32> poison, i32 [[TMP22]], i64 0 +; SHADERTEST-NEXT: [[TMP24:%.*]] = extractelement <4 x i32> [[TMP18]], i64 1 +; SHADERTEST-NEXT: [[TMP25:%.*]] = call i32 @llvm.amdgcn.readfirstlane(i32 [[TMP24]]) +; SHADERTEST-NEXT: [[TMP26:%.*]] = insertelement <4 x i32> [[TMP23]], i32 [[TMP25]], i64 1 +; SHADERTEST-NEXT: [[TMP27:%.*]] = extractelement <4 x i32> [[TMP18]], i64 2 +; SHADERTEST-NEXT: [[TMP28:%.*]] = call i32 @llvm.amdgcn.readfirstlane(i32 [[TMP27]]) +; SHADERTEST-NEXT: [[TMP29:%.*]] = insertelement <4 x i32> [[TMP26]], i32 [[TMP28]], i64 2 +; SHADERTEST-NEXT: [[TMP30:%.*]] = extractelement <4 x i32> [[TMP18]], i64 3 +; SHADERTEST-NEXT: [[TMP31:%.*]] = call i32 @llvm.amdgcn.readfirstlane(i32 [[TMP30]]) +; SHADERTEST-NEXT: [[TMP32:%.*]] = insertelement <4 x i32> [[TMP29]], i32 [[TMP31]], i64 3 +; SHADERTEST-NEXT: [[TMP33:%.*]] = call reassoc nnan nsz arcp contract afn <4 x float> @llvm.amdgcn.image.sample.2d.v4f32.f32(i32 15, float [[TMP19]], float [[TMP20]], <8 x i32> [[TMP17]], <4 x i32> [[TMP32]], i1 false, i32 0, i32 0) +; SHADERTEST-NEXT: call void @lgc.output.export.generic.i32.i32.v4f32(i32 0, i32 0, <4 x float> [[TMP33]]) #[[ATTR6:[0-9]+]] +; SHADERTEST-NEXT: ret void +; ; ; ; SHADERTEST-LABEL: @color_export_shader( -; SHADERTEST-NEXT: [[TMP2:%.*]] = extractelement <4 x float> [[TMP0:%.*]], i64 0 -; SHADERTEST-NEXT: [[TMP3:%.*]] = extractelement <4 x float> [[TMP0]], i64 1 -; SHADERTEST-NEXT: [[TMP4:%.*]] = extractelement <4 x float> [[TMP0]], i64 2 -; SHADERTEST-NEXT: [[TMP5:%.*]] = extractelement <4 x float> [[TMP0]], i64 3 -; SHADERTEST-NEXT: call void @llvm.amdgcn.exp.f32(i32 immarg 0, i32 immarg 15, float [[TMP2]], float [[TMP3]], float [[TMP4]], float [[TMP5]], i1 immarg true, i1 immarg true) +; SHADERTEST-NEXT: [[TMP3:%.*]] = extractelement <4 x float> [[TMP0:%.*]], i64 0 +; SHADERTEST-NEXT: [[TMP4:%.*]] = extractelement <4 x float> [[TMP0]], i64 1 +; SHADERTEST-NEXT: [[TMP5:%.*]] = extractelement <4 x float> [[TMP0]], i64 2 +; SHADERTEST-NEXT: [[TMP6:%.*]] = extractelement <4 x float> [[TMP0]], i64 3 +; SHADERTEST-NEXT: call void @llvm.amdgcn.exp.f32(i32 immarg 0, i32 immarg 15, float [[TMP3]], float [[TMP4]], float [[TMP5]], float [[TMP6]], i1 immarg true, i1 immarg true) #[[ATTR1]] ; SHADERTEST-NEXT: call void @llvm.amdgcn.endpgm() ; SHADERTEST-NEXT: unreachable ; -; SHADERTEST-LABEL: color_export_shader: -; SHADERTEST: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SHADERTEST-NEXT: exp mrt0 v0, v1, v2, v3 done vm -; SHADERTEST-NEXT: s_endpgm -; diff --git a/llpc/tool/amdllpc.cpp b/llpc/tool/amdllpc.cpp index 61211f861b..9515f034b0 100644 --- a/llpc/tool/amdllpc.cpp +++ b/llpc/tool/amdllpc.cpp @@ -680,8 +680,15 @@ static Error processInputs(ICompiler *compiler, InputSpecGroup &inputSpecs, bool const InputSpec &firstInput = inputSpecs.front(); if (isPipelineInfoFile(firstInput.filename)) { + bool unlinked = Unlinked; + + if (firstInput.filename.starts_with("PipelineLib") && !unlinked && !Unlinked.getNumOccurrences()) { + LLPC_WARN("Input filename starts with \"PipelineLib\". Assuming you meant -unlinked.\n"); + unlinked = true; + } + compileInfo.autoLayoutDesc = false; - if (Error err = processInputPipeline(compiler, compileInfo, firstInput, Unlinked, IgnoreColorAttachmentFormats)) + if (Error err = processInputPipeline(compiler, compileInfo, firstInput, unlinked, IgnoreColorAttachmentFormats)) return err; if (compileInfo.pipelineType == VfxPipelineTypeGraphicsLibrary) { @@ -792,6 +799,9 @@ static Error processInputs(ICompiler *compiler, InputSpecGroup &inputSpecs, bool dumpOptions->filterPipelineDumpByType = FilterPipelineDumpByType; dumpOptions->filterPipelineDumpByHash = FilterPipelineDumpByHash; dumpOptions->dumpDuplicatePipelines = DumpDuplicatePipelines; + + if (codegen::getFileType() != CodeGenFileType::ObjectFile) + return createResultError(Result::ErrorInvalidValue, "Pipeline dumps require the default (ELF) -filetype"); } std::unique_ptr builder = diff --git a/llpc/translator/lib/SPIRV/SPIRVReader.cpp b/llpc/translator/lib/SPIRV/SPIRVReader.cpp index 9d55f8e7c5..1aeb804992 100644 --- a/llpc/translator/lib/SPIRV/SPIRVReader.cpp +++ b/llpc/translator/lib/SPIRV/SPIRVReader.cpp @@ -1,4 +1,4 @@ -//===- SPIRVReader.cpp - Converts SPIR-V to LLVM ----------------*- C++ -*-===// +//===- SPIRVReader.cpp - Converts SPIR-V to LLVM ----------------*- C++ -*-===// // // The LLVM/SPIR-V Translator // @@ -277,7 +277,7 @@ SPIRVToLLVM::SPIRVToLLVM(Module *llvmModule, SPIRVModule *theSpirvModule, const const Vkgc::ShaderModuleUsage *moduleUsage, const Vkgc::PipelineShaderOptions *shaderOptions) : m_m(llvmModule), m_builder(builder), m_bm(theSpirvModule), m_entryTarget(nullptr), m_specConstMap(theSpecConstMap), m_convertingSamplers(convertingSamplers), m_dbgTran(m_bm, m_m, this), - m_moduleUsage(reinterpret_cast(moduleUsage)), m_debugOutputBuffer(nullptr), + m_moduleUsage(reinterpret_cast(moduleUsage)), m_shaderOptions(reinterpret_cast(shaderOptions)) { assert(m_m); m_context = &m_m->getContext(); @@ -1085,9 +1085,9 @@ Type *SPIRVToLLVM::transTypeImpl(SPIRVType *t, unsigned matrixStride, bool colum // image is not an array of three.) Type *imageTy = nullptr; if (st->getDescriptor().Dim == DimBuffer) { - imageTy = getBuilder()->getDescTy(ResourceNodeType::DescriptorTexelBuffer); + imageTy = PointerType::get(*m_context, SPIRAS_Constant); } else { - Type *singleImageTy = getBuilder()->getDescTy(ResourceNodeType::DescriptorResource); + Type *singleImageTy = PointerType::get(*m_context, SPIRAS_Constant); imageTy = ArrayType::get(singleImageTy, 3); if (st->getDescriptor().MS) { // A multisampled image is represented by a struct containing both the @@ -1105,7 +1105,7 @@ Type *SPIRVToLLVM::transTypeImpl(SPIRVType *t, unsigned matrixStride, bool colum // Get sampler type. // A sampler is represented by a struct containing the sampler itself, and the convertingSamplerIdx, an i32 // that is either 0 or the 1-based index into the converting samplers. - Type *ty = getBuilder()->getDescTy(ResourceNodeType::DescriptorSampler); + Type *ty = PointerType::get(*m_context, SPIRAS_Constant); ty = StructType::get(*m_context, {ty, getBuilder()->getInt32Ty()}); if (t->getOpCode() == OpTypeSampledImage) { // A sampledimage is represented by a struct containing the image descriptor @@ -1295,26 +1295,39 @@ Value *SPIRVToLLVM::transValue(SPIRVValue *bv, Function *f, BasicBlock *bb, bool Value *SPIRVToLLVM::transConvertInst(SPIRVValue *bv, Function *f, BasicBlock *bb) { SPIRVUnary *bc = static_cast(bv); + auto srcSpvType = bc->getOperand(0)->getType(); + auto dstSpvType = bc->getType(); auto src = transValue(bc->getOperand(0), f, bb, bb != nullptr); auto srcType = src->getType(); - auto dstType = transType(bc->getType()); + auto dstType = transType(dstSpvType); CastInst::CastOps co = Instruction::BitCast; + // Extension for OGLP: Only valid for bindless texture/image to convert uvec2 to gsampler/gimage + // uniform uvec2 textureHandle; + // vec4 result = texture(sampler2D(textureHandle), texCoord); + bool srcTypeUvec2 = srcSpvType->isTypeVectorInt(32) && (srcSpvType->getVectorComponentCount() == 2); + bool bindlessTexture = dstSpvType->isTypeSampledImage() && srcTypeUvec2; + bool bindlessImage = dstSpvType->isTypeImage() && srcTypeUvec2; + + if (bindlessTexture || bindlessImage) { + // 64 bit handle is stored in uvec2, we need to convert texHandle to uint64 at first + Value *imgDescGpuAddress = getBuilder()->CreateBitCast(src, getBuilder()->getInt64Ty()); + return transLoadBindlessImage(dstSpvType, imgDescGpuAddress, bindlessTexture); + } + lgc::CooperativeMatrixElementType srcElemTy = lgc::CooperativeMatrixElementType::Unknown; lgc::CooperativeMatrixElementType dstElemTy = lgc::CooperativeMatrixElementType::Unknown; lgc::CooperativeMatrixLayout srcLayout = lgc::CooperativeMatrixLayout::InvalidLayout; lgc::CooperativeMatrixLayout dstLayout = lgc::CooperativeMatrixLayout::InvalidLayout; if (bv->getType()->isTypeCooperativeMatrixKHR()) { - auto srcCompType = static_cast(bc->getOperand(0)->getType()) - ->getCooperativeMatrixKHRComponentType(); + auto srcCompType = static_cast(srcSpvType)->getCooperativeMatrixKHRComponentType(); srcElemTy = mapToBasicType(srcCompType); - auto dstCompType = - static_cast(bc->getType())->getCooperativeMatrixKHRComponentType(); + auto dstCompType = static_cast(dstSpvType)->getCooperativeMatrixKHRComponentType(); dstElemTy = mapToBasicType(dstCompType); - auto dstUse = static_cast(bc->getType())->getCooperativeMatrixKHRUse(); - unsigned rows = static_cast(bc->getType())->getCooperativeMatrixKHRRows(); - unsigned columns = static_cast(bc->getType())->getCooperativeMatrixKHRColumns(); + auto dstUse = static_cast(dstSpvType)->getCooperativeMatrixKHRUse(); + unsigned rows = static_cast(dstSpvType)->getCooperativeMatrixKHRRows(); + unsigned columns = static_cast(dstSpvType)->getCooperativeMatrixKHRColumns(); dstLayout = getCooperativeMatrixKHRLayout(static_cast(dstUse), dstElemTy, rows, columns); srcLayout = getCooperativeMatrixKHRLayout(static_cast(dstUse), srcElemTy, rows, columns); } @@ -2373,12 +2386,16 @@ static SyncScope::ID transScope(LLVMContext &context, const SPIRVConstant *const // Translate memory semantics from SPIR-V to LLVM. // // @param spvMemorySemantics : The semantics to translate. -// @param isAtomicRMW : Is the memory semantic from an atomic rmw operation. -static AtomicOrdering transMemorySemantics(const SPIRVConstant *const spvMemorySemantics, const bool isAtomicRMW) { +// @param readOnly : If the corresponding memory access only read. +// @param writeNone : If the corresponding memory access only write. +static AtomicOrdering transMemorySemantics(const SPIRVConstant *const spvMemorySemantics, const bool readOnly = false, + const bool writeOnly = false) { const unsigned semantics = static_cast(spvMemorySemantics->getZExtIntValue()); + // We are safe to downgrade the SequentiallyConsistent to Acquire/Release/AcquireRelease based on Vulkan validation + // rules within a module. if (semantics & MemorySemanticsSequentiallyConsistentMask) - return AtomicOrdering::SequentiallyConsistent; + return readOnly ? AtomicOrdering::Acquire : writeOnly ? AtomicOrdering::Release : AtomicOrdering::AcquireRelease; if (semantics & MemorySemanticsAcquireReleaseMask) return AtomicOrdering::AcquireRelease; if (semantics & MemorySemanticsAcquireMask) @@ -2400,8 +2417,7 @@ Value *SPIRVToLLVM::transAtomicRMW(SPIRVValue *const spvValue, const AtomicRMWIn SPIRVAtomicInstBase *const spvAtomicInst = static_cast(spvValue); const SyncScope::ID scope = transScope(*m_context, static_cast(spvAtomicInst->getOpValue(1))); - const AtomicOrdering ordering = - transMemorySemantics(static_cast(spvAtomicInst->getOpValue(2)), true); + const AtomicOrdering ordering = transMemorySemantics(static_cast(spvAtomicInst->getOpValue(2))); Value *const atomicPointer = transValue(spvAtomicInst->getOpValue(0), getBuilder()->GetInsertBlock()->getParent(), getBuilder()->GetInsertBlock()); @@ -2439,8 +2455,8 @@ template <> Value *SPIRVToLLVM::transValueWithOpcode(SPIRVValue *c SPIRVAtomicLoad *const spvAtomicLoad = static_cast(spvValue); const SyncScope::ID scope = transScope(*m_context, static_cast(spvAtomicLoad->getOpValue(1))); - const AtomicOrdering ordering = - transMemorySemantics(static_cast(spvAtomicLoad->getOpValue(2)), false); + const AtomicOrdering ordering = transMemorySemantics(static_cast(spvAtomicLoad->getOpValue(2)), + /*readOnly=*/true, /*writeOnly=*/false); Value *const loadPointer = transValue(spvAtomicLoad->getOpValue(0), getBuilder()->GetInsertBlock()->getParent(), getBuilder()->GetInsertBlock()); @@ -2467,8 +2483,8 @@ template <> Value *SPIRVToLLVM::transValueWithOpcode(SPIRVValue * SPIRVAtomicStore *const spvAtomicStore = static_cast(spvValue); const SyncScope::ID scope = transScope(*m_context, static_cast(spvAtomicStore->getOpValue(1))); - const AtomicOrdering ordering = - transMemorySemantics(static_cast(spvAtomicStore->getOpValue(2)), false); + const AtomicOrdering ordering = transMemorySemantics(static_cast(spvAtomicStore->getOpValue(2)), + /*readOnly=*/false, /*writeOnly=*/true); Value *const storePointer = transValue(spvAtomicStore->getOpValue(0), getBuilder()->GetInsertBlock()->getParent(), getBuilder()->GetInsertBlock()); @@ -2666,8 +2682,7 @@ template <> Value *SPIRVToLLVM::transValueWithOpcode(SPIRVVa SPIRVAtomicInstBase *const spvAtomicInst = static_cast(spvValue); const SyncScope::ID scope = transScope(*m_context, static_cast(spvAtomicInst->getOpValue(1))); - const AtomicOrdering ordering = - transMemorySemantics(static_cast(spvAtomicInst->getOpValue(2)), true); + const AtomicOrdering ordering = transMemorySemantics(static_cast(spvAtomicInst->getOpValue(2))); Value *const atomicPointer = transValue(spvAtomicInst->getOpValue(0), getBuilder()->GetInsertBlock()->getParent(), getBuilder()->GetInsertBlock()); @@ -2694,8 +2709,7 @@ template <> Value *SPIRVToLLVM::transValueWithOpcode(SPIRVVa SPIRVAtomicInstBase *const spvAtomicInst = static_cast(spvValue); const SyncScope::ID scope = transScope(*m_context, static_cast(spvAtomicInst->getOpValue(1))); - const AtomicOrdering ordering = - transMemorySemantics(static_cast(spvAtomicInst->getOpValue(2)), true); + const AtomicOrdering ordering = transMemorySemantics(static_cast(spvAtomicInst->getOpValue(2))); Value *const atomicPointer = transValue(spvAtomicInst->getOpValue(0), getBuilder()->GetInsertBlock()->getParent(), getBuilder()->GetInsertBlock()); @@ -2724,9 +2738,9 @@ template <> Value *SPIRVToLLVM::transValueWithOpcode(SP const SyncScope::ID scope = transScope(*m_context, static_cast(spvAtomicInst->getOpValue(1))); const AtomicOrdering successOrdering = - transMemorySemantics(static_cast(spvAtomicInst->getOpValue(2)), true); - const AtomicOrdering failureOrdering = - transMemorySemantics(static_cast(spvAtomicInst->getOpValue(3)), true); + transMemorySemantics(static_cast(spvAtomicInst->getOpValue(2))); + AtomicOrdering failureOrdering = transMemorySemantics(static_cast(spvAtomicInst->getOpValue(3)), + /*readOnly=*/true, /*writeOnly=*/false); Value *const atomicPointer = transValue(spvAtomicInst->getOpValue(0), getBuilder()->GetInsertBlock()->getParent(), getBuilder()->GetInsertBlock()); @@ -2977,6 +2991,94 @@ Value *SPIRVToLLVM::transLoadImage(SPIRVValue *spvImageLoadPtr) { return loadImageSampler(elementTy, base); } +// ===================================================================================================================== +// Translate a load for UniformConstant that is image/sampledimage +// +// @param spvElementTy : The image/sampledimage pointer +// @param imgDescGpuAddress : image descriptor's gpu memory address +// @param bindlessTexture : true is bindless texture, false is bindless image +Value *SPIRVToLLVM::transLoadBindlessImage(SPIRVType *spvElementTy, Value *imgDescGpuAddress, bool bindlessTexture) { + + Type *elementTy = transType(spvElementTy, 0, false, false, LayoutMode::Native); + Type *gpuAddrAsPtrTy = getBuilder()->getPtrTy(SPIRAS_Constant); + auto imageDescAddr = getBuilder()->CreateIntToPtr(imgDescGpuAddress, gpuAddrAsPtrTy); + + SPIRVTypeImage *spvImageTy = nullptr; + if (spvElementTy->getOpCode() == OpTypeSampledImage) { + spvImageTy = static_cast(spvElementTy)->getImageType(); + } else { + spvImageTy = static_cast(spvElementTy); + } + + auto desc = spvImageTy->getDescriptor(); + Value *imageDescPtr = nullptr; + + // Handle samplerBuffer or imageBuffer + if (desc.Dim == DimBuffer) { + auto bufferDescStride = getBuilder()->getInt32(DescriptorSizeBuffer); + imageDescPtr = getBuilder()->CreateInsertValue( + PoisonValue::get(StructType::get(*m_context, {imageDescAddr->getType(), bufferDescStride->getType(), + bufferDescStride->getType(), getBuilder()->getInt32Ty()})), + imageDescAddr, 0); + imageDescPtr = getBuilder()->CreateInsertValue(imageDescPtr, bufferDescStride, 1); + } else { + // The descriptor stride is unimportant for bindless texture/image, just use it as a placeholder + auto imageDescStride = getBuilder()->getInt32(DescriptorSizeResource); + imageDescPtr = getBuilder()->CreateInsertValue( + PoisonValue::get(StructType::get(*m_context, {imageDescAddr->getType(), imageDescStride->getType(), + imageDescStride->getType(), getBuilder()->getInt32Ty()})), + imageDescAddr, 0); + + imageDescPtr = getBuilder()->CreateInsertValue(imageDescPtr, imageDescStride, 1); + imageDescPtr = getBuilder()->CreateInsertValue(imageDescPtr, getBuilder()->getInt32(DescriptorSizeResource), 2); + imageDescPtr = getBuilder()->CreateInsertValue(imageDescPtr, getBuilder()->getInt32(1), 3); + } + + // Insert fmask descriptor address into structure + if (desc.MS) { + auto fMaskOffset = getBuilder()->getInt64(DescriptorSizeResource + DescriptorSizeSampler); + constexpr unsigned descriptorSizeFmask = 8 * sizeof(uint32_t); + auto fmaskDescStride = getBuilder()->getInt32(descriptorSizeFmask); + Value *fMaskDescAddr = + getBuilder()->CreateIntToPtr(getBuilder()->CreateAdd(imgDescGpuAddress, fMaskOffset), gpuAddrAsPtrTy); + + auto fmaskDescPtr = getBuilder()->CreateInsertValue( + PoisonValue::get(StructType::get(*m_context, {fMaskDescAddr->getType(), fmaskDescStride->getType(), + fmaskDescStride->getType(), getBuilder()->getInt32Ty()})), + fMaskDescAddr, 0); + fmaskDescPtr = getBuilder()->CreateInsertValue(fmaskDescPtr, fmaskDescStride, 1); + imageDescPtr = getBuilder()->CreateInsertValue( + PoisonValue::get(StructType::get(*m_context, {imageDescPtr->getType(), fmaskDescPtr->getType()})), imageDescPtr, + 0); + imageDescPtr = getBuilder()->CreateInsertValue(imageDescPtr, fmaskDescPtr, 1); + } + + // True for bindless texture, otherwise is bindless image + if (bindlessTexture) { + auto samplerOffset = getBuilder()->getInt64(DescriptorSizeResource); + auto samplerDescStride = getBuilder()->getInt32(DescriptorSizeSampler); + + Value *samplerDescAddr = + getBuilder()->CreateIntToPtr(getBuilder()->CreateAdd(imgDescGpuAddress, samplerOffset), gpuAddrAsPtrTy); + + Type *samplerPtrTy = StructType::get( + *m_context, {samplerDescAddr->getType(), getBuilder()->getInt32Ty(), getBuilder()->getInt32Ty()}); + Value *samplerDescPtr = Constant::getNullValue(samplerPtrTy); + + samplerDescPtr = getBuilder()->CreateInsertValue(samplerDescPtr, samplerDescAddr, 0); + samplerDescPtr = getBuilder()->CreateInsertValue(samplerDescPtr, samplerDescStride, 1); + + Value *descPtr = + PoisonValue::get(StructType::get(*m_context, {imageDescPtr->getType(), samplerDescPtr->getType()})); + descPtr = getBuilder()->CreateInsertValue(descPtr, imageDescPtr, 0); + descPtr = getBuilder()->CreateInsertValue(descPtr, samplerDescPtr, 1); + + return loadImageSampler(elementTy, descPtr); + } + + return loadImageSampler(elementTy, imageDescPtr); +} + // ===================================================================================================================== // Generate a load of an image, sampler or sampledimage // @@ -3017,33 +3119,21 @@ Value *SPIRVToLLVM::loadImageSampler(Type *elementTy, Value *base) { // an array of three image descriptors, to allow for multiple planes in YCbCr conversion. Normally we only // load one descriptor; if there are any converting samplers, we load all three, and rely on later optimizations // to remove the unused ones (and thus stop us reading off the end of the descriptor table). - elementTy = arrayTy->getElementType(); - auto *oneVal = getBuilder()->CreateLoad(elementTy, ptr); - oneVal->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(*m_context, {})); - - Value *result = getBuilder()->CreateInsertValue(PoisonValue::get(arrayTy), oneVal, 0); + Value *result = getBuilder()->CreateInsertValue(PoisonValue::get(arrayTy), ptr, 0); // Pointer to image is represented as a struct containing {pointer, stride, planeStride, isResource}. if (!m_convertingSamplers.empty() && base->getType()->getStructNumElements() >= 4) { Value *planeStride = getBuilder()->CreateExtractValue(base, 2); Type *ptrTy = ptr->getType(); for (unsigned planeIdx = 1; planeIdx != arrayTy->getNumElements(); ++planeIdx) { - ptr = getBuilder()->CreateBitCast( - ptr, getBuilder()->getInt8Ty()->getPointerTo(ptr->getType()->getPointerAddressSpace())); ptr = getBuilder()->CreateGEP(getBuilder()->getInt8Ty(), ptr, planeStride); ptr = getBuilder()->CreateBitCast(ptr, ptrTy); - oneVal = getBuilder()->CreateLoad(elementTy, ptr); - oneVal->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(*m_context, {})); - result = getBuilder()->CreateInsertValue(result, oneVal, planeIdx); + result = getBuilder()->CreateInsertValue(result, ptr, planeIdx); } } return result; } - - // Other cases: Just load the element from the pointer. - auto load = getBuilder()->CreateLoad(elementTy, ptr); - load->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(*m_context, {})); - return load; + return ptr; } // ===================================================================================================================== @@ -3070,7 +3160,8 @@ Value *SPIRVToLLVM::transImagePointer(SPIRVValue *spvImagePtr, SPIRVType *baseTy spvImagePtr->hasDecorate(DecorationBinding, 0, &binding); bool hasDescriptorSet = spvImagePtr->hasDecorate(DecorationDescriptorSet, 0, &descriptorSet); - assert(!getPipelineOptions()->replaceSetWithResourceType || !hasDescriptorSet || + + assert(!getPipelineOptions()->getGlState().replaceSetWithResourceType || !hasDescriptorSet || static_cast(spvImagePtr->getType())->getStorageClass() == StorageClassUniformConstant); (void)hasDescriptorSet; @@ -3092,7 +3183,7 @@ Value *SPIRVToLLVM::transImagePointer(SPIRVValue *spvImagePtr, SPIRVType *baseTy Value *imageDescPtr = nullptr; Value *samplerDescPtr = nullptr; - if (getPipelineOptions()->replaceSetWithResourceType) + if (getPipelineOptions()->getGlState().replaceSetWithResourceType) assert(spvTy->getOpCode() != OpTypeSampler); if (spvTy->getOpCode() != OpTypeSampler) { @@ -3106,11 +3197,11 @@ Value *SPIRVToLLVM::transImagePointer(SPIRVValue *spvImagePtr, SPIRVType *baseTy auto resType = desc->Dim == DimBuffer ? ResourceNodeType::DescriptorTexelBuffer : ResourceNodeType::DescriptorResource; - if (getPipelineOptions()->replaceSetWithResourceType) { + if (getPipelineOptions()->getGlState().replaceSetWithResourceType) { if (spvTy->getOpCode() == OpTypeImage) { descriptorSet = PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorImage); } else if (spvTy->getOpCode() == OpTypeSampledImage) { - if (getPipelineOptions()->enableCombinedTexture) { + if (getPipelineOptions()->getGlState().enableCombinedTexture) { descriptorSet = PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorCombinedTexture); } else { @@ -3123,7 +3214,7 @@ Value *SPIRVToLLVM::transImagePointer(SPIRVValue *spvImagePtr, SPIRVType *baseTy imageDescPtr = getDescPointerAndStride(resType, descriptorSet, binding, resType); if (desc->MS) { - if (getPipelineOptions()->replaceSetWithResourceType && spvTy->getOpCode() != OpTypeImage) + if (getPipelineOptions()->getGlState().replaceSetWithResourceType && spvTy->getOpCode() != OpTypeImage) descriptorSet = PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorFmask); // A multisampled image pointer is a struct containing an image desc pointer and an fmask desc pointer. Value *fmaskDescPtr = getDescPointerAndStride(ResourceNodeType::DescriptorFmask, descriptorSet, binding, @@ -3136,7 +3227,8 @@ Value *SPIRVToLLVM::transImagePointer(SPIRVValue *spvImagePtr, SPIRVType *baseTy } if (spvTy->getOpCode() != OpTypeImage) { - if (getPipelineOptions()->replaceSetWithResourceType && !getPipelineOptions()->enableCombinedTexture) + if (getPipelineOptions()->getGlState().replaceSetWithResourceType && + !getPipelineOptions()->getGlState().enableCombinedTexture) descriptorSet = PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorSampler); // Sampler or sampledimage -- need to get the sampler {pointer,stride,convertingSamplerIdx} samplerDescPtr = getDescPointerAndStride(ResourceNodeType::DescriptorSampler, descriptorSet, binding, @@ -3211,7 +3303,7 @@ Value *SPIRVToLLVM::getDescPointerAndStride(ResourceNodeType resType, unsigned d unsigned convertingSamplerIdx = 0; unsigned nextIdx = 1; unsigned convertingSamplerDescriptorSet = descriptorSet; - if (getPipelineOptions()->replaceSetWithResourceType && + if (getPipelineOptions()->getGlState().replaceSetWithResourceType && descriptorSet == PipelineContext::getGlResourceNodeSetFromType(Vkgc::ResourceMappingNodeType::DescriptorSampler)) { // When using 'replaceSetWithResourceType' option (OGL default) it's not possible to match converting samplers @@ -3743,8 +3835,6 @@ Value *SPIRVToLLVM::indexDescPtr(Type *elementTy, Value *base, Value *index) { // Do the indexing operation by GEPping as a byte pointer. Type *ptrTy = ptr->getType(); - ptr = getBuilder()->CreateBitCast(ptr, - getBuilder()->getInt8Ty()->getPointerTo(ptr->getType()->getPointerAddressSpace())); ptr = getBuilder()->CreateGEP(getBuilder()->getInt8Ty(), ptr, index); ptr = getBuilder()->CreateBitCast(ptr, ptrTy); base = getBuilder()->CreateInsertValue(base, ptr, 0); @@ -4859,39 +4949,14 @@ template <> Value *SPIRVToLLVM::transValueWithOpcode(SPIRVValue *cons // @param bb : Which basicblock to generate code Value *SPIRVToLLVM::transDebugPrintf(SPIRVInstruction *bi, const ArrayRef spvValues, Function *func, BasicBlock *bb) { - auto resMapping = getPipelineContext()->getResourceMapping(); - unsigned nodeIndex = 0; - if (findResourceNode(resMapping->pUserDataNodes, resMapping->userDataNodeCount, Vkgc::InternalDescriptorSetId, - Vkgc::PrintfBufferBindingId, &nodeIndex) == nullptr) - return getBuilder()->getInt64(0); - - if (!m_debugOutputBuffer) { - auto spvArrType = m_bm->addRuntimeArray(m_bm->addIntegerType(32)); - auto spvStructType = m_bm->addStructType({spvArrType}); - Type *bufType = transType(spvStructType); - - m_debugOutputBuffer = - new GlobalVariable(*m_m, bufType, false, GlobalValue::ExternalLinkage, nullptr, "debugOutputBuffer", nullptr, - GlobalVariable::NotThreadLocal, SPIRAS_Uniform); - - // Setup (desc,binding) resource metadata - auto intType = getBuilder()->getInt32Ty(); - SmallVector resourceMetas = { - ConstantAsMetadata::get(ConstantInt::get(intType, Vkgc::InternalDescriptorSetId)), - ConstantAsMetadata::get(ConstantInt::get(intType, Vkgc::PrintfBufferBindingId)), - ConstantAsMetadata::get(ConstantInt::get(intType, 0))}; - - auto resMdNode = MDNode::get(*m_context, resourceMetas); - m_debugOutputBuffer->addMetadata(gSPIRVMD::Resource, *resMdNode); - } - auto spvValueItr = spvValues.begin(); - Value *formatStr = mapEntry(*spvValueItr++, nullptr); + const SPIRVEntry *spvStrEntry = *spvValueItr++; + auto spvStr = static_cast(spvStrEntry); SmallVector args; for (; spvValueItr != spvValues.end(); ++spvValueItr) { args.push_back(transValue(*spvValueItr, func, bb)); } - return getBuilder()->create(m_debugOutputBuffer, formatStr, args); + return getBuilder()->create(spvStr->getStr(), args); } // Translate an initializer. This has special handling for the case where the type to initialize to does not match the @@ -7153,7 +7218,7 @@ static unsigned convertDimension(const SPIRVTypeImageDescriptor *desc) { case Dim1D: return lgc::Builder::Dim1D; case DimBuffer: - return lgc::Builder::Dim1D; + return lgc::Builder::Dim1DBuffer; case Dim2D: return lgc::Builder::Dim2D; case DimRect: @@ -7172,7 +7237,7 @@ static unsigned convertDimension(const SPIRVTypeImageDescriptor *desc) { case Dim1D: return lgc::Builder::Dim1DArray; case DimBuffer: - return lgc::Builder::Dim1DArray; + return lgc::Builder::Dim1DArrayBuffer; case Dim2D: return lgc::Builder::Dim2DArray; case DimCube: @@ -7720,8 +7785,11 @@ Value *SPIRVToLLVM::transSPIRVImageAtomicOpFromInst(SPIRVInstruction *bi, BasicB // Determine the atomic ordering. AtomicOrdering ordering = AtomicOrdering::NotAtomic; if (scope != ScopeInvocation) { + // We are safe to downgrade the SequentiallyConsistent to Acquire/AcquireRelease based on Vulkan validation rules + // within a module. + bool readOnly = bi->getOpCode() == OpAtomicLoad; if (semantics & MemorySemanticsSequentiallyConsistentMask) - ordering = AtomicOrdering::SequentiallyConsistent; + ordering = readOnly ? AtomicOrdering::Acquire : AtomicOrdering::AcquireRelease; else if (semantics & MemorySemanticsAcquireReleaseMask) ordering = AtomicOrdering::AcquireRelease; else if (semantics & MemorySemanticsAcquireMask) @@ -8994,7 +9062,7 @@ bool SPIRVToLLVM::transDecoration(SPIRVValue *bv, ArrayRef values) { Type *mdTy = nullptr; SPIRVType *bt = bv->getType()->getPointerElementType(); bool vs64BitsAttribInputSingleLoc = (as == SPIRAS_Input && m_execModule == ExecutionModelVertex && - getPipelineOptions()->vertex64BitsAttribSingleLoc); + getPipelineOptions()->getGlState().vertex64BitsAttribSingleLoc); auto md = buildShaderInOutMetadata(bt, inOutDec, mdTy, vs64BitsAttribInputSingleLoc); // Setup input/output metadata @@ -9036,7 +9104,7 @@ bool SPIRVToLLVM::transDecoration(SPIRVValue *bv, ArrayRef values) { assert(blockTy->isTypeStruct() || blockTy->isTypeAccelerationStructureKHR() || bv->getType()->getPointerStorageClass() == StorageClassAtomicCounter); - if (getPipelineOptions()->replaceSetWithResourceType) { + if (getPipelineOptions()->getGlState().replaceSetWithResourceType) { bool hasBlock = blockTy->hasDecorate(DecorationBlock); bool hasBufferBlock = blockTy->hasDecorate(DecorationBufferBlock); @@ -9340,6 +9408,14 @@ Constant *SPIRVToLLVM::buildShaderInOutMetadata(SPIRVType *bt, ShaderInOutDecora inOutMd.Component = inOutDec.Component; inOutMd.InterpMode = inOutDec.Interp.Mode; + auto llpcContext = static_cast(m_context); + auto info = static_cast(llpcContext->getPipelineBuildInfo()); + if ((llpcContext->getPipelineType() == PipelineType::Graphics) && info->glState.enableFlatShade && + (inOutMd.Value == Vkgc::GlCompatibilityInOutLocation::FrontColor || + inOutMd.Value == Vkgc::GlCompatibilityInOutLocation::BackColor || + inOutMd.Value == Vkgc::GlCompatibilityInOutLocation::FrontSecondaryColor || + inOutMd.Value == Vkgc::GlCompatibilityInOutLocation::BackSecondaryColor)) + inOutMd.InterpMode = InterpModeFlat; inOutMd.InterpLoc = inOutDec.Interp.Loc; inOutMd.PerPatch = inOutDec.PerPatch; inOutMd.PerPrimitive = inOutDec.PerPrimitive; @@ -10418,8 +10494,10 @@ Instruction *SPIRVToLLVM::transBarrier(BasicBlock *bb, SPIRVWord execScope, SPIR Instruction *SPIRVToLLVM::transMemFence(BasicBlock *bb, SPIRVWord memSema, SPIRVWord memScope) { AtomicOrdering ordering = AtomicOrdering::NotAtomic; + // We are safe to downgrade the SequentiallyConsistent to AcquireRelease based on Vulkan validation rules within a + // module. if (memSema & MemorySemanticsSequentiallyConsistentMask) - ordering = AtomicOrdering::SequentiallyConsistent; + ordering = AtomicOrdering::AcquireRelease; else if (memSema & MemorySemanticsAcquireReleaseMask) ordering = AtomicOrdering::AcquireRelease; else if (memSema & MemorySemanticsAcquireMask) @@ -10437,10 +10515,6 @@ Instruction *SPIRVToLLVM::transMemFence(BasicBlock *bb, SPIRVWord memSema, SPIRV if (ordering == AtomicOrdering::NotAtomic) return nullptr; - // Upgrade the ordering if we need to make it available or visible - if (memSema & (MemorySemanticsMakeAvailableKHRMask | MemorySemanticsMakeVisibleKHRMask)) - ordering = AtomicOrdering::SequentiallyConsistent; - SyncScope::ID scope = SyncScope::System; switch (memScope) { diff --git a/llpc/translator/lib/SPIRV/SPIRVReader.h b/llpc/translator/lib/SPIRV/SPIRVReader.h index 04e5929cd6..aadf063459 100644 --- a/llpc/translator/lib/SPIRV/SPIRVReader.h +++ b/llpc/translator/lib/SPIRV/SPIRVReader.h @@ -110,6 +110,7 @@ class SPIRVToLLVM { template SmallVector transValueMultiWithOpcode(SPIRVValue *); template SmallVector transValueMultiWithOpcode(SPIRVValue *, Function *f, BasicBlock *bb); Value *transLoadImage(SPIRVValue *spvImageLoadPtr); + Value *transLoadBindlessImage(SPIRVType *spvElementTy, Value *imgDescGpuAddress, bool bindlessTexture); Value *loadImageSampler(Type *elementTy, Value *base); Value *transImagePointer(SPIRVValue *spvImagePtr, SPIRVType *elementTy = nullptr); Value *getDescPointerAndStride(lgc::ResourceNodeType resType, unsigned descriptorSet, unsigned binding, @@ -287,7 +288,6 @@ class SPIRVToLLVM { DenseMap, Type *> m_overlappingStructTypeWorkaroundMap; DenseMap m_blockPredecessorToCount; const Vkgc::ShaderModuleUsage *m_moduleUsage; - GlobalVariable *m_debugOutputBuffer; const Vkgc::PipelineShaderOptions *m_shaderOptions; bool m_workaroundStorageImageFormats; diff --git a/llpc/util/llpcDebug.h b/llpc/util/llpcDebug.h index f406c1794d..804574e25a 100644 --- a/llpc/util/llpcDebug.h +++ b/llpc/util/llpcDebug.h @@ -41,6 +41,15 @@ } \ while (false) +// Output error message +#define LLPC_WARN(_msg) \ + do \ + if (Llpc::EnableErrs()) { \ + llvm::outs() << "WARNING: " << _msg; \ + llvm::outs().flush(); \ + } \ + while (false) + // Output general message #define LLPC_OUTS(_msg) \ do \ diff --git a/llpc/util/llpcShaderModuleHelper.cpp b/llpc/util/llpcShaderModuleHelper.cpp index 9f9959f940..4ac381ba2a 100644 --- a/llpc/util/llpcShaderModuleHelper.cpp +++ b/llpc/util/llpcShaderModuleHelper.cpp @@ -151,20 +151,94 @@ ShaderModuleUsage ShaderModuleHelper::getShaderModuleUsageInfo(const BinaryData break; } case BuiltInPointCoord: - case BuiltInPrimitiveId: case BuiltInLayer: case BuiltInClipDistance: case BuiltInCullDistance: { shaderModuleUsage.useGenericBuiltIn = true; break; } + case BuiltInBaryCoordKHR: + case BuiltInBaryCoordNoPerspKHR: { + shaderModuleUsage.useBarycentric = true; + break; + } + case BuiltInPrimitiveId: { + shaderModuleUsage.useGenericBuiltIn = true; + shaderModuleUsage.rtSystemValueUsage.primitive.primitiveIndex = 1; + break; + } + case BuiltInInstanceId: { + shaderModuleUsage.rtSystemValueUsage.primitive.instanceID = 1; + break; + } + case BuiltInLaunchIdKHR: { + shaderModuleUsage.rtSystemValueUsage.ray.launchId = 1; + break; + } + case BuiltInLaunchSizeKHR: { + shaderModuleUsage.rtSystemValueUsage.ray.launchSize = 1; + break; + } + case BuiltInWorldRayOriginKHR: { + shaderModuleUsage.rtSystemValueUsage.ray.worldRayOrigin = 1; + break; + } + case BuiltInWorldRayDirectionKHR: { + shaderModuleUsage.rtSystemValueUsage.ray.worldRayDirection = 1; + break; + } + case BuiltInObjectRayOriginKHR: { + shaderModuleUsage.rtSystemValueUsage.primitive.objectRayOrigin = 1; + break; + } + case BuiltInObjectRayDirectionKHR: { + shaderModuleUsage.rtSystemValueUsage.primitive.objectRayDirection = 1; + break; + } + case BuiltInRayTminKHR: { + shaderModuleUsage.rtSystemValueUsage.ray.tMin = 1; + break; + } + case BuiltInInstanceCustomIndexKHR: { + shaderModuleUsage.rtSystemValueUsage.primitive.instanceIndex = 1; + break; + } + case BuiltInObjectToWorldKHR: { + shaderModuleUsage.rtSystemValueUsage.primitive.objectToWorld = 1; + break; + } + case BuiltInWorldToObjectKHR: { + shaderModuleUsage.rtSystemValueUsage.primitive.worldToObject = 1; + break; + } + case BuiltInHitTNV: { + shaderModuleUsage.rtSystemValueUsage.ray.tCurrent = 1; + break; + } + case BuiltInHitKindKHR: { + shaderModuleUsage.rtSystemValueUsage.primitive.hitKind = 1; + break; + } + case BuiltInHitTriangleVertexPositionsKHR: { + shaderModuleUsage.rtSystemValueUsage.primitive.hitTrianglePosition = 1; + break; + } + case BuiltInIncomingRayFlagsKHR: { + shaderModuleUsage.rtSystemValueUsage.ray.flags = 1; + break; + } + case BuiltInRayGeometryIndexKHR: { + shaderModuleUsage.rtSystemValueUsage.primitive.geometryIndex = 1; + break; + } default: { break; } } } else if (decoration == DecorationIndex) { hasIndexDecoration = true; - } + } else if (decoration == DecorationPerVertexKHR) + shaderModuleUsage.useBarycentric = true; break; } case OpSpecConstantTrue: diff --git a/llvmraytracing/include/llvmraytracing/Continuations.h b/llvmraytracing/include/llvmraytracing/Continuations.h index a53a01df61..624ec64ced 100644 --- a/llvmraytracing/include/llvmraytracing/Continuations.h +++ b/llvmraytracing/include/llvmraytracing/Continuations.h @@ -72,6 +72,7 @@ #pragma once +#include "TypesMetadata.h" #include "compilerutils/CompilerUtils.h" #include "llvm-dialects/Dialect/Builder.h" #include "llvmraytracing/ContinuationsUtil.h" @@ -473,8 +474,4 @@ Function *lowerStructRetArgument(Function *Fn); /// Add necessary continuation transform passes for LGC. void addLgcContinuationTransform(ModulePassManager &MPM); -/// LLVM parser callback which adds !types metadata during DXIL parsing -void DXILValueTypeMetadataCallback(Value *V, unsigned TypeID, - GetTypeByIDTy GetTypeByID, - GetContainedTypeIDTy GetContainedTypeID); } // namespace llvm diff --git a/llvmraytracing/include/llvmraytracing/ContinuationsUtil.h b/llvmraytracing/include/llvmraytracing/ContinuationsUtil.h index 8fe18562f6..ac1fb42de5 100644 --- a/llvmraytracing/include/llvmraytracing/ContinuationsUtil.h +++ b/llvmraytracing/include/llvmraytracing/ContinuationsUtil.h @@ -173,16 +173,6 @@ class ContFuncTy { void writeMetadata(Function *F); }; -/// Return element type of a function argument resolving opaque pointers -/// via !types metadata where appropriate. -/// Returns nullptr for non-pointers. -Type *getFuncArgPtrElementType(const Argument *Arg); - -/// Return element type of a function argument resolving opaque pointers -/// via !types metadata where appropriate. -/// Returns nullptr for non-pointers. -Type *getFuncArgPtrElementType(const Function *F, int ArgNo); - struct ContSetting { /// A hash value that is used as name. uint64_t NameHash; @@ -272,10 +262,6 @@ class ContHelper { // Marks an await as a waiting one with a wait mask. static constexpr const char *MDIsWaitAwaitName = "continuation.wait.await"; - // Whether this is a load instruction that should translate to a last_use - // load. - static constexpr const char *MDIsLastUseName = "amdgpu.last.use"; - static std::optional extractZExtI32Constant(MDNode *Node) { if (Node) { uint64_t Result = @@ -595,13 +581,6 @@ class ContHelper { CI.setMetadata(ContHelper::MDIsWaitAwaitName, nullptr); } - // Specifies that this is a load that marks a last use of the pointer it loads - // from. - static void setIsLastUseLoad(LoadInst &Load) { - Load.setMetadata(ContHelper::MDIsLastUseName, - MDTuple::get(Load.getContext(), {})); - } - /// Returns true if a call to the given function should be rematerialized /// in a shader of the specified kind. /// diff --git a/llvmraytracing/include/llvmraytracing/TypesMetadata.h b/llvmraytracing/include/llvmraytracing/TypesMetadata.h new file mode 100644 index 0000000000..e1db8e80d7 --- /dev/null +++ b/llvmraytracing/include/llvmraytracing/TypesMetadata.h @@ -0,0 +1,49 @@ +/* + *********************************************************************************************************************** + * + * Copyright (c) 2024 Advanced Micro Devices, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + *all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + **********************************************************************************************************************/ + +//===- TypesMetadata.h - Pointee type metadata for processing DXIL ---------==// + +#pragma once + +#include "llvm/Bitcode/BitcodeReader.h" + +namespace llvm { + +/// Return element type of a function argument resolving opaque pointers +/// via !types metadata where appropriate. +/// Returns nullptr for non-pointers. +Type *getFuncArgPtrElementType(const Argument *Arg); + +/// Return element type of a function argument resolving opaque pointers +/// via !types metadata where appropriate. +/// Returns nullptr for non-pointers. +Type *getFuncArgPtrElementType(const Function *F, int ArgNo); + +/// LLVM parser callback which adds !types metadata during DXIL parsing +void DXILValueTypeMetadataCallback(Value *V, unsigned TypeID, + GetTypeByIDTy GetTypeByID, + GetContainedTypeIDTy GetContainedTypeID); + +} // namespace llvm diff --git a/llvmraytracing/lib/Continuations.cpp b/llvmraytracing/lib/Continuations.cpp index 5ecf797ef2..d314c9eb91 100644 --- a/llvmraytracing/lib/Continuations.cpp +++ b/llvmraytracing/lib/Continuations.cpp @@ -1265,6 +1265,8 @@ bool llvm::LgcMaterializable(Instruction &OrigI) { // FIXME: switch to dialectOp check. if (CalledName.starts_with("lgc.user.data") || CalledName.starts_with("lgc.shader.input") || + CalledName.starts_with("lgc.create.get.desc.ptr") || + CalledName.starts_with("lgc.load.buffer.desc") || CalledName.starts_with("lgc.load.user.data")) return true; } diff --git a/llvmraytracing/lib/DXILContPostProcess.cpp b/llvmraytracing/lib/DXILContPostProcess.cpp index 56c3c4f05b..ae434696fc 100644 --- a/llvmraytracing/lib/DXILContPostProcess.cpp +++ b/llvmraytracing/lib/DXILContPostProcess.cpp @@ -569,7 +569,7 @@ void DXILContPostProcessPassImpl::handleContStackIntrinsic( Align(CpsStackLowering::getContinuationStackAlignment())); if (FuncName.starts_with("LoadLastUse")) - ContHelper::setIsLastUseLoad(*cast(Replacement)); + CompilerUtils::setIsLastUseLoad(*cast(Replacement)); IsMemoryAccess = true; } else if (FuncName.starts_with("Store")) { diff --git a/llvmraytracing/test/dx/intrinsics/cont-payload-registers-get-i32.ll b/llvmraytracing/test/dx/intrinsics/cont-payload-registers-get-i32.ll index 5f4629bae2..c8abbcea25 100644 --- a/llvmraytracing/test/dx/intrinsics/cont-payload-registers-get-i32.ll +++ b/llvmraytracing/test/dx/intrinsics/cont-payload-registers-get-i32.ll @@ -31,7 +31,7 @@ define void @main() { ; ALL-NEXT: store i32 [[CSPINIT]], ptr [[CSP]], align 4 ; ALL-NEXT: [[DOTFCA_0_EXTRACT:%.*]] = extractvalue [[STRUCT_DISPATCHSYSTEMDATA]] [[TMP0]], 0 ; ALL-NEXT: call void @amd.dx.setLocalRootIndex(i32 0) -; ALL-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(20) getelementptr inbounds ([30 x i32], ptr addrspace(20) @REGISTERS, i32 0, i32 5), align 4 +; ALL-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(20) getelementptr {{(inbounds )?}}([30 x i32], ptr addrspace(20) @REGISTERS, i32 0, i32 5), align 4 ; ALL-NEXT: store i32 [[TMP2]], ptr @debug_global, align 4 ; ALL-NEXT: ret void ; ALL: entry.split: @@ -43,7 +43,7 @@ define void @main() { ; LOWERRAYTRACINGPIPELINE-NEXT: [[SYSTEM_DATA_ALLOCA:%.*]] = alloca [[STRUCT_DISPATCHSYSTEMDATA]], align 8 ; LOWERRAYTRACINGPIPELINE-NEXT: store [[STRUCT_DISPATCHSYSTEMDATA]] [[TMP0]], ptr [[SYSTEM_DATA_ALLOCA]], align 4 ; LOWERRAYTRACINGPIPELINE-NEXT: call void @amd.dx.setLocalRootIndex(i32 0) -; LOWERRAYTRACINGPIPELINE-NEXT: [[VAL:%.*]] = load i32, ptr addrspace(20) getelementptr inbounds ([30 x i32], ptr addrspace(20) @PAYLOAD, i32 0, i32 5), align 4 +; LOWERRAYTRACINGPIPELINE-NEXT: [[VAL:%.*]] = load i32, ptr addrspace(20) getelementptr {{(inbounds )?}}([30 x i32], ptr addrspace(20) @PAYLOAD, i32 0, i32 5), align 4 ; LOWERRAYTRACINGPIPELINE-NEXT: store i32 [[VAL]], ptr @debug_global, align 4 ; LOWERRAYTRACINGPIPELINE-NEXT: ret void ; diff --git a/llvmraytracing/test/dx/intrinsics/cont-payload-registers-set-i32.ll b/llvmraytracing/test/dx/intrinsics/cont-payload-registers-set-i32.ll index 14a1f07454..8eb99d7bc7 100644 --- a/llvmraytracing/test/dx/intrinsics/cont-payload-registers-set-i32.ll +++ b/llvmraytracing/test/dx/intrinsics/cont-payload-registers-set-i32.ll @@ -29,7 +29,7 @@ define void @main() { ; ALL-NEXT: store i32 [[CSPINIT]], ptr [[CSP]], align 4 ; ALL-NEXT: [[DOTFCA_0_EXTRACT:%.*]] = extractvalue [[STRUCT_DISPATCHSYSTEMDATA]] [[TMP0]], 0 ; ALL-NEXT: call void @amd.dx.setLocalRootIndex(i32 0) -; ALL-NEXT: store i32 42, ptr addrspace(20) getelementptr inbounds ([30 x i32], ptr addrspace(20) @REGISTERS, i32 0, i32 5), align 4 +; ALL-NEXT: store i32 42, ptr addrspace(20) getelementptr {{(inbounds )?}}([30 x i32], ptr addrspace(20) @REGISTERS, i32 0, i32 5), align 4 ; ALL-NEXT: ret void ; ALL: entry.split: ; ALL-NEXT: unreachable @@ -40,7 +40,7 @@ define void @main() { ; LOWERRAYTRACINGPIPELINE-NEXT: [[SYSTEM_DATA_ALLOCA:%.*]] = alloca [[STRUCT_DISPATCHSYSTEMDATA]], align 8 ; LOWERRAYTRACINGPIPELINE-NEXT: store [[STRUCT_DISPATCHSYSTEMDATA]] [[TMP0]], ptr [[SYSTEM_DATA_ALLOCA]], align 4 ; LOWERRAYTRACINGPIPELINE-NEXT: call void @amd.dx.setLocalRootIndex(i32 0) -; LOWERRAYTRACINGPIPELINE-NEXT: store i32 42, ptr addrspace(20) getelementptr inbounds ([30 x i32], ptr addrspace(20) @PAYLOAD, i32 0, i32 5), align 4 +; LOWERRAYTRACINGPIPELINE-NEXT: store i32 42, ptr addrspace(20) getelementptr {{(inbounds )?}}([30 x i32], ptr addrspace(20) @PAYLOAD, i32 0, i32 5), align 4 ; LOWERRAYTRACINGPIPELINE-NEXT: ret void ; entry: diff --git a/tool/dumper/vkgcPipelineDumper.cpp b/tool/dumper/vkgcPipelineDumper.cpp index 7ca0eb0c2f..534fce5bc2 100644 --- a/tool/dumper/vkgcPipelineDumper.cpp +++ b/tool/dumper/vkgcPipelineDumper.cpp @@ -936,14 +936,15 @@ void PipelineDumper::dumpPipelineOptions(const PipelineOptions *options, std::os dumpFile << "options.internalRtShaders = " << options->internalRtShaders << "\n"; dumpFile << "options.forceNonUniformResourceIndexStageMask = " << options->forceNonUniformResourceIndexStageMask << "\n"; - dumpFile << "options.replaceSetWithResourceType = " << options->replaceSetWithResourceType << "\n"; - dumpFile << "options.disableSampleMask = " << options->disableSampleMask << "\n"; - dumpFile << "options.buildResourcesDataForShaderModule = " << options->buildResourcesDataForShaderModule << "\n"; - dumpFile << "options.disableTruncCoordForGather = " << options->disableTruncCoordForGather << "\n"; - dumpFile << "options.enableCombinedTexture = " << options->enableCombinedTexture << "\n"; - dumpFile << "options.vertex64BitsAttribSingleLoc = " << options->vertex64BitsAttribSingleLoc << "\n"; - dumpFile << "options.enableFragColor = " << options->enableFragColor << "\n"; - dumpFile << "options.disableBaseVertex = " << options->disableBaseVertex << "\n"; + dumpFile << "options.replaceSetWithResourceType = " << options->getGlState().replaceSetWithResourceType << "\n"; + dumpFile << "options.disableSampleMask = " << options->getGlState().disableSampleMask << "\n"; + dumpFile << "options.buildResourcesDataForShaderModule = " << options->getGlState().buildResourcesDataForShaderModule + << "\n"; + dumpFile << "options.disableTruncCoordForGather = " << options->getGlState().disableTruncCoordForGather << "\n"; + dumpFile << "options.enableCombinedTexture = " << options->getGlState().enableCombinedTexture << "\n"; + dumpFile << "options.vertex64BitsAttribSingleLoc = " << options->getGlState().vertex64BitsAttribSingleLoc << "\n"; + dumpFile << "options.enableFragColor = " << options->getGlState().enableFragColor << "\n"; + dumpFile << "options.disableBaseVertex = " << options->getGlState().disableBaseVertex << "\n"; dumpFile << "options.enablePrimGeneratedQuery = " << options->enablePrimGeneratedQuery << "\n"; dumpFile << "options.disablePerCompFetch = " << options->disablePerCompFetch << "\n"; } @@ -1043,6 +1044,7 @@ void PipelineDumper::dumpGraphicsStateInfo(const GraphicsPipelineBuildInfo *pipe dumpFile << "dynamicTopology = " << pipelineInfo->dynamicTopology << "\n"; dumpFile << "enableColorClampVs = " << pipelineInfo->glState.enableColorClampVs << "\n"; dumpFile << "enableColorClampFs = " << pipelineInfo->glState.enableColorClampFs << "\n"; + dumpFile << "enableFlatShade = " << pipelineInfo->glState.enableFlatShade << "\n"; dumpFile << "originUpperLeft = " << pipelineInfo->getGlState().originUpperLeft << "\n"; if (pipelineInfo->clientMetadataSize > 0) { @@ -1570,6 +1572,7 @@ MetroHash::Hash PipelineDumper::generateHashForGraphicsPipeline(const GraphicsPi hasher.Update(pipeline->glState.enableColorClampVs); hasher.Update(pipeline->glState.enableColorClampFs); + hasher.Update(pipeline->glState.enableFlatShade); MetroHash::Hash hash = {}; hasher.Finalize(hash.bytes); @@ -1873,7 +1876,7 @@ void PipelineDumper::updateHashForPipelineOptions(const PipelineOptions *options } if (stage == UnlinkedStageFragment || stage == UnlinkedStageCount) { hasher->Update(options->enableInterpModePatch); - hasher->Update(options->disableSampleMask); + hasher->Update(options->getGlState().disableSampleMask); } hasher->Update(options->pageMigrationEnabled); hasher->Update(options->optimizationLevel); @@ -1886,13 +1889,13 @@ void PipelineDumper::updateHashForPipelineOptions(const PipelineOptions *options hasher->Update(options->reverseThreadGroup); hasher->Update(options->internalRtShaders); hasher->Update(options->forceNonUniformResourceIndexStageMask); - hasher->Update(options->replaceSetWithResourceType); - hasher->Update(options->buildResourcesDataForShaderModule); - hasher->Update(options->disableTruncCoordForGather); - hasher->Update(options->enableCombinedTexture); - hasher->Update(options->vertex64BitsAttribSingleLoc); - hasher->Update(options->enableFragColor); - hasher->Update(options->disableBaseVertex); + hasher->Update(options->getGlState().replaceSetWithResourceType); + hasher->Update(options->getGlState().buildResourcesDataForShaderModule); + hasher->Update(options->getGlState().disableTruncCoordForGather); + hasher->Update(options->getGlState().enableCombinedTexture); + hasher->Update(options->getGlState().vertex64BitsAttribSingleLoc); + hasher->Update(options->getGlState().enableFragColor); + hasher->Update(options->getGlState().disableBaseVertex); hasher->Update(options->enablePrimGeneratedQuery); // disablePerCompFetch has been handled in updateHashForNonFragmentState } @@ -2191,12 +2194,18 @@ template // @param reader : ELF object OStream &operator<<(OStream &out, ElfReader &reader) { unsigned sectionCount = reader.getSectionCount(); + bool sortSection = reader.getMap().size() == sectionCount; char formatBuf[256]; - for (unsigned sortIdx = 0; sortIdx < sectionCount; ++sortIdx) { + for (unsigned idx = 0; idx < sectionCount; ++idx) { typename ElfReader::SectionBuffer *section = nullptr; - unsigned secIdx = 0; - Result result = reader.getSectionDataBySortingIndex(sortIdx, &secIdx, §ion); + Result result = Result::Success; + unsigned secIdx = idx; + if (sortSection) { + result = reader.getSectionDataBySortingIndex(idx, &secIdx, §ion); + } else { + result = reader.getSectionDataBySectionIndex(idx, §ion); + } assert(result == Result::Success); (void(result)); // unused if (strcmp(section->name, ShStrTabName) == 0 || strcmp(section->name, StrTabName) == 0 || @@ -2418,7 +2427,7 @@ OStream &operator<<(OStream &out, ElfReader &reader) { while (startPos < section->secHead.sh_size) { if (symIdx < symbols.size()) - endPos = static_cast(symbols[symIdx].value); + endPos = static_cast(std::min(symbols[symIdx].value, section->secHead.sh_size)); else endPos = static_cast(section->secHead.sh_size); @@ -2428,12 +2437,16 @@ OStream &operator<<(OStream &out, ElfReader &reader) { out << " " << symbols[symIdx].pSymName << " (offset = " << symbols[symIdx].value << " size = " << symbols[symIdx].size; - MetroHash::Hash hash = {}; - MetroHash64::Hash( - reinterpret_cast(voidPtrInc(section->data, static_cast(symbols[symIdx].value))), - symbols[symIdx].size, hash.bytes); - uint64_t hashCode64 = MetroHash::compact64(&hash); - snprintf(formatBuf, sizeof(formatBuf), " hash = 0x%016" PRIX64 ")\n", hashCode64); + if ((symbols[symIdx].value + symbols[symIdx].size) <= section->secHead.sh_size) { + MetroHash::Hash hash = {}; + MetroHash64::Hash(reinterpret_cast( + voidPtrInc(section->data, static_cast(symbols[symIdx].value))), + symbols[symIdx].size, hash.bytes); + uint64_t hashCode64 = MetroHash::compact64(&hash); + snprintf(formatBuf, sizeof(formatBuf), " hash = 0x%016" PRIX64 ")\n", hashCode64); + } else { + snprintf(formatBuf, sizeof(formatBuf), " hash = Unknown )\n"); + } out << formatBuf; } ++symIdx; diff --git a/tool/vfx/vfxVkSection.h b/tool/vfx/vfxVkSection.h index 313c79789b..ce4cc75742 100644 --- a/tool/vfx/vfxVkSection.h +++ b/tool/vfx/vfxVkSection.h @@ -882,6 +882,7 @@ class SectionGraphicsState : public Section { INIT_STATE_SUB_MEMBER_NAME_TO_ADDR(SectionGraphicsState, cbState, dualSourceBlendDynamic, MemberTypeBool, false); INIT_STATE_SUB_MEMBER_NAME_TO_ADDR(SectionGraphicsState, glState, enableColorClampVs, MemberTypeBool, false); INIT_STATE_SUB_MEMBER_NAME_TO_ADDR(SectionGraphicsState, glState, enableColorClampFs, MemberTypeBool, false); + INIT_STATE_SUB_MEMBER_NAME_TO_ADDR(SectionGraphicsState, glState, enableFlatShade, MemberTypeBool, false); INIT_MEMBER_ARRAY_NAME_TO_ADDR(SectionGraphicsState, m_colorBuffer, MemberTypeColorBufferItem, Vkgc::MaxColorTargets, true); @@ -896,6 +897,7 @@ class SectionGraphicsState : public Section { INIT_STATE_MEMBER_NAME_TO_ADDR(SectionGraphicsState, useSoftwareVertexBufferDescriptors, MemberTypeBool, false); INIT_MEMBER_NAME_TO_ADDR(SectionGraphicsState, m_shaderLibrary, MemberTypeString, false); INIT_MEMBER_NAME_TO_ADDR(SectionGraphicsState, m_rtState, MemberTypeRtState, true); + INIT_MEMBER_NAME_TO_ADDR(SectionGraphicsState, m_clientMetadata, MemberTypeU8Array, false); INIT_MEMBER_ARRAY_NAME_TO_ADDR(SectionGraphicsState, m_uniformConstantMaps, MemberTypeUniformConstantMap, Vkgc::ShaderStageGfxCount, true); diff --git a/util/vkgcUtil.cpp b/util/vkgcUtil.cpp index da52ff8df4..8f948b8b13 100644 --- a/util/vkgcUtil.cpp +++ b/util/vkgcUtil.cpp @@ -52,6 +52,14 @@ const char *VKAPI_CALL IUtil::GetEntryPointNameFromSpirvBinary(const BinaryData return getEntryPointNameFromSpirvBinary(spvBin); } +// ===================================================================================================================== +// Translate enum "ResourceMappingNodeType" to string +// +// @param type : Resource map node type +const char *VKAPI_CALL IUtil::GetResourceMappingNodeTypeName(ResourceMappingNodeType type) { + return getResourceMappingNodeTypeName(type); +} + // ===================================================================================================================== // Gets name string of the abbreviation for the specified shader stage // diff --git a/version/include/llpcVersion.h.in b/version/include/llpcVersion.h.in index d947653255..e8d33c7a96 100644 --- a/version/include/llpcVersion.h.in +++ b/version/include/llpcVersion.h.in @@ -37,6 +37,8 @@ // %Version History // | %Version | Change Description | // | -------- | ----------------------------------------------------------------------------------------------------- | +// | 73.0 | Add all the ogl specific pipeline options in a new structure GLState | +// | 72.4 | Add enableFlatShade to GraphicsPipelineBuildInfo. | // | 72.3 | Add enableColorClampVs and enableColorClampFs to GraphicsPipelineBuildInfo. | // | 72.2 | Add pGpurtOptions and gpurtOptionCount to RayTracingPipelineBuildInfo | // | 72.1 | Add dynamicTopology to GraphicsPipelineBuildInfo |

    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