From 88f04c29244af23c1cdd472d8d1ae3e5a650494e Mon Sep 17 00:00:00 2001 From: Yong He Date: Wed, 10 Aug 2022 14:11:27 -0700 Subject: `is` and `as` operator and `Optional`. (#2355) * `is` and `as` operator and `Optional`. * Fix. Co-authored-by: Yong He --- source/slang/slang-ir-lower-optional-type.cpp | 239 ++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 source/slang/slang-ir-lower-optional-type.cpp (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 new file mode 100644 index 000000000..79be4e042 --- /dev/null +++ b/source/slang/slang-ir-lower-optional-type.cpp @@ -0,0 +1,239 @@ +// slang-ir-lower-optional-type.cpp + +#include "slang-ir-lower-optional-type.h" +#include "slang-ir.h" +#include "slang-ir-insts.h" + +namespace Slang +{ + struct OptionalTypeLoweringContext + { + IRModule* module; + DiagnosticSink* sink; + + SharedIRBuilder sharedBuilderStorage; + + List workList; + HashSet workListSet; + + struct LoweredOptionalTypeInfo : public RefObject + { + IRType* optionalType = nullptr; + IRType* valueType = nullptr; + IRType* loweredType = nullptr; + IRStructField* valueField = nullptr; + IRStructField* hasValueField = nullptr; + }; + Dictionary> mapLoweredTypeToOptionalTypeInfo; + Dictionary> loweredOptionalTypes; + + IRType* maybeLowerOptionalType(IRBuilder* builder, IRType* type) + { + if (auto info = getLoweredOptionalType(builder, type)) + return info->loweredType; + else + return type; + } + + LoweredOptionalTypeInfo* getLoweredOptionalType(IRBuilder* builder, 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) + return nullptr; + + RefPtr info = new LoweredOptionalTypeInfo(); + info->optionalType = (IRType*)type; + auto optionalType = cast(type); + auto valueType = optionalType->getValueType(); + info->valueType = valueType; + + auto structType = builder->createStructType(); + info->loweredType = structType; + builder->addNameHintDecoration(structType, UnownedStringSlice("OptionalType")); + + info->valueType = valueType; + auto valueKey = builder->createStructKey(); + builder->addNameHintDecoration(valueKey, UnownedStringSlice("value")); + info->valueField = builder->createStructField(structType, valueKey, (IRType*)valueType); + + auto boolType = builder->getBoolType(); + auto hasValueKey = builder->createStructKey(); + builder->addNameHintDecoration(hasValueKey, UnownedStringSlice("hasValue")); + info->hasValueField = builder->createStructField(structType, hasValueKey, (IRType*)boolType); + + mapLoweredTypeToOptionalTypeInfo[info->loweredType] = info; + loweredOptionalTypes[type] = info; + return info.Ptr(); + } + + void addToWorkList( + IRInst* inst) + { + for (auto ii = inst->getParent(); ii; ii = ii->getParent()) + { + if (as(ii)) + return; + } + + if (workListSet.Contains(inst)) + return; + + workList.add(inst); + workListSet.Add(inst); + } + + void processMakeOptionalValue(IRMakeOptionalValue* inst) + { + IRBuilder builderStorage(sharedBuilderStorage); + auto builder = &builderStorage; + builder->setInsertBefore(inst); + + auto info = getLoweredOptionalType(builder, inst->getDataType()); + List operands; + operands.add(inst->getOperand(0)); + operands.add(builder->getBoolValue(true)); + auto makeStruct = builder->emitMakeStruct(info->loweredType, operands); + inst->replaceUsesWith(makeStruct); + inst->removeAndDeallocate(); + } + + void processMakeOptionalNone(IRMakeOptionalNone* inst) + { + IRBuilder builderStorage(sharedBuilderStorage); + auto builder = &builderStorage; + builder->setInsertBefore(inst); + + auto info = getLoweredOptionalType(builder, inst->getDataType()); + + List operands; + operands.add(inst->getDefaultValue()); + operands.add(builder->getBoolValue(false)); + auto makeStruct = builder->emitMakeStruct(info->loweredType, operands); + inst->replaceUsesWith(makeStruct); + inst->removeAndDeallocate(); + } + + IRInst* getOptionalHasValue(IRBuilder* builder, IRInst* optionalInst) + { + auto loweredOptionalTypeInfo = getLoweredOptionalType(builder, optionalInst->getDataType()); + SLANG_ASSERT(loweredOptionalTypeInfo); + + auto value = builder->emitFieldExtract( + builder->getBoolType(), + optionalInst, + loweredOptionalTypeInfo->hasValueField->getKey()); + return value; + } + + void processGetOptionalHasValue(IROptionalHasValue* inst) + { + IRBuilder builderStorage(sharedBuilderStorage); + auto builder = &builderStorage; + builder->setInsertBefore(inst); + + auto optionalValue = inst->getOptionalOperand(); + auto hasVal = getOptionalHasValue(builder, optionalValue); + inst->replaceUsesWith(hasVal); + inst->removeAndDeallocate(); + } + + void processGetOptionalValue(IRGetOptionalValue* inst) + { + IRBuilder builderStorage(sharedBuilderStorage); + auto builder = &builderStorage; + builder->setInsertBefore(inst); + + auto base = inst->getOptionalOperand(); + auto loweredOptionalTypeInfo = getLoweredOptionalType(builder, base->getDataType()); + SLANG_ASSERT(loweredOptionalTypeInfo); + SLANG_ASSERT(loweredOptionalTypeInfo->valueField); + auto getElement = builder->emitFieldExtract( + loweredOptionalTypeInfo->valueType, + base, + loweredOptionalTypeInfo->valueField->getKey()); + inst->replaceUsesWith(getElement); + inst->removeAndDeallocate(); + } + + void processOptionalType(IROptionalType* inst) + { + IRBuilder builderStorage(sharedBuilderStorage); + auto builder = &builderStorage; + builder->setInsertBefore(inst); + + auto loweredOptionalTypeInfo = getLoweredOptionalType(builder, inst); + SLANG_ASSERT(loweredOptionalTypeInfo); + SLANG_UNUSED(loweredOptionalTypeInfo); + } + + void processInst(IRInst* inst) + { + switch (inst->getOp()) + { + case kIROp_MakeOptionalValue: + processMakeOptionalValue((IRMakeOptionalValue*)inst); + break; + case kIROp_MakeOptionalNone: + processMakeOptionalNone((IRMakeOptionalNone*)inst); + break; + case kIROp_OptionalHasValue: + processGetOptionalHasValue((IROptionalHasValue*)inst); + break; + case kIROp_GetOptionalValue: + processGetOptionalValue((IRGetOptionalValue*)inst); + break; + case kIROp_OptionalType: + processOptionalType((IROptionalType*)inst); + break; + default: + break; + } + } + + void processModule() + { + SharedIRBuilder* sharedBuilder = &sharedBuilderStorage; + sharedBuilder->init(module); + + // Deduplicate equivalent types. + sharedBuilder->deduplicateAndRebuildGlobalNumberingMap(); + + addToWorkList(module->getModuleInst()); + + while (workList.getCount() != 0) + { + IRInst* inst = workList.getLast(); + + workList.removeLast(); + workListSet.Remove(inst); + + processInst(inst); + + for (auto child = inst->getLastChild(); child; child = child->getPrevInst()) + { + addToWorkList(child); + } + } + + // Replace all optional types with lowered struct types. + for (auto kv : loweredOptionalTypes) + { + kv.Key->replaceUsesWith(kv.Value->loweredType); + } + } + }; + + void lowerOptionalType(IRModule* module, DiagnosticSink* sink) + { + OptionalTypeLoweringContext context; + context.module = module; + context.sink = sink; + context.processModule(); + } +} -- cgit v1.2.3