diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/core.meta.slang | 4 | ||||
| -rw-r--r-- | source/slang/glsl.meta.slang | 460 | ||||
| -rw-r--r-- | source/slang/slang-ast-modifier.h | 47 | ||||
| -rw-r--r-- | source/slang/slang-ast-support-types.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 32 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 68 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 51 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 1 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-emit-glsl.cpp | 47 | ||||
| -rw-r--r-- | source/slang/slang-emit-glsl.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-emit-spirv.cpp | 64 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-ir-spirv-legalize.cpp | 7 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 16 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 78 |
19 files changed, 876 insertions, 19 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 1f4a2908d..583dd5923 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -2363,6 +2363,10 @@ int __naturalStrideOf() __intrinsic_op($(kIROp_TreatAsDynamicUniform)) T asDynamicUniform<T>(T v); +__generic<T> +__intrinsic_op($(kIROp_GetLegalizedSPIRVGlobalParamAddr)) +Ptr<T> __getLegalizedSPIRVGlobalParamAddr(T val); + // Binding Attributes __attributeTarget(DeclBase) diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index 4101cc626..d7b646810 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -2821,6 +2821,466 @@ public vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod) return textureProjLod(sampler, coord, lod); } +//// gimageDim Implementation + +public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0; +public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 1; +public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 2; +public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 3; +public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 4; +public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 5; + +__generic<T : __BuiltinType> +[ForceInline] void typeRequireChecks_image_atomic_tier1() +{ + __target_switch + { + case glsl: + { + if (__type_equals<T, float>()) + __requireGLSLExtension("GL_EXT_shader_atomic_float"); + } + case spirv: + if (__type_equals<T, float>()) + { + spirv_asm + { + OpExtension "SPV_EXT_shader_atomic_float_add"; + OpCapability AtomicFloat32AddEXT + }; + } + } +} + +__generic<T : __BuiltinType> +[ForceInline] void typeRequireChecks_image_atomic_tier2() +{ + __target_switch + { + case glsl: + { + if (__type_equals<T, float>()) + __requireGLSLExtension("GL_EXT_shader_atomic_float2"); + } + case spirv: + if (__type_equals<T, float>()) + { + spirv_asm + { + OpExtension "SPV_EXT_shader_atomic_float_min_max"; + OpCapability AtomicFloat32MinMaxEXT + }; + } + } +} + +__generic<T : __BuiltinType> +[ForceInline] void typeRequireChecks_image_atomic_int64() +{ + __target_switch + { + case spirv: + if (__type_equals<T, uint64_t>() + || __type_equals<T, int64_t>()) + { + spirv_asm + { + OpCapability Int64Atomics + }; + } + return; + } +} + +${{{{ +{ + struct ImageTypeInfo + { + const char *prefix; + const char *type; + bool isInt; + const char *SPVTypePrefix; + const char *SPVSubTypePrefix; + const char *SPVAtomicSuffix; + }; + static const ImageTypeInfo kTypeWithPrefix[] = + { + { "", "float", false, "F", "F", "EXT"}, + { "u", "uint", true, "I", "U", ""}, + { "i", "int", true, "I", "S", ""}, + { "u64", "uint64_t", true, "I", "U", ""}, + { "i64", "int64_t", true, "I", "S", ""}, + }; + struct ShapeTypeInfo + { + const char *suffix; + int imageSizeIVecDim; + int imageCoordIVecIndexerDim; + const char *shape; + int isArray; + int isMS; + bool isRect; + } + static const kShapeType[] = + { + { "1D", 1, 1,"__Shape1D", 0, 0, 0}, + + { "2D", 2, 2, "__Shape2D", 0, 0, 0}, + { "3D", 3, 3, "__Shape3D", 0, 0, 0}, + { "Cube", 2, 3, "__ShapeCube", 0, 0, 0}, + { "2DRect", 2, 2, "__Shape2D", 0, 0, 1}, + { "1DArray", 2, 2, "__Shape1D", 1, 0, 0}, + + { "2DArray", 3, 3, "__Shape2D", 1, 0, 0}, + { "CubeArray", 3, 3, "__ShapeCube", 1, 0, 0}, + { "Buffer", 1, 1, "__ShapeBuffer", 0, 0, 0}, + { "2DMS", 2, 2, "__Shape2D", 0, 1, 0}, + { "2DMSArray", 3, 3, "__Shape2D", 1, 1, 0}, + }; + for (const auto& targetType : kTypeWithPrefix) + for (const auto& targetShape : kShapeType) + { + // gimageDim is the format of image buffers, we + // need to resolve a type name from the format: + // targetType.prefix is the 'g' + // targetShape.suffix is the 'Dim' + StringBuilder fullTypeNameBuilder; + fullTypeNameBuilder << targetType.prefix << "image" << targetShape.suffix; + auto fullTypeName = fullTypeNameBuilder.toString(); + + // We need a string to resolve for the imageSize return type + // since each shape has a different return which may not be + // a vec + StringBuilder imageSizeIntOrIVecBuilder; + if (targetShape.imageSizeIVecDim == 1) + imageSizeIntOrIVecBuilder << "int"; + else + imageSizeIntOrIVecBuilder << "ivec" << targetShape.imageSizeIVecDim; + auto imageSizeIntOrIVec = imageSizeIntOrIVecBuilder.toString(); + + // Following OpenGL/Vulkan semantics, IMAGE_PARAMS string represents + // the changing list of parameters per gimageDim type + // https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf + StringBuilder IMAGE_PARAMSBuilder; + IMAGE_PARAMSBuilder << fullTypeName << " image,"; + int paramC = targetShape.imageCoordIVecIndexerDim; + if (paramC == 1) + IMAGE_PARAMSBuilder << "int"; + else + IMAGE_PARAMSBuilder << "ivec" << paramC; + IMAGE_PARAMSBuilder << " P"; + if (targetShape.isMS) + { + IMAGE_PARAMSBuilder << ", int sample"; + } + auto IMAGE_PARAMS = IMAGE_PARAMSBuilder.toString(); + + // SPIR-V requires a 'sample' parameter for all texture + // functions. We need to handle a dynamic creation of + // 'sample' if 'sample' parameter is not in IMAGE_PARAMS + StringBuilder SPV_PREFIX_IMAGE_PARAMSBuilder; + StringBuilder SPV_SUFFIX_IMAGE_PARAMSBuilder; + StringBuilder SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder; + + SPV_PREFIX_IMAGE_PARAMSBuilder << "$image $P"; + SPV_SUFFIX_IMAGE_PARAMSBuilder; + if (targetShape.isMS) + { + SPV_SUFFIX_IMAGE_PARAMSBuilder << " Sample $sample"; + } + else + { + SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder << "let sample = 0;"; + } + + auto SPV_PREFIX_IMAGE_PARAMS = SPV_PREFIX_IMAGE_PARAMSBuilder.toString(); + auto SPV_SUFFIX_IMAGE_PARAMS = SPV_SUFFIX_IMAGE_PARAMSBuilder.toString(); + auto SPV_DEFAULT_SAMPLE_VAR_IF_MISSING = SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder.toString(); + }}}} + + __generic<let format:int=0> + public typealias $(fullTypeName) = __TextureImpl< + $(targetType.type), + $(targetShape.shape), + $(targetShape.isArray), // isArray + $(targetShape.isMS), // isMS + 0, // sampleCount + 1, // access + 0, // isShadow + 0, // isCombined + format + >; + +${{{{ + if(targetShape.isRect) + continue; +}}}} + + // readonly writeonly in GLSL means an object only allows information queries. + [require(spirv)] + [require(glsl)] + [__readNone] + [ForceInline] public $(imageSizeIntOrIVec) imageSize(readonly writeonly $(fullTypeName) image) + { + __target_switch + { + case glsl: __intrinsic_asm "imageSize($*0)"; + case spirv: + return spirv_asm + { + OpCapability ImageQuery; + result:$$$(imageSizeIntOrIVec) = OpImageQuerySize $image; + }; + } + } + [require(spirv)] + [require(glsl)] + [__NoSideEffect] + [ForceInline] public $(targetType.prefix)vec4 imageLoad(readonly $(IMAGE_PARAMS)) + { + __target_switch + { + case glsl: __intrinsic_asm "imageLoad($*0)"; + case spirv: + { + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + result:$$$(targetType.prefix)vec4 = OpImageRead $(SPV_PREFIX_IMAGE_PARAMS) $(SPV_SUFFIX_IMAGE_PARAMS); + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public void imageStore(writeonly $(IMAGE_PARAMS), $(targetType.prefix)vec4 data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageStore($*0)"; + case spirv: + { + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpImageWrite $(SPV_PREFIX_IMAGE_PARAMS) $data $(SPV_SUFFIX_IMAGE_PARAMS); + }; + } + } + } + +${{{{ + if (targetShape.isMS) + { +}}}} + // readonly writeonly in GLSL means an object only allows information queries. + [require(spirv)] + [require(glsl)] + [__readNone] + [ForceInline] public int imageSamples(readonly writeonly $(fullTypeName) image) + { + __target_switch + { + case glsl: __intrinsic_asm "imageSamples($*0)"; + case spirv: + return spirv_asm + { + OpCapability ImageQuery; + result:$$int = OpImageQuerySamples $image; + }; + } + } +${{{{ + } +}}}} + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicAdd($(IMAGE_PARAMS), $(targetType.type) data) + { + typeRequireChecks_image_atomic_tier1<$(targetType.type)>(); + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicAdd($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomic$(targetType.SPVTypePrefix)Add$(targetType.SPVAtomicSuffix) %ptr Device None $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicExchange($(IMAGE_PARAMS), $(targetType.type) data) + { + typeRequireChecks_image_atomic_tier1<$(targetType.type)>(); + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicExchange($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicExchange %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicMin($(IMAGE_PARAMS), $(targetType.type) data) + { + typeRequireChecks_image_atomic_tier2<$(targetType.type)>(); + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicMin($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomic$(targetType.SPVSubTypePrefix)Min$(targetType.SPVAtomicSuffix) %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicMax($(IMAGE_PARAMS), $(targetType.type) data) + { + typeRequireChecks_image_atomic_tier2<$(targetType.type)>(); + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicMax($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomic$(targetType.SPVSubTypePrefix)Max$(targetType.SPVAtomicSuffix) %ptr Device ImageMemory $data + }; + } + } + } +${{{{ + if (!targetType.isInt) + continue; +}}}} + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicAnd($(IMAGE_PARAMS), $(targetType.type) data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicAnd($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicAnd %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicOr($(IMAGE_PARAMS), $(targetType.type) data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicOr($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicOr %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicXor($(IMAGE_PARAMS), $(targetType.type) data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicXor($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicXor %ptr Device ImageMemory $data + }; + } + } + } + [require(spirv)] + [require(glsl)] + [ForceInline] public $(targetType.type) imageAtomicCompSwap($(IMAGE_PARAMS), $(targetType.type) compare, $(targetType.type) data) + { + __target_switch + { + case glsl: __intrinsic_asm "imageAtomicCompSwap($*0)"; + case spirv: + { + let imageP = __getLegalizedSPIRVGlobalParamAddr(image); + typeRequireChecks_image_atomic_int64<$(targetType.type)>(); + $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING) + return spirv_asm + { + OpCapability ImageQuery; + %ptrType = OpTypePointer Image $$$(targetType.type); + %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample; + result:$$$(targetType.type) = OpAtomicCompareExchange %ptr Device ImageMemory ImageMemory $data $compare + }; + } + } + } +${{{{ + } +} +}}}} //// RayTracing diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 87057b694..4ccca36ea 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -29,7 +29,6 @@ class PrefixModifier : public Modifier { SLANG_AST_CLASS(PrefixModifier)}; class PostfixModifier : public Modifier { SLANG_AST_CLASS(PostfixModifier)}; class ExportedModifier : public Modifier { SLANG_AST_CLASS(ExportedModifier)}; class ConstExprModifier : public Modifier { SLANG_AST_CLASS(ConstExprModifier)}; -class GloballyCoherentModifier : public Modifier { SLANG_AST_CLASS(GloballyCoherentModifier)}; class ExternCppModifier : public Modifier { SLANG_AST_CLASS(ExternCppModifier)}; class GLSLPrecisionModifier : public Modifier { SLANG_AST_CLASS(GLSLPrecisionModifier)}; class GLSLModuleModifier : public Modifier {SLANG_AST_CLASS(GLSLModuleModifier)}; @@ -1493,6 +1492,11 @@ class NoDiffModifier : public TypeModifier SLANG_AST_CLASS(NoDiffModifier) }; +class GloballyCoherentModifier : public SimpleModifier +{ + SLANG_AST_CLASS(GloballyCoherentModifier) +}; + // Some GLSL-specific modifiers class GLSLBufferModifier : public WrappingTypeModifier { @@ -1509,6 +1513,16 @@ class GLSLReadOnlyModifier : public SimpleModifier SLANG_AST_CLASS(GLSLReadOnlyModifier) }; +class GLSLVolatileModifier : public SimpleModifier +{ + SLANG_AST_CLASS(GLSLVolatileModifier) +}; + +class GLSLRestrictModifier : public SimpleModifier +{ + SLANG_AST_CLASS(GLSLRestrictModifier) +}; + class GLSLPatchModifier : public SimpleModifier { SLANG_AST_CLASS(GLSLPatchModifier) @@ -1531,4 +1545,35 @@ class DynamicUniformModifier : public Modifier SLANG_AST_CLASS(DynamicUniformModifier) }; +class MemoryQualifierCollectionModifier : public Modifier +{ + SLANG_AST_CLASS(MemoryQualifierCollectionModifier); + + List<Modifier*> memoryModifiers; + + uint32_t memoryQualifiers = 0; + +public: + struct Flags + { + enum MemoryQualifiersBit + { + kNone = 0b0, + kCoherent = 0b1, + kReadOnly = 0b10, + kWriteOnly = 0b100, + kVolatile = 0b1000, + kRestrict = 0b10000, + }; + }; + + void addQualifier(Modifier* mod, Flags::MemoryQualifiersBit type) + { + memoryModifiers.add(mod); + memoryQualifiers |= type; + } + uint32_t getMemoryQualifierBit() { return memoryQualifiers; } + List<Modifier*> getModifiers() { return memoryModifiers; } +}; + } // namespace Slang diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 4ad5fc432..e4e3be384 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -549,6 +549,8 @@ namespace Slang Type* type = nullptr; bool isLeftValue; + bool hasReadOnlyOnTarget = false; + bool isWriteOnly = false; QualType() : isLeftValue(false) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 386a0bba1..c844fb82a 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -944,7 +944,27 @@ namespace Slang } } + // Ensures child of struct is set read-only or not + bool isWriteOnly = false; + { + for (auto mod : varDeclRef.getDecl()->modifiers) + { + if (as<GLSLReadOnlyModifier>(mod)) + { + isLValue = false; + qualType.hasReadOnlyOnTarget = true; + if (isLValue == false && isWriteOnly) break; + } + if (as<GLSLWriteOnlyModifier>(mod)) + { + isWriteOnly = true; + if (isLValue == false && isWriteOnly) break; + } + } + } + qualType.isLeftValue = isLValue; + qualType.isWriteOnly = isWriteOnly; return qualType; } else if( auto propertyDeclRef = declRef.as<PropertyDecl>() ) @@ -1846,6 +1866,8 @@ namespace Slang // initExpr = subVisitor.CheckTerm(initExpr); + if (initExpr->type.isWriteOnly) + getSink()->diagnose(initExpr, Diagnostics::readingFromWriteOnly); initExpr = coerce(CoercionSite::Initializer, varDecl->type.Ptr(), initExpr); varDecl->initExpr = initExpr; @@ -7023,6 +7045,16 @@ namespace Slang } } } + + // Only texture types are allowed to have memory qualifiers on parameters + if(!paramDecl->type || paramDecl->type->astNodeType != ASTNodeType::TextureType) + { + auto memoryQualifierCollection = paramDecl->findModifier<MemoryQualifierCollectionModifier>(); + if(!memoryQualifierCollection) + return; + for(auto mod : memoryQualifierCollection->getModifiers()) + getSink()->diagnose(paramDecl, Diagnostics::memoryQualifierNotAllowedOnANonImageTypeParameter, mod); + } } // This checks that the declaration is marked as "out" and changes the hlsl diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index dc7a2d35b..a31e17123 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -412,6 +412,11 @@ namespace Slang expr->declRef = declRef; expr->memberOperatorLoc = _getMemberOpLoc(originalExpr); + // If any member declares the following value is a + // write only, we must declare the parent as a write + // only to avoid modifying the child + expr->type.isWriteOnly = baseExpr->type.isWriteOnly || expr->type.isWriteOnly; + // When referring to a member through an expression, // the result is only an l-value if both the base // expression and the member agree that it should be. @@ -424,7 +429,7 @@ namespace Slang // One exception to this is if we're reading the contents // of a GLSL buffer interface block which isn't marked as // read_only - expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr); + expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr) && (expr->type.hasReadOnlyOnTarget == false); } else { @@ -2078,6 +2083,9 @@ namespace Slang Expr* SemanticsVisitor::checkAssignWithCheckedOperands(AssignExpr* expr) { + if (expr->right->type.isWriteOnly) + getSink()->diagnose(expr, Diagnostics::readingFromWriteOnly); + expr->left = maybeOpenRef(expr->left); auto type = expr->left->type; auto right = maybeOpenRef(expr->right); @@ -2177,6 +2185,44 @@ namespace Slang return _canLValueCoerceScalarType(a, b); } + + void SemanticsVisitor::compareMemoryQualifierOfParamToArgument( + ParamDecl* paramIn, + Expr* argIn) + { + auto arg = as<VarExpr>(argIn); + if (!paramIn || !arg) + return; + + auto argDeclRef = arg->declRef; + if (!argDeclRef) + return; + auto argDecl = argDeclRef.getDecl(); + auto argMemMods = argDecl->findModifier<MemoryQualifierCollectionModifier>(); + if(!argMemMods) + return; + uint32_t argQualifiers = argMemMods->getMemoryQualifierBit(); + + uint32_t paramQualifiers = 0; + auto paramMemMods = paramIn->findModifier<MemoryQualifierCollectionModifier>(); + if(paramMemMods) + paramQualifiers = paramMemMods->getMemoryQualifierBit(); + + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kCoherent + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kCoherent)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "coherent"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kReadOnly + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kReadOnly)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "readonly"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kWriteOnly + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kWriteOnly)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "writeonly"); + if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kVolatile + && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kVolatile)) + getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "volatile"); + // dropping a `restrict` qualifier from arguments is allowed in GLSL with memory qualifiers + } + Expr* SemanticsVisitor::CheckInvokeExprWithCheckedOperands(InvokeExpr *expr) { auto rs = ResolveInvoke(expr); @@ -2194,10 +2240,25 @@ namespace Slang } } + auto funcDeclRefExpr = as<DeclRefExpr>(invoke->functionExpr); + FunctionDeclBase* funcDeclBase = nullptr; + if (funcDeclRefExpr) + funcDeclBase = as<FunctionDeclBase>(funcDeclRefExpr->declRef.getDecl()); + Index paramCount = funcType->getParamCount(); for (Index pp = 0; pp < paramCount; ++pp) { auto paramType = funcType->getParamType(pp); + Expr* argExpr = nullptr; + ParamDecl* paramDecl = nullptr; + if (pp < expr->arguments.getCount()) + { + argExpr = expr->arguments[pp]; + if(funcDeclBase) + paramDecl = funcDeclBase->getParameters()[pp]; + } + compareMemoryQualifierOfParamToArgument(paramDecl, argExpr); + if (as<OutTypeBase>(paramType) || as<RefType>(paramType)) { // `out`, `inout`, and `ref` parameters currently require @@ -2207,9 +2268,8 @@ namespace Slang // for an `inout` parameter to be converted in both // directions. // - if( pp < expr->arguments.getCount() ) + if( argExpr ) { - auto argExpr = expr->arguments[pp]; if( !argExpr->type.isLeftValue) { auto implicitCastExpr = as<ImplicitCastExpr>(argExpr); @@ -3280,6 +3340,8 @@ namespace Slang { auto elementType = QualType(pointerLikeType->getElementType()); elementType.isLeftValue = baseType.isLeftValue; + elementType.hasReadOnlyOnTarget = baseType.hasReadOnlyOnTarget; + elementType.isWriteOnly = baseType.isWriteOnly; auto derefExpr = m_astBuilder->create<DerefExpr>(); derefExpr->base = expr; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 392d78c5a..278fc3265 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2467,6 +2467,7 @@ namespace Slang Expr* CheckExpr(Expr* expr); + void compareMemoryQualifierOfParamToArgument(ParamDecl* paramIn, Expr* argIn); Expr* CheckInvokeExprWithCheckedOperands(InvokeExpr *expr); // Get the type to use when referencing a declaration QualType GetTypeForDeclRef(DeclRef<Decl> declRef, SourceLoc loc); diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 0b9688cb0..942afd559 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -1010,6 +1010,8 @@ namespace Slang case ASTNodeType::GLSLBufferModifier: case ASTNodeType::GLSLWriteOnlyModifier: case ASTNodeType::GLSLReadOnlyModifier: + case ASTNodeType::GLSLVolatileModifier: + case ASTNodeType::GLSLRestrictModifier: case ASTNodeType::GLSLPatchModifier: case ASTNodeType::RayPayloadAccessSemantic: case ASTNodeType::RayPayloadReadSemantic: @@ -1092,16 +1094,26 @@ namespace Slang case ASTNodeType::RefModifier: case ASTNodeType::ConstRefModifier: case ASTNodeType::GLSLBufferModifier: - case ASTNodeType::GLSLWriteOnlyModifier: - case ASTNodeType::GLSLReadOnlyModifier: case ASTNodeType::GLSLPatchModifier: case ASTNodeType::RayPayloadAccessSemantic: case ASTNodeType::RayPayloadReadSemantic: case ASTNodeType::RayPayloadWriteSemantic: return (as<VarDeclBase>(decl) && isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl); + case ASTNodeType::GLSLWriteOnlyModifier: + case ASTNodeType::GLSLReadOnlyModifier: + case ASTNodeType::GLSLVolatileModifier: + case ASTNodeType::GLSLRestrictModifier: + if(isGLSLInput) + return (as<VarDeclBase>(decl) && (isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl)) + || as<StructDecl>(getParentDecl(decl)) && isGlobalDecl(getParentDecl(decl)); + return (as<VarDeclBase>(decl) && (isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl)); + case ASTNodeType::GloballyCoherentModifier: case ASTNodeType::HLSLVolatileModifier: + if(isGLSLInput) + return as<VarDecl>(decl) && (isGlobalDecl(decl) || as<StructDecl>(getParentDecl(decl)) || as<GLSLInterfaceBlockDecl>(decl)) + || as<VarDeclBase>(decl) && isGlobalDecl(decl) || as<ParamDecl>(decl) || (as<StructDecl>(getParentDecl(decl)) && isGlobalDecl(getParentDecl(decl))); return as<VarDecl>(decl) && (isGlobalDecl(decl) || as<StructDecl>(getParentDecl(decl)) || as<GLSLInterfaceBlockDecl>(decl)); // Allowed only on parameters, struct fields and global variables. @@ -1216,6 +1228,40 @@ namespace Slang } } + MemoryQualifierCollectionModifier::Flags::MemoryQualifiersBit memoryQualifierBit = + MemoryQualifierCollectionModifier::Flags::kNone; + if(as<GloballyCoherentModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kCoherent; + else if(as<GLSLReadOnlyModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kReadOnly; + else if(as<GLSLWriteOnlyModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kWriteOnly; + else if(as<GLSLVolatileModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kVolatile; + else if(as<GLSLRestrictModifier>(m)) + memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kRestrict; + if(memoryQualifierBit != MemoryQualifierCollectionModifier::Flags::kNone) + { + bool newModifier = false; + MemoryQualifierCollectionModifier* memoryQualifiers = syntaxNode->findModifier<MemoryQualifierCollectionModifier>(); + if(!memoryQualifiers) + { + newModifier = true; + memoryQualifiers = getASTBuilder()->create<MemoryQualifierCollectionModifier>(); + } + memoryQualifiers->addQualifier(m, + memoryQualifierBit); + if (newModifier) + { + // insert in modifiers list the memoryQualifierCollection + Modifier* mod = m->next; + m->next = memoryQualifiers; + memoryQualifiers->next = mod; + return m; + } + return m; + } + if (auto hlslSemantic = as<HLSLSimpleSemantic>(m)) { if (hlslSemantic->name.getName() == getSession()->getCompletionRequestTokenName()) @@ -1519,6 +1565,7 @@ namespace Slang if (as<SharedModifiers>(modifier)) ignoreUnallowedModifier = true; + // may return a list of modifiers auto checkedModifier = checkModifier(modifier, syntaxNode, ignoreUnallowedModifier); if(checkedModifier) diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 757ce94ee..e1c929f7e 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -298,6 +298,7 @@ DIAGNOSTIC(30035, Error, componentOverloadTypeMismatch, "'$0': type of overloade DIAGNOSTIC(30041, Error, bitOperationNonIntegral, "bit operation: operand must be integral type.") DIAGNOSTIC(30043, Error, getStringHashRequiresStringLiteral, "getStringHash parameter can only accept a string literal") DIAGNOSTIC(30047, Error, argumentExpectedLValue, "argument passed to parameter '$0' must be l-value.") +DIAGNOSTIC(30048, Error, argumentHasMoreMemoryQualifiersThanParam, "argument passed in to parameter has a memory qualifier the parameter type is missing: '$0'") DIAGNOSTIC(30049, Note, thisIsImmutableByDefault, "a 'this' parameter is an immutable parameter by default in Slang; apply the `[mutating]` attribute to the function declaration to opt in to a mutable `this`") DIAGNOSTIC(30050, Error, mutatingMethodOnImmutableValue, "mutating method '$0' cannot be called on an immutable value") @@ -355,6 +356,8 @@ DIAGNOSTIC(30098, Error, nonStaticMemberFunctionNotAllowedAsDiffOperand, "non-st DIAGNOSTIC(30099, Error, sizeOfArgumentIsInvalid, "argument to sizeof is invalid") +DIAGNOSTIC(30101, Error, readingFromWriteOnly, "cannot read from writeonly, check modifiers.") + // Include DIAGNOSTIC(30500, Error, includedFileMissingImplementing, "missing 'implementing' declaration in the included source file '$0'.") DIAGNOSTIC(30501, Error, includedFileMissingImplementingDoYouMeanImport, "missing 'implementing' declaration in the included source file '$0'. The file declares that it defines module '$1', do you mean 'import' instead?") @@ -444,6 +447,7 @@ DIAGNOSTIC(31202, Error, duplicateModifier, "modifier '$0' is redundant or confl DIAGNOSTIC(31203, Error, cannotExportIncompleteType, "cannot export incomplete type '$0'") DIAGNOSTIC(31204, Error, incompleteTypeCannotBeUsedInBuffer, "incomplete type '$0' cannot be used in a buffer") DIAGNOSTIC(31205, Error, incompleteTypeCannotBeUsedInUniformParameter, "incomplete type '$0' cannot be used in a uniform parameter") +DIAGNOSTIC(31206, Error, memoryQualifierNotAllowedOnANonImageTypeParameter, "modifier $0 is not allowed on a non image type parameter.") // Enums diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index af53b545f..b60e0a4ac 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3537,6 +3537,7 @@ void CLikeSourceEmitter::emitStructDeclarationsBlock(IRStructType* structType, b emitPackOffsetModifier(fieldKey, fieldType, packOffsetDecoration); } } + emitMemoryQualifiers(fieldKey); emitType(fieldType, getName(fieldKey)); emitSemantics(fieldKey, allowOffsetLayout); m_writer->emit(";\n"); diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index 46cdf2145..fa99ae061 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -385,6 +385,7 @@ public: /// Emit type attributes that should appear after, e.g., a `struct` keyword void emitPostKeywordTypeAttributes(IRInst* inst) { emitPostKeywordTypeAttributesImpl(inst); } + virtual void emitMemoryQualifiers(IRInst* /*varInst*/) {}; void emitInterpolationModifiers(IRInst* varInst, IRType* valueType, IRVarLayout* layout); void emitMeshShaderModifiers(IRInst* varInst); virtual void emitPackOffsetModifier(IRInst* /*varInst*/, IRType* /*valueType*/, IRPackOffsetDecoration* /*decoration*/) {}; diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index 7e5c84533..bbd869eda 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -114,6 +114,38 @@ void GLSLSourceEmitter::_requireGLSLVersion(int version) } } +void GLSLSourceEmitter::_emitMemoryQualifierDecorations(IRInst* varDecl) +{ + for (auto decoration : varDecl->getDecorations()) + { + if (as<IRGloballyCoherentDecoration>(decoration)) + { + m_writer->emit("coherent "); + } + else if (as<IRGLSLVolatileDecoration>(decoration)) + { + m_writer->emit("volatile "); + } + else if (as<IRGLSLRestrictDecoration>(decoration)) + { + m_writer->emit("restrict "); + } + else if (as<IRGLSLReadOnlyDecoration>(decoration)) + { + m_writer->emit("readonly "); + } + else if (as<IRGLSLWriteOnlyDecoration>(decoration)) + { + m_writer->emit("writeonly "); + } + } +} + +void GLSLSourceEmitter::emitMemoryQualifiers(IRInst* varDecl) +{ + _emitMemoryQualifierDecorations(varDecl); +} + void GLSLSourceEmitter::_emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSLStructuredBufferTypeBase* structuredBufferType) { // Shader storage buffer is an OpenGL 430 feature @@ -182,10 +214,7 @@ void GLSLSourceEmitter::_emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSL HLSLAppendStructuredBufferType - Write HLSLConsumeStructuredBufferType - TODO (JS): Its possible that this can be readonly, but we currently don't support on GLSL */ - if (varDecl->findDecoration<IRGloballyCoherentDecoration>()) - { - m_writer->emit("coherent "); - } + _emitMemoryQualifierDecorations(varDecl); if (as<IRHLSLStructuredBufferType>(structuredBufferType)) { m_writer->emit("readonly "); @@ -288,10 +317,7 @@ void GLSLSourceEmitter::emitSSBOHeader(IRGlobalParam* varDecl, IRType* bufferTyp } m_writer->emit(") "); - if (varDecl->findDecoration<IRGloballyCoherentDecoration>()) - { - m_writer->emit("coherent "); - } + _emitMemoryQualifierDecorations(varDecl); /* If the output type is a buffer, and we can determine it is only readonly we can prefix before @@ -461,6 +487,11 @@ void GLSLSourceEmitter::_emitGLSLImageFormatModifier(IRInst* var, IRTextureType* } else { + auto formatInfo = getImageFormatInfo(format); + if (formatInfo.scalarType == SLANG_SCALAR_TYPE_UINT64 || formatInfo.scalarType == SLANG_SCALAR_TYPE_INT64) + { + _requireGLSLExtension(UnownedStringSlice::fromLiteral("GL_EXT_shader_image_int64")); + } // If there is an explicit format specified, then we // should emit a `layout` modifier using the GLSL name // for the format. diff --git a/source/slang/slang-emit-glsl.h b/source/slang/slang-emit-glsl.h index 1a95cd346..610a961d2 100644 --- a/source/slang/slang-emit-glsl.h +++ b/source/slang/slang-emit-glsl.h @@ -35,6 +35,7 @@ protected: virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE; virtual void emitPackOffsetModifier(IRInst* varInst, IRType* valueType, IRPackOffsetDecoration* decoration) SLANG_OVERRIDE; + virtual void emitMemoryQualifiers(IRInst* varInst) SLANG_OVERRIDE; virtual void emitMeshShaderModifiersImpl(IRInst* varInst) SLANG_OVERRIDE; virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE; virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE; @@ -56,6 +57,7 @@ protected: virtual void emitSimpleValueImpl(IRInst* inst) SLANG_OVERRIDE; virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl) SLANG_OVERRIDE; + void _emitMemoryQualifierDecorations(IRInst* varDecl); void _emitGLSLTextureOrTextureSamplerType(IRTextureTypeBase* type, char const* baseName); void _emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSLStructuredBufferTypeBase* structuredBufferType); diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index c48f0e978..ddcd5ae4d 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -1765,6 +1765,40 @@ struct SPIRVEmitContext } } + void setImageFormatCapabilityAndExtension(SpvImageFormat format, SpvCapability_ setCapabilityMask) + { + switch (format) + { + case SpvImageFormatUnknown: + case SpvImageFormatRgba32f: + case SpvImageFormatRgba16f: + case SpvImageFormatR32f: + case SpvImageFormatRgba8: + case SpvImageFormatRgba8Snorm: + case SpvImageFormatRgba32i: + case SpvImageFormatRgba16i: + case SpvImageFormatRgba8i: + case SpvImageFormatR32i: + case SpvImageFormatRgba32ui: + case SpvImageFormatRgba16ui: + case SpvImageFormatRgba8ui: + case SpvImageFormatR32ui: + if(setCapabilityMask == SpvCapabilityShader) return; + requireSPIRVCapability(SpvCapabilityShader); + return; + case SpvImageFormatR64ui: + case SpvImageFormatR64i: + if(setCapabilityMask == SpvCapabilityInt64ImageEXT) return; + ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_shader_image_int64")); + requireSPIRVCapability(SpvCapabilityInt64ImageEXT); + return; + default: + if(setCapabilityMask == SpvCapabilityStorageImageExtendedFormats) return; + requireSPIRVCapability(SpvCapabilityStorageImageExtendedFormats); + return; + } + } + SpvInst* ensureTextureType(IRInst* assignee, IRTextureTypeBase* inst) { // Some untyped constants from OpTypeImage @@ -1895,6 +1929,8 @@ struct SPIRVEmitContext // // SPIR-V requires that the sampled/rw info on the image isn't unknown SLANG_ASSERT(sampled == sampledImage || sampled == readWriteImage); + if(isMultisampled) + requireSPIRVCapability(SpvCapabilityStorageImageMultisample); switch(dim) { case SpvDim1D: @@ -1933,9 +1969,7 @@ struct SPIRVEmitContext requireSPIRVCapability(SpvCapabilityStorageImageWriteWithoutFormat); } - auto formatCapability = getImageFormatCapability(format); - if (formatCapability != SpvCapabilityShader) - requireSPIRVCapability(formatCapability); + setImageFormatCapabilityAndExtension(format, SpvCapabilityShader); // // The op itself @@ -3266,6 +3300,30 @@ struct SPIRVEmitContext dstID, SpvDecorationCoherent); break; + case kIROp_GLSLVolatileDecoration: + emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationVolatile); + break; + case kIROp_GLSLRestrictDecoration: + emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationRestrict); + break; + case kIROp_GLSLReadOnlyDecoration: + emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationNonWritable); + break; + case kIROp_GLSLWriteOnlyDecoration: + emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationNonReadable); + break; // ... } diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 63f063154..254a411cd 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -660,6 +660,8 @@ INST(GetOptiXSbtDataPtr, getOptiXSbtDataPointer, 0, 0) INST(GetVulkanRayTracingPayloadLocation, GetVulkanRayTracingPayloadLocation, 1, 0) +INST(GetLegalizedSPIRVGlobalParamAddr, kIROp_GetLegalizedSPIRVGlobalParamAddr, 1, 0) + INST(MakeArrayList, makeArrayList, 0, 0) INST(MakeTensorView, makeTensorView, 0, 0) INST(AllocateTorchTensor, allocTorchTensor, 0, 0) @@ -856,6 +858,10 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(GlobalInputDecoration, output, 0, 0) INST(GLSLLocationDecoration, glslLocation, 1, 0) INST(GLSLOffsetDecoration, glslOffset, 1, 0) + INST(GLSLVolatileDecoration, glslVolatile, 1, 0) + INST(GLSLRestrictDecoration, glslRestrict, 1, 0) + INST(GLSLReadOnlyDecoration, glslReadonly, 1, 0) + INST(GLSLWriteOnlyDecoration, glslWriteonly, 1, 0) INST(PayloadDecoration, payload, 0, 0) /* Mesh Shader outputs */ diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 36f9159a8..c884dd35f 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -354,6 +354,10 @@ IR_SIMPLE_DECORATION(ReadNoneDecoration) IR_SIMPLE_DECORATION(NoSideEffectDecoration) IR_SIMPLE_DECORATION(EarlyDepthStencilDecoration) IR_SIMPLE_DECORATION(GloballyCoherentDecoration) +IR_SIMPLE_DECORATION(GLSLVolatileDecoration) +IR_SIMPLE_DECORATION(GLSLRestrictDecoration) +IR_SIMPLE_DECORATION(GLSLReadOnlyDecoration) +IR_SIMPLE_DECORATION(GLSLWriteOnlyDecoration) IR_SIMPLE_DECORATION(PreciseDecoration) IR_SIMPLE_DECORATION(PublicDecoration) IR_SIMPLE_DECORATION(HLSLExportDecoration) diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp index ca3729abc..68f1e02a2 100644 --- a/source/slang/slang-ir-spirv-legalize.cpp +++ b/source/slang/slang-ir-spirv-legalize.cpp @@ -217,7 +217,12 @@ struct SPIRVLegalizationContext : public SourceEmitterBase IRBuilder builder(user); builder.setInsertBefore(user); - if((as<IRGetElement>(user) || as<IRFieldExtract>(user)) && + if(user->getOp() == kIROp_GetLegalizedSPIRVGlobalParamAddr) + { + user->replaceUsesWith(use->get()); + user->removeAndDeallocate(); + } + else if((as<IRGetElement>(user) || as<IRFieldExtract>(user)) && use == user->getOperands()) { // If the use is the address operand of a getElement or FieldExtract, diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 3dd8da9f1..41638dc83 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -2217,6 +2217,22 @@ void addVarDecorations( { builder->addDynamicUniformDecoration(inst); } + else if (as<GLSLVolatileModifier>(mod)) + { + builder->addSimpleDecoration<IRGLSLVolatileDecoration>(inst); + } + else if (as<GLSLRestrictModifier>(mod)) + { + builder->addSimpleDecoration<IRGLSLRestrictDecoration>(inst); + } + else if (as<GLSLReadOnlyModifier>(mod)) + { + builder->addSimpleDecoration<IRGLSLReadOnlyDecoration>(inst); + } + else if (as<GLSLWriteOnlyModifier>(mod)) + { + builder->addSimpleDecoration<IRGLSLWriteOnlyDecoration>(inst); + } // TODO: what are other modifiers we need to propagate through? } if(auto t = composeGetters<IRMeshOutputType>(inst->getFullType(), &IROutTypeBase::getValueType)) diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index f7a0376ce..5b8a1af4f 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -7843,6 +7843,70 @@ namespace Slang parser->sink->diagnose(token, Diagnostics::invalidCUDASMVersion); return nullptr; } + static NodeBase* parseVolatileModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto hlslMod = parser->astBuilder->create<HLSLVolatileModifier>(); + hlslMod->keywordName = getName(parser, "volatile"); + hlslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(hlslMod); + + auto glslMod = parser->astBuilder->create<GLSLVolatileModifier>(); + glslMod->keywordName = getName(parser, "volatile"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } + + static NodeBase* parseCoherentModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto glslMod = parser->astBuilder->create<GloballyCoherentModifier>(); + glslMod->keywordName = getName(parser, "coherent"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } + + static NodeBase* parseRestrictModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto glslMod = parser->astBuilder->create<GLSLRestrictModifier>(); + glslMod->keywordName = getName(parser, "restrict"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } + + static NodeBase* parseReadonlyModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto glslMod = parser->astBuilder->create<GLSLReadOnlyModifier>(); + glslMod->keywordName = getName(parser, "readonly"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } + + static NodeBase* parseWriteonlyModifier(Parser* parser, void* /*userData*/) + { + ModifierListBuilder listBuilder; + + auto glslMod = parser->astBuilder->create<GLSLWriteOnlyModifier>(); + glslMod->keywordName = getName(parser, "writeonly"); + glslMod->loc = parser->tokenReader.peekLoc(); + listBuilder.add(glslMod); + + return listBuilder.getFirst(); + } static NodeBase* parseLayoutModifier(Parser* parser, void* /*userData*/) { @@ -7850,6 +7914,8 @@ namespace Slang GLSLLayoutLocalSizeAttribute* numThreadsAttrib = nullptr; + ImageFormat format; + listBuilder.add(parser->astBuilder->create<GLSLLayoutModifierGroupBegin>()); parser->ReadToken(TokenType::LParent); @@ -7923,6 +7989,12 @@ namespace Slang } } } + else if(findImageFormatByName(nameText.getUnownedSlice(), &format)) + { + auto attr = parser->astBuilder->create<FormatAttribute>(); + attr->format = format; + listBuilder.add(attr); + } else { Modifier* modifier = nullptr; @@ -8208,7 +8280,11 @@ namespace Slang _makeParseModifier("groupshared", HLSLGroupSharedModifier::kReflectClassInfo), _makeParseModifier("static", HLSLStaticModifier::kReflectClassInfo), _makeParseModifier("uniform", HLSLUniformModifier::kReflectClassInfo), - _makeParseModifier("volatile", HLSLVolatileModifier::kReflectClassInfo), + _makeParseModifier("volatile", parseVolatileModifier), + _makeParseModifier("coherent", parseCoherentModifier), + _makeParseModifier("restrict", parseRestrictModifier), + _makeParseModifier("readonly", parseReadonlyModifier), + _makeParseModifier("writeonly", parseWriteonlyModifier), _makeParseModifier("export", HLSLExportModifier::kReflectClassInfo), _makeParseModifier("dynamic_uniform", DynamicUniformModifier::kReflectClassInfo), |
