diff options
Diffstat (limited to 'source/slang/lower-to-ir.cpp')
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 199 |
1 files changed, 192 insertions, 7 deletions
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 5ee6d5460..6f64a2215 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -1,6 +1,8 @@ // lower.cpp #include "lower-to-ir.h" +#include "../../slang.h" + #include "ir.h" #include "ir-insts.h" #include "type-layout.h" @@ -354,6 +356,73 @@ LoweredValInfo emitCompoundAssignOp( return LoweredValInfo::ptr(leftPtr); } +IRInst* getOneValOfType( + IRGenContext* context, + IRType* type) +{ + switch(type->op) + { + case kIROp_Int32Type: + case kIROp_UInt32Type: + return context->irBuilder->getIntValue(type, 1); + + case kIROp_Float32Type: + return context->irBuilder->getFloatValue(type, 1.0); + + default: + SLANG_UNEXPECTED("inc/dec type"); + return nullptr; + } +} + +LoweredValInfo emitPreOp( + IRGenContext* context, + IRType* type, + IROp op, + UInt argCount, + IRValue* const* args) +{ + auto builder = context->irBuilder; + + assert(argCount == 1); + auto argPtr = args[0]; + + auto preVal = builder->emitLoad(argPtr); + + IRInst* oneVal = getOneValOfType(context, type); + + IRInst* innerArgs[] = { preVal, oneVal }; + auto innerOp = builder->emitIntrinsicInst(type, op, 2, innerArgs); + + builder->emitStore(argPtr, innerOp); + + return LoweredValInfo::simple(preVal); +} + +LoweredValInfo emitPostOp( + IRGenContext* context, + IRType* type, + IROp op, + UInt argCount, + IRValue* const* args) +{ + auto builder = context->irBuilder; + + assert(argCount == 1); + auto argPtr = args[0]; + + auto preVal = builder->emitLoad(argPtr); + + IRInst* oneVal = getOneValOfType(context, type); + + IRInst* innerArgs[] = { preVal, oneVal }; + auto innerOp = builder->emitIntrinsicInst(type, op, 2, innerArgs); + + builder->emitStore(argPtr, innerOp); + + return LoweredValInfo::ptr(argPtr); +} + // Given a `DeclRef` for something callable, along with a bunch of // arguments, emit an appropriate call to it. LoweredValInfo emitCallToDeclRef( @@ -444,6 +513,18 @@ LoweredValInfo emitCallToDeclRef( #undef CASE +#define CASE(COMPOUND, OP) \ + case COMPOUND: return emitPreOp(context, type, OP, argCount, args) + CASE(kIRPseudoOp_PreInc, kIROp_Add); + CASE(kIRPseudoOp_PreDec, kIROp_Sub); +#undef CASE + +#define CASE(COMPOUND, OP) \ + case COMPOUND: return emitPostOp(context, type, OP, argCount, args) + CASE(kIRPseudoOp_PostInc, kIROp_Add); + CASE(kIRPseudoOp_PostDec, kIROp_Sub); +#undef CASE + default: SLANG_UNIMPLEMENTED_X("IR pseudo-op"); break; @@ -1603,6 +1684,65 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> insertBlock(breakLabel); } + void visitWhileStmt(WhileStmt* stmt) + { + // Generating IR for `while` statement is similar to a + // `for` statement, but without a lot of the complications. + + auto builder = getBuilder(); + + // We will create blocks for the various places + // we need to jump to inside the control flow, + // including the blocks that will be referenced + // by `continue` or `break` statements. + auto loopHead = createBlock(); + auto bodyLabel = createBlock(); + auto breakLabel = createBlock(); + + // A `continue` inside a `while` loop always + // jumps to the head of hte loop. + auto continueLabel = loopHead; + + // TODO: register appropriate targets for + // break/continue statements. + + // Emit the branch that will start out loop, + // and then insert the block for the head. + + auto loopInst = builder->emitLoop( + loopHead, + breakLabel, + continueLabel); + + addLoopDecorations(loopInst, stmt); + + insertBlock(loopHead); + + // Now that we are within the header block, we + // want to emit the expression for the loop condition: + if (auto condExpr = stmt->Predicate) + { + auto irCondition = getSimpleVal(context, + lowerRValueExpr(context, condExpr)); + + // Now we want to `break` if the loop condition is false. + builder->emitLoopTest( + irCondition, + bodyLabel, + breakLabel); + } + + // Emit the body of the loop + insertBlock(bodyLabel); + lowerStmt(context, stmt->Statement); + + // At the end of the body we need to jump back to the top. + builder->emitBranch(loopHead); + + // Finally we insert the label that a `break` will jump to + insertBlock(breakLabel); + } + void visitExpressionStmt(ExpressionStmt* stmt) { // The statement evaluates an expression @@ -1993,17 +2133,61 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> for( auto paramDecl : declForParameters->GetParameters() ) { IRType* irParamType = lowerSimpleType(context, paramDecl->getType()); - paramTypes.Add(irParamType); - IRParam* irParam = subBuilder->emitParam(irParamType); + LoweredValInfo paramVal; - subBuilder->addHighLevelDeclDecoration(irParam, paramDecl); + if (paramDecl->HasModifier<OutModifier>() + || paramDecl->HasModifier<InOutModifier>()) + { + // The parameter is being used for input/output purposes, + // so it will lower to an actual parameter with a pointer type. + // + // TODO: Is this the best representation we can use? - DeclRef<ParamDecl> paramDeclRef = makeDeclRef(paramDecl.Ptr()); + auto irPtrType = subBuilder->getPtrType(irParamType); + paramTypes.Add(irPtrType); + + IRParam* irParamPtr = subBuilder->emitParam(irPtrType); + subBuilder->addHighLevelDeclDecoration(irParamPtr, paramDecl); - LoweredValInfo irParamVal = LoweredValInfo::simple(irParam); + paramVal = LoweredValInfo::ptr(irParamPtr); - subContext->shared->declValues.Add(paramDeclRef, irParamVal); + // TODO: We might want to copy the pointed-to value into + // a temporary at the start of the function, and then copy + // back out at the end, so that we don't have to worry + // about things like aliasing in the function body. + // + // For now we will just use the storage that was passed + // in by the caller, knowing that our current lowering + // at call sites will guarantee a fresh/unique location. + } + else + { + // Simple case of a by-value input parameter. + // But note that HLSL allows an input parameter + // to be used as a local variable inside of a + // function body, so we need to introduce a temporary + // and then copy over to it... + // + // TODO: we could skip this step if we knew + // the parameter was marked `const` or similar. + + paramTypes.Add(irParamType); + + IRParam* irParam = subBuilder->emitParam(irParamType); + subBuilder->addHighLevelDeclDecoration(irParam, paramDecl); + paramVal = LoweredValInfo::simple(irParam); + + auto irLocal = subBuilder->emitVar(irParamType); + auto localVal = LoweredValInfo::ptr(irLocal); + + assign(subContext, localVal, paramVal); + + paramVal = localVal; + } + + DeclRef<ParamDecl> paramDeclRef = makeDeclRef(paramDecl.Ptr()); + subContext->shared->declValues.Add(paramDeclRef, paramVal); } auto irResultType = lowerSimpleType(context, declForReturnType->ReturnType); @@ -2235,4 +2419,5 @@ String emitSlangIRAssemblyForEntryPoint( return getSlangIRAssembly(irModule); } -} + +} // namespace Slang |
