summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-lower-result-type.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2022-06-01 17:37:07 -0700
committerGitHub <noreply@github.com>2022-06-01 17:37:07 -0700
commit17e3b88b541ed7f45d575f0f9caaa808cd0a6619 (patch)
treeefacd5d4bf6381a5adf8055daa28f91ddc048a76 /source/slang/slang-ir-lower-result-type.cpp
parentfa10f7dc23f8b93c0f9ef3fb5477871a20aaa974 (diff)
New language feature: basic error handling. (#2253)
* New language feature: basic error handling. * Fix. * Fix `tryCall` encoding according to code review. Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source/slang/slang-ir-lower-result-type.cpp')
-rw-r--r--source/slang/slang-ir-lower-result-type.cpp317
1 files changed, 317 insertions, 0 deletions
diff --git a/source/slang/slang-ir-lower-result-type.cpp b/source/slang/slang-ir-lower-result-type.cpp
new file mode 100644
index 000000000..e46a0ceb5
--- /dev/null
+++ b/source/slang/slang-ir-lower-result-type.cpp
@@ -0,0 +1,317 @@
+// slang-ir-lower-result-type.cpp
+
+#include "slang-ir-lower-result-type.h"
+#include "slang-ir.h"
+#include "slang-ir-insts.h"
+
+namespace Slang
+{
+ struct ResultTypeLoweringContext
+ {
+ IRModule* module;
+ DiagnosticSink* sink;
+
+ SharedIRBuilder sharedBuilderStorage;
+
+ List<IRInst*> workList;
+ HashSet<IRInst*> workListSet;
+
+ struct LoweredResultTypeInfo : public RefObject
+ {
+ IRType* resultType = nullptr;
+ IRType* errorType = nullptr;
+ IRType* valueType = nullptr;
+ IRType* loweredType = nullptr;
+ IRStructField* valueField = nullptr;
+ IRStructField* errorField = nullptr;
+ };
+ Dictionary<IRInst*, RefPtr<LoweredResultTypeInfo>> mapLoweredTypeToResultTypeInfo;
+ Dictionary<IRInst*, RefPtr<LoweredResultTypeInfo>> loweredResultTypes;
+
+ IRType* maybeLowerResultType(IRBuilder* builder, IRType* type)
+ {
+ if (auto info = getLoweredResultType(builder, type))
+ return info->loweredType;
+ else
+ return type;
+ }
+
+ LoweredResultTypeInfo* getLoweredResultType(IRBuilder* builder, IRInst* type)
+ {
+ if (auto loweredInfo = loweredResultTypes.TryGetValue(type))
+ return loweredInfo->Ptr();
+ if (auto loweredInfo = mapLoweredTypeToResultTypeInfo.TryGetValue(type))
+ return loweredInfo->Ptr();
+
+ if (!type)
+ return nullptr;
+ if (type->getOp() != kIROp_ResultType)
+ return nullptr;
+
+ RefPtr<LoweredResultTypeInfo> info = new LoweredResultTypeInfo();
+ info->resultType = (IRType*)type;
+ info->errorType = cast<IRResultType>(type)->getErrorType();
+
+ auto resultType = cast<IRResultType>(type);
+ auto valueType = resultType->getValueType();
+ if (valueType->getOp() != kIROp_VoidType)
+ {
+ auto structType = builder->createStructType();
+ info->loweredType = structType;
+ builder->addNameHintDecoration(structType, UnownedStringSlice("ResultType"));
+
+ info->valueType = valueType;
+ auto valueKey = builder->createStructKey();
+ builder->addNameHintDecoration(valueKey, UnownedStringSlice("value"));
+ info->valueField = builder->createStructField(structType, valueKey, (IRType*)valueType);
+
+ auto errorType = resultType->getErrorType();
+ auto errorKey = builder->createStructKey();
+ builder->addNameHintDecoration(errorKey, UnownedStringSlice("error"));
+ info->errorField = builder->createStructField(structType, errorKey, (IRType*)errorType);
+ }
+ else
+ {
+ info->loweredType = resultType->getErrorType();
+ }
+ mapLoweredTypeToResultTypeInfo[info->loweredType] = info;
+ loweredResultTypes[type] = info;
+ return info.Ptr();
+ }
+
+ void addToWorkList(
+ IRInst* inst)
+ {
+ for (auto ii = inst->getParent(); ii; ii = ii->getParent())
+ {
+ if (as<IRGeneric>(ii))
+ return;
+ }
+
+ if (workListSet.Contains(inst))
+ return;
+
+ workList.add(inst);
+ workListSet.Add(inst);
+ }
+
+ IRInst* getSuccessErrorValue(IRType* type)
+ {
+ switch (type->getOp())
+ {
+ case kIROp_Int8Type:
+ case kIROp_Int16Type:
+ case kIROp_IntType:
+ case kIROp_Int64Type:
+ case kIROp_UInt8Type:
+ case kIROp_UInt16Type:
+ case kIROp_UIntType:
+ case kIROp_UInt64Type:
+ break;
+ default:
+ SLANG_ASSERT_FAILURE("error type is not lowered to an integer type.");
+ }
+ IRBuilder builderStorage(sharedBuilderStorage);
+ auto builder = &builderStorage;
+ builder->setInsertInto(module);
+ return builder->getIntValue(type, 0);
+ }
+
+ void processMakeResultValue(IRMakeResultValue* inst)
+ {
+ IRBuilder builderStorage(sharedBuilderStorage);
+ auto builder = &builderStorage;
+ builder->setInsertBefore(inst);
+
+ auto info = getLoweredResultType(builder, inst->getDataType());
+ List<IRInst*> operands;
+ operands.add(inst->getOperand(0));
+ operands.add(getSuccessErrorValue(info->errorType));
+ auto makeStruct = builder->emitMakeStruct(info->loweredType, operands);
+ inst->replaceUsesWith(makeStruct);
+ inst->removeAndDeallocate();
+ }
+
+ void processMakeResultValueVoid(IRMakeResultValueVoid* inst)
+ {
+ IRBuilder builderStorage(sharedBuilderStorage);
+ auto builder = &builderStorage;
+ builder->setInsertBefore(inst);
+
+ auto info = getLoweredResultType(builder, inst->getDataType());
+ auto errCode = getSuccessErrorValue(info->errorType);
+ inst->replaceUsesWith(errCode);
+ inst->removeAndDeallocate();
+ }
+
+ void processMakeResultError(IRMakeResultError* inst)
+ {
+ IRBuilder builderStorage(sharedBuilderStorage);
+ auto builder = &builderStorage;
+ builder->setInsertBefore(inst);
+
+ auto info = getLoweredResultType(builder, inst->getDataType());
+ if (info->valueField)
+ {
+ List<IRInst*> operands;
+ operands.add(builder->emitConstructorInst(info->valueType, 0, nullptr));
+ operands.add(inst->getErrorValue());
+ auto makeStruct = builder->emitMakeStruct(info->loweredType, operands);
+ inst->replaceUsesWith(makeStruct);
+ }
+ else
+ {
+ inst->replaceUsesWith(inst->getErrorValue());
+ }
+ inst->removeAndDeallocate();
+ }
+
+ IRInst* getResultError(IRBuilder* builder, IRInst* resultInst)
+ {
+ auto loweredResultTypeInfo = getLoweredResultType(builder, resultInst->getDataType());
+ SLANG_ASSERT(loweredResultTypeInfo);
+ if (loweredResultTypeInfo->valueField)
+ {
+ auto value = builder->emitFieldExtract(
+ loweredResultTypeInfo->errorType,
+ resultInst,
+ loweredResultTypeInfo->errorField->getKey());
+ return value;
+ }
+ else
+ {
+ return resultInst;
+ }
+ }
+
+ void processGetResultError(IRGetResultError* inst)
+ {
+ IRBuilder builderStorage(sharedBuilderStorage);
+ auto builder = &builderStorage;
+ builder->setInsertBefore(inst);
+
+ auto resultValue = inst->getResultOperand();
+ auto errValue = getResultError(builder, resultValue);
+ inst->replaceUsesWith(errValue);
+ inst->removeAndDeallocate();
+ }
+
+ void processGetResultValue(IRGetResultValue* inst)
+ {
+ IRBuilder builderStorage(sharedBuilderStorage);
+ auto builder = &builderStorage;
+ builder->setInsertBefore(inst);
+
+ auto base = inst->getResultOperand();
+ auto loweredResultTypeInfo = getLoweredResultType(builder, base->getDataType());
+ SLANG_ASSERT(loweredResultTypeInfo);
+ SLANG_ASSERT(loweredResultTypeInfo->valueField);
+ auto getElement = builder->emitFieldExtract(
+ loweredResultTypeInfo->errorType,
+ base,
+ loweredResultTypeInfo->valueField->getKey());
+ inst->replaceUsesWith(getElement);
+ inst->removeAndDeallocate();
+ }
+
+ void processIsResultError(IRIsResultError* inst)
+ {
+ IRBuilder builderStorage(sharedBuilderStorage);
+ auto builder = &builderStorage;
+ builder->setInsertBefore(inst);
+
+ auto base = inst->getResultOperand();
+ auto loweredResultTypeInfo = getLoweredResultType(builder, base->getDataType());
+ SLANG_ASSERT(loweredResultTypeInfo);
+ SLANG_ASSERT(loweredResultTypeInfo->valueField);
+
+ auto resultValue = inst->getResultOperand();
+ auto errValue = getResultError(builder, resultValue);
+ auto isSuccess =
+ builder->emitNeq(errValue, getSuccessErrorValue(loweredResultTypeInfo->errorType));
+ inst->replaceUsesWith(isSuccess);
+ inst->removeAndDeallocate();
+ }
+
+ void processResultType(IRResultType* inst)
+ {
+ IRBuilder builderStorage(sharedBuilderStorage);
+ auto builder = &builderStorage;
+ builder->setInsertBefore(inst);
+
+ auto loweredResultTypeInfo = getLoweredResultType(builder, inst);
+ SLANG_ASSERT(loweredResultTypeInfo);
+ SLANG_UNUSED(loweredResultTypeInfo);
+ }
+
+ void processInst(IRInst* inst)
+ {
+ switch (inst->getOp())
+ {
+ case kIROp_MakeResultValue:
+ processMakeResultValue((IRMakeResultValue*)inst);
+ break;
+ case kIROp_MakeResultValueVoid:
+ processMakeResultValueVoid((IRMakeResultValueVoid*)inst);
+ break;
+ case kIROp_MakeResultError:
+ processMakeResultError((IRMakeResultError*)inst);
+ break;
+ case kIROp_GetResultError:
+ processGetResultError((IRGetResultError*)inst);
+ break;
+ case kIROp_GetResultValue:
+ processGetResultValue((IRGetResultValue*)inst);
+ break;
+ case kIROp_IsResultError:
+ processIsResultError((IRIsResultError*)inst);
+ break;
+ case kIROp_ResultType:
+ processResultType((IRResultType*)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 result types with lowered struct types.
+ for (auto kv : loweredResultTypes)
+ {
+ kv.Key->replaceUsesWith(kv.Value->loweredType);
+ }
+ }
+ };
+
+ void lowerResultType(IRModule* module, DiagnosticSink* sink)
+ {
+ ResultTypeLoweringContext context;
+ context.module = module;
+ context.sink = sink;
+ context.processModule();
+ }
+}