summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-ir-lower-optional-type.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-06-04 13:05:58 -0700
committerGitHub <noreply@github.com>2025-06-04 13:05:58 -0700
commit812e478989e27983b8dea7ab11964de751654ba2 (patch)
treee6db6def9c7896ee48c5fe42926856644e81c0e6 /source/slang/slang-ir-lower-optional-type.cpp
parentb9dc21d362f65f22bc707bede733a9537b80460a (diff)
Make interface types non c-style in Slang2026. (#7260)
* Make interface types non c-style. * Make Optional<T> 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>
Diffstat (limited to 'source/slang/slang-ir-lower-optional-type.cpp')
-rw-r--r--source/slang/slang-ir-lower-optional-type.cpp107
1 files changed, 63 insertions, 44 deletions
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<IRInst*, RefPtr<LoweredOptionalTypeInfo>> mapLoweredTypeToOptionalTypeInfo;
Dictionary<IRInst*, RefPtr<LoweredOptionalTypeInfo>> 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<LoweredOptionalTypeInfo> info = new LoweredOptionalTypeInfo();
auto optionalType = cast<IROptionalType>(type);
auto valueType = optionalType->getValueType();
+ while (auto valueOptionalType = as<IROptionalType>(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