From 812e478989e27983b8dea7ab11964de751654ba2 Mon Sep 17 00:00:00 2001 From: Yong He Date: Wed, 4 Jun 2025 13:05:58 -0700 Subject: Make interface types non c-style in Slang2026. (#7260) * Make interface types non c-style. * Make Optional work with autodiff and existential types. * Fix. * patch behind slang 2026. * Fix warnings. * cleanup. * Fix tests. * Fix. * Fix com interface lowering. * Add comment to test. * regenerate command line reference * Add test for passing `none` to autodiff function. * Fix recording of `getDynamicObjectRTTIBytes`. * Fix nested Optional types. --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com> --- source/slang/slang-ir-lower-optional-type.cpp | 107 +++++++++++++++----------- 1 file changed, 63 insertions(+), 44 deletions(-) (limited to 'source/slang/slang-ir-lower-optional-type.cpp') diff --git a/source/slang/slang-ir-lower-optional-type.cpp b/source/slang/slang-ir-lower-optional-type.cpp index 5c9dcd722..1f9f398d3 100644 --- a/source/slang/slang-ir-lower-optional-type.cpp +++ b/source/slang/slang-ir-lower-optional-type.cpp @@ -8,6 +8,13 @@ namespace Slang { +enum LoweredOptionalTypeKind +{ + Struct, + PtrValue, + ExistentialValue, +}; + struct OptionalTypeLoweringContext { IRModule* module; @@ -16,10 +23,6 @@ struct OptionalTypeLoweringContext InstWorkList workList; InstHashSet workListSet; - IRGeneric* genericOptionalStructType = nullptr; - IRStructKey* valueKey = nullptr; - IRStructKey* hasValueKey = nullptr; - OptionalTypeLoweringContext(IRModule* inModule) : module(inModule), workList(inModule), workListSet(inModule) { @@ -30,6 +33,9 @@ struct OptionalTypeLoweringContext IRType* optionalType = nullptr; IRType* valueType = nullptr; IRType* loweredType = nullptr; + IRStructKey* hasValueKey = nullptr; + IRStructKey* valueKey = nullptr; + LoweredOptionalTypeKind kind = LoweredOptionalTypeKind::Struct; }; Dictionary> mapLoweredTypeToOptionalTypeInfo; Dictionary> loweredOptionalTypes; @@ -42,37 +48,29 @@ struct OptionalTypeLoweringContext return type; } - IRInst* getOrCreateGenericOptionalStruct() + IRInst* createOptionalStruct(IRType* type, LoweredOptionalTypeInfo* info) { - if (genericOptionalStructType) - return genericOptionalStructType; IRBuilder builder(module); builder.setInsertInto(module->getModuleInst()); - valueKey = builder.createStructKey(); - builder.addNameHintDecoration(valueKey, UnownedStringSlice("value")); - hasValueKey = builder.createStructKey(); - builder.addNameHintDecoration(hasValueKey, UnownedStringSlice("hasValue")); - - genericOptionalStructType = builder.emitGeneric(); - builder.addNameHintDecoration( - genericOptionalStructType, - UnownedStringSlice("_slang_Optional")); + info->valueKey = builder.createStructKey(); + builder.addNameHintDecoration(info->valueKey, UnownedStringSlice("value")); + info->hasValueKey = builder.createStructKey(); + builder.addNameHintDecoration(info->hasValueKey, UnownedStringSlice("hasValue")); - builder.setInsertInto(genericOptionalStructType); - auto block = builder.emitBlock(); - auto typeParam = builder.emitParam(builder.getTypeKind()); auto structType = builder.createStructType(); - builder.addNameHintDecoration(structType, UnownedStringSlice("_slang_Optional")); - builder.createStructField(structType, valueKey, (IRType*)typeParam); - builder.createStructField(structType, hasValueKey, builder.getBoolType()); - builder.setInsertInto(block); - builder.emitReturn(structType); - genericOptionalStructType->setFullType(builder.getTypeKind()); - return genericOptionalStructType; + StringBuilder sb; + sb << "_slang_Optional_"; + getTypeNameHint(sb, type); + builder.addNameHintDecoration(structType, sb.getUnownedSlice()); + builder.createStructField(structType, info->valueKey, type); + builder.createStructField(structType, info->hasValueKey, builder.getBoolType()); + + info->kind = LoweredOptionalTypeKind::Struct; + return structType; } - bool typeHasNullValue(IRInst* type) + bool typeHasNullValue(IRInst* type, LoweredOptionalTypeKind& outKind) { switch (type->getOp()) { @@ -81,21 +79,25 @@ struct OptionalTypeLoweringContext case kIROp_NativeStringType: case kIROp_PtrType: case kIROp_ClassType: + outKind = LoweredOptionalTypeKind::PtrValue; return true; case kIROp_InterfaceType: - return isComInterfaceType((IRType*)type); + if (isComInterfaceType((IRType*)type)) + outKind = LoweredOptionalTypeKind::PtrValue; + else + outKind = LoweredOptionalTypeKind::ExistentialValue; + return true; default: return false; } } - LoweredOptionalTypeInfo* getLoweredOptionalType(IRBuilder* builder, IRInst* type) + LoweredOptionalTypeInfo* getLoweredOptionalType(IRBuilder*, IRInst* type) { if (auto loweredInfo = loweredOptionalTypes.tryGetValue(type)) return loweredInfo->Ptr(); if (auto loweredInfo = mapLoweredTypeToOptionalTypeInfo.tryGetValue(type)) return loweredInfo->Ptr(); - if (!type) return nullptr; if (type->getOp() != kIROp_OptionalType) @@ -104,19 +106,21 @@ struct OptionalTypeLoweringContext RefPtr info = new LoweredOptionalTypeInfo(); auto optionalType = cast(type); auto valueType = optionalType->getValueType(); + while (auto valueOptionalType = as(valueType)) + { + // If the value type is also an Optional, we need to keep lowering it. + valueType = valueOptionalType->getValueType(); + } + info->optionalType = (IRType*)type; info->valueType = valueType; - if (typeHasNullValue(valueType)) + if (typeHasNullValue(valueType, info->kind)) { info->loweredType = valueType; } else { - auto genericType = getOrCreateGenericOptionalStruct(); - IRInst* args[] = {valueType}; - auto specializedType = - builder->emitSpecializeInst(builder->getTypeKind(), genericType, 1, args); - info->loweredType = (IRType*)specializedType; + info->loweredType = (IRType*)createOptionalStruct(valueType, info); } mapLoweredTypeToOptionalTypeInfo[info->loweredType] = info; loweredOptionalTypes[type] = info; @@ -171,6 +175,12 @@ struct OptionalTypeLoweringContext inst->replaceUsesWith(makeStruct); inst->removeAndDeallocate(); } + else if (info->kind == LoweredOptionalTypeKind::ExistentialValue) + { + auto zero = builder->emitDefaultConstruct(info->loweredType); + inst->replaceUsesWith(zero); + inst->removeAndDeallocate(); + } else { inst->replaceUsesWith(builder->getNullPtrValue(info->valueType)); @@ -183,13 +193,20 @@ struct OptionalTypeLoweringContext auto loweredOptionalTypeInfo = getLoweredOptionalType(builder, optionalInst->getDataType()); SLANG_ASSERT(loweredOptionalTypeInfo); IRInst* result = nullptr; - if (loweredOptionalTypeInfo->loweredType != loweredOptionalTypeInfo->valueType) - { - result = builder->emitFieldExtract(builder->getBoolType(), optionalInst, hasValueKey); - } - else + switch (loweredOptionalTypeInfo->kind) { + case LoweredOptionalTypeKind::Struct: + result = builder->emitFieldExtract( + builder->getBoolType(), + optionalInst, + loweredOptionalTypeInfo->hasValueKey); + break; + case LoweredOptionalTypeKind::PtrValue: result = builder->emitCastPtrToBool(optionalInst); + break; + case LoweredOptionalTypeKind::ExistentialValue: + result = builder->emitIsNullExistential(optionalInst); + break; } return result; } @@ -214,11 +231,13 @@ struct OptionalTypeLoweringContext auto base = inst->getOptionalOperand(); auto loweredOptionalTypeInfo = getLoweredOptionalType(builder, base->getDataType()); - if (loweredOptionalTypeInfo->loweredType != loweredOptionalTypeInfo->valueType) + if (loweredOptionalTypeInfo->kind == LoweredOptionalTypeKind::Struct) { SLANG_ASSERT(loweredOptionalTypeInfo); - auto getElement = - builder->emitFieldExtract(loweredOptionalTypeInfo->valueType, base, valueKey); + auto getElement = builder->emitFieldExtract( + loweredOptionalTypeInfo->valueType, + base, + loweredOptionalTypeInfo->valueKey); inst->replaceUsesWith(getElement); } else -- cgit v1.2.3