summaryrefslogtreecommitdiff
path: root/source/slang/slang-lower-to-ir.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-lower-to-ir.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-lower-to-ir.cpp')
-rw-r--r--source/slang/slang-lower-to-ir.cpp123
1 files changed, 104 insertions, 19 deletions
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 5cfb07c1c..1448139fb 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -16,6 +16,7 @@
#include "slang-ir-validate.h"
#include "slang-ir-string-hash.h"
#include "slang-ir-clone.h"
+#include "slang-ir-lower-error-handling.h"
#include "slang-mangle.h"
#include "slang-type-layout.h"
@@ -612,6 +613,12 @@ int32_t getIntrinsicOp(
return int32_t(irOp);
}
+struct TryClauseEnvironment
+{
+ TryClauseType clauseType = TryClauseType::None;
+ IRBlock* catchBlock = nullptr;
+};
+
// Given a `LoweredValInfo` for something callable, along with a
// bunch of arguments, emit an appropriate call to it.
LoweredValInfo emitCallToVal(
@@ -619,7 +626,8 @@ LoweredValInfo emitCallToVal(
IRType* type,
LoweredValInfo funcVal,
UInt argCount,
- IRInst* const* args)
+ IRInst* const* args,
+ const TryClauseEnvironment& tryEnv)
{
auto builder = context->irBuilder;
switch (funcVal.flavor)
@@ -627,8 +635,33 @@ LoweredValInfo emitCallToVal(
case LoweredValInfo::Flavor::None:
SLANG_UNEXPECTED("null function");
default:
- return LoweredValInfo::simple(
- builder->emitCallInst(type, getSimpleVal(context, funcVal), argCount, args));
+ switch (tryEnv.clauseType)
+ {
+ case TryClauseType::None:
+ return LoweredValInfo::simple(
+ builder->emitCallInst(type, getSimpleVal(context, funcVal), argCount, args));
+
+ case TryClauseType::Standard:
+ {
+ auto callee = getSimpleVal(context, funcVal);
+ auto succBlock = builder->createBlock();
+ auto failBlock = builder->createBlock();
+ auto funcType = as<IRFuncType>(callee->getDataType());
+ auto throwAttr = funcType->findAttr<IRFuncThrowTypeAttr>();
+ assert(throwAttr);
+ auto voidType = builder->getVoidType();
+ builder->emitTryCallInst(voidType, succBlock, failBlock, callee, argCount, args);
+ builder->insertBlock(failBlock);
+ auto errParam = builder->emitParam(throwAttr->getErrorType());
+ builder->emitThrow(errParam);
+ builder->insertBlock(succBlock);
+ auto value = builder->emitParam(type);
+ return LoweredValInfo::simple(value);
+ }
+ break;
+ default:
+ SLANG_UNIMPLEMENTED_X("emitCallToVal(tryClauseType)");
+ }
}
}
@@ -655,7 +688,8 @@ LoweredValInfo emitCallToDeclRef(
DeclRef<Decl> funcDeclRef,
IRType* funcType,
UInt argCount,
- IRInst* const* args)
+ IRInst* const* args,
+ const TryClauseEnvironment& tryEnv)
{
SLANG_ASSERT(funcType);
@@ -700,7 +734,7 @@ LoweredValInfo emitCallToDeclRef(
// Fallback case is to emit an actual call.
//
LoweredValInfo funcVal = emitDeclRef(context, funcDeclRef, funcType);
- return emitCallToVal(context, type, funcVal, argCount, args);
+ return emitCallToVal(context, type, funcVal, argCount, args, tryEnv);
}
LoweredValInfo emitCallToDeclRef(
@@ -708,9 +742,17 @@ LoweredValInfo emitCallToDeclRef(
IRType* type,
DeclRef<Decl> funcDeclRef,
IRType* funcType,
- List<IRInst*> const& args)
+ List<IRInst*> const& args,
+ const TryClauseEnvironment& tryEnv)
{
- return emitCallToDeclRef(context, type, funcDeclRef, funcType, args.getCount(), args.getBuffer());
+ return emitCallToDeclRef(
+ context,
+ type,
+ funcDeclRef,
+ funcType,
+ args.getCount(),
+ args.getBuffer(),
+ tryEnv);
}
/// Represents the "direction" that a parameter is being passed (e.g., `in` or `out`
@@ -1580,10 +1622,21 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
{
paramTypes.add(lowerType(context, type->getParamType(pp)));
}
- return getBuilder()->getFuncType(
- paramCount,
- paramTypes.getBuffer(),
- resultType);
+ if (type->errorType->equals(context->astBuilder->getVoidType()))
+ {
+ return getBuilder()->getFuncType(
+ paramCount,
+ paramTypes.getBuffer(),
+ resultType);
+ }
+ else
+ {
+ auto errorType = lowerType(context, type->getErrorType());
+ auto irThrowFuncTypeAttribute =
+ getBuilder()->getAttr(kIROp_FuncThrowTypeAttr, 1, (IRInst**)&errorType);
+ return getBuilder()->getFuncType(
+ paramCount, paramTypes.getBuffer(), resultType, irThrowFuncTypeAttribute);
+ }
}
IRType* visitPtrType(PtrType* type)
@@ -2784,11 +2837,20 @@ void _lowerFuncDeclBaseTypeInfo(
// being accessed, rather than a simple value.
irResultType = builder->getPtrType(irResultType);
}
-
- outInfo.type = builder->getFuncType(
- paramTypes.getCount(),
- paramTypes.getBuffer(),
- irResultType);
+
+ auto errorType = lowerType(context, getErrorCodeType(context->astBuilder, declRef));
+ if (errorType->getOp() != kIROp_VoidType)
+ {
+ IRAttr* throwTypeAttr = nullptr;
+ throwTypeAttr = builder->getAttr(kIROp_FuncThrowTypeAttr, 1, (IRInst**)&errorType);
+ outInfo.type = builder->getFuncType(
+ paramTypes.getCount(), paramTypes.getBuffer(), irResultType, throwTypeAttr);
+ }
+ else
+ {
+ outInfo.type =
+ builder->getFuncType(paramTypes.getCount(), paramTypes.getBuffer(), irResultType);
+ }
}
static LoweredValInfo _emitCallToAccessor(
@@ -2824,7 +2886,8 @@ static LoweredValInfo _emitCallToAccessor(
accessorDeclRef,
info.type,
allArgs.getCount(),
- allArgs.getBuffer());
+ allArgs.getBuffer(),
+ TryClauseEnvironment());
applyOutArgumentFixups(context, fixups);
@@ -3524,6 +3587,11 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
LoweredValInfo visitInvokeExpr(InvokeExpr* expr)
{
+ return visitInvokeExprImpl(expr, TryClauseEnvironment());
+ }
+
+ LoweredValInfo visitInvokeExprImpl(InvokeExpr* expr, const TryClauseEnvironment& tryEnv)
+ {
auto type = lowerType(context, expr->type);
// We are going to look at the syntactic form of
@@ -3636,7 +3704,8 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
type,
funcDeclRef,
funcType,
- irArgs);
+ irArgs,
+ tryEnv);
applyOutArgumentFixups(context, argFixups);
return result;
}
@@ -3658,6 +3727,16 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
UNREACHABLE_RETURN(LoweredValInfo());
}
+ /// Emit code for a `try` invoke.
+ LoweredValInfo visitTryExpr(TryExpr* expr)
+ {
+ auto invokeExpr = as<InvokeExpr>(expr->base);
+ assert(invokeExpr);
+ TryClauseEnvironment tryEnv;
+ tryEnv.clauseType = expr->tryClauseType;
+ return visitInvokeExprImpl(invokeExpr, tryEnv);
+ }
+
/// Emit code to cast `value` to a concrete `superType` (e.g., a `struct`).
///
/// The `subTypeWitness` is expected to witness the sub-type relationship
@@ -8338,7 +8417,13 @@ RefPtr<IRModule> generateIRForTranslationUnit(
// dumpIR(module);
- // First, inline calls to any functions that have been
+ // First, lower error handling logic into normal control flow.
+ // This includes lowering throwing functions into functions that
+ // returns a `Result<T,E>` value, translating `tryCall` into
+ // normal `call` + `ifElse`, etc.
+ lowerErrorHandling(module, compileRequest->getSink());
+
+ // Next, inline calls to any functions that have been
// marked for mandatory "early" inlining.
//
performMandatoryEarlyInlining(module);