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 | |
| 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')
| -rw-r--r-- | source/slang/bytecode.cpp | 3 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 261 | ||||
| -rw-r--r-- | source/slang/ir-inst-defs.h | 8 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 26 | ||||
| -rw-r--r-- | source/slang/ir-legalize-types.cpp | 50 | ||||
| -rw-r--r-- | source/slang/ir-ssa.cpp | 1 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 85 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 60 | ||||
| -rw-r--r-- | source/slang/vm.cpp | 8 |
9 files changed, 388 insertions, 114 deletions
diff --git a/source/slang/bytecode.cpp b/source/slang/bytecode.cpp index 3b92b78e1..eb6b755fc 100644 --- a/source/slang/bytecode.cpp +++ b/source/slang/bytecode.cpp @@ -918,12 +918,15 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst( break; case kIROp_global_var: + case kIROp_global_constant: { auto bcVar = allocate<BCSymbol>(context); bcVar->op = inst->op; bcVar->typeID = getTypeID(context, inst->type); + // TODO: actually need to intialize with body instructions + return bcVar; } break; 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); diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h index 41e614807..9d6330eae 100644 --- a/source/slang/ir-inst-defs.h +++ b/source/slang/ir-inst-defs.h @@ -103,6 +103,12 @@ INST(lookup_interface_method, lookup_interface_method, 2, 0) INST(lookup_witness_table, lookup_witness_table, 2, 0) INST(Construct, construct, 0, 0) + +INST(makeVector, makeVector, 0, 0) +INST(makeMatrix, makeMatrix, 0, 0) +INST(makeArray, makeArray, 0, 0) +INST(makeStruct, makeStruct, 0, 0) + INST(Call, call, 1, 0) INST(Module, module, 0, PARENT) @@ -110,6 +116,8 @@ INST(Func, func, 0, PARENT) INST(Block, block, 0, PARENT) INST(global_var, global_var, 0, 0) +INST(global_constant, global_constant, 0, 0) + INST(witness_table, witness_table, 0, 0) INST(witness_table_entry, witness_table_entry, 2, 0) diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index 266374545..eec42d59a 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -304,6 +304,15 @@ struct IRGlobalVar : IRGlobalValueWithCode PtrType* getType() { return type.As<PtrType>(); } }; +/// @brief A global constant. +/// +/// Represents a global-scope constant value in the IR. +/// The initializer for the constant is represented by +/// the code in the basic block(s) nested in this value. +struct IRGlobalConstant : IRGlobalValueWithCode +{ +}; + // An entry in a witness table (see below) struct IRWitnessTableEntry : IRUser { @@ -453,6 +462,21 @@ struct IRBuilder UInt argCount, IRValue* const* args); + IRInst* emitMakeVector( + IRType* type, + UInt argCount, + IRValue* const* args); + + IRInst* emitMakeArray( + IRType* type, + UInt argCount, + IRValue* const* args); + + IRInst* emitMakeStruct( + IRType* type, + UInt argCount, + IRValue* const* args); + IRUndefined* emitUndefined(IRType* type); @@ -462,6 +486,8 @@ struct IRBuilder IRFunc* createFunc(); IRGlobalVar* createGlobalVar( IRType* valueType); + IRGlobalConstant* createGlobalConstant( + IRType* valueType); IRWitnessTable* createWitnessTable(); IRWitnessTableEntry* createWitnessTableEntry( IRWitnessTable* witnessTable, diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp index d4f6d2a64..9234af8f5 100644 --- a/source/slang/ir-legalize-types.cpp +++ b/source/slang/ir-legalize-types.cpp @@ -104,7 +104,7 @@ static void registerLegalizedValue( static void maybeRegisterLegalizedGlobal( IRTypeLegalizationContext* context, - IRGlobalVar* irGlobalVar, + IRGlobalValue* irGlobalVar, LegalVal const& legalVal) { // Check the mangled name of the symbol and don't register @@ -122,7 +122,7 @@ static void maybeRegisterLegalizedGlobal( struct IRGlobalNameInfo { - IRGlobalVar* globalVar; + IRGlobalValue* globalVar; UInt counter; }; @@ -1095,6 +1095,48 @@ static void legalizeGlobalVar( } } +static void legalizeGlobalConstant( + IRTypeLegalizationContext* context, + IRGlobalConstant* irGlobalConstant) +{ + // Legalize the type for the variable's value + auto legalValueType = legalizeType( + context, + irGlobalConstant->getType()); + + switch (legalValueType.flavor) + { + case LegalType::Flavor::simple: + // Easy case: the type is usable as-is, and we + // should just do that. + irGlobalConstant->type = legalValueType.getSimple(); + break; + + default: + { + context->insertBeforeGlobal = irGlobalConstant->getNextValue(); + + IRGlobalNameInfo globalNameInfo; + globalNameInfo.globalVar = irGlobalConstant; + globalNameInfo.counter = 0; + + // TODO: need to handle initializer here! + LegalVal newVal = declareVars(context, kIROp_global_constant, legalValueType, nullptr, nullptr, &globalNameInfo); + + // Register the new value as the replacement for the old + registerLegalizedValue(context, irGlobalConstant, newVal); + + // Also register the variable according to its mangled name, if any. + maybeRegisterLegalizedGlobal(context, irGlobalConstant, newVal); + + // Remove the old global from the module. + irGlobalConstant->removeFromParent(); + // TODO: actually clean up the global! + } + break; + } +} + static void legalizeGlobalValue( IRTypeLegalizationContext* context, IRGlobalValue* irValue) @@ -1113,6 +1155,10 @@ static void legalizeGlobalValue( legalizeGlobalVar(context, (IRGlobalVar*)irValue); break; + case kIROp_global_constant: + legalizeGlobalConstant(context, (IRGlobalConstant*)irValue); + break; + default: SLANG_UNEXPECTED("unknown global value type"); break; diff --git a/source/slang/ir-ssa.cpp b/source/slang/ir-ssa.cpp index 8a2d201dd..d58fd22e4 100644 --- a/source/slang/ir-ssa.cpp +++ b/source/slang/ir-ssa.cpp @@ -857,6 +857,7 @@ void constructSSA(IRModule* module, IRGlobalValue* globalVal) { case kIROp_Func: case kIROp_global_var: + case kIROp_global_constant: constructSSA(module, (IRGlobalValueWithCode*)globalVal); default: diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index 824af64ae..40c7e20d5 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -1004,6 +1004,30 @@ namespace Slang return inst; } + IRInst* IRBuilder::emitMakeVector( + IRType* type, + UInt argCount, + IRValue* const* args) + { + return emitIntrinsicInst(type, kIROp_makeVector, argCount, args); + } + + IRInst* IRBuilder::emitMakeArray( + IRType* type, + UInt argCount, + IRValue* const* args) + { + return emitIntrinsicInst(type, kIROp_makeArray, argCount, args); + } + + IRInst* IRBuilder::emitMakeStruct( + IRType* type, + UInt argCount, + IRValue* const* args) + { + return emitIntrinsicInst(type, kIROp_makeStruct, argCount, args); + } + IRModule* IRBuilder::createModule() { auto module = new IRModule(); @@ -1176,6 +1200,18 @@ namespace Slang return globalVar; } + IRGlobalConstant* IRBuilder::createGlobalConstant( + IRType* valueType) + { + IRGlobalConstant* globalConstant = createValue<IRGlobalConstant>( + this, + kIROp_global_constant, + valueType); + maybeSetSourceLoc(this, globalConstant); + addGlobalValue(getModule(), globalConstant); + return globalConstant; + } + IRWitnessTable* IRBuilder::createWitnessTable() { IRWitnessTable* witnessTable = createValue<IRWitnessTable>( @@ -1747,6 +1783,7 @@ namespace Slang { case kIROp_Func: case kIROp_global_var: + case kIROp_global_constant: case kIROp_witness_table: { auto irFunc = (IRFunc*) inst; @@ -2391,6 +2428,22 @@ namespace Slang dump(context, ";\n"); } + void dumpIRGlobalConstant( + IRDumpContext* context, + IRGlobalConstant* val) + { + dump(context, "\n"); + dumpIndent(context); + dump(context, "ir_global_constant "); + dumpID(context, val); + dumpInstTypeClause(context, val->getType()); + + // TODO: deal with the case where a global + // might have embedded initialization logic. + + dump(context, ";\n"); + } + void dumpIRWitnessTableEntry( IRDumpContext* context, IRWitnessTableEntry* entry) @@ -2436,6 +2489,10 @@ namespace Slang dumpIRGlobalVar(context, (IRGlobalVar*)value); break; + case kIROp_global_constant: + dumpIRGlobalConstant(context, (IRGlobalConstant*)value); + break; + case kIROp_witness_table: dumpIRWitnessTable(context, (IRWitnessTable*)value); break; @@ -3501,6 +3558,7 @@ namespace Slang switch (originalValue->op) { case kIROp_global_var: + case kIROp_global_constant: case kIROp_Func: case kIROp_witness_table: return cloneGlobalValue(this, (IRGlobalValue*) originalValue); @@ -3776,6 +3834,29 @@ namespace Slang return clonedVar; } + IRGlobalConstant* cloneGlobalConstantImpl( + IRSpecContext* context, + IRGlobalConstant* originalVal, + IROriginalValuesForClone const& originalValues) + { + auto clonedVal = context->builder->createGlobalConstant(context->maybeCloneType(originalVal->getType())); + registerClonedValue(context, clonedVal, originalValues); + + auto mangledName = originalVal->mangledName; + clonedVal->mangledName = mangledName; + + cloneDecorations(context, clonedVal, originalVal); + + // Clone any code in the body of the constant, since this + // represents the initializer. + cloneGlobalValueWithCodeCommon( + context, + clonedVal, + originalVal); + + return clonedVal; + } + IRWitnessTable* cloneWitnessTableImpl( IRSpecContextBase* context, IRWitnessTable* originalTable, @@ -4051,6 +4132,7 @@ namespace Slang return ((IRWitnessTable*)val)->entries.first != nullptr; case kIROp_global_var: + case kIROp_global_constant: case kIROp_Func: return ((IRGlobalValueWithCode*)val)->firstBlock != nullptr; @@ -4149,6 +4231,9 @@ namespace Slang case kIROp_global_var: return cloneGlobalVarImpl(context, (IRGlobalVar*)originalVal, sym); + case kIROp_global_constant: + return cloneGlobalConstantImpl(context, (IRGlobalConstant*)originalVal, sym); + case kIROp_witness_table: return cloneWitnessTableImpl(context, (IRWitnessTable*)originalVal, sym); diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 5c6f62c38..53cb2e772 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -1295,7 +1295,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> { // Allocate a temporary of the given type RefPtr<Type> type = lowerSimpleType(context, expr->type); - LoweredValInfo val = createVar(context, type); + List<IRValue*> args; UInt argCount = expr->args.Count(); @@ -1305,28 +1305,23 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> { UInt elementCount = (UInt) GetIntVal(arrayType->ArrayLength); auto elementType = lowerType(context, arrayType->baseType); + for (UInt ee = 0; ee < elementCount; ++ee) { - IRValue* indexVal = context->irBuilder->getIntValue( - getIntType(context), - ee); - LoweredValInfo elemVal = subscriptValue( - elementType, - val, - indexVal); - if (ee < argCount) { auto argExpr = expr->args[ee]; LoweredValInfo argVal = lowerRValueExpr(context, argExpr); - - assign(context, elemVal, argVal); + args.Add(getSimpleVal(context, argVal)); } else { SLANG_UNEXPECTED("need to default-initialize array elements"); } } + + return LoweredValInfo::simple( + getBuilder()->emitMakeArray(type, args.Count(), args.Buffer())); } else if (auto vectorType = type->As<VectorExpressionType>()) { @@ -1335,7 +1330,6 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> UInt elementCount = (UInt) GetIntVal(vectorType->elementCount); UInt argCounter = 0; - List<IRValue*> elements; for (UInt ee = 0; ee < elementCount; ++ee) { UInt argIndex = argCounter++; @@ -1343,8 +1337,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> { auto argExpr = expr->args[argIndex]; LoweredValInfo argVal = lowerRValueExpr(context, argExpr); - - elements.Add(getSimpleVal(context, argVal)); + args.Add(getSimpleVal(context, argVal)); } else { @@ -1352,10 +1345,8 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } } - assign(context, val, LoweredValInfo::simple(getBuilder()->emitConstructorInst( - lowerSimpleType(context, vectorType), - elementCount, - elements.Buffer()))); + return LoweredValInfo::simple( + getBuilder()->emitMakeVector(type, args.Count(), args.Buffer())); } else if (auto declRefType = type->As<DeclRefType>()) { @@ -1368,26 +1359,21 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> if (ff.getDecl()->HasModifier<HLSLStaticModifier>()) continue; - auto loweredFieldType = lowerType( - context, - GetType(ff)); - LoweredValInfo fieldVal = extractField( - loweredFieldType, - val, - ff); - UInt argIndex = argCounter++; if (argIndex < argCount) { auto argExpr = expr->args[argIndex]; LoweredValInfo argVal = lowerRValueExpr(context, argExpr); - assign(context, fieldVal, argVal); + args.Add(getSimpleVal(context, argVal)); } else { SLANG_UNEXPECTED("need to default-initialize struct fields"); } } + + return LoweredValInfo::simple( + getBuilder()->emitMakeStruct(type, args.Count(), args.Buffer())); } else { @@ -1399,8 +1385,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> SLANG_UNEXPECTED("not sure how to initialize this type"); } - - return val; + UNREACHABLE_RETURN(LoweredValInfo()); } LoweredValInfo visitConstantExpr(ConstantExpr* expr) @@ -2997,7 +2982,21 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // to a variable over to its type, when it makes sense. auto builder = getBuilder(); - auto irGlobal = builder->createGlobalVar(varType); + + IRGlobalValueWithCode* irGlobal = nullptr; + LoweredValInfo globalVal; + + // a `static const` global is actually a compile-time constant + if (decl->HasModifier<HLSLStaticModifier>() && decl->HasModifier<ConstModifier>()) + { + irGlobal = builder->createGlobalConstant(varType); + globalVal = LoweredValInfo::simple(irGlobal); + } + else + { + irGlobal = builder->createGlobalVar(varType); + globalVal = LoweredValInfo::ptr(irGlobal); + } irGlobal->mangledName = getMangledName(decl); if (decl) @@ -3007,7 +3006,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // A global variable's SSA value is a *pointer* to // the underlying storage. - auto globalVal = LoweredValInfo::ptr(irGlobal); context->shared->declValues[ DeclRef<VarDeclBase>(decl, nullptr)] = globalVal; diff --git a/source/slang/vm.cpp b/source/slang/vm.cpp index e910870ba..38083d631 100644 --- a/source/slang/vm.cpp +++ b/source/slang/vm.cpp @@ -650,6 +650,14 @@ void* loadVMSymbol( } break; + case kIROp_global_constant: + { + auto type = getType(vmModule, bcSymbol->typeID); + void* valPtr = allocate(vm, type); + return valPtr; + } + break; + case kIROp_Func: { auto bcFunc = (BCFunc*) bcSymbol; |
