diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2024-10-29 14:49:26 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-29 14:49:26 +0800 |
| commit | f65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch) | |
| tree | ea1d61342cd29368e19135000ec2948813096205 /source/slang/slang-ir-generics-lowering-context.cpp | |
| parent | a729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff) | |
format
* format
* Minor test fixes
* enable checking cpp format in ci
Diffstat (limited to 'source/slang/slang-ir-generics-lowering-context.cpp')
| -rw-r--r-- | source/slang/slang-ir-generics-lowering-context.cpp | 394 |
1 files changed, 209 insertions, 185 deletions
diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp index a7f75d7be..e02b54ecc 100644 --- a/source/slang/slang-ir-generics-lowering-context.cpp +++ b/source/slang/slang-ir-generics-lowering-context.cpp @@ -1,4 +1,4 @@ -//slang-ir-generics-lowering-context.cpp +// slang-ir-generics-lowering-context.cpp #include "slang-ir-generics-lowering-context.h" @@ -7,18 +7,17 @@ namespace Slang { - bool isPolymorphicType(IRInst* typeInst) +bool isPolymorphicType(IRInst* typeInst) +{ + if (as<IRParam>(typeInst) && as<IRTypeType>(typeInst->getDataType())) + return true; + switch (typeInst->getOp()) { - if (as<IRParam>(typeInst) && as<IRTypeType>(typeInst->getDataType())) - return true; - switch (typeInst->getOp()) - { - case kIROp_ThisType: - case kIROp_AssociatedType: - case kIROp_InterfaceType: - case kIROp_LookupWitness: - return true; - case kIROp_Specialize: + case kIROp_ThisType: + case kIROp_AssociatedType: + case kIROp_InterfaceType: + case kIROp_LookupWitness: return true; + case kIROp_Specialize: { for (UInt i = 0; i < typeInst->getOperandCount(); i++) { @@ -27,138 +26,141 @@ namespace Slang } return false; } - default: - break; - } - if (auto ptrType = as<IRPtrTypeBase>(typeInst)) - { - return isPolymorphicType(ptrType->getValueType()); - } - return false; + default: break; } - - bool isTypeValue(IRInst* typeInst) + if (auto ptrType = as<IRPtrTypeBase>(typeInst)) { - if (typeInst) - { - switch (typeInst->getOp()) - { - case kIROp_TypeType: - case kIROp_TypeKind: - return true; - default: - return false; - } - } - return false; + return isPolymorphicType(ptrType->getValueType()); } + return false; +} - IRInst* SharedGenericsLoweringContext::maybeEmitRTTIObject(IRInst* typeInst) +bool isTypeValue(IRInst* typeInst) +{ + if (typeInst) { - IRInst* result = nullptr; - if (mapTypeToRTTIObject.tryGetValue(typeInst, result)) - return result; - IRBuilder builderStorage(module); - auto builder = &builderStorage; - builder->setInsertAfter(typeInst); - - result = builder->emitMakeRTTIObject(typeInst); - - // For now the only type info we encapsualte is type size. - IRSizeAndAlignment sizeAndAlignment; - getNaturalSizeAndAlignment(targetProgram->getOptionSet(), (IRType*)typeInst, &sizeAndAlignment); - builder->addRTTITypeSizeDecoration(result, sizeAndAlignment.size); - - // Give a name to the rtti object. - if (auto exportDecoration = typeInst->findDecoration<IRExportDecoration>()) + switch (typeInst->getOp()) { - String rttiObjName = exportDecoration->getMangledName(); - builder->addExportDecoration(result, rttiObjName.getUnownedSlice()); + case kIROp_TypeType: + case kIROp_TypeKind: return true; + default: return false; } + } + return false; +} - // Make sure the RTTI object for an exported struct type is marked as export if the type is. - if (typeInst->findDecoration<IRHLSLExportDecoration>()) - { - builder->addHLSLExportDecoration(result); - builder->addKeepAliveDecoration(result); - } - mapTypeToRTTIObject[typeInst] = result; +IRInst* SharedGenericsLoweringContext::maybeEmitRTTIObject(IRInst* typeInst) +{ + IRInst* result = nullptr; + if (mapTypeToRTTIObject.tryGetValue(typeInst, result)) return result; - } + IRBuilder builderStorage(module); + auto builder = &builderStorage; + builder->setInsertAfter(typeInst); + + result = builder->emitMakeRTTIObject(typeInst); + + // For now the only type info we encapsualte is type size. + IRSizeAndAlignment sizeAndAlignment; + getNaturalSizeAndAlignment(targetProgram->getOptionSet(), (IRType*)typeInst, &sizeAndAlignment); + builder->addRTTITypeSizeDecoration(result, sizeAndAlignment.size); - IRInst* SharedGenericsLoweringContext::findInterfaceRequirementVal(IRInterfaceType* interfaceType, IRInst* requirementKey) + // Give a name to the rtti object. + if (auto exportDecoration = typeInst->findDecoration<IRExportDecoration>()) { - if (auto dict = mapInterfaceRequirementKeyValue.tryGetValue(interfaceType)) - return dict->getValue(requirementKey); - _builldInterfaceRequirementMap(interfaceType); - return findInterfaceRequirementVal(interfaceType, requirementKey); + String rttiObjName = exportDecoration->getMangledName(); + builder->addExportDecoration(result, rttiObjName.getUnownedSlice()); } - void SharedGenericsLoweringContext::_builldInterfaceRequirementMap(IRInterfaceType* interfaceType) + // Make sure the RTTI object for an exported struct type is marked as export if the type is. + if (typeInst->findDecoration<IRHLSLExportDecoration>()) { - mapInterfaceRequirementKeyValue.add(interfaceType, - Dictionary<IRInst*, IRInst*>()); - auto dict = mapInterfaceRequirementKeyValue.tryGetValue(interfaceType); - for (UInt i = 0; i < interfaceType->getOperandCount(); i++) - { - auto entry = cast<IRInterfaceRequirementEntry>(interfaceType->getOperand(i)); - (*dict)[entry->getRequirementKey()] = entry->getRequirementVal(); - } + builder->addHLSLExportDecoration(result); + builder->addKeepAliveDecoration(result); } + mapTypeToRTTIObject[typeInst] = result; + return result; +} + +IRInst* SharedGenericsLoweringContext::findInterfaceRequirementVal( + IRInterfaceType* interfaceType, + IRInst* requirementKey) +{ + if (auto dict = mapInterfaceRequirementKeyValue.tryGetValue(interfaceType)) + return dict->getValue(requirementKey); + _builldInterfaceRequirementMap(interfaceType); + return findInterfaceRequirementVal(interfaceType, requirementKey); +} - IRType* SharedGenericsLoweringContext::lowerAssociatedType(IRBuilder* builder, IRInst* type) +void SharedGenericsLoweringContext::_builldInterfaceRequirementMap(IRInterfaceType* interfaceType) +{ + mapInterfaceRequirementKeyValue.add(interfaceType, Dictionary<IRInst*, IRInst*>()); + auto dict = mapInterfaceRequirementKeyValue.tryGetValue(interfaceType); + for (UInt i = 0; i < interfaceType->getOperandCount(); i++) { - if (type->getOp() != kIROp_AssociatedType) - return (IRType*)type; - IRIntegerValue anyValueSize = kInvalidAnyValueSize; - for (UInt i = 0; i < type->getOperandCount(); i++) - { - anyValueSize = Math::Min( - anyValueSize, - getInterfaceAnyValueSize(type->getOperand(i), type->sourceLoc)); - } - if (anyValueSize == kInvalidAnyValueSize) - { - // We could conceivably make it an error to have an associated type - // without an `[anyValueSize(...)]` attribute, but then we risk - // producing error messages even when doing 100% static specialization. - // - // It is simpler to use a reasonable default size and treat any - // type without an explicit attribute as using that size. - // - anyValueSize = kDefaultAnyValueSize; - } - return builder->getAnyValueType(anyValueSize); + auto entry = cast<IRInterfaceRequirementEntry>(interfaceType->getOperand(i)); + (*dict)[entry->getRequirementKey()] = entry->getRequirementVal(); } +} - IRType* SharedGenericsLoweringContext::lowerType(IRBuilder* builder, IRInst* paramType, const Dictionary<IRInst*, IRInst*>& typeMapping, IRType* concreteType) +IRType* SharedGenericsLoweringContext::lowerAssociatedType(IRBuilder* builder, IRInst* type) +{ + if (type->getOp() != kIROp_AssociatedType) + return (IRType*)type; + IRIntegerValue anyValueSize = kInvalidAnyValueSize; + for (UInt i = 0; i < type->getOperandCount(); i++) + { + anyValueSize = + Math::Min(anyValueSize, getInterfaceAnyValueSize(type->getOperand(i), type->sourceLoc)); + } + if (anyValueSize == kInvalidAnyValueSize) { - if (!paramType) - return nullptr; + // We could conceivably make it an error to have an associated type + // without an `[anyValueSize(...)]` attribute, but then we risk + // producing error messages even when doing 100% static specialization. + // + // It is simpler to use a reasonable default size and treat any + // type without an explicit attribute as using that size. + // + anyValueSize = kDefaultAnyValueSize; + } + return builder->getAnyValueType(anyValueSize); +} - IRInst* resultType; - if (typeMapping.tryGetValue(paramType, resultType)) - return (IRType*)resultType; +IRType* SharedGenericsLoweringContext::lowerType( + IRBuilder* builder, + IRInst* paramType, + const Dictionary<IRInst*, IRInst*>& typeMapping, + IRType* concreteType) +{ + if (!paramType) + return nullptr; - if (isTypeValue(paramType)) - { - return builder->getRTTIHandleType(); - } + IRInst* resultType; + if (typeMapping.tryGetValue(paramType, resultType)) + return (IRType*)resultType; - switch (paramType->getOp()) - { - case kIROp_WitnessTableType: - case kIROp_WitnessTableIDType: - case kIROp_ExtractExistentialType: - // Do not translate these types. - return (IRType*)paramType; - case kIROp_Param: + if (isTypeValue(paramType)) + { + return builder->getRTTIHandleType(); + } + + switch (paramType->getOp()) + { + case kIROp_WitnessTableType: + case kIROp_WitnessTableIDType: + case kIROp_ExtractExistentialType: + // Do not translate these types. + return (IRType*)paramType; + case kIROp_Param: { if (auto anyValueSizeDecor = paramType->findDecoration<IRTypeConstraintDecoration>()) { if (isBuiltin(anyValueSizeDecor->getConstraintType())) return (IRType*)paramType; - auto anyValueSize = getInterfaceAnyValueSize(anyValueSizeDecor->getConstraintType(), paramType->sourceLoc); + auto anyValueSize = getInterfaceAnyValueSize( + anyValueSizeDecor->getConstraintType(), + paramType->sourceLoc); return builder->getAnyValueType(anyValueSize); } // We could conceivably make it an error to have a generic parameter @@ -170,7 +172,7 @@ namespace Slang // return builder->getAnyValueType(kDefaultAnyValueSize); } - case kIROp_ThisType: + case kIROp_ThisType: { auto interfaceType = cast<IRThisType>(paramType)->getConstraintType(); @@ -185,11 +187,11 @@ namespace Slang paramType->sourceLoc); return builder->getAnyValueType(anyValueSize); } - case kIROp_AssociatedType: + case kIROp_AssociatedType: { return lowerAssociatedType(builder, paramType); } - case kIROp_InterfaceType: + case kIROp_InterfaceType: { if (isBuiltin(paramType)) return (IRType*)paramType; @@ -211,7 +213,7 @@ namespace Slang // type. // IRType* pendingType = nullptr; - if( concreteType ) + if (concreteType) { // Because static specialization is being used (at least in part), // we do *not* have a guarantee that the `concreteType` is one @@ -235,8 +237,11 @@ namespace Slang // value must be stored out-of-line. // IRSizeAndAlignment sizeAndAlignment; - Result result = getNaturalSizeAndAlignment(targetProgram->getOptionSet(), concreteType, &sizeAndAlignment); - if(SLANG_FAILED(result) || (sizeAndAlignment.size > anyValueSize)) + Result result = getNaturalSizeAndAlignment( + targetProgram->getOptionSet(), + concreteType, + &sizeAndAlignment); + if (SLANG_FAILED(result) || (sizeAndAlignment.size > anyValueSize)) { // If the value must be stored out-of-line, we construct // a "pseudo pointer" to the concrete type, and the @@ -260,7 +265,7 @@ namespace Slang auto rttiType = builder->getRTTIHandleType(); IRType* tupleType = nullptr; - if( !pendingType ) + if (!pendingType) { // In the oridnary (dynamic) case, an existential type decomposes // into a tuple of: @@ -276,7 +281,8 @@ namespace Slang // // (RTTI, witness table, pseudo pointer, any-value) // - tupleType = builder->getTupleType(rttiType, witnessTableType, pendingType, anyValueType); + tupleType = + builder->getTupleType(rttiType, witnessTableType, pendingType, anyValueType); // // Note that in each of the cases, the third element of the tuple // is a representation of the value being stored in the existential. @@ -289,28 +295,28 @@ namespace Slang return tupleType; } - case kIROp_LookupWitness: + case kIROp_LookupWitness: { auto lookupInterface = static_cast<IRLookupWitnessMethod*>(paramType); - auto witnessTableType = as<IRWitnessTableType>( - lookupInterface->getWitnessTable()->getDataType()); + auto witnessTableType = + as<IRWitnessTableType>(lookupInterface->getWitnessTable()->getDataType()); if (!witnessTableType) return (IRType*)paramType; auto interfaceType = as<IRInterfaceType>(witnessTableType->getConformanceType()); if (!interfaceType || 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. - // In lowered interface type, that entry is lowered into an Ptr(RTTIType) and this info is lost. + // Only in the original interface type will an associated type entry have an + // IRAssociatedType value. We need to extract AnyValueSize from this IRAssociatedType. + // In lowered interface type, that entry is lowered into an Ptr(RTTIType) and this info + // is lost. mapLoweredInterfaceToOriginal.tryGetValue(interfaceType, interfaceType); - auto reqVal = findInterfaceRequirementVal( - interfaceType, - lookupInterface->getRequirementKey()); + auto reqVal = + findInterfaceRequirementVal(interfaceType, lookupInterface->getRequirementKey()); SLANG_ASSERT(reqVal && reqVal->getOp() == kIROp_AssociatedType); return lowerType(builder, reqVal, typeMapping, nullptr); } - case kIROp_BoundInterfaceType: + case kIROp_BoundInterfaceType: { // A bound interface type represents an existential together with // static knowledge that the value stored in the extistential has @@ -321,84 +327,102 @@ namespace Slang // layout of the interface type. // auto boundInterfaceType = static_cast<IRBoundInterfaceType*>(paramType); - return lowerType(builder, boundInterfaceType->getInterfaceType(), typeMapping, boundInterfaceType->getConcreteType()); + return lowerType( + builder, + boundInterfaceType->getInterfaceType(), + typeMapping, + boundInterfaceType->getConcreteType()); } - default: + default: { bool translated = false; List<IRInst*> loweredOperands; for (UInt i = 0; i < paramType->getOperandCount(); i++) { - loweredOperands.add(lowerType(builder, paramType->getOperand(i), typeMapping, nullptr)); + loweredOperands.add( + lowerType(builder, paramType->getOperand(i), typeMapping, nullptr)); if (loweredOperands.getLast() != paramType->getOperand(i)) translated = true; } if (translated) - return builder->getType(paramType->getOp(), loweredOperands.getCount(), loweredOperands.getBuffer()); + return builder->getType( + paramType->getOp(), + loweredOperands.getCount(), + loweredOperands.getBuffer()); return (IRType*)paramType; } - } } +} - List<IRWitnessTable*> getWitnessTablesFromInterfaceType(IRModule* module, IRInst* interfaceType) +List<IRWitnessTable*> getWitnessTablesFromInterfaceType(IRModule* module, IRInst* interfaceType) +{ + List<IRWitnessTable*> witnessTables; + for (auto globalInst : module->getGlobalInsts()) { - List<IRWitnessTable*> witnessTables; - for (auto globalInst : module->getGlobalInsts()) + if (globalInst->getOp() == kIROp_WitnessTable && + cast<IRWitnessTableType>(globalInst->getDataType())->getConformanceType() == + interfaceType) { - if (globalInst->getOp() == kIROp_WitnessTable && - cast<IRWitnessTableType>(globalInst->getDataType())->getConformanceType() == - interfaceType) - { - witnessTables.add(cast<IRWitnessTable>(globalInst)); - } + witnessTables.add(cast<IRWitnessTable>(globalInst)); } - return witnessTables; - } - - List<IRWitnessTable*> SharedGenericsLoweringContext::getWitnessTablesFromInterfaceType(IRInst* interfaceType) - { - return Slang::getWitnessTablesFromInterfaceType(module, interfaceType); } + return witnessTables; +} - IRIntegerValue SharedGenericsLoweringContext::getInterfaceAnyValueSize(IRInst* type, SourceLoc usageLoc) - { - SLANG_UNUSED(usageLoc); +List<IRWitnessTable*> SharedGenericsLoweringContext::getWitnessTablesFromInterfaceType( + IRInst* interfaceType) +{ + return Slang::getWitnessTablesFromInterfaceType(module, interfaceType); +} - if (auto decor = type->findDecoration<IRAnyValueSizeDecoration>()) - { - return decor->getSize(); - } +IRIntegerValue SharedGenericsLoweringContext::getInterfaceAnyValueSize( + IRInst* type, + SourceLoc usageLoc) +{ + SLANG_UNUSED(usageLoc); - // We could conceivably make it an error to have an interface - // without an `[anyValueSize(...)]` attribute, but then we risk - // producing error messages even when doing 100% static specialization. - // - // It is simpler to use a reasonable default size and treat any - // type without an explicit attribute as using that size. - // - return kDefaultAnyValueSize; + if (auto decor = type->findDecoration<IRAnyValueSizeDecoration>()) + { + return decor->getSize(); } + // We could conceivably make it an error to have an interface + // without an `[anyValueSize(...)]` attribute, but then we risk + // producing error messages even when doing 100% static specialization. + // + // It is simpler to use a reasonable default size and treat any + // type without an explicit attribute as using that size. + // + return kDefaultAnyValueSize; +} - bool SharedGenericsLoweringContext::doesTypeFitInAnyValue(IRType* concreteType, IRInterfaceType* interfaceType, IRIntegerValue* outTypeSize, IRIntegerValue* outLimit) - { - auto anyValueSize = getInterfaceAnyValueSize(interfaceType, interfaceType->sourceLoc); - if (outLimit) *outLimit = anyValueSize; - IRSizeAndAlignment sizeAndAlignment; - Result result = getNaturalSizeAndAlignment(targetProgram->getOptionSet(), concreteType, &sizeAndAlignment); - if (outTypeSize) *outTypeSize = sizeAndAlignment.size; +bool SharedGenericsLoweringContext::doesTypeFitInAnyValue( + IRType* concreteType, + IRInterfaceType* interfaceType, + IRIntegerValue* outTypeSize, + IRIntegerValue* outLimit) +{ + auto anyValueSize = getInterfaceAnyValueSize(interfaceType, interfaceType->sourceLoc); + if (outLimit) + *outLimit = anyValueSize; - if(SLANG_FAILED(result) || (sizeAndAlignment.size > anyValueSize)) - { - // The value does not fit, either because it is too large, - // or because it includes types that cannot be stored - // in uniform/ordinary memory for this target. - // - return false; - } + IRSizeAndAlignment sizeAndAlignment; + Result result = + getNaturalSizeAndAlignment(targetProgram->getOptionSet(), concreteType, &sizeAndAlignment); + if (outTypeSize) + *outTypeSize = sizeAndAlignment.size; - return true; + if (SLANG_FAILED(result) || (sizeAndAlignment.size > anyValueSize)) + { + // The value does not fit, either because it is too large, + // or because it includes types that cannot be stored + // in uniform/ordinary memory for this target. + // + return false; } + return true; } + +} // namespace Slang |
