diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-02-08 14:46:12 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-02-08 14:46:12 -0800 |
| commit | c7c97ad4bb62b83efd6e26cdd4f38ebf164ec40e (patch) | |
| tree | db419221788d50dd1e8940b547713e5dcfceb48d /source/slang/emit.cpp | |
| parent | 112caca00ba9bfd9e1051bb94969efa9e74c6c03 (diff) | |
Basic IR support for `static const` globals (#404)
* Basic IR support for `static const` globals
Our strategy for lowering global *variables* can fall back to putting their initialization into a function, but that isn't really appropriate for global constants (it also isn't appropriate for arrays, but we'll need to deal with that seaprately).
This change adds a distinct case for global constants (rather than treating them as variables), and forces the emission logic to always emit them as a single expression.
Doing this makes assumptions about how the IR for these constants gets emitted (and what optimziations might do to it).
In order to make things work, I had to switch the handling of initializer-list expressions to not be lowered via temporaries and mutation (since that isn't a good fit for reverting to a single expression).
I've added a single test case to ensure that this works in the simplest scenario. My next priority will be to see if this unblocks my work in Falcor.
* Fixup: bug fixes
Diffstat (limited to 'source/slang/emit.cpp')
| -rw-r--r-- | source/slang/emit.cpp | 261 |
1 files changed, 180 insertions, 81 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 0a71c7fa9..335662ab3 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -4728,6 +4728,7 @@ emitDeclImpl(decl, nullptr); switch (inst->op) { case kIROp_global_var: + case kIROp_global_constant: case kIROp_Func: { auto& mangledName = ((IRGlobalValue*)inst)->mangledName; @@ -4786,7 +4787,7 @@ emitDeclImpl(decl, nullptr); case IRDeclaratorInfo::Flavor::Array: emitDeclarator(ctx, declarator->next); emit("["); - emitIROperand(ctx, declarator->elementCount); + emitIROperand(ctx, declarator->elementCount, IREmitMode::Default); emit("]"); break; } @@ -5041,9 +5042,17 @@ emitDeclImpl(decl, nullptr); } #endif + // Hack to allow IR emit for global constant to override behavior + enum class IREmitMode + { + Default, + GlobalConstant, + }; + bool shouldFoldIRInstIntoUseSites( EmitContext* ctx, - IRValue* inst) + IRValue* inst, + IREmitMode mode) { // Certain opcodes should always be folded in switch( inst->op ) @@ -5053,6 +5062,7 @@ emitDeclImpl(decl, nullptr); case kIROp_Var: case kIROp_global_var: + case kIROp_global_constant: case kIROp_Param: return false; @@ -5066,6 +5076,10 @@ emitDeclImpl(decl, nullptr); return true; } + // Always fold when we are inside a global constant initializer + if (mode == IREmitMode::GlobalConstant) + return true; + // Certain *types* will usually want to be folded in, // because they aren't allowed as types for temporary // variables. @@ -5137,12 +5151,13 @@ emitDeclImpl(decl, nullptr); void emitIROperand( EmitContext* ctx, - IRValue* inst) + IRValue* inst, + IREmitMode mode) { - if( shouldFoldIRInstIntoUseSites(ctx, inst) ) + if( shouldFoldIRInstIntoUseSites(ctx, inst, mode) ) { emit("("); - emitIRInstExpr(ctx, inst); + emitIRInstExpr(ctx, inst, mode); emit(")"); return; } @@ -5158,7 +5173,8 @@ emitDeclImpl(decl, nullptr); void emitIRArgs( EmitContext* ctx, - IRInst* inst) + IRInst* inst, + IREmitMode mode) { UInt argCount = inst->argCount; IRUse* args = inst->getArgs(); @@ -5167,7 +5183,7 @@ emitDeclImpl(decl, nullptr); for(UInt aa = 0; aa < argCount; ++aa) { if(aa != 0) emit(", "); - emitIROperand(ctx, args[aa].usedValue); + emitIROperand(ctx, args[aa].usedValue, mode); } emit(")"); } @@ -5450,7 +5466,8 @@ emitDeclImpl(decl, nullptr); EmitContext* ctx, IRCall* inst, IRFunc* /* func */, - IRTargetIntrinsicDecoration* targetIntrinsic) + IRTargetIntrinsicDecoration* targetIntrinsic, + IREmitMode mode) { IRUse* args = inst->getArgs(); UInt argCount = inst->getArgCount(); @@ -5471,7 +5488,7 @@ emitDeclImpl(decl, nullptr); for (UInt aa = 0; aa < argCount; ++aa) { if (aa != 0) Emit(", "); - emitIROperand(ctx, args[aa].usedValue); + emitIROperand(ctx, args[aa].usedValue, mode); } Emit(")"); return; @@ -5507,7 +5524,7 @@ emitDeclImpl(decl, nullptr); UInt argIndex = d - '0'; SLANG_RELEASE_ASSERT((0 <= argIndex) && (argIndex < argCount)); Emit("("); - emitIROperand(ctx, args[argIndex].usedValue); + emitIROperand(ctx, args[argIndex].usedValue, mode); Emit(")"); } break; @@ -5535,9 +5552,9 @@ emitDeclImpl(decl, nullptr); } Emit("("); - emitIROperand(ctx, textureArg); + emitIROperand(ctx, textureArg, mode); Emit(","); - emitIROperand(ctx, samplerArg); + emitIROperand(ctx, samplerArg, mode); Emit(")"); } else @@ -5564,7 +5581,7 @@ emitDeclImpl(decl, nullptr); { emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler"); Emit("("); - emitIROperand(ctx, textureArg); + emitIROperand(ctx, textureArg, mode); Emit(","); Emit("SLANG_hack_samplerForTexelFetch"); context->shared->needHackSamplerForTexelFetch = true; @@ -5631,7 +5648,8 @@ emitDeclImpl(decl, nullptr); void emitIntrinsicCallExpr( EmitContext* ctx, IRCall* inst, - IRFunc* func) + IRFunc* func, + IREmitMode mode) { // For a call with N arguments, the instruction will // have N+1 operands. We will start consuming operands @@ -5648,7 +5666,8 @@ emitDeclImpl(decl, nullptr); ctx, inst, func, - targetIntrinsicDecoration); + targetIntrinsicDecoration, + mode); return; } @@ -5676,15 +5695,15 @@ emitDeclImpl(decl, nullptr); { // The user is invoking a built-in subscript operator emit("("); - emitIROperand(ctx, inst->getArg(operandIndex++)); + emitIROperand(ctx, inst->getArg(operandIndex++), mode); emit(")["); - emitIROperand(ctx, inst->getArg(operandIndex++)); + emitIROperand(ctx, inst->getArg(operandIndex++), mode); emit("]"); if(operandIndex < operandCount) { emit(" = "); - emitIROperand(ctx, inst->getArg(operandIndex++)); + emitIROperand(ctx, inst->getArg(operandIndex++), mode); } return; } @@ -5700,7 +5719,7 @@ emitDeclImpl(decl, nullptr); { // Looks like a member function call emit("("); - emitIROperand(ctx, inst->getArg(operandIndex)); + emitIROperand(ctx, inst->getArg(operandIndex), mode); emit(")."); operandIndex++; @@ -5712,7 +5731,7 @@ emitDeclImpl(decl, nullptr); for(; operandIndex < operandCount; ++operandIndex ) { if(!first) emit(", "); - emitIROperand(ctx, inst->getArg(operandIndex)); + emitIROperand(ctx, inst->getArg(operandIndex), mode); first = false; } emit(")"); @@ -5720,24 +5739,25 @@ emitDeclImpl(decl, nullptr); void emitIRCallExpr( EmitContext* ctx, - IRCall* inst) + IRCall* inst, + IREmitMode mode) { // We want to detect any call to an intrinsic operation, // that we can emit it directly without mangling, etc. auto funcValue = inst->getArg(0); if(auto irFunc = asTargetIntrinsic(ctx, funcValue)) { - emitIntrinsicCallExpr(ctx, inst, irFunc); + emitIntrinsicCallExpr(ctx, inst, irFunc, mode); } else { - emitIROperand(ctx, funcValue); + emitIROperand(ctx, funcValue, mode); emit("("); UInt argCount = inst->getArgCount(); for( UInt aa = 1; aa < argCount; ++aa ) { if(aa != 1) emit(", "); - emitIROperand(ctx, inst->getArg(aa)); + emitIROperand(ctx, inst->getArg(aa), mode); } emit(")"); } @@ -5745,7 +5765,8 @@ emitDeclImpl(decl, nullptr); void emitIRInstExpr( EmitContext* ctx, - IRValue* value) + IRValue* value, + IREmitMode mode) { IRInst* inst = (IRInst*) value; @@ -5760,6 +5781,8 @@ emitDeclImpl(decl, nullptr); break; case kIROp_Construct: + case kIROp_makeVector: + case kIROp_makeMatrix: // Simple constructor call if( inst->getArgCount() == 1 && getTarget(ctx) == CodeGenTarget::HLSL) { @@ -5767,12 +5790,12 @@ emitDeclImpl(decl, nullptr); emit("("); emitIRType(ctx, inst->getType()); emit(") "); - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); } else { emitIRType(ctx, inst->getType()); - emitIRArgs(ctx, inst); + emitIRArgs(ctx, inst, mode); } break; @@ -5789,7 +5812,7 @@ emitDeclImpl(decl, nullptr); emitIRType(ctx, inst->getType()); } emit("("); - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(")"); break; @@ -5801,7 +5824,7 @@ emitDeclImpl(decl, nullptr); if (!isDerefBaseImplicit(ctx, fieldExtract->getBase())) { - emitIROperand(ctx, fieldExtract->getBase()); + emitIROperand(ctx, fieldExtract->getBase(), mode); emit("."); } emit(getIRName(fieldExtract->getField())); @@ -5816,7 +5839,7 @@ emitDeclImpl(decl, nullptr); if (!isDerefBaseImplicit(ctx, ii->getBase())) { - emitIROperand(ctx, ii->getBase()); + emitIROperand(ctx, ii->getBase(), mode); emit("."); } @@ -5826,9 +5849,9 @@ emitDeclImpl(decl, nullptr); #define CASE(OPCODE, OP) \ case OPCODE: \ - emitIROperand(ctx, inst->getArg(0)); \ + emitIROperand(ctx, inst->getArg(0), mode); \ emit(" " #OP " "); \ - emitIROperand(ctx, inst->getArg(1)); \ + emitIROperand(ctx, inst->getArg(1), mode); \ break CASE(kIROp_Add, +); @@ -5866,18 +5889,18 @@ emitDeclImpl(decl, nullptr); && inst->type->As<MatrixExpressionType>()) { emit("matrixCompMult("); - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(", "); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit(")"); } else { // Default handling is to just rely on infix // `operator*`. - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(" * "); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); } break; @@ -5891,77 +5914,77 @@ emitDeclImpl(decl, nullptr); { emit("~"); } - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); } break; case kIROp_Neg: { emit("-"); - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); } break; case kIROp_BitNot: { emit("~"); - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); } break; case kIROp_Sample: - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(".Sample("); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit(", "); - emitIROperand(ctx, inst->getArg(2)); + emitIROperand(ctx, inst->getArg(2), mode); emit(")"); break; case kIROp_SampleGrad: // argument 0 is the instruction's type - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(".SampleGrad("); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit(", "); - emitIROperand(ctx, inst->getArg(2)); + emitIROperand(ctx, inst->getArg(2), mode); emit(", "); - emitIROperand(ctx, inst->getArg(3)); + emitIROperand(ctx, inst->getArg(3), mode); emit(", "); - emitIROperand(ctx, inst->getArg(4)); + emitIROperand(ctx, inst->getArg(4), mode); emit(")"); break; case kIROp_Load: // TODO: this logic will really only work for a simple variable reference... - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); break; case kIROp_Store: // TODO: this logic will really only work for a simple variable reference... - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(" = "); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); break; case kIROp_Call: { - emitIRCallExpr(ctx, (IRCall*)inst); + emitIRCallExpr(ctx, (IRCall*)inst, mode); } break; case kIROp_BufferLoad: case kIROp_BufferElementRef: - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit("["); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit("]"); break; case kIROp_BufferStore: - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit("["); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit("] = "); - emitIROperand(ctx, inst->getArg(2)); + emitIROperand(ctx, inst->getArg(2), mode); break; case kIROp_GroupMemoryBarrierWithGroupSync: @@ -5970,9 +5993,9 @@ emitDeclImpl(decl, nullptr); case kIROp_getElement: case kIROp_getElementPtr: - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit("["); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit("]"); break; @@ -5989,16 +6012,16 @@ emitDeclImpl(decl, nullptr); // because the notion of what is a "row" vs. a "column" // is reversed between HLSL/Slang and GLSL. // - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit(" * "); - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); } else { emit("mul("); - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(", "); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit(")"); } break; @@ -6006,7 +6029,7 @@ emitDeclImpl(decl, nullptr); case kIROp_swizzle: { auto ii = (IRSwizzle*)inst; - emitIROperand(ctx, ii->getBase()); + emitIROperand(ctx, ii->getBase(), mode); emit("."); UInt elementCount = ii->getElementCount(); for (UInt ee = 0; ee < elementCount; ++ee) @@ -6026,17 +6049,17 @@ emitDeclImpl(decl, nullptr); case kIROp_specialize: { - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); } break; case kIROp_Select: { - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(" ? "); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit(" : "); - emitIROperand(ctx, inst->getArg(2)); + emitIROperand(ctx, inst->getArg(2), mode); } break; @@ -6044,6 +6067,24 @@ emitDeclImpl(decl, nullptr); emit(getIRName(inst)); break; + case kIROp_makeArray: + case kIROp_makeStruct: + { + // TODO: initializer-list syntax may not always + // be appropriate, depending on the context + // of the expression. + + emit("{ "); + UInt argCount = inst->getArgCount(); + for (UInt aa = 0; aa < argCount; ++aa) + { + if (aa != 0) emit(", "); + emitIROperand(ctx, inst->getArg(aa), mode); + } + emit(" }"); + } + break; + default: emit("/* unhandled */"); break; @@ -6052,9 +6093,10 @@ emitDeclImpl(decl, nullptr); void emitIRInst( EmitContext* ctx, - IRInst* inst) + IRInst* inst, + IREmitMode mode) { - if (shouldFoldIRInstIntoUseSites(ctx, inst)) + if (shouldFoldIRInstIntoUseSites(ctx, inst, mode)) { return; } @@ -6065,7 +6107,7 @@ emitDeclImpl(decl, nullptr); { default: emitIRInstResultDecl(ctx, inst); - emitIRInstExpr(ctx, inst); + emitIRInstExpr(ctx, inst, mode); emit(";\n"); break; @@ -6103,7 +6145,7 @@ emitDeclImpl(decl, nullptr); case kIROp_ReturnVal: emit("return "); - emitIROperand(ctx, ((IRReturnVal*) inst)->getVal()); + emitIROperand(ctx, ((IRReturnVal*) inst)->getVal(), mode); emit(";\n"); break; @@ -6115,9 +6157,9 @@ emitDeclImpl(decl, nullptr); { auto ii = (IRSwizzleSet*)inst; emitIRInstResultDecl(ctx, inst); - emitIROperand(ctx, inst->getArg(0)); + emitIROperand(ctx, inst->getArg(0), mode); emit(";\n"); - emitIROperand(ctx, inst); + emitIROperand(ctx, inst, mode); emit("."); UInt elementCount = ii->getElementCount(); for (UInt ee = 0; ee < elementCount; ++ee) @@ -6133,7 +6175,7 @@ emitDeclImpl(decl, nullptr); emit(kComponents[elementIndex]); } emit(" = "); - emitIROperand(ctx, inst->getArg(1)); + emitIROperand(ctx, inst->getArg(1), mode); emit(";\n"); } break; @@ -6229,9 +6271,9 @@ emitDeclImpl(decl, nullptr); IRValue* arg = args[argIndex].usedValue; - emitIROperand(ctx, pp); + emitIROperand(ctx, pp, IREmitMode::Default); emit(" = "); - emitIROperand(ctx, arg); + emitIROperand(ctx, arg, IREmitMode::Default); emit(";\n"); } } @@ -6331,7 +6373,7 @@ emitDeclImpl(decl, nullptr); assert(isTerminatorInst(terminator)); for (auto inst = block->getFirstInst(); inst != terminator; inst = inst->getNextInst()) { - emitIRInst(ctx, inst); + emitIRInst(ctx, inst, IREmitMode::Default); } // Now look at the terminator instruction, which will tell us what we need to emit next. @@ -6350,7 +6392,7 @@ emitDeclImpl(decl, nullptr); case kIROp_ReturnVal: case kIROp_ReturnVoid: case kIROp_discard: - emitIRInst(ctx, terminator); + emitIRInst(ctx, terminator, IREmitMode::Default); return; case kIROp_ifElse: @@ -6368,7 +6410,7 @@ emitDeclImpl(decl, nullptr); // instead of the current `if(cond) {} else {falseBlock}` emit("if("); - emitIROperand(ctx, t->getCondition()); + emitIROperand(ctx, t->getCondition(), IREmitMode::Default); emit(")\n{\n"); emitIRStmtsForBlocks( ctx, @@ -6606,7 +6648,7 @@ emitDeclImpl(decl, nullptr); // Emit the start of our statement. emit("switch("); - emitIROperand(ctx, conditionVal); + emitIROperand(ctx, conditionVal, IREmitMode::Default); emit(")\n{\n"); // Now iterate over the `case`s of the branch @@ -6634,7 +6676,7 @@ emitDeclImpl(decl, nullptr); for(;;) { emit("case "); - emitIROperand(ctx, caseVal); + emitIROperand(ctx, caseVal, IREmitMode::Default); emit(":\n"); if(caseIndex >= caseCount) @@ -7744,6 +7786,51 @@ emitDeclImpl(decl, nullptr); emit(";\n"); } + void emitIRGlobalConstantInitializer( + EmitContext* ctx, + IRGlobalConstant* valDecl) + { + // We expect to see only a single block + auto block = valDecl->getFirstBlock(); + assert(block); + assert(!block->getNextBlock()); + + // We expect the terminator to be a `return` + // instruction with a value. + auto returnInst = (IRReturnVal*) block->getLastInst(); + assert(returnInst->op == kIROp_ReturnVal); + + // Now we want to emit the expression form of + // the value being returned, and force any + // sub-expressions to be included. + emitIRInstExpr(ctx, returnInst->getVal(), IREmitMode::GlobalConstant); + } + + void emitIRGlobalConstant( + EmitContext* ctx, + IRGlobalConstant* valDecl) + { + auto valType = valDecl->getType(); + + emit("static const "); + emitIRType(ctx, valType, getIRName(valDecl)); + + if (valDecl->firstBlock) + { + // There is an initializer (which we expect for + // any global constant...). + + emit(" = "); + + // We need to emit the entire initializer as + // a single expression. + emitIRGlobalConstantInitializer(ctx, valDecl); + } + + + emit(";\n"); + } + void emitIRGlobalInst( EmitContext* ctx, IRGlobalValue* inst) @@ -7760,6 +7847,10 @@ emitDeclImpl(decl, nullptr); emitIRGlobalVar(ctx, (IRGlobalVar*) inst); break; + case kIROp_global_constant: + emitIRGlobalConstant(ctx, (IRGlobalConstant*) inst); + break; + case kIROp_Var: emitIRVar(ctx, (IRVar*) inst); break; @@ -7921,6 +8012,14 @@ emitDeclImpl(decl, nullptr); } break; + case kIROp_global_constant: + { + auto irGlobal = (IRGlobalConstant*) value; + emitIRUsedType(ctx, irGlobal->type); + emitIRUsedTypesForGlobalValueWithCode(ctx, irGlobal); + } + break; + default: { emitIRUsedType(ctx, value->type); |
