diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/core/hash.h | 28 | ||||
| -rw-r--r-- | source/slang/check.cpp | 35 | ||||
| -rw-r--r-- | source/slang/compiler.h | 33 | ||||
| -rw-r--r-- | source/slang/diagnostics.h | 2 | ||||
| -rw-r--r-- | source/slang/ir-legalize-types.cpp | 54 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 18 | ||||
| -rw-r--r-- | source/slang/reflection.cpp | 44 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 19 | ||||
| -rw-r--r-- | source/slang/syntax.cpp | 102 | ||||
| -rw-r--r-- | source/slang/syntax.h | 26 | ||||
| -rw-r--r-- | source/slang/type-defs.h | 13 |
11 files changed, 334 insertions, 40 deletions
diff --git a/source/core/hash.h b/source/core/hash.h index fc0bca737..83e99179b 100644 --- a/source/core/hash.h +++ b/source/core/hash.h @@ -7,6 +7,8 @@ namespace Slang { + typedef int HashCode; + inline int GetHashCode(double key) { return FloatAsInt((float)key); @@ -120,6 +122,32 @@ namespace Slang { return (left * 16777619) ^ right; } + + struct Hasher + { + public: + Hasher() {} + + template<typename T> + void hashValue(T const& value) + { + m_hashCode = combineHash(m_hashCode, GetHashCode(value)); + } + + template<typename T> + void hashObject(T const& object) + { + m_hashCode = combineHash(m_hashCode, object->GetHashCode()); + } + + HashCode getResult() const + { + return m_hashCode; + } + + private: + HashCode m_hashCode = 0; + }; } #endif diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 6a40f436a..d51785112 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -10763,6 +10763,41 @@ static bool doesParameterMatch( Slang::_specializeExistentialTypeParams(getLinkage(), m_globalExistentialSlots, args, sink); } + Type* Linkage::specializeType( + Type* unspecializedType, + Int argCount, + Type* const* args, + DiagnosticSink* sink) + { + // TODO: We should cache and re-use specialized types + // when the exact same arguments are provided again later. + + SemanticsVisitor visitor(this, sink); + + + ExistentialTypeSlots slots; + _collectExistentialTypeParamsRec(slots, unspecializedType); + + assert(slots.paramTypes.getCount() == argCount); + + for( Int aa = 0; aa < argCount; ++aa ) + { + auto argType = args[aa]; + + ExistentialTypeSlots::Arg arg; + arg.type = argType; + arg.witness = visitor.tryGetSubtypeWitness(argType, slots.paramTypes[aa]); + slots.args.add(arg); + } + + RefPtr<ExistentialSpecializedType> specializedType = new ExistentialSpecializedType(); + specializedType->baseType = unspecializedType; + specializedType->slots = slots; + + m_specializedTypes.add(specializedType); + + return specializedType; + } /// Specialize a program to global generic arguments RefPtr<Program> createSpecializedProgram( diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 233fa3d05..9b7e06be0 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -133,31 +133,6 @@ namespace Slang ComPtr<ISlangBlob> blob; }; - /// Collects information about existential type parameters and their arguments. - struct ExistentialTypeSlots - { - /// For each type parameter, holds the interface/existential type that constrains it. - List<RefPtr<Type>> paramTypes; - - /// An argument for an existential type parameter. - /// - /// Comprises a concrete type and a witness for its conformance to the desired - /// interface/existential type for the corresponding parameter. - /// - struct Arg - { - RefPtr<Type> type; - RefPtr<Val> witness; - }; - - /// Any arguments provided for the existential type parameters. - /// - /// It is possible for `args` to be empty even if `paramTypes` is non-empty; - /// that situation represents an unspecialized program or entry point. - /// - List<Arg> args; - }; - /// Information collected about global or entry-point shader parameters struct ShaderParamInfo { @@ -665,6 +640,12 @@ namespace Slang RefPtr<Expr> parseTypeString(String typeStr, RefPtr<Scope> scope); + Type* specializeType( + Type* unspecializedType, + Int argCount, + Type* const* args, + DiagnosticSink* sink); + /// Add a mew target amd return its index. UInt addTarget( CodeGenTarget target); @@ -754,6 +735,8 @@ namespace Slang /// Is the given module in the middle of being imported? bool isBeingImported(Module* module); + + List<RefPtr<Type>> m_specializedTypes; }; /// Shared functionality between front- and back-end compile requests. diff --git a/source/slang/diagnostics.h b/source/slang/diagnostics.h index 7d76ffa85..8e5ba809b 100644 --- a/source/slang/diagnostics.h +++ b/source/slang/diagnostics.h @@ -227,6 +227,8 @@ namespace Slang /// During propagation of an exception for an internal /// error, note that this source location was involved void noteInternalErrorLoc(SourceLoc const& loc); + + SlangResult getBlobIfNeeded(ISlangBlob** outBlob); }; /// An `ISlangWriter` that writes directly to a diagnostic sink. diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp index cfc495070..18039315e 100644 --- a/source/slang/ir-legalize-types.cpp +++ b/source/slang/ir-legalize-types.cpp @@ -127,7 +127,8 @@ static LegalVal declareVars( LegalVarChain const& varChain, UnownedStringSlice nameHint, IRInst* leafVar, - IRGlobalNameInfo* globalNameInfo); + IRGlobalNameInfo* globalNameInfo, + bool isSpecial); /// Unwrap a value with flavor `wrappedBuffer` /// @@ -1266,9 +1267,10 @@ static LegalVal legalizeLocalVar( IRVar* irLocalVar) { // Legalize the type for the variable's value + auto originalValueType = irLocalVar->getDataType()->getValueType(); auto legalValueType = legalizeType( context, - irLocalVar->getDataType()->getValueType()); + originalValueType); auto originalRate = irLocalVar->getRate(); @@ -1311,7 +1313,7 @@ static LegalVal legalizeLocalVar( UnownedStringSlice nameHint = findNameHint(irLocalVar); context->builder->setInsertBefore(irLocalVar); - LegalVal newVal = declareVars(context, kIROp_Var, legalValueType, typeLayout, varChain, nameHint, irLocalVar, nullptr); + LegalVal newVal = declareVars(context, kIROp_Var, legalValueType, typeLayout, varChain, nameHint, irLocalVar, nullptr, context->isSpecialType(originalValueType)); // Remove the old local var. irLocalVar->removeFromParent(); @@ -1345,7 +1347,7 @@ static LegalVal legalizeParam( UnownedStringSlice nameHint = findNameHint(originalParam); context->builder->setInsertBefore(originalParam); - auto newVal = declareVars(context, kIROp_Param, legalParamType, nullptr, LegalVarChain(), nameHint, originalParam, nullptr); + auto newVal = declareVars(context, kIROp_Param, legalParamType, nullptr, LegalVarChain(), nameHint, originalParam, nullptr, context->isSpecialType(originalParam->getDataType())); originalParam->removeFromParent(); context->replacedInstructions.add(originalParam); @@ -2219,12 +2221,31 @@ static LegalVal declareVars( IRTypeLegalizationContext* context, IROp op, LegalType type, - TypeLayout* typeLayout, - LegalVarChain const& varChain, + TypeLayout* inTypeLayout, + LegalVarChain const& inVarChain, UnownedStringSlice nameHint, IRInst* leafVar, - IRGlobalNameInfo* globalNameInfo) + IRGlobalNameInfo* globalNameInfo, + bool isSpecial) { + LegalVarChain varChain = inVarChain; + TypeLayout* typeLayout = inTypeLayout; + if( isSpecial ) + { + if( varChain.pendingChain ) + { + varChain.primaryChain = varChain.pendingChain; + varChain.pendingChain = nullptr; + } + if( typeLayout ) + { + if( auto pendingTypeLayout = typeLayout->pendingDataTypeLayout ) + { + typeLayout = pendingTypeLayout; + } + } + } + switch (type.flavor) { case LegalType::Flavor::none: @@ -2247,7 +2268,8 @@ static LegalVal declareVars( varChain, nameHint, leafVar, - globalNameInfo); + globalNameInfo, + isSpecial); return LegalVal::implicitDeref(val); } break; @@ -2255,8 +2277,8 @@ static LegalVal declareVars( case LegalType::Flavor::pair: { auto pairType = type.getPair(); - auto ordinaryVal = declareVars(context, op, pairType->ordinaryType, typeLayout, varChain, nameHint, leafVar, globalNameInfo); - auto specialVal = declareVars(context, op, pairType->specialType, typeLayout, varChain, nameHint, leafVar, globalNameInfo); + auto ordinaryVal = declareVars(context, op, pairType->ordinaryType, typeLayout, varChain, nameHint, leafVar, globalNameInfo, false); + auto specialVal = declareVars(context, op, pairType->specialType, typeLayout, varChain, nameHint, leafVar, globalNameInfo, true); return LegalVal::pair(ordinaryVal, specialVal, pairType->pairInfo); } @@ -2305,7 +2327,8 @@ static LegalVal declareVars( newVarChain, fieldNameHint, ee.key, - globalNameInfo); + globalNameInfo, + true); TuplePseudoVal::Element element; element.key = ee.key; @@ -2348,9 +2371,10 @@ static LegalVal legalizeGlobalVar( IRGlobalVar* irGlobalVar) { // Legalize the type for the variable's value + auto originalValueType = irGlobalVar->getDataType()->getValueType(); auto legalValueType = legalizeType( context, - irGlobalVar->getDataType()->getValueType()); + originalValueType); switch (legalValueType.flavor) { @@ -2373,7 +2397,7 @@ static LegalVal legalizeGlobalVar( UnownedStringSlice nameHint = findNameHint(irGlobalVar); context->builder->setInsertBefore(irGlobalVar); - LegalVal newVal = declareVars(context, kIROp_GlobalVar, legalValueType, nullptr, LegalVarChain(), nameHint, irGlobalVar, &globalNameInfo); + LegalVal newVal = declareVars(context, kIROp_GlobalVar, legalValueType, nullptr, LegalVarChain(), nameHint, irGlobalVar, &globalNameInfo, context->isSpecialType(originalValueType)); // Register the new value as the replacement for the old registerLegalizedValue(context, irGlobalVar, newVal); @@ -2417,7 +2441,7 @@ static LegalVal legalizeGlobalConstant( UnownedStringSlice nameHint = findNameHint(irGlobalConstant); context->builder->setInsertBefore(irGlobalConstant); - LegalVal newVal = declareVars(context, kIROp_GlobalConstant, legalValueType, nullptr, LegalVarChain(), nameHint, irGlobalConstant, &globalNameInfo); + LegalVal newVal = declareVars(context, kIROp_GlobalConstant, legalValueType, nullptr, LegalVarChain(), nameHint, irGlobalConstant, &globalNameInfo, context->isSpecialType(irGlobalConstant->getDataType())); // Register the new value as the replacement for the old registerLegalizedValue(context, irGlobalConstant, newVal); @@ -2466,7 +2490,7 @@ static LegalVal legalizeGlobalParam( UnownedStringSlice nameHint = findNameHint(irGlobalParam); context->builder->setInsertBefore(irGlobalParam); - LegalVal newVal = declareVars(context, kIROp_GlobalParam, legalValueType, typeLayout, varChain, nameHint, irGlobalParam, &globalNameInfo); + LegalVal newVal = declareVars(context, kIROp_GlobalParam, legalValueType, typeLayout, varChain, nameHint, irGlobalParam, &globalNameInfo, context->isSpecialType(irGlobalParam->getDataType())); // Register the new value as the replacement for the old registerLegalizedValue(context, irGlobalParam, newVal); diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 2e9915669..a7be244c8 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -1608,6 +1608,24 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower return LoweredValInfo::simple(irType); } + LoweredValInfo visitExistentialSpecializedType(ExistentialSpecializedType* type) + { + auto irBaseType = lowerType(context, type->baseType); + + List<IRInst*> slotArgs; + for(auto arg : type->slots.args) + { + auto irArgType = lowerType(context, arg.type); + auto irArgWitness = lowerSimpleVal(context, arg.witness); + + slotArgs.add(irArgType); + slotArgs.add(irArgWitness); + } + + auto irType = getBuilder()->getBindExistentialsType(irBaseType, slotArgs.getCount(), slotArgs.getBuffer()); + return LoweredValInfo::simple(irType); + } + // We do not expect to encounter the following types in ASTs that have // passed front-end semantic checking. #define UNEXPECTED_CASE(NAME) IRType* visit##NAME(NAME*) { SLANG_UNEXPECTED(#NAME); UNREACHABLE_RETURN(nullptr); } diff --git a/source/slang/reflection.cpp b/source/slang/reflection.cpp index 326a27854..4ac48d2e7 100644 --- a/source/slang/reflection.cpp +++ b/source/slang/reflection.cpp @@ -860,6 +860,24 @@ SLANG_API int spReflectionTypeLayout_getGenericParamIndex(SlangReflectionTypeLay } } +SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getPendingDataTypeLayout(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + auto pendingDataTypeLayout = typeLayout->pendingDataTypeLayout.Ptr(); + return convert(pendingDataTypeLayout); +} + +SLANG_API SlangReflectionVariableLayout* spReflectionVariableLayout_getPendingDataLayout(SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return nullptr; + + auto pendingDataLayout = varLayout->pendingVarLayout.Ptr(); + return convert(pendingDataLayout); +} + // Variable Reflection @@ -1381,3 +1399,29 @@ SLANG_API size_t spReflection_getGlobalConstantBufferSize(SlangReflection* inPro if (!uniform) return 0; return getReflectionSize(uniform->count); } + +SLANG_API SlangReflectionType* spReflection_specializeType( + SlangReflection* inProgramLayout, + SlangReflectionType* inType, + SlangInt specializationArgCount, + SlangReflectionType* const* specializationArgs, + ISlangBlob** outDiagnostics) +{ + auto programLayout = convert(inProgramLayout); + if(!programLayout) return nullptr; + + auto unspecializedType = convert(inType); + if(!unspecializedType) return nullptr; + + auto linkage = programLayout->getProgram()->getLinkage(); + + DiagnosticSink sink; + sink.sourceManager = linkage->getSourceManager(); + + auto specializedType = linkage->specializeType(unspecializedType, specializationArgCount, (Type* const*) specializationArgs, &sink); + + sink.getBlobIfNeeded(outDiagnostics); + + return convert(specializedType); +} + diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 7556ac9b2..c78a27f54 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -567,6 +567,9 @@ Type* Program::getTypeFromString(String typeStr, DiagnosticSink* sink) return type; } + + + CompileRequestBase::CompileRequestBase( Linkage* linkage, DiagnosticSink* sink) @@ -1444,6 +1447,22 @@ void DiagnosticSink::noteInternalErrorLoc(SourceLoc const& loc) internalErrorLocsNoted++; } +SlangResult DiagnosticSink::getBlobIfNeeded(ISlangBlob** outBlob) +{ + // If the client doesn't want an output blob, there is nothing to do. + // + if(!outBlob) return SLANG_OK; + + // If there were no errors, and there was no diagnostic output, there is nothing to do. + if(!GetErrorCount() && !outputBuffer.getLength()) return SLANG_OK; + + Slang::ComPtr<ISlangBlob> blob = Slang::StringUtil::createStringBlob(outputBuffer); + *outBlob = blob.detach(); + + return SLANG_OK; +} + + Session* CompileRequestBase::getSession() { return getLinkage()->getSession(); diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index c069c69d7..17c85175d 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -2757,7 +2757,109 @@ char const* getGLSLNameForImageFormat(ImageFormat format) } } +// +// ExistentialSpecializedType +// + +String ExistentialSpecializedType::ToString() +{ + String result; + result.append("__ExistentialSpecializedType("); + result.append(baseType->ToString()); + for( auto arg : slots.args ) + { + result.append(", "); + result.append(arg.type->ToString()); + } + result.append(")"); + return result; +} + +bool ExistentialSpecializedType::EqualsImpl(Type * type) +{ + auto other = as<ExistentialSpecializedType>(type); + if(!other) + return false; + + if(!baseType->Equals(other->baseType)) + return false; + auto argCount = slots.args.getCount(); + if(argCount != other->slots.args.getCount()) + return false; + for( Index ii = 0; ii < argCount; ++ii ) + { + if(!slots.args[ii].type->Equals(other->slots.args[ii].type)) + return false; + + if(!slots.args[ii].witness->EqualsVal(other->slots.args[ii].witness)) + return false; + } + return true; +} + +int ExistentialSpecializedType::GetHashCode() +{ + Hasher hasher; + hasher.hashObject(baseType); + for(auto arg : slots.args) + { + hasher.hashObject(arg.type); + hasher.hashObject(arg.witness); + } + return hasher.getResult(); +} + +RefPtr<Type> ExistentialSpecializedType::CreateCanonicalType() +{ + RefPtr<ExistentialSpecializedType> canType = new ExistentialSpecializedType(); + canType->setSession(getSession()); + + canType->baseType = baseType->GetCanonicalType(); + for( auto paramType : slots.paramTypes ) + { + canType->slots.paramTypes.add( paramType->GetCanonicalType() ); + } + for( auto arg : slots.args ) + { + ExistentialTypeSlots::Arg canArg; + canArg.type = arg.type->GetCanonicalType(); + canArg.witness = arg.witness; + canType->slots.args.add(canArg); + } + return canType; +} + +RefPtr<Val> ExistentialSpecializedType::SubstituteImpl(SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + + auto substBaseType = baseType->SubstituteImpl(subst, &diff).as<Type>(); + + ExistentialTypeSlots substSlots; + for( auto paramType : slots.paramTypes ) + { + substSlots.paramTypes.add( paramType->SubstituteImpl(subst, &diff).as<Type>() ); + } + for( auto arg : slots.args ) + { + ExistentialTypeSlots::Arg substArg; + substArg.type = arg.type->SubstituteImpl(subst, &diff).as<Type>(); + substArg.witness = arg.witness->SubstituteImpl(subst, &diff); + substSlots.args.add(substArg); + } + + if(!diff) + return this; + + (*ioDiff)++; + + RefPtr<ExistentialSpecializedType> substType = new ExistentialSpecializedType(); + substType->setSession(getSession()); + substType->baseType = substBaseType; + substType->slots = substSlots; + return substType; +} } // namespace Slang diff --git a/source/slang/syntax.h b/source/slang/syntax.h index eb7cee40a..aa3944d0a 100644 --- a/source/slang/syntax.h +++ b/source/slang/syntax.h @@ -1104,6 +1104,32 @@ namespace Slang typedef Dictionary<unsigned int, RefPtr<RefObject>> AttributeArgumentValueDict; + /// Collects information about existential type parameters and their arguments. + struct ExistentialTypeSlots + { + /// For each type parameter, holds the interface/existential type that constrains it. + List<RefPtr<Type>> paramTypes; + + /// An argument for an existential type parameter. + /// + /// Comprises a concrete type and a witness for its conformance to the desired + /// interface/existential type for the corresponding parameter. + /// + struct Arg + { + RefPtr<Type> type; + RefPtr<Val> witness; + }; + + /// Any arguments provided for the existential type parameters. + /// + /// It is possible for `args` to be empty even if `paramTypes` is non-empty; + /// that situation represents an unspecialized program or entry point. + /// + List<Arg> args; + }; + + // Generate class definition for all syntax classes #define SYNTAX_FIELD(TYPE, NAME) TYPE NAME; #define FIELD(TYPE, NAME) TYPE NAME; diff --git a/source/slang/type-defs.h b/source/slang/type-defs.h index 2d376d754..d0c00c73a 100644 --- a/source/slang/type-defs.h +++ b/source/slang/type-defs.h @@ -475,3 +475,16 @@ RAW( virtual RefPtr<Val> SubstituteImpl(SubstitutionSet subst, int* ioDiff) override; ) END_SYNTAX_CLASS() + +SYNTAX_CLASS(ExistentialSpecializedType, Type) +RAW( + RefPtr<Type> baseType; + ExistentialTypeSlots slots; + + virtual String ToString() override; + virtual bool EqualsImpl(Type * type) override; + virtual int GetHashCode() override; + virtual RefPtr<Type> CreateCanonicalType() override; + virtual RefPtr<Val> SubstituteImpl(SubstitutionSet subst, int* ioDiff) override; +) +END_SYNTAX_CLASS()
\ No newline at end of file |
