diff options
| author | Yong He <yonghe@outlook.com> | 2020-08-28 09:04:55 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-28 09:04:55 -0700 |
| commit | ab5b0a7f9fbc47f7c51a7ec4a20ac0be55333e93 (patch) | |
| tree | abeb62d38f2af31e39a6dac216bc77e88af8ffbc /source | |
| parent | e9bf8de3123563df6f2ca4d3b99291c6a8c99d5d (diff) | |
Enable lower-generics pass universally. (#1518)
* Enable lower-generics pass universally.
* Exclude builtin interfaces and functions from lower-generics pass.
* Update stdlib.
* Fixup.
* Fixes handling of nested intrinsic generic functions.
* Fixes.
* Fixes.
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/core.meta.slang | 12 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 1 | ||||
| -rw-r--r-- | source/slang/slang-ast-modifier.h | 6 | ||||
| -rwxr-xr-x | source/slang/slang-compiler.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 8 | ||||
| -rw-r--r-- | source/slang/slang-emit-cpp.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-emit.cpp | 18 | ||||
| -rw-r--r-- | source/slang/slang-ir-generics-lowering-context.cpp | 8 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 14 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-generic-call.cpp | 27 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-generic-function.cpp | 18 | ||||
| -rw-r--r-- | source/slang/slang-ir-witness-table-wrapper.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 17 | ||||
| -rw-r--r-- | source/slang/slang-ir.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-options.cpp | 4 |
17 files changed, 156 insertions, 24 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 5ba31fc33..0eaf5cb1a 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -19,10 +19,12 @@ syntax globallycoherent : GloballyCoherentModifier; // A type that can be used as an operand for builtins [sealed] +[builtin] interface __BuiltinType {} // A type that can be used for arithmetic operations [sealed] +[builtin] interface __BuiltinArithmeticType : __BuiltinType { /// Initialize from a 32-bit signed integer value. @@ -31,23 +33,28 @@ interface __BuiltinArithmeticType : __BuiltinType /// A type that can be used for logical/bitwsie operations [sealed] +[builtin] interface __BuiltinLogicalType : __BuiltinType {} // A type that logically has a sign (positive/negative/zero) [sealed] +[builtin] interface __BuiltinSignedArithmeticType : __BuiltinArithmeticType {} // A type that can represent integers [sealed] +[builtin] interface __BuiltinIntegerType : __BuiltinArithmeticType {} // A type that can represent non-integers [sealed] +[builtin] interface __BuiltinRealType : __BuiltinSignedArithmeticType {} // A type that uses a floating-point representation [sealed] +[builtin] interface __BuiltinFloatingPointType : __BuiltinRealType { /// Initialize from a 32-bit floating-point value. @@ -58,6 +65,7 @@ interface __BuiltinFloatingPointType : __BuiltinRealType } // A type resulting from an `enum` declaration. +[builtin] __magic_type(EnumTypeType) interface __EnumType { @@ -112,6 +120,7 @@ extension __EnumType // A type resulting from an `enum` declaration // with the `[flags]` attribute. +[builtin] interface __FlagsEnumType : __EnumType { }; @@ -2042,3 +2051,6 @@ attribute_syntax [open] : OpenAttribute; __attributeTarget(InterfaceDecl) attribute_syntax [anyValueSize(size:int)] : AnyValueSizeAttribute; + +__attributeTarget(DeclBase) +attribute_syntax [builtin] : BuiltinAttribute; diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 3a574bc42..167a60b1e 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -4302,6 +4302,7 @@ void DispatchMesh<P>(uint threadGroupCountX, uint threadGroupCountY, uint thread // But slang enums are always 'enum class like', so I use an empty struct type here [sealed] +[builtin] interface __BuiltinSamplerFeedbackType {}; [sealed] diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index eb30e880e..6a80d8722 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -878,6 +878,12 @@ class OpenAttribute : public InheritanceControlAttribute { SLANG_CLASS(OpenAttri /// An attribute that marks a type declaration as disallowing the type to be inherited from in other modules. class SealedAttribute : public InheritanceControlAttribute { SLANG_CLASS(SealedAttribute) }; + /// An attribute that marks a decl as a compiler built-in object. +class BuiltinAttribute : public Attribute +{ + SLANG_CLASS(BuiltinAttribute) +}; + /// An attribute that defines the size of `AnyValue` type to represent a polymoprhic value that conforms to /// the decorated interface type. class AnyValueSizeAttribute : public Attribute diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index ac22270f8..88bf7d2b3 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1760,8 +1760,8 @@ namespace Slang bool shouldEmitSPIRVDirectly = false; - // If true will allow generating dynamic dispatch code for generics. - bool allowDynamicCode = false; + // If true will disable generics/existential value specialization pass. + bool disableSpecialization = false; String m_dumpIntermediatePrefix; diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 9e9117dcd..d85085639 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -299,7 +299,6 @@ void CLikeSourceEmitter::_emitType(IRType* type, EDeclarator* declarator) void CLikeSourceEmitter::emitWitnessTable(IRWitnessTable* witnessTable) { SLANG_UNUSED(witnessTable); - SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "Unimplemented emit: IROpWitnessTable."); } void CLikeSourceEmitter::emitInterface(IRInterfaceType* interfaceType) @@ -3824,13 +3823,6 @@ void CLikeSourceEmitter::ensureGlobalInst(ComputeEmitActionsContext* ctx, IRInst // Skip certain instructions that don't affect output. switch(inst->op) { - case kIROp_WitnessTable: - // Only skip witness tables when we are generating - // static code. - if (!m_compileRequest->allowDynamicCode) - return; - break; - case kIROp_InterfaceRequirementEntry: case kIROp_Generic: return; diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index e7c90f657..1f40a2640 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -1607,6 +1607,11 @@ void CPPSourceEmitter::emitParamTypeImpl(IRType* type, String const& name) void CPPSourceEmitter::emitWitnessTable(IRWitnessTable* witnessTable) { auto interfaceType = cast<IRInterfaceType>(witnessTable->getOperand(0)); + + // Ignore witness tables for builtin interface types. + if (isBuiltin(interfaceType)) + return; + auto witnessTableItems = witnessTable->getChildren(); _maybeEmitWitnessTableTypeDefinition(interfaceType); diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 0b09338b3..c614a7a50 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -302,20 +302,20 @@ Result linkAndOptimizeIR( // perform specialization of functions based on parameter // values that need to be compile-time constants. // - if (!compileRequest->allowDynamicCode) + if (!compileRequest->disableSpecialization) specializeModule(irModule); + eliminateDeadCode(irModule); + switch (target) { case CodeGenTarget::CPPSource: // For targets that supports dynamic dispatch, we need to lower the // generics / interface types to ordinary functions and types using // function pointers. - if (compileRequest->allowDynamicCode) - { - lowerGenerics(irModule, sink); - dumpIRIfEnabled(compileRequest, irModule, "LOWER-GENERICS"); - } + dumpIRIfEnabled(compileRequest, irModule, "BEFORE-LOWER-GENERICS"); + lowerGenerics(irModule, sink); + dumpIRIfEnabled(compileRequest, irModule, "LOWER-GENERICS"); break; default: break; @@ -658,12 +658,16 @@ Result linkAndOptimizeIR( break; } - if (!compileRequest->allowDynamicCode) + switch (target) { + case CodeGenTarget::CPPSource: + break; + default: // For all targets that don't support true dynamic dispatch through // witness tables, we need to eliminate witness tables from the IR so // that they don't keep symbols live that we don't actually need. stripWitnessTables(irModule); + break; } #if 0 diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp index 7e78bcfbd..26581c653 100644 --- a/source/slang/slang-ir-generics-lowering-context.cpp +++ b/source/slang/slang-ir-generics-lowering-context.cpp @@ -142,6 +142,8 @@ namespace Slang { if (auto anyValueSizeDecor = paramType->findDecoration<IRTypeConstraintDecoration>()) { + if (isBuiltin(anyValueSizeDecor->getConstraintType())) + return (IRType*)paramType; anyValueSize = getInterfaceAnyValueSize(anyValueSizeDecor->getConstraintType(), paramType->sourceLoc); return builder->getAnyValueType(anyValueSize); } @@ -149,6 +151,8 @@ namespace Slang return builder->getAnyValueType(kInvalidAnyValueSize); } case kIROp_ThisType: + if (isBuiltin(cast<IRThisType>(paramType)->getConstraintType())) + return (IRType*)paramType; anyValueSize = getInterfaceAnyValueSize( cast<IRThisType>(paramType)->getConstraintType(), paramType->sourceLoc); @@ -159,6 +163,8 @@ namespace Slang } case kIROp_InterfaceType: { + if (isBuiltin(paramType)) + return (IRType*)paramType; // An existential type translates into a tuple of (AnyValue, WitnessTable, RTTI*) anyValueSize = getInterfaceAnyValueSize(paramType, paramType->sourceLoc); auto anyValueType = builder->getAnyValueType(anyValueSize); @@ -172,6 +178,8 @@ namespace Slang auto lookupInterface = static_cast<IRLookupWitnessMethod*>(paramType); auto interfaceType = cast<IRInterfaceType>(cast<IRWitnessTableType>( lookupInterface->getWitnessTable()->getDataType())->getConformanceType()); + if (isBuiltin(interfaceType)) + return (IRType*)paramType; // Make sure we are looking up inside the original interface type (prior to lowering). // Only in the original interface type will an associated type entry have an IRAssociatedType value. // We need to extract AnyValueSize from this IRAssociatedType. diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 05ad07668..4074a435f 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -561,6 +561,8 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(TypeConstraintDecoration, TypeConstraintDecoration, 1, 0) INST_RANGE(LinkageDecoration, ImportDecoration, ExportDecoration) + INST(BuiltinDecoration, BuiltinDecoration, 0, 0) + INST(SemanticDecoration, semantic, 2, 0) INST_RANGE(Decoration, HighLevelDeclDecoration, SemanticDecoration) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 65a2dd4a6..ecffbd4d7 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -423,6 +423,15 @@ struct IRNaturalOffsetDecoration : IRDecoration IRIntegerValue getOffset() { return getOffsetOperand()->getValue(); } }; +struct IRBuiltinDecoration : IRDecoration +{ + enum + { + kOp = kIROp_BuiltinDecoration + }; + IR_LEAF_ISA(BuiltinDecoration) +}; + // An instruction that specializes another IR value // (representing a generic) to a particular set of generic arguments // (instructions representing types, witness tables, etc.) @@ -2457,6 +2466,11 @@ struct IRBuilder { addDecoration(inst, kIROp_TypeConstraintDecoration, constraintType); } + + void addBuiltinDecoration(IRInst* inst) + { + addDecoration(inst, kIROp_BuiltinDecoration); + } }; void addHoistableInst( diff --git a/source/slang/slang-ir-lower-generic-call.cpp b/source/slang/slang-ir-lower-generic-call.cpp index 90216b915..e3080c612 100644 --- a/source/slang/slang-ir-lower-generic-call.cpp +++ b/source/slang/slang-ir-lower-generic-call.cpp @@ -170,6 +170,14 @@ namespace Slang } } + IRInst* findInnerMostSpecializingBase(IRSpecialize* inst) + { + auto result = inst->getBase(); + while (auto specialize = as<IRSpecialize>(result)) + result = specialize->getBase(); + return result; + } + void lowerCallToSpecializedFunc(IRCall* callInst, IRSpecialize* specializeInst) { // If we see a call(specialize(gFunc, Targs), args), @@ -180,9 +188,23 @@ namespace Slang // them here. if (loweredFunc->op == kIROp_Generic) { - // This is an intrinsic function, don't transform. return; } + else if (loweredFunc->op == kIROp_Specialize) + { + // All nested generic functions are supposed to be flattend before this pass. + // If they are not, they represent an intrinsic function that should not be + // modified in this pass. + auto innerMostFunc = findInnerMostSpecializingBase(static_cast<IRSpecialize*>(loweredFunc)); + if (innerMostFunc && innerMostFunc->op == kIROp_Generic) + { + innerMostFunc = + findInnerMostGenericReturnVal(static_cast<IRGeneric*>(innerMostFunc)); + } + if (innerMostFunc->findDecoration<IRTargetIntrinsicDecoration>()) + return; + SLANG_UNEXPECTED("Nested generics specialization."); + } IRFuncType* funcType = cast<IRFuncType>(loweredFunc->getDataType()); translateCallInst(callInst, funcType, loweredFunc, specializeInst); } @@ -193,6 +215,9 @@ namespace Slang // all occurences of associatedtypes. auto funcType = cast<IRFuncType>(lookupInst->getDataType()); auto loweredFunc = lookupInst; + if (isBuiltin(cast<IRWitnessTableType>( + lookupInst->getWitnessTable()->getDataType())->getConformanceType())) + return; translateCallInst(callInst, funcType, loweredFunc, nullptr); } diff --git a/source/slang/slang-ir-lower-generic-function.cpp b/source/slang/slang-ir-lower-generic-function.cpp index f9a7e0a24..c02e9e3d6 100644 --- a/source/slang/slang-ir-lower-generic-function.cpp +++ b/source/slang/slang-ir-lower-generic-function.cpp @@ -21,9 +21,21 @@ namespace Slang IRInst* result = nullptr; if (sharedContext->loweredGenericFunctions.TryGetValue(genericValue, result)) return result; + // Do not lower intrinsic functions. + if (genericValue->findDecoration<IRTargetIntrinsicDecoration>()) + return genericValue; auto genericParent = as<IRGeneric>(genericValue); SLANG_ASSERT(genericParent); auto func = as<IRFunc>(findGenericReturnVal(genericParent)); + if (!func) + { + // Nested generic functions are supposed to be flattened before entering + // this pass. The reason we are still seeing them must be that they are + // intrinsic functions. In this case we ignore the function. + SLANG_ASSERT(findInnerMostGenericReturnVal(genericParent) + ->findDecoration<IRTargetIntrinsicDecoration>() != nullptr); + return genericValue; + } SLANG_ASSERT(func); if (!func->isDefinition()) { @@ -133,7 +145,9 @@ namespace Slang return loweredType; if (sharedContext->mapLoweredInterfaceToOriginal.ContainsKey(interfaceType)) return interfaceType; - + // Do not lower intrinsic interfaces. + if (isBuiltin(interfaceType)) + return interfaceType; List<IRInterfaceRequirementEntry*> newEntries; IRBuilder builder; @@ -189,6 +203,8 @@ namespace Slang auto interfaceType = maybeLowerInterfaceType(cast<IRInterfaceType>(witnessTable->getConformanceType())); if (interfaceType != witnessTable->getConformanceType()) witnessTable->setConformanceType(interfaceType); + if (isBuiltin(interfaceType)) + return; for (auto child : witnessTable->getChildren()) { auto entry = as<IRWitnessTableEntry>(child); diff --git a/source/slang/slang-ir-witness-table-wrapper.cpp b/source/slang/slang-ir-witness-table-wrapper.cpp index 084571642..219513fc7 100644 --- a/source/slang/slang-ir-witness-table-wrapper.cpp +++ b/source/slang/slang-ir-witness-table-wrapper.cpp @@ -174,6 +174,8 @@ namespace Slang void lowerWitnessTable(IRWitnessTable* witnessTable) { auto interfaceType = cast<IRInterfaceType>(witnessTable->getConformanceType()); + if (isBuiltin(interfaceType)) + return; for (auto child : witnessTable->getChildren()) { auto entry = as<IRWitnessTableEntry>(child); diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index c5943da3c..2f27bbebc 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -5263,6 +5263,7 @@ namespace Slang case kIROp_GlobalGenericParam: case kIROp_WitnessTable: case kIROp_WitnessTableEntry: + case kIROp_InterfaceRequirementEntry: case kIROp_Block: return false; @@ -5384,6 +5385,14 @@ namespace Slang auto val = returnInst->getVal(); return val; } + + IRInst* findInnerMostGenericReturnVal(IRGeneric* generic) + { + IRInst* inst = generic; + while (auto genericInst = as<IRGeneric>(inst)) + inst = findGenericReturnVal(genericInst); + return inst; + } IRGeneric* findSpecializedGeneric(IRSpecialize* specialize) { @@ -5488,9 +5497,15 @@ namespace Slang { return ptrType && ptrType->op == kIROp_PtrType && ptrType->getOperand(0) == elementType; } + bool isPointerOfType(IRInst* ptrType, IROp opCode) { return ptrType && ptrType->op == kIROp_PtrType && ptrType->getOperand(0) && ptrType->getOperand(0)->op == opCode; } -} + bool isBuiltin(IRInst* inst) + { + return inst->findDecoration<IRBuiltinDecoration>() != nullptr; + } +} // namespace Slang + diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index d6c655a7c..2c6ad244b 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -1362,6 +1362,8 @@ struct IRGeneric : IRGlobalValueWithParams // Find the value that is returned from a generic, so that // a pass can glean information from it. IRInst* findGenericReturnVal(IRGeneric* generic); +// Recursively find the inner most generic return value. +IRInst* findInnerMostGenericReturnVal(IRGeneric* generic); struct IRSpecialize; IRGeneric* findSpecializedGeneric(IRSpecialize* specialize); @@ -1465,6 +1467,9 @@ bool isPointerOfType(IRInst* ptrType, IRInst* elementType); // True if ptrType is a pointer type to a type of opCode bool isPointerOfType(IRInst* ptrType, IROp opCode); + // True if the IR inst represents a builtin object (e.g. __BuiltinFloatingPointType). +bool isBuiltin(IRInst* inst); + } #endif diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 6361c135a..f7c71adf9 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -5942,6 +5942,16 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return LoweredValInfo::simple(assocType); } + Dictionary<IRType*, IRWitnessTable*> placeholderWitnessTables; + IRWitnessTable* getPlaceholderWitnessTable(IRType* type) + { + if (auto rs = placeholderWitnessTables.TryGetValue(type)) + return *rs; + auto w = getBuilder()->createWitnessTable(type); + placeholderWitnessTables[type] = w; + return w; + } + LoweredValInfo visitInterfaceDecl(InterfaceDecl* decl) { // The members of an interface will turn into the keys that will @@ -5997,6 +6007,14 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> for (auto assocTypeDecl : decl->getMembersOfType<AssocTypeDecl>()) { ensureDecl(subContext, assocTypeDecl); + // The type constraints on an associated type lowers to a dummy + // witness table, since only the type of the witness table matters. + for (auto constraintDecl : assocTypeDecl->getMembersOfType<TypeConstraintDecl>()) + { + auto constraintInterfaceType = lowerType(context, constraintDecl->getSup().type); + auto placeholderWitnessTable = getPlaceholderWitnessTable(constraintInterfaceType); + setValue(context, constraintDecl, LoweredValInfo::simple(placeholderWitnessTable)); + } } UInt entryIndex = 0; @@ -6036,9 +6054,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> for (auto constraintDecl : associatedTypeDecl->getMembersOfType<TypeConstraintDecl>()) { auto constraintKey = getInterfaceRequirementKey(constraintDecl); + auto constraintInterfaceType = + lowerType(context, constraintDecl->getSup().type); + auto witnessTableType = + getBuilder()->getWitnessTableType(constraintInterfaceType); irInterface->setOperand(entryIndex, subBuilder->createInterfaceRequirementEntry(constraintKey, - getBuilder()->getWitnessTableType(lowerType(context, constraintDecl->getSup().type)))); + witnessTableType)); entryIndex++; } } @@ -6057,7 +6079,10 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> { subBuilder->addAnyValueSizeDecoration(irInterface, anyValueSizeAttr->size); } - + if (auto builtinAttr = decl->findModifier<BuiltinAttribute>()) + { + subBuilder->addBuiltinDecoration(irInterface); + } subBuilder->setInsertInto(irInterface); // TODO: are there any interface members that should be // nested inside the interface type itself? diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 5da87bde6..cae3397dd 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -559,9 +559,9 @@ struct OptionsParser { requestImpl->getFrontEndReq()->useSerialIRBottleneck = true; } - else if (argStr == "-allow-dynamic-code") + else if (argStr == "-disable-specialization") { - requestImpl->getBackEndReq()->allowDynamicCode = true; + requestImpl->getBackEndReq()->disableSpecialization = true; } else if (argStr == "-verbose-paths") { |
