diff options
| author | Yong He <yonghe@outlook.com> | 2022-06-01 17:37:07 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-01 17:37:07 -0700 |
| commit | 17e3b88b541ed7f45d575f0f9caaa808cd0a6619 (patch) | |
| tree | efacd5d4bf6381a5adf8055daa28f91ddc048a76 /source/slang/slang-lower-to-ir.cpp | |
| parent | fa10f7dc23f8b93c0f9ef3fb5477871a20aaa974 (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.cpp | 123 |
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); |
