diff options
| -rw-r--r-- | source/slang/bytecode.cpp | 101 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 190 | ||||
| -rw-r--r-- | source/slang/ir-constexpr.cpp | 63 | ||||
| -rw-r--r-- | source/slang/ir-inst-defs.h | 54 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 174 | ||||
| -rw-r--r-- | source/slang/ir-legalize-types.cpp | 152 | ||||
| -rw-r--r-- | source/slang/ir-ssa.cpp | 58 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 1152 | ||||
| -rw-r--r-- | source/slang/ir.h | 463 | ||||
| -rw-r--r-- | source/slang/legalize-types.h | 6 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 144 | ||||
| -rw-r--r-- | source/slang/slang.natvis | 122 | ||||
| -rw-r--r-- | source/slang/syntax.h | 1 |
13 files changed, 1292 insertions, 1388 deletions
diff --git a/source/slang/bytecode.cpp b/source/slang/bytecode.cpp index 6b6e4170e..8a062faaa 100644 --- a/source/slang/bytecode.cpp +++ b/source/slang/bytecode.cpp @@ -103,7 +103,7 @@ struct SharedBytecodeGenerationContext // Map from an IR value to a global entity // that encodes it: - Dictionary<IRValue*, BCConst> mapValueToGlobal; + Dictionary<IRInst*, BCConst> mapValueToGlobal; // Types that have been emitted List<BytecodeGenerationPtr<BCType>> bcTypes; @@ -111,7 +111,7 @@ struct SharedBytecodeGenerationContext // Compile-time constant values that need // to be emitted... - List<IRValue*> constants; + List<IRInst*> constants; }; struct BytecodeGenerationContext @@ -131,7 +131,7 @@ struct BytecodeGenerationContext // Map an instruction to its ID for use local // to the current context - Dictionary<IRValue*, Int> mapInstToLocalID; + Dictionary<IRInst*, Int> mapInstToLocalID; }; template<typename T> @@ -239,7 +239,7 @@ void encodeSInt( BCConst getGlobalValue( BytecodeGenerationContext* context, - IRValue* value) + IRInst* value) { { BCConst bcConst; @@ -281,7 +281,7 @@ BCConst getGlobalValue( Int getLocalID( BytecodeGenerationContext* context, - IRValue* value) + IRInst* value) { Int localID = 0; if( context->mapInstToLocalID.TryGetValue(value, localID) ) @@ -300,7 +300,7 @@ Int getLocalID( void encodeOperand( BytecodeGenerationContext* context, - IRValue* operand) + IRInst* operand) { auto id = getLocalID(context, operand); encodeSInt(context, id); @@ -317,7 +317,7 @@ void encodeOperand( encodeUInt(context, getTypeID(context, type)); } -bool opHasResult(IRValue* inst) +bool opHasResult(IRInst* inst) { auto type = inst->getDataType(); if (!type) return false; @@ -350,13 +350,13 @@ void generateBytecodeForInst( // encode the necessary extra info: // - auto argCount = inst->getArgCount(); + auto operandCount = inst->getOperandCount(); encodeUInt(context, inst->op); encodeOperand(context, inst->getDataType()); - encodeUInt(context, argCount); - for( UInt aa = 0; aa < argCount; ++aa ) + encodeUInt(context, operandCount); + for( UInt aa = 0; aa < operandCount; ++aa ) { - encodeOperand(context, inst->getArg(aa)); + encodeOperand(context, inst->getOperand(aa)); } if (!opHasResult(inst)) @@ -446,9 +446,9 @@ void generateBytecodeForInst( // We need to encode the type being stored, to make // our lives easier. - encodeOperand(context, inst->getArg(1)->getDataType()); - encodeOperand(context, inst->getArg(0)); - encodeOperand(context, inst->getArg(1)); + encodeOperand(context, inst->getOperand(1)->getDataType()); + encodeOperand(context, inst->getOperand(0)); + encodeOperand(context, inst->getOperand(1)); } break; @@ -456,7 +456,7 @@ void generateBytecodeForInst( { encodeUInt(context, inst->op); encodeOperand(context, inst->getDataType()); - encodeOperand(context, inst->getArg(0)); + encodeOperand(context, inst->getOperand(0)); encodeOperand(context, inst); } break; @@ -609,7 +609,7 @@ uint32_t getTypeID( uint32_t getTypeIDForGlobalSymbol( BytecodeGenerationContext* context, - IRValue* inst) + IRInst* inst) { auto type = inst->getDataType(); if(!type) @@ -721,15 +721,6 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst( UInt blockID = blockCounter++; UInt paramCount = 0; - for( auto pp = bb->getFirstParam(); pp; pp = pp->getNextParam() ) - { - // A parameter always uses a register. - regCounter++; - // - // We also want to keep a count of the parameters themselves. - paramCount++; - } - for( auto ii = bb->getFirstInst(); ii; ii = ii->getNextInst() ) { switch( ii->op ) @@ -743,6 +734,14 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst( } break; + case kIROp_Param: + // A parameter always uses a register. + regCounter++; + // + // We also want to keep a count of the parameters themselves. + paramCount++; + break; + case kIROp_Var: // A `var` (`alloca`) node needs two registers: // one to hold the actual storage, and another @@ -772,35 +771,21 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst( { UInt blockID = blockCounter++; - // Loop over just the parameters first, to ensure they - // are always the first N registers of a block. - // - // This means the parameters of the function itself - // are always the first N registers in the overall list. + // Loop over the instruction in the block, to allocate registers + // for them. The parameters of a block will always be the first + // N instructions in the block, so they will always get the + // first N registers in that block. Similarly, the entry block + // is always the first block, so that the parameters of the function + // will always be the first N registers. // bcBlocks[blockID].params = bcRegs + regCounter; - for( auto pp = bb->getFirstParam(); pp; pp = pp->getNextParam() ) - { - Int localID = regCounter++; - subContext->mapInstToLocalID.Add(pp, localID); - - bcRegs[localID].op = pp->op; -#if 0 - bcRegs[localID].name = tryGenerateNameForSymbol(context, pp); -#endif - bcRegs[localID].previousVarIndexPlusOne = (uint32_t)localID; - bcRegs[localID].typeID = getTypeIDForGlobalSymbol(context, pp); - } - - // Now loop over the non-parameter instructions and - // allocate actual register locations to them. for( auto ii = bb->getFirstInst(); ii; ii = ii->getNextInst() ) { switch(ii->op) { default: - // For an ordinary instruction with a result, - // allocate it here. + // For a parameter, or an ordinary instruction with + // a result, allocate it here. if( opHasResult(ii) ) { Int localID = regCounter++; @@ -816,12 +801,12 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst( break; case kIROp_Var: + // As handled in the earlier loop, we are + // allocating *two* locations for each `var` + // instruction. The first of these will be + // the actual pointer value, while the second + // will be the storage for the variable value. { - // As handled in the earlier loop, we are - // allocating *two* locations for each `var` - // instruction. The first of these will be - // the actual pointer value, while the second - // will be the storage for the variable value. Int localID = regCounter; regCounter += 2; @@ -967,8 +952,12 @@ BytecodeGenerationPtr<BCModule> generateBytecodeForModule( // for the module, where the registers represent the // values being computed at the global scope. UInt symbolCount = 0; - for( auto gv = irModule->getFirstGlobalValue(); gv; gv = gv->getNextValue() ) + for(auto ii : irModule->getGlobalInsts()) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; + Int globalID = Int(symbolCount++); // Ensure that local code inside functions can see these symbols @@ -986,8 +975,12 @@ BytecodeGenerationPtr<BCModule> generateBytecodeForModule( bcModule->symbolCount = (uint32_t)symbolCount; bcModule->symbols = bcSymbols; - for( auto gv = irModule->getFirstGlobalValue(); gv; gv = gv->getNextValue() ) + for(auto ii : irModule->getGlobalInsts()) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; + UInt symbolIndex = *context->mapInstToLocalID.TryGetValue(gv); auto bcSymbol = generateBytecodeSymbolForInst(context, gv); diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index c91fa1b90..189c1c4bd 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -117,7 +117,7 @@ struct SharedEmitContext ExtensionUsageTracker extensionUsageTracker; UInt uniqueIDCounter = 1; - Dictionary<IRValue*, UInt> mapIRValueToID; + Dictionary<IRInst*, UInt> mapIRValueToID; Dictionary<Decl*, UInt> mapDeclToID; HashSet<String> irDeclsVisited; @@ -4481,7 +4481,7 @@ emitDeclImpl(decl, nullptr); // IR-level emit logc - UInt getID(IRValue* value) + UInt getID(IRInst* value) { auto& mapIRValueToID = context->shared->mapIRValueToID; @@ -4548,7 +4548,7 @@ emitDeclImpl(decl, nullptr); } String getIRName( - IRValue* inst) + IRInst* inst) { switch(inst->op) { @@ -4903,7 +4903,7 @@ emitDeclImpl(decl, nullptr); bool shouldFoldIRInstIntoUseSites( EmitContext* ctx, - IRValue* inst, + IRInst* inst, IREmitMode mode) { // Certain opcodes should always be folded in @@ -4984,7 +4984,7 @@ emitDeclImpl(decl, nullptr); bool isDerefBaseImplicit( EmitContext* /*context*/, - IRValue* inst) + IRInst* inst) { auto type = inst->getDataType(); @@ -5003,7 +5003,7 @@ emitDeclImpl(decl, nullptr); void emitIROperand( EmitContext* ctx, - IRValue* inst, + IRInst* inst, IREmitMode mode) { if( shouldFoldIRInstIntoUseSites(ctx, inst, mode) ) @@ -5028,8 +5028,8 @@ emitDeclImpl(decl, nullptr); IRInst* inst, IREmitMode mode) { - UInt argCount = inst->argCount; - IRUse* args = inst->getArgs(); + UInt argCount = inst->getOperandCount(); + IRUse* args = inst->getOperands(); emit("("); for(UInt aa = 0; aa < argCount; ++aa) @@ -5085,7 +5085,7 @@ emitDeclImpl(decl, nullptr); void emitIRRateQualifiers( EmitContext* ctx, - IRValue* value) + IRInst* value) { emitIRRateQualifiers(ctx, value->getRate()); } @@ -5371,8 +5371,8 @@ emitDeclImpl(decl, nullptr); IRTargetIntrinsicDecoration* targetIntrinsic, IREmitMode mode) { - IRUse* args = inst->getArgs(); - UInt argCount = inst->getArgCount(); + IRUse* args = inst->getOperands(); + UInt argCount = inst->getOperandCount(); // First operand was the function to be called args++; @@ -5578,7 +5578,7 @@ emitDeclImpl(decl, nullptr); // For a call with N arguments, the instruction will // have N+1 operands. We will start consuming operands // starting at the index 1. - UInt operandCount = inst->getArgCount(); + UInt operandCount = inst->getOperandCount(); UInt argCount = operandCount - 1; UInt operandIndex = 1; @@ -5619,15 +5619,15 @@ emitDeclImpl(decl, nullptr); { // The user is invoking a built-in subscript operator emit("("); - emitIROperand(ctx, inst->getArg(operandIndex++), mode); + emitIROperand(ctx, inst->getOperand(operandIndex++), mode); emit(")["); - emitIROperand(ctx, inst->getArg(operandIndex++), mode); + emitIROperand(ctx, inst->getOperand(operandIndex++), mode); emit("]"); if(operandIndex < operandCount) { emit(" = "); - emitIROperand(ctx, inst->getArg(operandIndex++), mode); + emitIROperand(ctx, inst->getOperand(operandIndex++), mode); } return; } @@ -5643,7 +5643,7 @@ emitDeclImpl(decl, nullptr); { // Looks like a member function call emit("("); - emitIROperand(ctx, inst->getArg(operandIndex), mode); + emitIROperand(ctx, inst->getOperand(operandIndex), mode); emit(")."); operandIndex++; @@ -5655,7 +5655,7 @@ emitDeclImpl(decl, nullptr); for(; operandIndex < operandCount; ++operandIndex ) { if(!first) emit(", "); - emitIROperand(ctx, inst->getArg(operandIndex), mode); + emitIROperand(ctx, inst->getOperand(operandIndex), mode); first = false; } emit(")"); @@ -5668,7 +5668,7 @@ emitDeclImpl(decl, nullptr); { // We want to detect any call to an intrinsic operation, // that we can emit it directly without mangling, etc. - auto funcValue = inst->getArg(0); + auto funcValue = inst->getOperand(0); if(auto irFunc = asTargetIntrinsic(ctx, funcValue)) { emitIntrinsicCallExpr(ctx, inst, irFunc, mode); @@ -5677,11 +5677,11 @@ emitDeclImpl(decl, nullptr); { emitIROperand(ctx, funcValue, mode); emit("("); - UInt argCount = inst->getArgCount(); + UInt argCount = inst->getOperandCount(); for( UInt aa = 1; aa < argCount; ++aa ) { if(aa != 1) emit(", "); - emitIROperand(ctx, inst->getArg(aa), mode); + emitIROperand(ctx, inst->getOperand(aa), mode); } emit(")"); } @@ -5689,14 +5689,12 @@ emitDeclImpl(decl, nullptr); void emitIRInstExpr( EmitContext* ctx, - IRValue* value, + IRInst* inst, IREmitMode mode) { - IRInst* inst = (IRInst*) value; - advanceToSourceLocation(inst->sourceLoc); - switch(value->op) + switch(inst->op) { case kIROp_IntLit: case kIROp_FloatLit: @@ -5708,13 +5706,13 @@ emitDeclImpl(decl, nullptr); case kIROp_makeVector: case kIROp_makeMatrix: // Simple constructor call - if( inst->getArgCount() == 1 && getTarget(ctx) == CodeGenTarget::HLSL) + if( inst->getOperandCount() == 1 && getTarget(ctx) == CodeGenTarget::HLSL) { // Need to emit as cast for HLSL emit("("); emitIRType(ctx, inst->getDataType()); emit(") "); - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); } else { @@ -5736,7 +5734,7 @@ emitDeclImpl(decl, nullptr); emitIRType(ctx, inst->getDataType()); } emit("("); - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(")"); break; @@ -5771,11 +5769,11 @@ emitDeclImpl(decl, nullptr); } break; -#define CASE(OPCODE, OP) \ - case OPCODE: \ - emitIROperand(ctx, inst->getArg(0), mode); \ - emit(" " #OP " "); \ - emitIROperand(ctx, inst->getArg(1), mode); \ +#define CASE(OPCODE, OP) \ + case OPCODE: \ + emitIROperand(ctx, inst->getOperand(0), mode); \ + emit(" " #OP " "); \ + emitIROperand(ctx, inst->getOperand(1), mode); \ break CASE(kIROp_Add, +); @@ -5813,18 +5811,18 @@ emitDeclImpl(decl, nullptr); && inst->type->As<MatrixExpressionType>()) { emit("matrixCompMult("); - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(", "); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit(")"); } else { // Default handling is to just rely on infix // `operator*`. - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(" * "); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); } break; @@ -5838,55 +5836,55 @@ emitDeclImpl(decl, nullptr); { emit("~"); } - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); } break; case kIROp_Neg: { emit("-"); - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); } break; case kIROp_BitNot: { emit("~"); - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); } break; case kIROp_Sample: - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(".Sample("); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit(", "); - emitIROperand(ctx, inst->getArg(2), mode); + emitIROperand(ctx, inst->getOperand(2), mode); emit(")"); break; case kIROp_SampleGrad: // argument 0 is the instruction's type - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(".SampleGrad("); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit(", "); - emitIROperand(ctx, inst->getArg(2), mode); + emitIROperand(ctx, inst->getOperand(2), mode); emit(", "); - emitIROperand(ctx, inst->getArg(3), mode); + emitIROperand(ctx, inst->getOperand(3), mode); emit(", "); - emitIROperand(ctx, inst->getArg(4), mode); + emitIROperand(ctx, inst->getOperand(4), mode); emit(")"); break; case kIROp_Load: // TODO: this logic will really only work for a simple variable reference... - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); break; case kIROp_Store: // TODO: this logic will really only work for a simple variable reference... - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(" = "); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); break; case kIROp_Call: @@ -5897,18 +5895,18 @@ emitDeclImpl(decl, nullptr); case kIROp_BufferLoad: case kIROp_BufferElementRef: - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit("["); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit("]"); break; case kIROp_BufferStore: - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit("["); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit("] = "); - emitIROperand(ctx, inst->getArg(2), mode); + emitIROperand(ctx, inst->getOperand(2), mode); break; case kIROp_GroupMemoryBarrierWithGroupSync: @@ -5917,9 +5915,9 @@ emitDeclImpl(decl, nullptr); case kIROp_getElement: case kIROp_getElementPtr: - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit("["); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit("]"); break; @@ -5936,16 +5934,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), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit(" * "); - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); } else { emit("mul("); - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(", "); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit(")"); } break; @@ -5958,7 +5956,7 @@ emitDeclImpl(decl, nullptr); UInt elementCount = ii->getElementCount(); for (UInt ee = 0; ee < elementCount; ++ee) { - IRValue* irElementIndex = ii->getElementIndex(ee); + IRInst* irElementIndex = ii->getElementIndex(ee); assert(irElementIndex->op == kIROp_IntLit); IRConstant* irConst = (IRConstant*)irElementIndex; @@ -5973,17 +5971,17 @@ emitDeclImpl(decl, nullptr); case kIROp_specialize: { - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); } break; case kIROp_Select: { - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(" ? "); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit(" : "); - emitIROperand(ctx, inst->getArg(2), mode); + emitIROperand(ctx, inst->getOperand(2), mode); } break; @@ -5999,11 +5997,11 @@ emitDeclImpl(decl, nullptr); // of the expression. emit("{ "); - UInt argCount = inst->getArgCount(); + UInt argCount = inst->getOperandCount(); for (UInt aa = 0; aa < argCount; ++aa) { if (aa != 0) emit(", "); - emitIROperand(ctx, inst->getArg(aa), mode); + emitIROperand(ctx, inst->getOperand(aa), mode); } emit(" }"); } @@ -6081,14 +6079,14 @@ emitDeclImpl(decl, nullptr); { auto ii = (IRSwizzleSet*)inst; emitIRInstResultDecl(ctx, inst); - emitIROperand(ctx, inst->getArg(0), mode); + emitIROperand(ctx, inst->getOperand(0), mode); emit(";\n"); emitIROperand(ctx, inst, mode); emit("."); UInt elementCount = ii->getElementCount(); for (UInt ee = 0; ee < elementCount; ++ee) { - IRValue* irElementIndex = ii->getElementIndex(ee); + IRInst* irElementIndex = ii->getElementIndex(ee); assert(irElementIndex->op == kIROp_IntLit); IRConstant* irConst = (IRConstant*)irElementIndex; @@ -6099,7 +6097,7 @@ emitDeclImpl(decl, nullptr); emit(kComponents[elementIndex]); } emit(" = "); - emitIROperand(ctx, inst->getArg(1), mode); + emitIROperand(ctx, inst->getOperand(1), mode); emit(";\n"); } break; @@ -6108,7 +6106,7 @@ emitDeclImpl(decl, nullptr); void emitIRSemantics( EmitContext* ctx, - IRValue* inst) + IRInst* inst) { // Don't emit semantics if we aren't translating down to HLSL switch (ctx->shared->target) @@ -6150,7 +6148,7 @@ emitDeclImpl(decl, nullptr); VarLayout* getVarLayout( EmitContext* /*context*/, - IRValue* var) + IRInst* var) { auto decoration = var->findDecoration<IRLayoutDecoration>(); if (!decoration) @@ -6161,7 +6159,7 @@ emitDeclImpl(decl, nullptr); void emitIRLayoutSemantics( EmitContext* ctx, - IRValue* inst, + IRInst* inst, char const* uniformSemanticSpelling = "register") { auto layout = getVarLayout(ctx, inst); @@ -6193,7 +6191,7 @@ emitDeclImpl(decl, nullptr); break; } - IRValue* arg = args[argIndex].get(); + IRInst* arg = args[argIndex].get(); emitIROperand(ctx, pp, IREmitMode::Default); emit(" = "); @@ -6294,7 +6292,7 @@ emitDeclImpl(decl, nullptr); // Start by emitting the non-terminator instructions in the block. auto terminator = block->getLastInst(); - assert(isTerminatorInst(terminator)); + assert(as<IRTerminatorInst>(terminator)); for (auto inst = block->getFirstInst(); inst != terminator; inst = inst->getNextInst()) { emitIRInst(ctx, inst, IREmitMode::Default); @@ -6367,12 +6365,12 @@ emitDeclImpl(decl, nullptr); auto targetBlock = t->getTargetBlock(); auto breakBlock = t->getBreakBlock(); - UInt argCount = t->getArgCount(); + UInt argCount = t->getOperandCount(); static const UInt kFixedArgCount = 3; emitPhiVarAssignments( ctx, argCount - kFixedArgCount, - t->getArgs() + kFixedArgCount, + t->getOperands() + kFixedArgCount, targetBlock); // Set up entries on our label stack for break/continue @@ -6514,12 +6512,12 @@ emitDeclImpl(decl, nullptr); auto t = (IRUnconditionalBranch*)terminator; auto targetBlock = t->getTargetBlock(); - UInt argCount = t->getArgCount(); + UInt argCount = t->getOperandCount(); static const UInt kFixedArgCount = 1; emitPhiVarAssignments( ctx, argCount - kFixedArgCount, - t->getArgs() + kFixedArgCount, + t->getOperands() + kFixedArgCount, targetBlock); block = t->getTargetBlock(); @@ -7107,7 +7105,7 @@ emitDeclImpl(decl, nullptr); // if it does. IRFunc* asTargetIntrinsic( EmitContext* ctxt, - IRValue* value) + IRInst* value) { if(!value) return nullptr; @@ -7704,7 +7702,7 @@ emitDeclImpl(decl, nullptr); auto varType = allocatedType->getValueType(); String initFuncName; - if (varDecl->firstBlock) + if (varDecl->getFirstBlock()) { // A global variable with code means it has an initializer // associated with it. Eventually we'd like to emit that @@ -7715,7 +7713,7 @@ emitDeclImpl(decl, nullptr); initFuncName.append("_init"); emitIRType(ctx, varType, initFuncName); Emit("()\n{\n"); - emitIRStmtsForBlocks(ctx, varDecl->firstBlock, nullptr, nullptr); + emitIRStmtsForBlocks(ctx, varDecl->getFirstBlock(), nullptr, nullptr); Emit("}\n"); } @@ -7788,7 +7786,7 @@ emitDeclImpl(decl, nullptr); emitIRLayoutSemantics(ctx, varDecl); - if (varDecl->firstBlock) + if (varDecl->getFirstBlock()) { Emit(" = "); emit(initFuncName); @@ -7827,7 +7825,7 @@ emitDeclImpl(decl, nullptr); emit("static const "); emitIRType(ctx, valType, getIRName(valDecl)); - if (valDecl->firstBlock) + if (valDecl->getFirstBlock()) { // There is an initializer (which we expect for // any global constant...). @@ -7845,10 +7843,8 @@ emitDeclImpl(decl, nullptr); void emitIRGlobalInst( EmitContext* ctx, - IRGlobalValue* inst) + IRInst* inst) { - // TODO: need to be able to `switch` on the IR opcode here, - // so there is some work to be done. switch(inst->op) { case kIROp_Func: @@ -7995,7 +7991,7 @@ emitDeclImpl(decl, nullptr); void emitIRUsedTypesForValue( EmitContext* ctx, - IRValue* value) + IRInst* value) { if(!value) return; switch( value->op ) @@ -8044,9 +8040,9 @@ emitDeclImpl(decl, nullptr); EmitContext* ctx, IRModule* module) { - for( auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue() ) + for(auto ii : module->getGlobalInsts()) { - emitIRUsedTypesForValue(ctx, gv); + emitIRUsedTypesForValue(ctx, ii); } } @@ -8059,20 +8055,18 @@ emitDeclImpl(decl, nullptr); // Before we emit code, we need to forward-declare // all of our functions so that we don't have to // sort them by dependencies. - for( auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue() ) + for(auto ii : module->getGlobalInsts()) { - if(gv->op != kIROp_Func) + if(ii->op != kIROp_Func) continue; - auto func = (IRFunc*) gv; + auto func = (IRFunc*) ii; emitIRFuncDecl(ctx, func); } - - - for( auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue() ) + for(auto ii : module->getGlobalInsts()) { - emitIRGlobalInst(ctx, gv); + emitIRGlobalInst(ctx, ii); } } diff --git a/source/slang/ir-constexpr.cpp b/source/slang/ir-constexpr.cpp index f5738c036..8463851ac 100644 --- a/source/slang/ir-constexpr.cpp +++ b/source/slang/ir-constexpr.cpp @@ -8,6 +8,9 @@ namespace Slang { struct PropagateConstExprContext { + IRModule* module; + IRModule* getModule() { return module; } + DiagnosticSink* sink; SharedIRBuilder sharedBuilder; @@ -35,7 +38,7 @@ bool isConstExpr(Type* type) return false; } -bool isConstExpr(IRValue* value) +bool isConstExpr(IRInst* value) { // Certain IR value ops are implicitly `constexpr` // @@ -84,7 +87,7 @@ bool opCanBeConstExpr(IROp op) } } -bool opCanBeConstExpr(IRValue* value) +bool opCanBeConstExpr(IRInst* value) { // TODO: realistically need to special-case `call` // operations here, so that we check whether the @@ -96,7 +99,7 @@ bool opCanBeConstExpr(IRValue* value) void markConstExpr( PropagateConstExprContext* context, - IRValue* value) + IRInst* value) { Slang::markConstExpr(context->getSession(), value); } @@ -126,10 +129,10 @@ bool propagateConstExprForward( // Are all arguments `constexpr`? bool allArgsConstExpr = true; - UInt argCount = ii->getArgCount(); + UInt argCount = ii->getOperandCount(); for( UInt aa = 0; aa < argCount; ++aa ) { - auto arg = ii->getArg(aa); + auto arg = ii->getOperand(aa); if( !isConstExpr(arg) ) { @@ -166,7 +169,7 @@ void maybeAddToWorkList( bool maybeMarkConstExpr( PropagateConstExprContext* context, - IRValue* value) + IRInst* value) { if(isConstExpr(value)) return false; @@ -204,7 +207,7 @@ bool maybeMarkConstExpr( case kIROp_Call: { auto inst = (IRCall*) user; - auto caller = inst->getParentBlock()->getParent(); + auto caller = as<IRGlobalValueWithCode>(inst->getParent()->getParent()); maybeAddToWorkList(context, caller); } break; @@ -226,7 +229,7 @@ bool propagateConstExprBackward( IRGlobalValueWithCode* code) { SharedIRBuilder sharedBuilder; - sharedBuilder.module = code->parentModule; + sharedBuilder.module = context->getModule(); sharedBuilder.session = sharedBuilder.module->session; IRBuilder builder; @@ -253,10 +256,10 @@ bool propagateConstExprBackward( if( isConstExpr(ii) ) { // If this instruction is `constexpr`, then its operands should be too. - UInt argCount = ii->getArgCount(); + UInt argCount = ii->getOperandCount(); for( UInt aa = 0; aa < argCount; ++aa ) { - auto arg = ii->getArg(aa); + auto arg = ii->getOperand(aa); if(isConstExpr(arg)) continue; @@ -277,15 +280,15 @@ bool propagateConstExprBackward( // constexpr from the parameters back to the arguments. auto callInst = (IRCall*) ii; - UInt operandCount = callInst->getArgCount(); + UInt operandCount = callInst->getOperandCount(); UInt firstCallArg = 1; UInt callArgCount = operandCount - firstCallArg; - auto callee = callInst->getArg(0); + auto callee = callInst->getOperand(0); while( callee->op == kIROp_specialize ) { - callee = ((IRSpecialize*) callee)->getArg(0); + callee = ((IRSpecialize*) callee)->getOperand(0); } if( callee->op == kIROp_Func ) { @@ -297,7 +300,7 @@ bool propagateConstExprBackward( // If the callee has a definition, then we can read `constexpr` // information off of the parameters of its first IR block. - if( auto calleeFirstBlock = calleeFunc->firstBlock ) + if( auto calleeFirstBlock = calleeFunc->getFirstBlock() ) { UInt paramCounter = 0; for( auto pp = calleeFirstBlock->getFirstParam(); pp; pp = pp->getNextParam() ) @@ -305,7 +308,7 @@ bool propagateConstExprBackward( UInt paramIndex = paramCounter++; auto param = pp; - auto arg = callInst->getArg(firstCallArg + paramIndex); + auto arg = callInst->getOperand(firstCallArg + paramIndex); if( isConstExpr(param) ) { @@ -326,7 +329,7 @@ bool propagateConstExprBackward( for( UInt pp = 0; pp < paramCount; ++pp ) { auto paramType = calleeType->getParamType(pp); - auto arg = callInst->getArg(firstCallArg + pp); + auto arg = callInst->getOperand(firstCallArg + pp); if( isConstExpr(paramType) ) { if( maybeMarkConstExpr(context, arg) ) @@ -336,14 +339,6 @@ bool propagateConstExprBackward( } } } - - // TODO: this currently only works if the callee has a definition, - // because that is the only case where will generate IR values for - // its parameter list. Otherwise we'd need to pull this information - // from the function *type* for builtins. - if(!calleeFunc->firstBlock) - continue; - } } } @@ -370,9 +365,9 @@ bool propagateConstExprBackward( continue; UInt operandIndex = paramIndex + 1; - SLANG_RELEASE_ASSERT(operandIndex < terminator->getArgCount()); + SLANG_RELEASE_ASSERT(operandIndex < terminator->getOperandCount()); - auto operand = terminator->getArg(operandIndex); + auto operand = terminator->getOperand(operandIndex); if( maybeMarkConstExpr(context, operand) ) { changedThisIteration = true; @@ -406,10 +401,10 @@ void validateConstExpr( // For an instruction that must be `constexpr`, we need // to ensure that its argumenst are all `constexpr` - UInt argCount = ii->getArgCount(); + UInt argCount = ii->getOperandCount(); for( UInt aa = 0; aa < argCount; ++aa ) { - auto arg = ii->getArg(aa); + auto arg = ii->getOperand(aa); if( !isConstExpr(arg) ) { @@ -432,6 +427,7 @@ void propagateConstExpr( auto session = module->session; PropagateConstExprContext context; + context.module = module; context.sink = sink; context.sharedBuilder.module = module; context.sharedBuilder.session = session; @@ -460,8 +456,11 @@ void propagateConstExpr( // We will build an initial work list with all of the global values in it. - for( auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue() ) + for( auto ii : module->getGlobalInsts() ) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; maybeAddToWorkList(&context, gv); } @@ -508,9 +507,9 @@ void propagateConstExpr( // we find that they are *required* to be `constexpr`, but *cannot* // be, for some reason. - for( auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue() ) + for(auto ii : module->getGlobalInsts()) { - switch( gv->op ) + switch( ii->op ) { default: break; @@ -519,7 +518,7 @@ void propagateConstExpr( case kIROp_global_var: case kIROp_global_constant: { - IRGlobalValueWithCode* code = (IRGlobalValueWithCode*) gv; + IRGlobalValueWithCode* code = (IRGlobalValueWithCode*) ii; validateConstExpr(&context, code); } break; diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h index 9d6330eae..cac3c086e 100644 --- a/source/slang/ir-inst-defs.h +++ b/source/slang/ir-inst-defs.h @@ -4,6 +4,10 @@ #error Must #define `INST` before including `ir-inst-defs.h` #endif +#ifndef INST_RANGE +#define INST_RANGE(BASE, FIRST, LAST) /* empty */ +#endif + #ifndef PSEUDO_INST #define PSEUDO_INST(ID) /* empty */ #endif @@ -112,13 +116,22 @@ INST(makeStruct, makeStruct, 0, 0) INST(Call, call, 1, 0) INST(Module, module, 0, PARENT) -INST(Func, func, 0, PARENT) + INST(Block, block, 0, PARENT) -INST(global_var, global_var, 0, 0) -INST(global_constant, global_constant, 0, 0) +/*IRGlobalValue*/ + + /*IRGlobalValueWithCode*/ + INST(Func, func, 0, PARENT) + INST(global_var, global_var, 0, 0) + INST(global_constant, global_constant, 0, 0) + INST_RANGE(GlobalValueWithCode, Func, global_constant) + + INST(witness_table, witness_table, 0, 0) + + INST_RANGE(GlobalValue, Func, witness_table) + -INST(witness_table, witness_table, 0, 0) INST(witness_table_entry, witness_table_entry, 2, 0) INST(Param, param, 0, 0) @@ -180,26 +193,30 @@ INST(swizzle, swizzle, 1, 0) INST(swizzleSet, swizzleSet, 2, 0) -INST(ReturnVal, return_val, 1, 0) -INST(ReturnVoid, return_void, 1, 0) +/* IRTerminatorInst */ + + INST(ReturnVal, return_val, 1, 0) + INST(ReturnVoid, return_void, 1, 0) + + // unconditionalBranch <target> + INST(unconditionalBranch, unconditionalBranch, 1, 0) -// unconditionalBranch <target> -INST(unconditionalBranch, unconditionalBranch, 1, 0) + // loop <target> <breakLabel> <continueLabel> + INST(loop, loop, 3, 0) -// loop <target> <breakLabel> <continueLabel> -INST(loop, loop, 3, 0) + // conditionalBranch <condition> <trueBlock> <falseBlock> + INST(conditionalBranch, conditionalBranch, 3, 0) -// conditionalBranch <condition> <trueBlock> <falseBlock> -INST(conditionalBranch, conditionalBranch, 3, 0) + // ifElse <condition> <trueBlock> <falseBlock> <mergeBlock> + INST(ifElse, ifElse, 4, 0) -// ifElse <condition> <trueBlock> <falseBlock> <mergeBlock> -INST(ifElse, ifElse, 4, 0) + // switch <val> <break> <default> <caseVal1> <caseBlock1> ... + INST(switch, switch, 3, 0) -// switch <val> <break> <default> <caseVal1> <caseBlock1> ... -INST(switch, switch, 3, 0) + INST(discard, discard, 0, 0) + INST(unreachable, unreachable, 0, 0) -INST(discard, discard, 0, 0) -INST(unreachable, unreachable, 0, 0) +INST_RANGE(TerminatorInst, ReturnVal, unreachable) INST(Add, add, 2, 0) INST(Sub, sub, 2, 0) @@ -306,5 +323,6 @@ PSEUDO_INST(Or) #undef PSEUDO_INST #undef PARENT +#undef INST_RANGE #undef INST diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index f41e8a506..a3fd97351 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -85,12 +85,12 @@ struct IRTargetIntrinsicDecoration : IRTargetSpecificDecoration // An IR node to represent a reference to an AST-level // declaration. -struct IRDeclRef : IRValue +struct IRDeclRef : IRInst { DeclRef<Decl> declRef; virtual void dispose() override { - IRValue::dispose(); + IRInst::dispose(); declRef = decltype(declRef)(); } }; @@ -144,8 +144,8 @@ struct IRFieldExtract : IRInst IRUse base; IRUse field; - IRValue* getBase() { return base.get(); } - IRValue* getField() { return field.get(); } + IRInst* getBase() { return base.get(); } + IRInst* getField() { return field.get(); } }; struct IRFieldAddress : IRInst @@ -153,8 +153,8 @@ struct IRFieldAddress : IRInst IRUse base; IRUse field; - IRValue* getBase() { return base.get(); } - IRValue* getField() { return field.get(); } + IRInst* getBase() { return base.get(); } + IRInst* getField() { return field.get(); } }; // Terminators @@ -166,7 +166,7 @@ struct IRReturnVal : IRReturn { IRUse val; - IRValue* getVal() { return val.get(); } + IRInst* getVal() { return val.get(); } }; struct IRReturnVoid : IRReturn @@ -221,7 +221,7 @@ struct IRConditionalBranch : IRTerminatorInst IRUse trueBlock; IRUse falseBlock; - IRValue* getCondition() { return condition.get(); } + IRInst* getCondition() { return condition.get(); } IRBlock* getTrueBlock() { return (IRBlock*)trueBlock.get(); } IRBlock* getFalseBlock() { return (IRBlock*)falseBlock.get(); } }; @@ -260,29 +260,29 @@ struct IRSwitch : IRTerminatorInst IRUse breakLabel; IRUse defaultLabel; - IRValue* getCondition() { return condition.get(); } + IRInst* getCondition() { return condition.get(); } IRBlock* getBreakLabel() { return (IRBlock*) breakLabel.get(); } IRBlock* getDefaultLabel() { return (IRBlock*) defaultLabel.get(); } // remaining args are: caseVal, caseLabel, ... - UInt getCaseCount() { return (getArgCount() - 3) / 2; } - IRValue* getCaseValue(UInt index) { return getArg(3 + index*2 + 0); } - IRBlock* getCaseLabel(UInt index) { return (IRBlock*) getArg(3 + index*2 + 1); } + UInt getCaseCount() { return (getOperandCount() - 3) / 2; } + IRInst* getCaseValue(UInt index) { return getOperand(3 + index*2 + 0); } + IRBlock* getCaseLabel(UInt index) { return (IRBlock*) getOperand(3 + index*2 + 1); } }; struct IRSwizzle : IRReturn { IRUse base; - IRValue* getBase() { return base.get(); } + IRInst* getBase() { return base.get(); } UInt getElementCount() { - return getArgCount() - 1; + return getOperandCount() - 1; } - IRValue* getElementIndex(UInt index) + IRInst* getElementIndex(UInt index) { - return getArg(index + 1); + return getOperand(index + 1); } }; @@ -291,15 +291,15 @@ struct IRSwizzleSet : IRReturn IRUse base; IRUse source; - IRValue* getBase() { return base.get(); } - IRValue* getSource() { return source.get(); } + IRInst* getBase() { return base.get(); } + IRInst* getSource() { return source.get(); } UInt getElementCount() { - return getArgCount() - 2; + return getOperandCount() - 2; } - IRValue* getElementIndex(UInt index) + IRInst* getElementIndex(UInt index) { - return getArg(index + 2); + return getOperand(index + 2); } }; @@ -309,8 +309,10 @@ struct IRVar : IRInst { PtrType* getDataType() { - return (PtrType*) ((IRValue*) this)->getDataType(); + return (PtrType*) IRInst::getDataType(); } + + static bool isaImpl(IROp op) { return op == kIROp_Var; } }; /// @brief A global variable. @@ -323,7 +325,7 @@ struct IRGlobalVar : IRGlobalValueWithCode { PtrType* getDataType() { - return (PtrType*) ((IRValue*) this)->getDataType(); + return (PtrType*) IRInst::getDataType(); } }; @@ -337,7 +339,7 @@ struct IRGlobalConstant : IRGlobalValueWithCode }; // An entry in a witness table (see below) -struct IRWitnessTableEntry : IRUser +struct IRWitnessTableEntry : IRInst { // The AST-level requirement IRUse requirementKey; @@ -353,9 +355,14 @@ struct IRWitnessTableEntry : IRUser // to the IR values that satisfy those requirements. struct IRWitnessTable : IRGlobalValue { + IRInstList<IRWitnessTableEntry> getEntries() + { + return IRInstList<IRWitnessTableEntry>(getChildren()); + } + RefPtr<GenericDecl> genericDecl; DeclRef<Decl> subTypeDeclRef, supTypeDeclRef; - IRValueList<IRWitnessTableEntry> entries; + virtual void dispose() override { IRGlobalValue::dispose(); @@ -436,76 +443,75 @@ struct IRBuilder IRBuilderSourceLocRAII* sourceLocInfo = nullptr; - void addInst(IRBlock* block, IRInst* inst); void addInst(IRInst* inst); - IRValue* getBoolValue(bool value); - IRValue* getIntValue(IRType* type, IRIntegerValue value); - IRValue* getFloatValue(IRType* type, IRFloatingPointValue value); + IRInst* getBoolValue(bool value); + IRInst* getIntValue(IRType* type, IRIntegerValue value); + IRInst* getFloatValue(IRType* type, IRFloatingPointValue value); - IRValue* getDeclRefVal( + IRInst* getDeclRefVal( DeclRefBase const& declRef); - IRValue* getTypeVal(IRType* type); // create an IR value that represents a type - IRValue* emitSpecializeInst( + IRInst* getTypeVal(IRType* type); // create an IR value that represents a type + IRInst* emitSpecializeInst( IRType* type, - IRValue* genericVal, - IRValue* specDeclRef); + IRInst* genericVal, + IRInst* specDeclRef); - IRValue* emitSpecializeInst( + IRInst* emitSpecializeInst( IRType* type, - IRValue* genericVal, + IRInst* genericVal, DeclRef<Decl> specDeclRef); - IRValue* emitLookupInterfaceMethodInst( + IRInst* emitLookupInterfaceMethodInst( IRType* type, - IRValue* witnessTableVal, - IRValue* interfaceMethodVal); + IRInst* witnessTableVal, + IRInst* interfaceMethodVal); - IRValue* emitLookupInterfaceMethodInst( + IRInst* emitLookupInterfaceMethodInst( IRType* type, DeclRef<Decl> witnessTableDeclRef, DeclRef<Decl> interfaceMethodDeclRef); - IRValue* emitLookupInterfaceMethodInst( + IRInst* emitLookupInterfaceMethodInst( IRType* type, - IRValue* witnessTableVal, + IRInst* witnessTableVal, DeclRef<Decl> interfaceMethodDeclRef); - IRValue* emitFindWitnessTable( + IRInst* emitFindWitnessTable( DeclRef<Decl> baseTypeDeclRef, IRType* interfaceType); IRInst* emitCallInst( IRType* type, - IRValue* func, + IRInst* func, UInt argCount, - IRValue* const* args); + IRInst* const* args); IRInst* emitIntrinsicInst( IRType* type, IROp op, UInt argCount, - IRValue* const* args); + IRInst* const* args); IRInst* emitConstructorInst( IRType* type, UInt argCount, - IRValue* const* args); + IRInst* const* args); IRInst* emitMakeVector( IRType* type, UInt argCount, - IRValue* const* args); + IRInst* const* args); IRInst* emitMakeArray( IRType* type, UInt argCount, - IRValue* const* args); + IRInst* const* args); IRInst* emitMakeStruct( IRType* type, UInt argCount, - IRValue* const* args); + IRInst* const* args); IRUndefined* emitUndefined(IRType* type); @@ -521,8 +527,8 @@ struct IRBuilder IRWitnessTable* createWitnessTable(); IRWitnessTableEntry* createWitnessTableEntry( IRWitnessTable* witnessTable, - IRValue* requirementKey, - IRValue* satisfyingVal); + IRInst* requirementKey, + IRInst* satisfyingVal); IRWitnessTable* lookupWitnessTable(Name* mangledName); void registerWitnessTable(IRWitnessTable* table); IRBlock* createBlock(); @@ -537,60 +543,60 @@ struct IRBuilder IRType* type); IRInst* emitLoad( - IRValue* ptr); + IRInst* ptr); IRInst* emitStore( - IRValue* dstPtr, - IRValue* srcVal); + IRInst* dstPtr, + IRInst* srcVal); IRInst* emitFieldExtract( IRType* type, - IRValue* base, - IRValue* field); + IRInst* base, + IRInst* field); IRInst* emitFieldAddress( IRType* type, - IRValue* basePtr, - IRValue* field); + IRInst* basePtr, + IRInst* field); IRInst* emitElementExtract( IRType* type, - IRValue* base, - IRValue* index); + IRInst* base, + IRInst* index); IRInst* emitElementAddress( IRType* type, - IRValue* basePtr, - IRValue* index); + IRInst* basePtr, + IRInst* index); IRInst* emitSwizzle( IRType* type, - IRValue* base, + IRInst* base, UInt elementCount, - IRValue* const* elementIndices); + IRInst* const* elementIndices); IRInst* emitSwizzle( IRType* type, - IRValue* base, + IRInst* base, UInt elementCount, UInt const* elementIndices); IRInst* emitSwizzleSet( IRType* type, - IRValue* base, - IRValue* source, + IRInst* base, + IRInst* source, UInt elementCount, - IRValue* const* elementIndices); + IRInst* const* elementIndices); IRInst* emitSwizzleSet( IRType* type, - IRValue* base, - IRValue* source, + IRInst* base, + IRInst* source, UInt elementCount, UInt const* elementIndices); IRInst* emitReturn( - IRValue* val); + IRInst* val); IRInst* emitReturn(); @@ -613,35 +619,35 @@ struct IRBuilder IRBlock* continueBlock); IRInst* emitBranch( - IRValue* val, + IRInst* val, IRBlock* trueBlock, IRBlock* falseBlock); IRInst* emitIf( - IRValue* val, + IRInst* val, IRBlock* trueBlock, IRBlock* afterBlock); IRInst* emitIfElse( - IRValue* val, + IRInst* val, IRBlock* trueBlock, IRBlock* falseBlock, IRBlock* afterBlock); IRInst* emitLoopTest( - IRValue* val, + IRInst* val, IRBlock* bodyBlock, IRBlock* breakBlock); IRInst* emitSwitch( - IRValue* val, + IRInst* val, IRBlock* breakLabel, IRBlock* defaultLabel, UInt caseArgCount, - IRValue* const* caseArgs); + IRInst* const* caseArgs); template<typename T> - T* addDecoration(IRValue* value, IRDecorationOp op) + T* addDecoration(IRInst* value, IRDecorationOp op) { assert(getModule()); auto decorationSize = sizeof(T); @@ -657,13 +663,13 @@ struct IRBuilder } template<typename T> - T* addDecoration(IRValue* value) + T* addDecoration(IRInst* value) { return addDecoration<T>(value, IRDecorationOp(T::kDecorationOp)); } - IRHighLevelDeclDecoration* addHighLevelDeclDecoration(IRValue* value, Decl* decl); - IRLayoutDecoration* addLayoutDecoration(IRValue* value, Layout* layout); + IRHighLevelDeclDecoration* addHighLevelDeclDecoration(IRInst* value, Decl* decl); + IRLayoutDecoration* addLayoutDecoration(IRInst* value, Layout* layout); }; // Helper to establish the source location that will be used @@ -737,8 +743,8 @@ void specializeGenerics( // void markConstExpr( - Session* session, - IRValue* irValue); + Session* session, + IRInst* irValue); // diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp index 3a0edbb60..4570ecf81 100644 --- a/source/slang/ir-legalize-types.cpp +++ b/source/slang/ir-legalize-types.cpp @@ -83,22 +83,23 @@ struct IRTypeLegalizationContext TypeLegalizationContext* typeLegalizationContext; // When inserting new globals, put them before this one. - IRGlobalValue* insertBeforeGlobal = nullptr; + IRInst* insertBeforeGlobal = nullptr; // When inserting new parameters, put them before this one. IRParam* insertBeforeParam = nullptr; - Dictionary<IRValue*, LegalVal> mapValToLegalVal; + Dictionary<IRInst*, LegalVal> mapValToLegalVal; IRVar* insertBeforeLocalVar = nullptr; - // store local var instructions that have been replaced here, so we can free them + + // store instructions that have been replaced here, so we can free them // when legalization has done - List<IRInst*> oldLocalVars; + List<IRInst*> replacedInstructions; }; static void registerLegalizedValue( IRTypeLegalizationContext* context, - IRValue* irValue, + IRInst* irValue, LegalVal const& legalVal) { context->mapValToLegalVal.Add(irValue, legalVal); @@ -165,7 +166,7 @@ static RefPtr<Type> legalizeSimpleType( // and turn it into the equivalent legalized value. static LegalVal legalizeOperand( IRTypeLegalizationContext* context, - IRValue* irValue) + IRInst* irValue) { LegalVal legalVal; if (context->mapValToLegalVal.TryGetValue(irValue, legalVal)) @@ -178,7 +179,7 @@ static LegalVal legalizeOperand( } static void getArgumentValues( - List<IRValue*> & instArgs, + List<IRInst*> & instArgs, LegalVal val) { switch (val.flavor) @@ -226,9 +227,9 @@ static LegalVal legalizeCall( auto retType = legalizeType(context, callInst->type); SLANG_ASSERT(retType.flavor == LegalType::Flavor::simple); - List<IRValue*> instArgs; - for (auto i = 1u; i < callInst->argCount; i++) - getArgumentValues(instArgs, legalizeOperand(context, callInst->getArg(i))); + List<IRInst*> instArgs; + for (auto i = 1u; i < callInst->getOperandCount(); i++) + getArgumentValues(instArgs, legalizeOperand(context, callInst->getOperand(i))); return LegalVal::simple(context->builder->emitCallInst( callInst->type, @@ -479,7 +480,7 @@ static LegalVal legalizeGetElementPtr( IRTypeLegalizationContext* context, LegalType type, LegalVal legalPtrOperand, - IRValue* indexOperand) + IRInst* indexOperand) { auto builder = context->builder; @@ -613,7 +614,7 @@ static LegalVal legalizeInst( } } -RefPtr<VarLayout> findVarLayout(IRValue* value) +RefPtr<VarLayout> findVarLayout(IRInst* value) { if (auto layoutDecoration = value->findDecoration<IRLayoutDecoration>()) return layoutDecoration->layout.As<VarLayout>(); @@ -667,27 +668,66 @@ static LegalVal legalizeLocalVar( // Remove the old local var. irLocalVar->removeFromParent(); // add old local var to list - context->oldLocalVars.Add(irLocalVar); + context->replacedInstructions.Add(irLocalVar); return newVal; } break; } } +static LegalVal legalizeParam( + IRTypeLegalizationContext* context, + IRParam* originalParam) +{ + auto legalParamType = legalizeType(context, originalParam->getFullType()); + if (legalParamType.flavor == LegalType::Flavor::simple) + { + // Simple case: things were legalized to a simple type, + // so we can just use the original parameter as-is. + originalParam->type = legalParamType.getSimple(); + return LegalVal::simple(originalParam); + } + else + { + // Complex case: we need to insert zero or more new parameters, + // which will replace the old ones. + + context->insertBeforeParam = originalParam; + + auto newVal = declareVars(context, kIROp_Param, legalParamType, nullptr, nullptr, nullptr); + + originalParam->removeFromParent(); + context->replacedInstructions.Add(originalParam); + return newVal; + } +} + + + static LegalVal legalizeInst( - IRTypeLegalizationContext* context, + IRTypeLegalizationContext* context, IRInst* inst) { - if (inst->op == kIROp_Var) - return legalizeLocalVar(context, (IRVar*)inst); + // Special-case certain operations + switch (inst->op) + { + case kIROp_Var: + return legalizeLocalVar(context, cast<IRVar>(inst)); + + case kIROp_Param: + return legalizeParam(context, cast<IRParam>(inst)); + + default: + break; + } // Need to legalize all the operands. - auto argCount = inst->getArgCount(); + auto argCount = inst->getOperandCount(); List<LegalVal> legalArgs; bool anyComplex = false; for (UInt aa = 0; aa < argCount; ++aa) { - auto oldArg = inst->getArg(aa); + auto oldArg = inst->getOperand(aa); auto legalArg = legalizeOperand(context, oldArg); legalArgs.Add(legalArg); @@ -706,7 +746,7 @@ static LegalVal legalizeInst( for (UInt aa = 0; aa < argCount; ++aa) { auto legalArg = legalArgs[aa]; - inst->setArg(aa, legalArg.getSimple()); + inst->setOperand(aa, legalArg.getSimple()); } inst->type = legalType.getSimple(); @@ -720,9 +760,9 @@ static LegalVal legalizeInst( // We will set up the IR builder so that any new // instructions generated will be placed after - // the location of the original instruct. + // the location of the original instruction. auto builder = context->builder; - builder->curBlock = inst->getParentBlock(); + builder->curBlock = as<IRBlock>(inst->getParent()); builder->insertBeforeInst = inst->getNextInst(); LegalVal legalVal = legalizeInst( @@ -795,47 +835,15 @@ static void legalizeFunc( addParamType(newFuncType, legalParamType); } irFunc->type = newFuncType; - List<LegalVal> paramVals; - List<IRValue*> oldParams; // we use this list to store replaced local var insts. // these old instructions will be freed when we are done. - context->oldLocalVars.Clear(); + context->replacedInstructions.Clear(); // Go through the blocks of the function for (auto bb = irFunc->getFirstBlock(); bb; bb = bb->getNextBlock()) { - // Legalize the parameters of the block, which may - // involve increasing the number of parameters - for (auto pp = bb->getFirstParam(); pp; pp = pp->nextParam) - { - auto legalParamType = legalizeType(context, pp->getFullType()); - if (legalParamType.flavor != LegalType::Flavor::simple) - { - context->insertBeforeParam = pp; - context->builder->curBlock = nullptr; - - auto paramVal = declareVars(context, kIROp_Param, legalParamType, nullptr, nullptr, nullptr); - paramVals.Add(paramVal); - if (pp == bb->getFirstParam()) - { - bb->firstParam = pp; - while (bb->firstParam->prevParam) - bb->firstParam = bb->firstParam->prevParam; - } - bb->lastParam = pp->prevParam; - if (pp->prevParam) - pp->prevParam->nextParam = pp->nextParam; - if (pp->nextParam) - pp->nextParam->prevParam = pp->prevParam; - auto oldParam = pp; - oldParams.Add(oldParam); - registerLegalizedValue(context, oldParam, paramVal); - } - - } - - // Now legalize the instructions inside the block + // Legalize the instructions inside the block IRInst* nextInst = nullptr; for (auto ii = bb->getFirstInst(); ii; ii = nextInst) { @@ -847,13 +855,12 @@ static void legalizeFunc( } } - for (auto & op : oldParams) + + // Clean up after any instructions we replaced along the way. + for (auto & lv : context->replacedInstructions) { - SLANG_ASSERT(op->firstUse == nullptr || op->firstUse->nextUse == nullptr); - op->deallocate(); - } - for (auto & lv : context->oldLocalVars) lv->deallocate(); + } } static LegalVal declareSimpleVar( @@ -874,7 +881,7 @@ static LegalVal declareSimpleVar( IRBuilder* builder = context->builder; - IRValue* irVar = nullptr; + IRInst* irVar = nullptr; LegalVal legalVarVal; switch (op) @@ -883,7 +890,7 @@ static LegalVal declareSimpleVar( { auto globalVar = builder->createGlobalVar(type); globalVar->removeFromParent(); - globalVar->insertBefore(context->insertBeforeGlobal, builder->getModule()); + globalVar->insertBefore(context->insertBeforeGlobal); // The legalization of a global variable with linkage (one that has // a mangled name), must also have an exported name, so that code @@ -924,11 +931,7 @@ static LegalVal declareSimpleVar( case kIROp_Param: { auto param = builder->emitParam(type); - if (context->insertBeforeParam->prevParam) - context->insertBeforeParam->prevParam->nextParam = param; - param->prevParam = context->insertBeforeParam->prevParam; - param->nextParam = context->insertBeforeParam; - context->insertBeforeParam->prevParam = param; + param->insertBefore(context->insertBeforeParam); irVar = param; legalVarVal = LegalVal::simple(irVar); @@ -1069,7 +1072,7 @@ static void legalizeGlobalVar( default: { - context->insertBeforeGlobal = irGlobalVar->getNextValue(); + context->insertBeforeGlobal = irGlobalVar->getNextInst(); LegalVarChain* varChain = nullptr; LegalVarChain varChainStorage; @@ -1119,7 +1122,7 @@ static void legalizeGlobalConstant( default: { - context->insertBeforeGlobal = irGlobalConstant->getNextValue(); + context->insertBeforeGlobal = irGlobalConstant->getNextInst(); IRGlobalNameInfo globalNameInfo; globalNameInfo.globalVar = irGlobalConstant; @@ -1174,8 +1177,17 @@ static void legalizeTypes( IRTypeLegalizationContext* context) { auto module = context->module; - for (auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue()) + IRInst* next = nullptr; + for(auto ii = module->getGlobalInsts().getFirst(); ii; ii = next) { + next = ii->getNextInst(); + + // TODO: Once we start having global-scope instructions that + // aren't `IRGlobalValue`s, we'll actually want to handle those + // here too. + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; legalizeGlobalValue(context, gv); } } diff --git a/source/slang/ir-ssa.cpp b/source/slang/ir-ssa.cpp index b793f5320..ef1f8c4d8 100644 --- a/source/slang/ir-ssa.cpp +++ b/source/slang/ir-ssa.cpp @@ -30,7 +30,7 @@ struct PhiInfo : RefObject // If this phi ended up being removed as trivial, then // this will be the value that we replaced it with. - IRValue* replacement = nullptr; + IRInst* replacement = nullptr; }; // Information about a basic block that we generate/use @@ -39,7 +39,7 @@ struct SSABlockInfo : RefObject { // Map a promotable variable to the value to // use for that variable - Dictionary<IRVar*, IRValue*> valueForVar; + Dictionary<IRVar*, IRInst*> valueForVar; // The underlying basic block. IRBlock* block; @@ -63,7 +63,7 @@ struct SSABlockInfo : RefObject // Arguments that this block needs to pass along // to the phi nodes defined by is sucessor - List<IRValue*> successorArgs; + List<IRInst*> successorArgs; }; // State for constructing SSA form for a global value @@ -176,7 +176,7 @@ void identifyPromotableVars( IRVar* asPromotableVar( ConstructSSAContext* context, - IRValue* value) + IRInst* value) { if (value->op != kIROp_Var) return nullptr; @@ -194,7 +194,7 @@ IRVar* asPromotableVar( // that value will be used. If not, this all // may recursively work its way up through // the predecessors of the block. -IRValue* readVar( +IRInst* readVar( ConstructSSAContext* context, SSABlockInfo* blockInfo, IRVar* var); @@ -226,7 +226,7 @@ PhiInfo* addPhi( return phiInfo; } -IRValue* tryRemoveTrivialPhi( +IRInst* tryRemoveTrivialPhi( ConstructSSAContext* context, PhiInfo* phiInfo) { @@ -236,7 +236,7 @@ IRValue* tryRemoveTrivialPhi( // to the phi are either the same, or are equal // to the phi itself. - IRValue* same = nullptr; + IRInst* same = nullptr; for (auto u : phiInfo->operands) { auto usedVal = u.get(); @@ -319,7 +319,7 @@ IRValue* tryRemoveTrivialPhi( return same; } -IRValue* addPhiOperands( +IRInst* addPhiOperands( ConstructSSAContext* context, SSABlockInfo* blockInfo, PhiInfo* phiInfo) @@ -328,7 +328,7 @@ IRValue* addPhiOperands( auto block = blockInfo->block; - List<IRValue*> operandValues; + List<IRInst*> operandValues; for (auto predBlock : block->getPredecessors()) { // Precondition: if we have multiple predecessors, then @@ -362,7 +362,7 @@ void writeVar( ConstructSSAContext* /*context*/, SSABlockInfo* blockInfo, IRVar* var, - IRValue* val) + IRInst* val) { blockInfo->valueForVar[var] = val; } @@ -403,12 +403,12 @@ void maybeSealBlock( blockInfo->isSealed = true; } -IRValue* readVarRec( +IRInst* readVarRec( ConstructSSAContext* context, SSABlockInfo* blockInfo, IRVar* var) { - IRValue* val = nullptr; + IRInst* val = nullptr; if (!blockInfo->isSealed) { // If block isn't sealed, we need to @@ -499,7 +499,7 @@ IRValue* readVarRec( } -IRValue* readVar( +IRInst* readVar( ConstructSSAContext* context, SSABlockInfo* blockInfo, IRVar* var) @@ -507,7 +507,7 @@ IRValue* readVar( // In the easy case, there will be a preceeding // store in the same block, so we can use // that local value. - IRValue* val = nullptr; + IRInst* val = nullptr; if (blockInfo->valueForVar.TryGetValue(var, val)) { // Hooray, we found a value to use, and we @@ -617,7 +617,7 @@ void processBlock( } } - blockInfo->builder.insertBeforeInst = block->lastInst; + blockInfo->builder.insertBeforeInst = block->getLastChild(); // Once we are done with all of the instructions // in a block, we can mark it as "filled," which @@ -757,7 +757,7 @@ void constructSSA(ConstructSSAContext* context) // and stores of promotable variables with simple values. auto globalVal = context->globalVal; - for (auto bb = globalVal->firstBlock; bb; bb = bb->nextBlock) + for(auto bb : globalVal->getBlocks()) { auto blockInfo = new SSABlockInfo(); blockInfo->block = bb; @@ -765,11 +765,11 @@ void constructSSA(ConstructSSAContext* context) blockInfo->builder.sharedBuilder = &context->sharedBuilder; blockInfo->builder.curBlock = bb; blockInfo->builder.curFunc = globalVal; - blockInfo->builder.insertBeforeInst = bb->lastInst; + blockInfo->builder.insertBeforeInst = bb->getLastInst(); context->blockInfos.Add(bb, blockInfo); } - for (auto bb = globalVal->firstBlock; bb; bb = bb->nextBlock) + for(auto bb : globalVal->getBlocks()) { auto blockInfo = * context->blockInfos.TryGetValue(bb); processBlock(context, bb, blockInfo); @@ -778,7 +778,7 @@ void constructSSA(ConstructSSAContext* context) // We need to transfer the logical arguments to our phi nodes // from the phi nodes back to the predecessor blocks that will // pass them in. - for (auto bb = globalVal->firstBlock; bb; bb = bb->nextBlock) + for(auto bb : globalVal->getBlocks()) { auto blockInfo = *context->blockInfos.TryGetValue(bb); @@ -799,7 +799,7 @@ void constructSSA(ConstructSSAContext* context) UInt predIndex = predCounter++; auto predInfo = *context->blockInfos.TryGetValue(pp); - IRValue* operandVal = phiInfo->operands[predIndex].get(); + IRInst* operandVal = phiInfo->operands[predIndex].get(); phiInfo->operands[predIndex].clear(); @@ -810,7 +810,7 @@ void constructSSA(ConstructSSAContext* context) // Some blocks may now need to pass along arguments to their sucessor, // which have been stored into the `SSABlockInfo::successorArgs` field. - for (auto bb = globalVal->firstBlock; bb; bb = bb->nextBlock) + for(auto bb : globalVal->getBlocks()) { auto blockInfo = * context->blockInfos.TryGetValue(bb); @@ -827,18 +827,18 @@ void constructSSA(ConstructSSAContext* context) // We need to replace the terminator instruction with one that // has additional arguments. - IRTerminatorInst* oldTerminator = (IRTerminatorInst*) bb->getLastInst(); - assert(isTerminatorInst(oldTerminator)); + IRTerminatorInst* oldTerminator = bb->getTerminator(); + assert(oldTerminator); blockInfo->builder.insertBeforeInst = nullptr; - auto oldArgCount = oldTerminator->argCount; + auto oldArgCount = oldTerminator->getOperandCount(); auto newArgCount = oldArgCount + addedArgCount; - List<IRValue*> newArgs; + List<IRInst*> newArgs; for (UInt aa = 0; aa < oldArgCount; ++aa) { - newArgs.Add(oldTerminator->getArg(aa)); + newArgs.Add(oldTerminator->getOperand(aa)); } for (UInt aa = 0; aa < addedArgCount; ++aa) { @@ -884,7 +884,7 @@ void constructSSA(IRModule* module, IRGlobalValueWithCode* globalVal) constructSSA(&context); } -void constructSSA(IRModule* module, IRGlobalValue* globalVal) +void constructSSA(IRModule* module, IRInst* globalVal) { switch (globalVal->op) { @@ -900,9 +900,9 @@ void constructSSA(IRModule* module, IRGlobalValue* globalVal) void constructSSA(IRModule* module) { - for (auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue()) + for(auto ii : module->getGlobalInsts()) { - constructSSA(module, gv); + constructSSA(module, ii); } } diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index 8dc158b6c..b4d19c0d5 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -82,7 +82,7 @@ namespace Slang #endif } - void IRUse::init(IRUser* u, IRValue* v) + void IRUse::init(IRInst* u, IRInst* v) { clear(); @@ -104,7 +104,7 @@ namespace Slang debugValidate(); } - void IRUse::set(IRValue* uv) + void IRUse::set(IRInst* uv) { init(user, uv); } @@ -138,7 +138,7 @@ namespace Slang // - IRUse* IRUser::getArgs() + IRUse* IRInst::getOperands() { // We assume that *all* instructions are laid out // in memory such that their arguments come right @@ -150,7 +150,7 @@ namespace Slang return (IRUse*)(this + 1); } - IRDecoration* IRValue::findDecorationImpl(IRDecorationOp decorationOp) + IRDecoration* IRInst::findDecorationImpl(IRDecorationOp decorationOp) { for( auto dd = firstDecoration; dd; dd = dd->next ) { @@ -160,20 +160,37 @@ namespace Slang return nullptr; } + // IRParam + + IRParam* IRParam::getNextParam() + { + return as<IRParam>(getNextInst()); + } + // IRBlock + IRParam* IRBlock::getLastParam() + { + IRParam* param = getFirstParam(); + if (!param) return nullptr; + + while (auto nextParam = param->getNextParam()) + param = nextParam; + + return param; + } + void IRBlock::addParam(IRParam* param) { - if (auto lp = lastParam) + auto lastParam = getLastParam(); + if (lastParam) { - lp->nextParam = param; - param->prevParam = lp; + param->insertAfter(lastParam); } else { - firstParam = param; + param->insertAtStart(this); } - lastParam = param; } // The predecessors of a block should all show up as users @@ -191,7 +208,7 @@ namespace Slang // If the block somehow isn't terminated, then // there is no way to read its successors, so // we return an empty list. - if (!terminator || !isTerminatorInst(terminator)) + if (!terminator || !as<IRTerminatorInst>(terminator)) return IRBlock::SuccessorList(nullptr, nullptr); // Otherwise, based on the opcode of the terminator @@ -200,7 +217,7 @@ namespace Slang IRUse* end = nullptr; UInt stride = 1; - auto args = terminator->getArgs(); + auto operands = terminator->getOperands(); switch (terminator->op) { case kIROp_ReturnVal: @@ -212,21 +229,25 @@ namespace Slang case kIROp_unconditionalBranch: case kIROp_loop: // unconditonalBranch <block> - begin = args + 0; + begin = operands + 0; end = begin + 1; break; case kIROp_conditionalBranch: case kIROp_ifElse: // conditionalBranch <condition> <trueBlock> <falseBlock> - begin = args + 1; + begin = operands + 1; end = begin + 2; break; case kIROp_switch: // switch <val> <break> <default> <caseVal1> <caseBlock1> ... - begin = args + 4; - end = args + terminator->getArgCount() + 1; + begin = operands + 4; + + // TODO: this ends up point one *after* the "one after the end" + // location, so we should really change the representation + // so that we don't need to form this pointer... + end = operands + terminator->getOperandCount() + 1; stride = 2; break; @@ -238,47 +259,6 @@ namespace Slang return IRBlock::SuccessorList(begin, end, stride); } - void IRBlock::insertAfter(IRBlock* other) - { - assert(other); - insertAfter(other, other->parentFunc); - } - - void IRBlock::insertAfter(IRBlock* other, IRGlobalValueWithCode* func) - { - assert(other || func); - - if (!other) other = func->lastBlock; - if (!func) func = other->parentFunc; - - assert(func); - - auto pp = other; - auto nn = other ? other->nextBlock : nullptr; - - if (pp) - { - pp->nextBlock = this; - } - else - { - func->firstBlock = this; - } - - if (nn) - { - nn->prevBlock = this; - } - else - { - func->lastBlock = this; - } - - this->prevBlock = pp; - this->nextBlock = nn; - this->parentFunc = func; - } - static IRUse* adjustPredecessorUse(IRUse* use) { // We will search until we either find a @@ -410,18 +390,7 @@ namespace Slang void IRGlobalValueWithCode::addBlock(IRBlock* block) { - block->parentFunc = this; - - if (auto lb = lastBlock) - { - lb->nextBlock = block; - block->prevBlock = lb; - } - else - { - firstBlock = block; - } - lastBlock = block; + block->insertAtEnd(this); } // @@ -454,52 +423,6 @@ namespace Slang // - void IRValueListBase::addImpl(IRValue* parent, IRChildValue* val) - { - val->parent = parent; - val->prev = last; - val->next = nullptr; - - if (last) - { - last->next = val; - } - else - { - first = val; - } - - last = val; - } - - - // - - // Add an instruction to a specific parent - void IRBuilder::addInst(IRBlock* pblock, IRInst* inst) - { - inst->parent = pblock; - - if (!pblock->firstInst) - { - inst->prev = nullptr; - inst->next = nullptr; - - pblock->firstInst = inst; - pblock->lastInst = inst; - } - else - { - auto prev = pblock->lastInst; - - inst->prev = prev; - inst->next = nullptr; - - prev->next = inst; - pblock->lastInst = inst; - } - } - // Add an instruction into the current scope void IRBuilder::addInst( IRInst* inst) @@ -509,17 +432,19 @@ namespace Slang inst->insertBefore(insertBeforeInst); return; } - - auto parent = curBlock; - if (!parent) - return; - - addInst(parent, inst); + else if (curBlock) + { + inst->insertAtEnd(curBlock); + } + else + { + // Don't append the instruction anywhere + } } static void maybeSetSourceLoc( IRBuilder* builder, - IRValue* value) + IRInst* value) { if(!builder) return; @@ -566,20 +491,21 @@ namespace Slang // argument for all instructions). template<typename T> static T* createInstImpl( + IRModule* module, IRBuilder* builder, UInt size, IROp op, IRType* type, UInt fixedArgCount, - IRValue* const* fixedArgs, + IRInst* const* fixedArgs, UInt varArgCount = 0, - IRValue* const* varArgs = nullptr) + IRInst* const* varArgs = nullptr) { - assert(builder->getModule()); - T* inst = (T*)builder->getModule()->memoryPool.allocZero(size); + assert(module); + T* inst = (T*)module->memoryPool.allocZero(size); new(inst)T(); - inst->argCount = (uint32_t)(fixedArgCount + varArgCount); + inst->operandCount = (uint32_t)(fixedArgCount + varArgCount); inst->op = op; @@ -587,7 +513,7 @@ namespace Slang maybeSetSourceLoc(builder, inst); - auto operand = inst->getArgs(); + auto operand = inst->getOperands(); for( UInt aa = 0; aa < fixedArgCount; ++aa ) { @@ -606,17 +532,40 @@ namespace Slang } operand++; } - builder->getModule()->irObjectsToFree.Add(inst); + module->irObjectsToFree.Add(inst); return inst; } template<typename T> + static T* createInstImpl( + IRBuilder* builder, + UInt size, + IROp op, + IRType* type, + UInt fixedArgCount, + IRInst* const* fixedArgs, + UInt varArgCount = 0, + IRInst* const* varArgs = nullptr) + { + return createInstImpl<T>( + builder->getModule(), + builder, + size, + op, + type, + fixedArgCount, + fixedArgs, + varArgCount, + varArgs); + } + + template<typename T> static T* createInst( IRBuilder* builder, IROp op, IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { return createInstImpl<T>( builder, @@ -647,7 +596,7 @@ namespace Slang IRBuilder* builder, IROp op, IRType* type, - IRValue* arg) + IRInst* arg) { return createInstImpl<T>( builder, @@ -663,10 +612,10 @@ namespace Slang IRBuilder* builder, IROp op, IRType* type, - IRValue* arg1, - IRValue* arg2) + IRInst* arg1, + IRInst* arg2) { - IRValue* args[] = { arg1, arg2 }; + IRInst* args[] = { arg1, arg2 }; return createInstImpl<T>( builder, sizeof(T), @@ -682,7 +631,7 @@ namespace Slang IROp op, IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { return createInstImpl<T>( builder, @@ -699,9 +648,9 @@ namespace Slang IROp op, IRType* type, UInt fixedArgCount, - IRValue* const* fixedArgs, + IRInst* const* fixedArgs, UInt varArgCount, - IRValue* const* varArgs) + IRInst* const* varArgs) { return createInstImpl<T>( builder, @@ -719,11 +668,11 @@ namespace Slang IRBuilder* builder, IROp op, IRType* type, - IRValue* arg1, + IRInst* arg1, UInt varArgCount, - IRValue* const* varArgs) + IRInst* const* varArgs) { - IRValue* fixedArgs[] = { arg1 }; + IRInst* fixedArgs[] = { arg1 }; UInt fixedArgCount = sizeof(fixedArgs) / sizeof(fixedArgs[0]); return createInstImpl<T>( @@ -742,11 +691,11 @@ namespace Slang { if(left.inst->op != right.inst->op) return false; if(left.inst->parent != right.inst->parent) return false; - if(left.inst->argCount != right.inst->argCount) return false; + if(left.inst->operandCount != right.inst->operandCount) return false; - auto argCount = left.inst->argCount; - auto leftArgs = left.inst->getArgs(); - auto rightArgs = right.inst->getArgs(); + auto argCount = left.inst->operandCount; + auto leftArgs = left.inst->getOperands(); + auto rightArgs = right.inst->getOperands(); for( UInt aa = 0; aa < argCount; ++aa ) { if(leftArgs[aa].get() != rightArgs[aa].get()) @@ -760,10 +709,10 @@ namespace Slang { auto code = Slang::GetHashCode(inst->op); code = combineHash(code, Slang::GetHashCode(inst->parent)); - code = combineHash(code, Slang::GetHashCode(inst->argCount)); + code = combineHash(code, Slang::GetHashCode(inst->getOperandCount())); - auto argCount = inst->argCount; - auto args = inst->getArgs(); + auto argCount = inst->getOperandCount(); + auto args = inst->getOperands(); for( UInt aa = 0; aa < argCount; ++aa ) { code = combineHash(code, Slang::GetHashCode(args[aa].get())); @@ -838,7 +787,7 @@ namespace Slang // - IRValue* IRBuilder::getBoolValue(bool inValue) + IRInst* IRBuilder::getBoolValue(bool inValue) { IRIntegerValue value = inValue; return findOrEmitConstant( @@ -849,7 +798,7 @@ namespace Slang &value); } - IRValue* IRBuilder::getIntValue(IRType* type, IRIntegerValue value) + IRInst* IRBuilder::getIntValue(IRType* type, IRIntegerValue value) { return findOrEmitConstant( this, @@ -859,7 +808,7 @@ namespace Slang &value); } - IRValue* IRBuilder::getFloatValue(IRType* type, IRFloatingPointValue value) + IRInst* IRBuilder::getFloatValue(IRType* type, IRFloatingPointValue value) { return findOrEmitConstant( this, @@ -881,7 +830,7 @@ namespace Slang return inst; } - IRValue* IRBuilder::getDeclRefVal( + IRInst* IRBuilder::getDeclRefVal( DeclRefBase const& declRef) { // TODO: we should cache these... @@ -893,9 +842,9 @@ namespace Slang return irValue; } - IRValue * IRBuilder::getTypeVal(IRType * type) + IRInst* IRBuilder::getTypeVal(IRType * type) { - auto irValue = createValue<IRValue>( + auto irValue = createValue<IRInst>( this, kIROp_TypeType, nullptr); @@ -905,10 +854,10 @@ namespace Slang return irValue; } - IRValue* IRBuilder::emitSpecializeInst( + IRInst* IRBuilder::emitSpecializeInst( Type* type, - IRValue* genericVal, - IRValue* specDeclRef) + IRInst* genericVal, + IRInst* specDeclRef) { auto inst = createInst<IRSpecialize>( this, @@ -920,9 +869,9 @@ namespace Slang return inst; } - IRValue* IRBuilder::emitSpecializeInst( + IRInst* IRBuilder::emitSpecializeInst( Type* type, - IRValue* genericVal, + IRInst* genericVal, DeclRef<Decl> specDeclRef) { auto specDeclRefVal = getDeclRefVal(specDeclRef); @@ -936,10 +885,10 @@ namespace Slang return inst; } - IRValue* IRBuilder::emitLookupInterfaceMethodInst( - IRType* type, - IRValue* witnessTableVal, - IRValue* interfaceMethodVal) + IRInst* IRBuilder::emitLookupInterfaceMethodInst( + IRType* type, + IRInst* witnessTableVal, + IRInst* interfaceMethodVal) { auto inst = createInst<IRLookupWitnessMethod>( this, @@ -951,7 +900,7 @@ namespace Slang return inst; } - IRValue* IRBuilder::emitLookupInterfaceMethodInst( + IRInst* IRBuilder::emitLookupInterfaceMethodInst( IRType* type, DeclRef<Decl> witnessTableDeclRef, DeclRef<Decl> interfaceMethodDeclRef) @@ -963,9 +912,9 @@ namespace Slang return emitLookupInterfaceMethodInst(type, witnessTableVal, interfaceMethodVal); } - IRValue* IRBuilder::emitLookupInterfaceMethodInst( + IRInst* IRBuilder::emitLookupInterfaceMethodInst( IRType* type, - IRValue* witnessTableVal, + IRInst* witnessTableVal, DeclRef<Decl> interfaceMethodDeclRef) { DeclRef<Decl> removeSubstDeclRef = interfaceMethodDeclRef; @@ -974,7 +923,7 @@ namespace Slang return emitLookupInterfaceMethodInst(type, witnessTableVal, interfaceMethodVal); } - IRValue* IRBuilder::emitFindWitnessTable( + IRInst* IRBuilder::emitFindWitnessTable( DeclRef<Decl> baseTypeDeclRef, IRType* interfaceType) { @@ -992,9 +941,9 @@ namespace Slang IRInst* IRBuilder::emitCallInst( IRType* type, - IRValue* pFunc, + IRInst* pFunc, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto inst = createInstWithTrailingArgs<IRCall>( this, @@ -1012,7 +961,7 @@ namespace Slang IRType* type, IROp op, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto inst = createInstWithTrailingArgs<IRInst>( this, @@ -1027,7 +976,7 @@ namespace Slang IRInst* IRBuilder::emitConstructorInst( IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto inst = createInstWithTrailingArgs<IRInst>( this, @@ -1042,7 +991,7 @@ namespace Slang IRInst* IRBuilder::emitMakeVector( IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { return emitIntrinsicInst(type, kIROp_makeVector, argCount, args); } @@ -1050,7 +999,7 @@ namespace Slang IRInst* IRBuilder::emitMakeArray( IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { return emitIntrinsicInst(type, kIROp_makeArray, argCount, args); } @@ -1058,7 +1007,7 @@ namespace Slang IRInst* IRBuilder::emitMakeStruct( IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { return emitIntrinsicInst(type, kIROp_makeStruct, argCount, args); } @@ -1067,148 +1016,28 @@ namespace Slang { auto module = new IRModule(); module->session = getSession(); - return module; - } - - void IRGlobalValue::insertBefore(IRGlobalValue* other) - { - assert(other); - insertBefore(other, other->parentModule); - } - - void IRGlobalValue::insertBefore(IRGlobalValue* other, IRModule* module) - { - assert(other || module); - - if(!other) other = module->firstGlobalValue; - if(!module) module = other->parentModule; - assert(module); - - auto nn = other; - auto pp = other ? other->prevGlobalValue : nullptr; - - if(pp) - { - pp->nextGlobalValue = this; - } - else - { - module->firstGlobalValue = this; - } - - if(nn) - { - nn->prevGlobalValue = this; - } - else - { - module->lastGlobalValue = this; - } - - this->prevGlobalValue = pp; - this->nextGlobalValue = nn; - this->parentModule = module; - } - - void IRGlobalValue::insertAtStart(IRModule* module) - { - insertBefore(module->firstGlobalValue, module); - } - - void IRGlobalValue::insertAfter(IRGlobalValue* other) - { - assert(other); - insertAfter(other, other->parentModule); - } - - void IRGlobalValue::insertAfter(IRGlobalValue* other, IRModule* module) - { - assert(other || module); - - if(!other) other = module->lastGlobalValue; - if(!module) module = other->parentModule; - - assert(module); - - auto pp = other; - auto nn = other ? other->nextGlobalValue : nullptr; - - if(pp) - { - pp->nextGlobalValue = this; - } - else - { - module->firstGlobalValue = this; - } - - if(nn) - { - nn->prevGlobalValue = this; - } - else - { - module->lastGlobalValue = this; - } - - this->prevGlobalValue = pp; - this->nextGlobalValue = nn; - this->parentModule = module; - } - - void IRGlobalValue::insertAtEnd(IRModule* module) - { - assert(module); - insertAfter(module->lastGlobalValue, module); - } - - void IRGlobalValue::removeFromParent() - { - auto module = parentModule; - if(!module) - return; - - auto pp = this->prevGlobalValue; - auto nn = this->nextGlobalValue; - - if(pp) - { - pp->nextGlobalValue = nn; - } - else - { - module->firstGlobalValue = nn; - } - - if( nn ) - { - nn->prevGlobalValue = pp; - } - else - { - module->lastGlobalValue = pp; - } - } + auto moduleInst = createInstImpl<IRModuleInst>( + module, + this, + sizeof(IRModuleInst), + kIROp_Module, + nullptr, + 0, + nullptr); + module->moduleInst = moduleInst; - void IRGlobalValue::moveToEnd() - { - auto module = parentModule; - removeFromParent(); - insertAtEnd(module); + return module; } - - void addGlobalValue( - IRModule* module, + IRModule* module, IRGlobalValue* value) { if(!module) return; - value->parentModule = module; - value->insertAfter(module->lastGlobalValue, module); + value->insertAtEnd(module->moduleInst); } IRFunc* IRBuilder::createFunc() @@ -1259,8 +1088,8 @@ namespace Slang IRWitnessTableEntry* IRBuilder::createWitnessTableEntry( IRWitnessTable* witnessTable, - IRValue* requirementKey, - IRValue* satisfyingVal) + IRInst* requirementKey, + IRInst* satisfyingVal) { IRWitnessTableEntry* entry = createInst<IRWitnessTableEntry>( this, @@ -1271,7 +1100,7 @@ namespace Slang if (witnessTable) { - witnessTable->entries.add(witnessTable, entry); + entry->insertAtEnd(witnessTable); } return entry; @@ -1347,7 +1176,7 @@ namespace Slang } IRInst* IRBuilder::emitLoad( - IRValue* ptr) + IRInst* ptr) { // Note: a `load` operation does not consider the rate // (if any) attached to its operand (see the use of `getDataType` @@ -1394,8 +1223,8 @@ namespace Slang } IRInst* IRBuilder::emitStore( - IRValue* dstPtr, - IRValue* srcVal) + IRInst* dstPtr, + IRInst* srcVal) { auto inst = createInst<IRStore>( this, @@ -1409,9 +1238,9 @@ namespace Slang } IRInst* IRBuilder::emitFieldExtract( - IRType* type, - IRValue* base, - IRValue* field) + IRType* type, + IRInst* base, + IRInst* field) { auto inst = createInst<IRFieldExtract>( this, @@ -1425,9 +1254,9 @@ namespace Slang } IRInst* IRBuilder::emitFieldAddress( - IRType* type, - IRValue* base, - IRValue* field) + IRType* type, + IRInst* base, + IRInst* field) { auto inst = createInst<IRFieldAddress>( this, @@ -1441,9 +1270,9 @@ namespace Slang } IRInst* IRBuilder::emitElementExtract( - IRType* type, - IRValue* base, - IRValue* index) + IRType* type, + IRInst* base, + IRInst* index) { auto inst = createInst<IRFieldAddress>( this, @@ -1458,8 +1287,8 @@ namespace Slang IRInst* IRBuilder::emitElementAddress( IRType* type, - IRValue* basePtr, - IRValue* index) + IRInst* basePtr, + IRInst* index) { auto inst = createInst<IRFieldAddress>( this, @@ -1474,9 +1303,9 @@ namespace Slang IRInst* IRBuilder::emitSwizzle( IRType* type, - IRValue* base, + IRInst* base, UInt elementCount, - IRValue* const* elementIndices) + IRInst* const* elementIndices) { auto inst = createInstWithTrailingArgs<IRSwizzle>( this, @@ -1492,13 +1321,13 @@ namespace Slang IRInst* IRBuilder::emitSwizzle( IRType* type, - IRValue* base, + IRInst* base, UInt elementCount, UInt const* elementIndices) { auto intType = getSession()->getBuiltinType(BaseType::Int); - IRValue* irElementIndices[4]; + IRInst* irElementIndices[4]; for (UInt ii = 0; ii < elementCount; ++ii) { irElementIndices[ii] = getIntValue(intType, elementIndices[ii]); @@ -1510,12 +1339,12 @@ namespace Slang IRInst* IRBuilder::emitSwizzleSet( IRType* type, - IRValue* base, - IRValue* source, + IRInst* base, + IRInst* source, UInt elementCount, - IRValue* const* elementIndices) + IRInst* const* elementIndices) { - IRValue* fixedArgs[] = { base, source }; + IRInst* fixedArgs[] = { base, source }; UInt fixedArgCount = sizeof(fixedArgs) / sizeof(fixedArgs[0]); auto inst = createInstWithTrailingArgs<IRSwizzleSet>( @@ -1533,14 +1362,14 @@ namespace Slang IRInst* IRBuilder::emitSwizzleSet( IRType* type, - IRValue* base, - IRValue* source, + IRInst* base, + IRInst* source, UInt elementCount, UInt const* elementIndices) { auto intType = getSession()->getBuiltinType(BaseType::Int); - IRValue* irElementIndices[4]; + IRInst* irElementIndices[4]; for (UInt ii = 0; ii < elementCount; ++ii) { irElementIndices[ii] = getIntValue(intType, elementIndices[ii]); @@ -1550,7 +1379,7 @@ namespace Slang } IRInst* IRBuilder::emitReturn( - IRValue* val) + IRInst* val) { auto inst = createInst<IRReturnVal>( this, @@ -1621,7 +1450,7 @@ namespace Slang IRBlock* breakBlock, IRBlock* continueBlock) { - IRValue* args[] = { target, breakBlock, continueBlock }; + IRInst* args[] = { target, breakBlock, continueBlock }; UInt argCount = sizeof(args) / sizeof(args[0]); auto inst = createInst<IRLoop>( @@ -1635,11 +1464,11 @@ namespace Slang } IRInst* IRBuilder::emitBranch( - IRValue* val, + IRInst* val, IRBlock* trueBlock, IRBlock* falseBlock) { - IRValue* args[] = { val, trueBlock, falseBlock }; + IRInst* args[] = { val, trueBlock, falseBlock }; UInt argCount = sizeof(args) / sizeof(args[0]); auto inst = createInst<IRConditionalBranch>( @@ -1653,12 +1482,12 @@ namespace Slang } IRInst* IRBuilder::emitIfElse( - IRValue* val, + IRInst* val, IRBlock* trueBlock, IRBlock* falseBlock, IRBlock* afterBlock) { - IRValue* args[] = { val, trueBlock, falseBlock, afterBlock }; + IRInst* args[] = { val, trueBlock, falseBlock, afterBlock }; UInt argCount = sizeof(args) / sizeof(args[0]); auto inst = createInst<IRIfElse>( @@ -1672,7 +1501,7 @@ namespace Slang } IRInst* IRBuilder::emitIf( - IRValue* val, + IRInst* val, IRBlock* trueBlock, IRBlock* afterBlock) { @@ -1680,7 +1509,7 @@ namespace Slang } IRInst* IRBuilder::emitLoopTest( - IRValue* val, + IRInst* val, IRBlock* bodyBlock, IRBlock* breakBlock) { @@ -1688,13 +1517,13 @@ namespace Slang } IRInst* IRBuilder::emitSwitch( - IRValue* val, + IRInst* val, IRBlock* breakLabel, IRBlock* defaultLabel, UInt caseArgCount, - IRValue* const* caseArgs) + IRInst* const* caseArgs) { - IRValue* fixedArgs[] = { val, breakLabel, defaultLabel }; + IRInst* fixedArgs[] = { val, breakLabel, defaultLabel }; UInt fixedArgCount = sizeof(fixedArgs) / sizeof(fixedArgs[0]); auto inst = createInstWithTrailingArgs<IRSwitch>( @@ -1709,14 +1538,14 @@ namespace Slang return inst; } - IRHighLevelDeclDecoration* IRBuilder::addHighLevelDeclDecoration(IRValue* inst, Decl* decl) + IRHighLevelDeclDecoration* IRBuilder::addHighLevelDeclDecoration(IRInst* inst, Decl* decl) { auto decoration = addDecoration<IRHighLevelDeclDecoration>(inst, kIRDecorationOp_HighLevelDecl); decoration->decl = decl; return decoration; } - IRLayoutDecoration* IRBuilder::addLayoutDecoration(IRValue* inst, Layout* layout) + IRLayoutDecoration* IRBuilder::addLayoutDecoration(IRInst* inst, Layout* layout) { auto decoration = addDecoration<IRLayoutDecoration>(inst); decoration->layout = layout; @@ -1732,7 +1561,7 @@ namespace Slang int indent = 0; UInt idCounter = 1; - Dictionary<IRValue*, UInt> mapValueToID; + Dictionary<IRInst*, UInt> mapValueToID; }; static void dump( @@ -1778,11 +1607,11 @@ namespace Slang } } - bool opHasResult(IRValue* inst); + bool opHasResult(IRInst* inst); static UInt getID( IRDumpContext* context, - IRValue* value) + IRInst* value) { UInt id = 0; if (context->mapValueToID.TryGetValue(value, id)) @@ -1799,7 +1628,7 @@ namespace Slang static void dumpID( IRDumpContext* context, - IRValue* inst) + IRInst* inst) { if (!inst) { @@ -1847,7 +1676,7 @@ namespace Slang static void dumpOperand( IRDumpContext* context, - IRValue* inst) + IRInst* inst) { // TODO: we should have a dedicated value for the `undef` case if (!inst) @@ -2107,16 +1936,6 @@ namespace Slang IRDumpContext* context, IRInst* inst); - static void dumpChildrenRaw( - IRDumpContext* context, - IRBlock* block) - { - for (auto ii = block->firstInst; ii; ii = ii->getNextInst()) - { - dumpInst(context, ii); - } - } - static void dumpBlock( IRDumpContext* context, IRBlock* block) @@ -2125,19 +1944,30 @@ namespace Slang dump(context, "block "); dumpID(context, block); - if( block->getFirstParam() ) + IRInst* inst = block->getFirstInst(); + + // First walk through any `param` instructions, + // so that we can format them nicely + if (auto firstParam = as<IRParam>(inst)) { dump(context, "(\n"); context->indent += 2; - for (auto pp = block->getFirstParam(); pp; pp = pp->getNextParam()) + + for(;;) { - if (pp != block->getFirstParam()) + auto param = as<IRParam>(inst); + if (!param) + break; + + if (param != firstParam) dump(context, ",\n"); + inst = inst->getNextInst(); + dumpIndent(context); dump(context, "param "); - dumpID(context, pp); - dumpInstTypeClause(context, pp->getFullType()); + dumpID(context, param); + dumpInstTypeClause(context, param->getFullType()); } context->indent -= 2; dump(context, ")"); @@ -2145,191 +1975,10 @@ namespace Slang dump(context, ":\n"); context->indent++; - dumpChildrenRaw(context, block); - } -#if 0 - static void dumpChildrenRaw( - IRDumpContext* context, - IRFunc* func) - { - for (auto bb = func->getFirstBlock(); bb; bb = bb->getNextBlock()) - { - dumpBlock(context, bb); - } - } - - static void dumpChildren( - IRDumpContext* context, - IRFunc* func) - { - dumpIndent(context); - dump(context, "{\n"); - context->indent++; - dumpChildrenRaw(context, func); - context->indent--; - dumpIndent(context); - dump(context, "}\n"); - } -#endif - static void dumpInst( - IRDumpContext* context, - IRInst* inst) - { - if (!inst) - { - dumpIndent(context); - dump(context, "<null>"); - return; - } - - auto op = inst->op; - - // There are several ops we want to special-case here, - // so that they will be more pleasant to look at. - // -#if 0 - switch (op) - { - case kIROp_Module: - dumpIndent(context); - dump(context, "module\n"); - dumpChildren(context, inst); - return; - - case kIROp_Func: - { - IRFunc* func = (IRFunc*)inst; - dump(context, "\n"); - dumpIndent(context); - dump(context, "func "); - dumpID(context, func); - dumpInstTypeClause(context, func->getType()); - dump(context, "\n"); - - dumpIndent(context); - dump(context, "{\n"); - context->indent++; - - for (auto bb = func->getFirstBlock(); bb; bb = bb->getNextBlock()) - { - if (bb != func->getFirstBlock()) - dump(context, "\n"); - dumpInst(context, bb); - } - - context->indent--; - dump(context, "}\n"); - } - return; - - case kIROp_TypeType: - case kIROp_Param: - case kIROp_IntLit: - case kIROp_FloatLit: - case kIROp_boolConst: - // Don't dump here - return; - - case kIROp_Block: - { - IRBlock* block = (IRBlock*)inst; - - context->indent--; - dump(context, "block "); - dumpID(context, block); - - if( block->getFirstParam() ) - { - dump(context, "("); - context->indent++; - for (auto pp = block->getFirstParam(); pp; pp = pp->getNextParam()) - { - if (pp != block->getFirstParam()) - dump(context, ",\n"); - - dumpIndent(context); - dump(context, "param "); - dumpID(context, pp); - dumpInstTypeClause(context, pp->getType()); - } - context->indent--; - dump(context, ")\n"); - } - dump(context, ":\n"); - context->indent++; - - dumpChildrenRaw(context, block); - } - return; - - default: - break; - } -#endif - -#if 0 - // We also want to special-case based on the *type* - // of the instruction - auto type = inst->getType(); - if (type && type->op == kIROp_TypeType) - { - // We probably don't want to print most types - // when producing "friendly" output. - switch (type->op) - { - case kIROp_StructType: - break; - - default: - return; - } - } -#endif - - - // Okay, we have a seemingly "ordinary" op now - dumpIndent(context); - - auto opInfo = &kIROpInfos[op]; - auto type = inst->getFullType(); - auto dataType = inst->getDataType(); - - if (!dataType) + for(; inst; inst = inst->getNextInst()) { - // No result, okay... + dumpInst(context, inst); } - else - { - auto basicType = dataType->As<BasicExpressionType>(); - if (basicType && basicType->baseType == BaseType::Void) - { - // No result, okay... - } - else - { - dump(context, "let "); - dumpID(context, inst); - dumpInstTypeClause(context, type); - dump(context, "\t= "); - } - } - - dump(context, opInfo->name); - - uint32_t argCount = inst->argCount; - dump(context, "("); - for (uint32_t ii = 0; ii < argCount; ++ii) - { - if (ii != 0) - dump(context, ", "); - - auto argVal = inst->getArgs()[ii].get(); - - dumpOperand(context, argVal); - } - dump(context, ")"); - - dump(context, "\n"); } void dumpGenericSignature( @@ -2506,50 +2155,109 @@ namespace Slang dump(context, "\n{\n"); context->indent++; - for (auto entry : witnessTable->entries) + for (auto ii : witnessTable->getChildren()) { - dumpIRWitnessTableEntry(context, entry); + dumpInst(context, ii); } context->indent--; dump(context, "}\n"); } - void dumpIRGlobalValue( + static void dumpInst( IRDumpContext* context, - IRGlobalValue* value) + IRInst* inst) { - switch (value->op) + if (!inst) + { + dumpIndent(context); + dump(context, "<null>"); + return; + } + + auto op = inst->op; + + // There are several ops we want to special-case here, + // so that they will be more pleasant to look at. + // + switch (op) { case kIROp_Func: - dumpIRFunc(context, (IRFunc*)value); - break; + dumpIRFunc(context, (IRFunc*)inst); + return; case kIROp_global_var: - dumpIRGlobalVar(context, (IRGlobalVar*)value); - break; + dumpIRGlobalVar(context, (IRGlobalVar*)inst); + return; case kIROp_global_constant: - dumpIRGlobalConstant(context, (IRGlobalConstant*)value); - break; + dumpIRGlobalConstant(context, (IRGlobalConstant*)inst); + return; case kIROp_witness_table: - dumpIRWitnessTable(context, (IRWitnessTable*)value); - break; + dumpIRWitnessTable(context, (IRWitnessTable*)inst); + return; + + case kIROp_witness_table_entry: + dumpIRWitnessTableEntry(context, (IRWitnessTableEntry*)inst); + return; default: - dump(context, "???\n"); break; } + + // Okay, we have a seemingly "ordinary" op now + dumpIndent(context); + + auto opInfo = &kIROpInfos[op]; + auto type = inst->getFullType(); + auto dataType = inst->getDataType(); + + if (!dataType) + { + // No result, okay... + } + else + { + auto basicType = dataType->As<BasicExpressionType>(); + if (basicType && basicType->baseType == BaseType::Void) + { + // No result, okay... + } + else + { + dump(context, "let "); + dumpID(context, inst); + dumpInstTypeClause(context, type); + dump(context, "\t= "); + } + } + + dump(context, opInfo->name); + + UInt argCount = inst->getOperandCount(); + dump(context, "("); + for (UInt ii = 0; ii < argCount; ++ii) + { + if (ii != 0) + dump(context, ", "); + + auto argVal = inst->getOperand(ii); + + dumpOperand(context, argVal); + } + dump(context, ")"); + + dump(context, "\n"); } void dumpIRModule( IRDumpContext* context, IRModule* module) { - for( auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue() ) + for(auto ii : module->getGlobalInsts()) { - dumpIRGlobalValue(context, gv); + dumpInst(context, ii); } } @@ -2570,7 +2278,7 @@ namespace Slang context.builder = &sb; context.indent = 0; - dumpIRGlobalValue(&context, globalVal); + dumpInst(&context, globalVal); fprintf(stderr, "%s\n", sb.Buffer()); fflush(stderr); @@ -2595,7 +2303,7 @@ namespace Slang // // - Type* IRValue::getRate() + Type* IRInst::getRate() { if(auto rateQualifiedType = type->As<RateQualifiedType>()) return rateQualifiedType->rate; @@ -2603,7 +2311,7 @@ namespace Slang return nullptr; } - Type* IRValue::getDataType() + Type* IRInst::getDataType() { if(auto rateQualifiedType = type->As<RateQualifiedType>()) return rateQualifiedType->valueType; @@ -2611,7 +2319,7 @@ namespace Slang return type; } - void IRValue::replaceUsesWith(IRValue* other) + void IRInst::replaceUsesWith(IRInst* other) { // We will walk through the list of uses for the current // instruction, and make them point to the other inst. @@ -2635,11 +2343,11 @@ namespace Slang // Try to move to the next use, but bail // out if we are at the last one. - IRUse* next = uu->nextUse; - if( !next ) + IRUse* nn = uu->nextUse; + if( !nn ) break; - uu = next; + uu = nn; } // We are at the last use (and there must @@ -2673,19 +2381,13 @@ namespace Slang ff->debugValidate(); } - void IRValue::deallocate() + void IRInst::deallocate() { -#if 0 - // I'm going to intentionally leak here, - // just to test that this is the source - // of my heap-corruption crashes. -#else // Run destructor to be sure... - this->~IRValue(); -#endif + this->~IRInst(); } - void IRValue::dispose() + void IRInst::dispose() { IRObject::dispose(); type = decltype(type)(); @@ -2695,60 +2397,146 @@ namespace Slang // as `other`, right before it. void IRInst::insertBefore(IRInst* other) { + assert(other); + insertBefore(other, other->parent); + } + + void IRInst::insertAtStart(IRParentInst* newParent) + { + assert(newParent); + insertBefore(newParent->children.first, newParent); + } + + void IRInst::moveToStart() + { + auto p = parent; + removeFromParent(); + insertAtStart(p); + } + + void IRInst::insertBefore(IRInst* other, IRParentInst* newParent) + { // Make sure this instruction has been removed from any previous parent this->removeFromParent(); - auto bb = other->getParentBlock(); - assert(bb); + assert(other || newParent); + if (!other) other = newParent->children.first; + if (!newParent) newParent = other->parent; + assert(newParent); + + auto nn = other; + auto pp = other ? other->getPrevInst() : nullptr; - auto pp = other->getPrevInst(); if( pp ) { pp->next = this; } else { - bb->firstInst = this; + newParent->children.first = this; + } + + if (nn) + { + nn->prev = this; + } + else + { + newParent->children.last = this; } this->prev = pp; - this->next = other; - this->parent = bb; + this->next = nn; + this->parent = newParent; + } + + void IRInst::insertAfter(IRInst* other) + { + assert(other); + insertAfter(other, other->parent); + } + + void IRInst::insertAtEnd(IRParentInst* newParent) + { + assert(newParent); + insertAfter(newParent->children.last, newParent); + } + + void IRInst::moveToEnd() + { + auto p = parent; + removeFromParent(); + insertAtEnd(p); + } + + void IRInst::insertAfter(IRInst* other, IRParentInst* newParent) + { + // Make sure this instruction has been removed from any previous parent + this->removeFromParent(); + + assert(other || newParent); + if (!other) other = newParent->children.last; + if (!newParent) newParent = other->parent; + assert(newParent); + + auto pp = other; + auto nn = other ? other->next : nullptr; + + if (pp) + { + pp->next = this; + } + else + { + newParent->children.first = this; + } + + if (nn) + { + nn->prev = this; + } + else + { + newParent->children.last = this; + } - other->prev = this; + this->prev = pp; + this->next = nn; + this->parent = newParent; } // Remove this instruction from its parent block, // and then destroy it (it had better have no uses!) void IRInst::removeFromParent() { + auto oldParent = getParent(); + // If we don't currently have a parent, then // we are doing fine. - if(!getParentBlock()) + if(!oldParent) return; - auto bb = getParentBlock(); auto pp = getPrevInst(); auto nn = getNextInst(); if(pp) { - SLANG_ASSERT(pp->getParentBlock() == bb); + SLANG_ASSERT(pp->getParent() == oldParent); pp->next = nn; } else { - bb->firstInst = nn; + oldParent->children.first = nn; } if(nn) { - SLANG_ASSERT(nn->getParentBlock() == bb); + SLANG_ASSERT(nn->getParent() == oldParent); nn->prev = pp; } else { - bb->lastInst = pp; + oldParent->children.last = pp; } prev = nullptr; @@ -2758,9 +2546,9 @@ namespace Slang void IRInst::removeArguments() { - for( UInt aa = 0; aa < argCount; ++aa ) + for( UInt aa = 0; aa < operandCount; ++aa ) { - IRUse& use = getArgs()[aa]; + IRUse& use = getOperands()[aa]; use.clear(); } } @@ -2824,10 +2612,10 @@ namespace Slang // no value (null pointer) none, - // A simple `IRValue*` that represents the actual value + // A simple `IRInst*` that represents the actual value value, - // An `IRValue*` that represents the address of the actual value + // An `IRInst*` that represents the address of the actual value address, // A `TupleValImpl` that represents zero or more `ScalarizedVal`s @@ -2840,7 +2628,7 @@ namespace Slang }; // Create a value representing a simple value - static ScalarizedVal value(IRValue* irValue) + static ScalarizedVal value(IRInst* irValue) { ScalarizedVal result; result.flavor = Flavor::value; @@ -2850,7 +2638,7 @@ namespace Slang // Create a value representing an address - static ScalarizedVal address(IRValue* irValue) + static ScalarizedVal address(IRInst* irValue) { ScalarizedVal result; result.flavor = Flavor::address; @@ -2875,7 +2663,7 @@ namespace Slang } Flavor flavor = Flavor::none; - IRValue* irValue = nullptr; + IRInst* irValue = nullptr; RefPtr<ScalarizedValImpl> impl; }; @@ -3457,7 +3245,7 @@ namespace Slang ScalarizedVal adaptType( IRBuilder* builder, - IRValue* val, + IRInst* val, Type* toType, Type* /*fromType*/) { @@ -3585,7 +3373,7 @@ namespace Slang IRBuilder* builder, Type* elementType, ScalarizedVal val, - IRValue* indexVal) + IRInst* indexVal) { switch( val.flavor ) { @@ -3667,11 +3455,11 @@ namespace Slang index)); } - IRValue* materializeValue( + IRInst* materializeValue( IRBuilder* builder, ScalarizedVal const& val); - IRValue* materializeTupleValue( + IRInst* materializeTupleValue( IRBuilder* builder, ScalarizedVal val) { @@ -3689,7 +3477,7 @@ namespace Slang // We will extract a value for each array element, and // then use these to construct our result. - List<IRValue*> arrayElementVals; + List<IRInst*> arrayElementVals; UInt arrayElementCount = (UInt) GetIntVal(arrayType->ArrayLength); for( UInt ii = 0; ii < arrayElementCount; ++ii ) @@ -3720,7 +3508,7 @@ namespace Slang // // TODO: this should be using a `makeStruct` instruction. - List<IRValue*> elementVals; + List<IRInst*> elementVals; for( UInt ee = 0; ee < elementCount; ++ee ) { auto elementVal = materializeValue(builder, tupleVal->elements[ee].val); @@ -3734,7 +3522,7 @@ namespace Slang } } - IRValue* materializeValue( + IRInst* materializeValue( IRBuilder* builder, ScalarizedVal const& val) { @@ -3776,7 +3564,7 @@ namespace Slang } IRTargetIntrinsicDecoration* findTargetIntrinsicDecoration( - IRValue* val, + IRInst* val, String const& targetName) { for( auto dd = val->firstDecoration; dd; dd = dd->next ) @@ -3794,6 +3582,7 @@ namespace Slang void legalizeEntryPointForGLSL( Session* session, + IRModule* module, IRFunc* func, EntryPointLayout* entryPointLayout, DiagnosticSink* sink, @@ -3805,8 +3594,6 @@ namespace Slang context.sink = sink; context.extensionUsageTracker = extensionUsageTracker; - auto module = func->parentModule; - // We require that the entry-point function has no uses, // because otherwise we'd invalidate the signature // at all existing call sites. @@ -3881,7 +3668,7 @@ namespace Slang continue; IRReturnVal* returnInst = (IRReturnVal*) ii; - IRValue* returnValue = returnInst->getVal(); + IRInst* returnValue = returnInst->getVal(); // Make sure we add these instructions to the right block builder.curBlock = bb; @@ -3978,10 +3765,10 @@ namespace Slang continue; // Is it calling the append operation? - auto callee = ii->getArg(0); + auto callee = ii->getOperand(0); while( callee->op == kIROp_specialize ) { - callee = ((IRSpecialize*) callee)->getArg(0); + callee = ((IRSpecialize*) callee)->getOperand(0); } if(callee->op != kIROp_Func) continue; @@ -4003,7 +3790,7 @@ namespace Slang builder.curBlock = bb; builder.insertBeforeInst = ii; - assign(&builder, globalOutputVal, ScalarizedVal::value(ii->getArg(2))); + assign(&builder, globalOutputVal, ScalarizedVal::value(ii->getOperand(2))); } } @@ -4092,7 +3879,7 @@ namespace Slang // references to the variable(s). We are going to do that // somewhat naively, by simply materializing the // variables at the start. - IRValue* materialized = materializeValue(&builder, globalValue); + IRInst* materialized = materializeValue(&builder, globalValue); pp->replaceUsesWith(materialized); } @@ -4107,14 +3894,13 @@ namespace Slang // // We can safely go through and destroy the parameters // themselves, and then clear out the parameter list. + for( auto pp = firstBlock->getFirstParam(); pp; ) { auto next = pp->getNextParam(); pp->deallocate(); pp = next; } - firstBlock->firstParam = nullptr; - firstBlock->lastParam = nullptr; } // Finally, we need to patch up the type of the entry point, @@ -4163,7 +3949,7 @@ namespace Slang // A map from values in the original IR module // to their equivalent in the cloned module. - typedef Dictionary<IRValue*, IRValue*> ClonedValueDictionary; + typedef Dictionary<IRInst*, IRInst*> ClonedValueDictionary; ClonedValueDictionary clonedValues; SharedIRBuilder sharedBuilderStorage; @@ -4199,7 +3985,7 @@ namespace Slang // A callback to be used when a value that is not registerd in `clonedValues` // is needed during cloning. This gives the subtype a chance to intercept // the operation and clone (or not) as needed. - virtual IRValue* maybeCloneValue(IRValue* originalVal) + virtual IRInst* maybeCloneValue(IRInst* originalVal) { return originalVal; } @@ -4225,8 +4011,8 @@ namespace Slang void registerClonedValue( IRSpecContextBase* context, - IRValue* clonedValue, - IRValue* originalValue) + IRInst* clonedValue, + IRInst* originalValue) { if(!originalValue) return; @@ -4249,12 +4035,12 @@ namespace Slang // Information on values to use when registering a cloned value struct IROriginalValuesForClone { - IRValue* originalVal = nullptr; + IRInst* originalVal = nullptr; IRSpecSymbol* sym = nullptr; IROriginalValuesForClone() {} - IROriginalValuesForClone(IRValue* originalValue) + IROriginalValuesForClone(IRInst* originalValue) : originalVal(originalValue) {} @@ -4265,7 +4051,7 @@ namespace Slang void registerClonedValue( IRSpecContextBase* context, - IRValue* clonedValue, + IRInst* clonedValue, IROriginalValuesForClone const& originalValues) { registerClonedValue(context, clonedValue, originalValues.originalVal); @@ -4277,8 +4063,8 @@ namespace Slang void cloneDecorations( IRSpecContextBase* context, - IRValue* clonedValue, - IRValue* originalValue) + IRInst* clonedValue, + IRInst* originalValue) { for (auto dd = originalValue->firstDecoration; dd; dd = dd->next) { @@ -4322,7 +4108,7 @@ namespace Slang struct IRSpecContext : IRSpecContextBase { // Override the "maybe clone" logic so that we always clone - virtual IRValue* maybeCloneValue(IRValue* originalVal) override; + virtual IRInst* maybeCloneValue(IRInst* originalVal) override; // Override teh "maybe clone" logic so that we carefully // clone any IR proxy values inside substitutions @@ -4349,7 +4135,7 @@ namespace Slang } - IRValue* IRSpecContext::maybeCloneValue(IRValue* originalValue) + IRInst* IRSpecContext::maybeCloneValue(IRInst* originalValue) { switch (originalValue->op) { @@ -4425,7 +4211,7 @@ namespace Slang break; case kIROp_TypeType: { - IRValue* od = (IRValue*)originalValue; + IRInst* od = (IRInst*)originalValue; int ioDiff = 0; auto newType = od->type->SubstituteImpl(subst, &ioDiff); return builder->getTypeVal(newType.As<Type>()); @@ -4437,9 +4223,9 @@ namespace Slang } } - IRValue* cloneValue( + IRInst* cloneValue( IRSpecContextBase* context, - IRValue* originalValue); + IRInst* originalValue); RefPtr<Val> cloneSubstitutionArg( IRSpecContext* context, @@ -4526,11 +4312,11 @@ namespace Slang return newDeclRef; } - IRValue* cloneValue( + IRInst* cloneValue( IRSpecContextBase* context, - IRValue* originalValue) + IRInst* originalValue) { - IRValue* clonedValue = nullptr; + IRInst* clonedValue = nullptr; if (context->getClonedValues().TryGetValue(originalValue, clonedValue)) { return clonedValue; @@ -4539,12 +4325,16 @@ namespace Slang return context->maybeCloneValue(originalValue); } - IRValue* maybeCloneValueWithMangledName( + IRInst* maybeCloneValueWithMangledName( IRSpecContextBase* context, IRGlobalValue* originalValue) { - for (auto gv = context->shared->module->firstGlobalValue; gv; gv = gv->nextGlobalValue) + for(auto ii : context->shared->module->getGlobalInsts()) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; + if (gv->mangledName == originalValue->mangledName) return gv; } @@ -4567,7 +4357,7 @@ namespace Slang // The common case is that we just need to construct a cloned // instruction with the right number of operands, intialize // it, and then add it to the sequence. - UInt argCount = originalInst->getArgCount(); + UInt argCount = originalInst->getOperandCount(); IRInst* clonedInst = createInstWithTrailingArgs<IRInst>( builder, originalInst->op, context->maybeCloneType(originalInst->type), @@ -4578,14 +4368,14 @@ namespace Slang context->builder = builder; for (UInt aa = 0; aa < argCount; ++aa) { - IRValue* originalArg = originalInst->getArg(aa); - IRValue* clonedArg; + IRInst* originalArg = originalInst->getOperand(aa); + IRInst* clonedArg; if (originalArg->op == kIROp_witness_table) clonedArg = cloneGlobalValueWithMangledName((IRSpecContext*)context, ((IRGlobalValue*)originalArg)->mangledName, (IRGlobalValue*)originalArg); else clonedArg = cloneValue(context, originalArg); - clonedInst->getArgs()[aa].init(clonedInst, clonedArg); + clonedInst->getOperands()[aa].init(clonedInst, clonedArg); } builder->addInst(clonedInst); context->builder = oldBuilder; @@ -4681,7 +4471,7 @@ namespace Slang cloneDecorations(context, clonedTable, originalTable); // Clone the entries in the witness table as well - for( auto originalEntry : originalTable->entries ) + for(auto originalEntry : originalTable->getEntries() ) { auto clonedKey = cloneValue(context, originalEntry->requirementKey.get()); @@ -4729,6 +4519,7 @@ namespace Slang clonedValue->addBlock(clonedBlock); registerClonedValue(context, clonedBlock, originalBlock); +#if 0 // We can go ahead and clone parameters here, while we are at it. builder->curBlock = clonedBlock; for (auto originalParam = originalBlock->getFirstParam(); @@ -4741,6 +4532,7 @@ namespace Slang cloneDecorations(context, clonedParam, originalParam); registerClonedValue(context, clonedParam, originalParam); } +#endif } // Okay, now we are in a good position to start cloning @@ -4788,7 +4580,7 @@ namespace Slang // // TODO: This isn't really a good requirement to place on the IR... clonedFunc->removeFromParent(); - clonedFunc->insertAtEnd(context->getModule()); + clonedFunc->insertAtEnd(context->getModule()->getModuleInst()); } IRFunc* specializeIRForEntryPoint( @@ -4933,12 +4725,10 @@ namespace Slang switch (val->op) { case kIROp_witness_table: - return ((IRWitnessTable*)val)->entries.first != nullptr; - case kIROp_global_var: case kIROp_global_constant: case kIROp_Func: - return ((IRGlobalValueWithCode*)val)->firstBlock != nullptr; + return ((IRParentInst*)val)->getFirstChild() != nullptr; default: return false; @@ -5058,7 +4848,7 @@ namespace Slang { // Check if we've already cloned this value, for the case where // an original value has already been established. - IRValue* clonedVal = nullptr; + IRInst* clonedVal = nullptr; if( originalVal && context->getClonedValues().TryGetValue(originalVal, clonedVal) ) { return (IRGlobalValue*) clonedVal; @@ -5168,8 +4958,11 @@ namespace Slang if (!originalModule) return; - for (auto gv = originalModule->firstGlobalValue; gv; gv = gv->nextGlobalValue) + for(auto ii : originalModule->getGlobalInsts()) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; insertGlobalValueSymbol(sharedContext, gv); } } @@ -5385,6 +5178,7 @@ namespace Slang { legalizeEntryPointForGLSL( session, + context->getModule(), irEntryPoint, entryPointLayout, &compileRequest->mSink, @@ -5402,14 +5196,14 @@ namespace Slang IRSharedSpecContext* getShared() { return shared; } // Override the "maybe clone" logic so that we always clone - virtual IRValue* maybeCloneValue(IRValue* originalVal) override; + virtual IRInst* maybeCloneValue(IRInst* originalVal) override; virtual RefPtr<Type> maybeCloneType(Type* originalType) override; virtual RefPtr<Val> maybeCloneVal(Val* val) override; }; // Convert a type-level value into an IR-level equivalent. - IRValue* getIRValue( + IRInst* getIRValue( IRGenericSpecContext* context, Val* val) { @@ -5467,7 +5261,7 @@ namespace Slang } } - IRValue* getSubstValue( + IRInst* getSubstValue( IRGenericSpecContext* context, DeclRef<Decl> declRef) { @@ -5538,7 +5332,7 @@ namespace Slang } } - IRValue* IRGenericSpecContext::maybeCloneValue(IRValue* originalVal) + IRInst* IRGenericSpecContext::maybeCloneValue(IRInst* originalVal) { switch( originalVal->op ) { @@ -5692,8 +5486,12 @@ namespace Slang if (!dstTable) { auto module = sharedContext->module; - for (auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue()) + for(auto ii : module->getGlobalInsts()) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; + if (getText(gv->mangledName) == specializedMangledName) return (IRWitnessTable*)gv; } @@ -5718,7 +5516,7 @@ namespace Slang // Specialization of witness tables should trigger cascading specializations // of involved functions. - for (auto entry : specTable->entries) + for (auto entry : specTable->getEntries()) { if (entry->satisfyingVal.get()->op == kIROp_Func) { @@ -5761,8 +5559,12 @@ namespace Slang // avoid it by building a dictionary ahead of time, // as is being done for the `IRSpecContext` used above. // We can probalby use the same basic context, actually. - for (auto gv = sharedContext->module->getFirstGlobalValue(); gv; gv = gv->getNextValue()) + for(auto ii : sharedContext->module->getGlobalInsts()) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; + if (gv->mangledName == specMangledNameObj) return (IRFunc*) gv; } @@ -5823,12 +5625,12 @@ namespace Slang // Find the value in the given witness table that // satisfies the given requirement (or return // null if not found). - IRValue* findWitnessVal( + IRInst* findWitnessVal( IRWitnessTable* witnessTable, DeclRef<Decl> const& requirementDeclRef) { // For now we will do a dumb linear search - for( auto entry : witnessTable->entries ) + for( auto entry : witnessTable->getEntries() ) { // We expect the key on the entry to be a decl-ref, // but lets go ahead and check, just to be sure. @@ -5889,10 +5691,12 @@ namespace Slang // function. // // We start by building up a work list of non-generic functions. - for( auto gv = module->getFirstGlobalValue(); - gv; - gv = gv->getNextValue() ) + for(auto ii : module->getGlobalInsts()) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; + // Is it a function? If not, skip. if(gv->op != kIROp_Func) continue; @@ -5907,10 +5711,12 @@ namespace Slang // Build dictionary for witness tables Dictionary<Name*, IRWitnessTable*> witnessTables; - for (auto gv = module->getFirstGlobalValue(); - gv; - gv = gv->getNextValue()) + for(auto ii : module->getGlobalInsts()) { + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; + if (gv->op == kIROp_witness_table) witnessTables.AddIfNotExists(gv->mangledName, (IRWitnessTable*)gv); } @@ -6115,20 +5921,18 @@ namespace Slang if (subtypeWitness->sub->EqualsVal(paramSubst->actualType)) { auto witnessTableName = getMangledNameForConformanceWitness(subtypeWitness->sub, subtypeWitness->sup); - auto findWitnessTableByName = [&](String name) + auto findWitnessTableByName = [&](String name) -> IRGlobalValue* { - auto globalVar = originalIRModule->getFirstGlobalValue(); - IRGlobalValue * rs = nullptr; - while (globalVar) + for (auto ii : originalIRModule->getGlobalInsts()) { - if (getText(globalVar->mangledName) == name) - { - rs = globalVar; - break; - } - globalVar = globalVar->getNextValue(); + auto gv = as<IRGlobalValue>(ii); + if (!gv) + continue; + + if (getText(gv->mangledName) == name) + return gv; } - return rs; + return nullptr; }; auto table = findWitnessTableByName(witnessTableName); if (!table) @@ -6170,7 +5974,7 @@ namespace Slang void markConstExpr( Session* session, - IRValue* irValue) + IRInst* irValue) { // We will take an IR value with type `T`, // and turn it into one with type `@ConstExpr T`. diff --git a/source/slang/ir.h b/source/slang/ir.h index 8f350827a..95a7a97d1 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -25,8 +25,6 @@ struct IRFunc; struct IRGlobalValueWithCode; struct IRInst; struct IRModule; -struct IRUser; -struct IRValue; typedef unsigned int IROpFlags; enum : IROpFlags @@ -57,6 +55,13 @@ enum IROp : int16_t #include "ir-inst-defs.h" +#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) /* empty */ +#define INST_RANGE(BASE, FIRST, LAST) \ + kIROp_First##BASE = kIROp_##FIRST, \ + kIROp_Last##BASE = kIROp_##LAST, + +#include "ir-inst-defs.h" + kIROp_Invalid = -1, }; @@ -83,18 +88,18 @@ IROpInfo getIROpInfo(IROp op); // A use of another value/inst within an IR operation struct IRUse { - IRValue* get() { return usedValue; } - IRUser* getUser() { return user; } + IRInst* get() { return usedValue; } + IRInst* getUser() { return user; } - void init(IRUser* user, IRValue* usedValue); - void set(IRValue* usedValue); + void init(IRInst* user, IRInst* usedValue); + void set(IRInst* usedValue); void clear(); - // The value that is being used - IRValue* usedValue = nullptr; + // The instruction that is being used + IRInst* usedValue = nullptr; - // The value that is doing the using. - IRUser* user = nullptr; + // The instruction that is doing the using. + IRInst* user = nullptr; // The next use of the same value IRUse* nextUse = nullptr; @@ -145,22 +150,30 @@ struct IRDecoration : public IRObject typedef Type IRType; struct IRBlock; +struct IRParentInst; -// Base class for values in the IR -struct IRValue : public IRObject +// Every value in the IR is an instruction (even things +// like literal values). +// +struct IRInst : public IRObject { // The operation that this value represents IROp op; - // The type of the result value of this instruction, - // or `null` to indicate that the instruction has - // no value. - RefPtr<Type> type; + // The total number of operands of this instruction. + // + // TODO: We shouldn't need to allocate this on + // all instructions. Instead we should have + // instructions that need "vararg" support to + // allocate this field ahead of the `this` + // pointer. + uint32_t operandCount = 0; - Type* getFullType() { return type; } + UInt getOperandCount() + { + return operandCount; + } - Type* getRate(); - Type* getDataType(); // Source location information for this value, if any SourceLoc sourceLoc; @@ -180,154 +193,196 @@ struct IRValue : public IRObject IRUse* firstUse = nullptr; + // The parent of this instruction. + IRParentInst* parent; + + IRParentInst* getParent() { return parent; } + + // The next and previous instructions with the same parent + IRInst* next; + IRInst* prev; + + IRInst* getNextInst() { return next; } + IRInst* getPrevInst() { return prev; } + + // The type of the result value of this instruction, + // or `null` to indicate that the instruction has + // no value. + RefPtr<Type> type; + + Type* getFullType() { return type; } + + Type* getRate(); + Type* getDataType(); + + // After the type, we have data that is specific to + // the subtype of `IRInst`. In most cases, this is + // just a series of `IRUse` values representing + // operands of the instruction. + + IRUse* getOperands(); + + IRInst* getOperand(UInt index) + { + return getOperands()[index].get(); + } + + void setOperand(UInt index, IRInst* value) + { + getOperands()[index].set(value); + } + + + // + // Replace all uses of this value with `other`, so // that this value will now have no uses. - void replaceUsesWith(IRValue* other); + void replaceUsesWith(IRInst* other); // Free a value (which needs to have been removed // from its parent, had its uses eliminated, etc.) void deallocate(); + // Clean up any non-pool resources used by this instruction virtual void dispose() override; -}; -// Values that are contained in a doubly-linked -// list inside of some parent. -// -// TODO: consider merging this into `IRValue` so -// that *all* values have a parent. -struct IRChildValue : IRValue -{ - // The parent of this value. - IRValue* parent; + // Insert this instruction into the same basic block + // as `other`, right before/after it. + void insertBefore(IRInst* other); + void insertAfter(IRInst* other); + + // Insert as first/last child of given parent + void insertAtStart(IRParentInst* parent); + void insertAtEnd(IRParentInst* parent); + + // Move to the start/end of current parent + void moveToStart(); + void moveToEnd(); + + // Insert before/after the given instruction, in a specific block + void insertBefore(IRInst* other, IRParentInst* parent); + void insertAfter(IRInst* other, IRParentInst* parent); + + // Remove this instruction from its parent block, + // but don't delete it, or replace uses. + void removeFromParent(); + + // Remove this instruction from its parent block, + // and then destroy it (it had better have no uses!) + void removeAndDeallocate(); + + // Clear out the arguments of this instruction, + // so that we don't appear on the list of uses + // for those values. + void removeArguments(); - // The next and previous values in the same - // list on teh same parent. - IRChildValue* next; - IRChildValue* prev; }; -// Helper for storing linked lists of child values. -struct IRValueListBase +// `dynamic_cast` equivalent +template<typename T> +T* as(IRInst* inst, T* /* */ = nullptr) { - IRChildValue* first = 0; - IRChildValue* last = 0; + if (inst && T::isaImpl(inst->op)) + return (T*) inst; + return nullptr; +} -protected: - void addImpl(IRValue* parent, IRChildValue* val); -}; +// `static_cast` equivalent, with debug validation template<typename T> -struct IRValueList : IRValueListBase +T* cast(IRInst* inst, T* /* */ = nullptr) { - T* getFirst() { return (T*)first; } - T* getLast() { return (T*)last; } + SLANG_ASSERT(!inst || as<T>(inst)); + return (T*)inst; +} + + +// A double-linked list of instruction +struct IRInstListBase +{ + IRInstListBase() + {} + + IRInstListBase(IRInst* first, IRInst* last) + : first(first) + , last(last) + {} + - void add(IRValue* parent, T* val) - { - addImpl(parent, val); - } + + IRInst* first = 0; + IRInst* last = 0; + + IRInst* getFirst() { return first; } + IRInst* getLast() { return last; } struct Iterator { - T* val; + IRInst* inst; - Iterator() : val(0) {} - Iterator(T* val) : val(val) {} + Iterator() : inst(nullptr) {} + Iterator(IRInst* inst) : inst(inst) {} void operator++() { - if (val) + if (inst) { - val = (T*)val->next; + inst = inst->next; } } - T* operator*() + IRInst* operator*() { - return val; + return inst; } bool operator!=(Iterator const& i) { - return val != i.val; + return inst != i.inst; } }; - Iterator begin() { return Iterator(getFirst()); } - Iterator end() { return Iterator(nullptr); } + Iterator begin() { return Iterator(first); } + Iterator end() { return Iterator(last ? last->next : nullptr); } }; -// Values that can use other values. These always -// have their operands "tail allocated" after -// the fields of this type, so derived types must -// either: -// -// - Add no new fields, or -// - Add only fields that represent the `IRUse` operands -// - Add a fixed number of `IRUse` operand fields and -// then any additional data after them. -// -struct IRUser : IRChildValue +// Specialization of `IRInstListBase` for the case where +// we know (or at least expect) all of the instructions +// to be of type `T` +template<typename T> +struct IRInstList : IRInstListBase { - // The total number of arguments of this instruction. - // - // TODO: We shouldn't need to allocate this on - // all instructions. Instead we should have - // instructions that need "vararg" support to - // allocate this field ahead of the `this` - // pointer. - uint32_t argCount = 0; + IRInstList() {} - UInt getArgCount() - { - return argCount; - } + IRInstList(T* first, T* last) + : IRInstListBase(first, last) + {} - IRUse* getArgs(); + explicit IRInstList(IRInstListBase const& list) + : IRInstListBase(list) + {} - IRValue* getArg(UInt index) - { - return getArgs()[index].get(); - } + T* getFirst() { return (T*) first; } + T* getLast() { return (T*) last; } - void setArg(UInt index, IRValue* value) + struct Iterator : public IRInstListBase::Iterator { - getArgs()[index].set(value); - } -}; - -// Instructions are values that are children of a basic block, -// and can actually be executed. -struct IRInst : IRUser -{ - IRBlock* getParentBlock() { return (IRBlock*)parent; } + Iterator() {} + Iterator(IRInst* inst) : IRInstListBase::Iterator(inst) {} - IRInst* getPrevInst() { return (IRInst*)prev; } - IRInst* getNextInst() { return (IRInst*)next; } - - - // Insert this instruction into the same basic block - // as `other`, right before it. - void insertBefore(IRInst* other); - - // Remove this instruction from its parent block, - // but don't delete it, or replace uses. - void removeFromParent(); - - // Remove this instruction from its parent block, - // and then destroy it (it had better have no uses!) - void removeAndDeallocate(); + T* operator*() + { + return (T*) inst; + } + }; - // Clear out the arguments of this instruction, - // so that we don't appear on the list of uses - // for those values. - void removeArguments(); + Iterator begin() { return Iterator(first); } + Iterator end() { return Iterator(last ? last->next : nullptr); } }; typedef int64_t IRIntegerValue; typedef double IRFloatingPointValue; -struct IRConstant : IRValue +struct IRConstant : IRInst { union { @@ -341,10 +396,12 @@ struct IRConstant : IRValue // A instruction that ends a basic block (usually because of control flow) struct IRTerminatorInst : IRInst -{}; - -bool isTerminatorInst(IROp op); -bool isTerminatorInst(IRInst* inst); +{ + static bool isaImpl(IROp op) + { + return (op >= kIROp_FirstTerminatorInst) && (op <= kIROp_LastTerminatorInst); + } +}; // A function parameter is owned by a basic block, and represents // either an incoming function parameter (in the entry block), or @@ -354,15 +411,26 @@ bool isTerminatorInst(IRInst* inst); // In each case, the basic idea is that a block is a "label with // arguments." // -// Note: an `IRParam` is an `IRUser` *just* so that we can use -// it as the user of other values during SSA generation. -struct IRParam : IRUser +struct IRParam : IRInst +{ + IRParam* getNextParam(); + IRParam* getPrevParam(); + + static bool isaImpl(IROp op) { return op == kIROp_Param; } +}; + +// A "parent" instruction is one that contains other instructions +// as its children. The most common case of a parent instruction +// is a basic block, but there are other cases (e.g., a function +// is in turn a parent for basic blocks). +struct IRParentInst : IRInst { - IRParam* nextParam; - IRParam* prevParam; + // The instructions stored under this parent + IRInstListBase children; - IRParam* getNextParam() { return nextParam; } - IRParam* getPrevParam() { return prevParam; } + IRInst* getFirstChild() { return children.first; } + IRInst* getLastChild() { return children.last; } + IRInstListBase getChildren() { return children; } }; // A basic block is a parent instruction that adds the constraint @@ -370,42 +438,63 @@ struct IRParam : IRUser // no function declarations, or nested blocks). We also expect // that the previous/next instruction are always a basic block. // -struct IRBlock : IRValue +struct IRBlock : IRParentInst { // Linked list of the instructions contained in this block // - // Note that in a valid program, every block must end with - // a "terminator" instruction, so these should be non-NULL, - // and `lastInst` should actually be an `IRTerminatorInst`. - IRInst* firstInst; - IRInst* lastInst; + IRInstListBase getChildren() { return children; } + IRInst* getFirstInst() { return children.first; } + IRInst* getLastInst() { return children.last; } - IRInst* getFirstInst() { return firstInst; } - IRInst* getLastInst() { return lastInst; } - - // Links for the list of basic blocks in the parent function - IRBlock* prevBlock; - IRBlock* nextBlock; - - IRBlock* getPrevBlock() { return prevBlock; } - IRBlock* getNextBlock() { return nextBlock; } - - // Linked list of parameters of this block - IRParam* firstParam; - IRParam* lastParam; + // In a valid program, every basic block should end with + // a "terminator" instruction. + // + // This function will return the terminator, if it exists, + // or `null` if there is none. + IRTerminatorInst* getTerminator() { return as<IRTerminatorInst>(getLastInst()); } + + // We expect that the siblings of a basic block will + // always be other basic blocks (we don't allow + // mixing of blocks and other instructions in the + // same parent). + IRBlock* getPrevBlock() { return cast<IRBlock>(getPrevInst()); } + IRBlock* getNextBlock() { return cast<IRBlock>(getNextInst()); } + + // The parameters of a block are represented by `IRParam` + // instructions at the start of the block. These play + // the role of function parameters for the entry block + // of a function, and of phi nodes in other blocks. + IRParam* getFirstParam() { return as<IRParam>(getFirstInst()); } + IRParam* getLastParam(); + IRInstList<IRParam> getParams() + { + return IRInstList<IRParam>( + getFirstParam(), + getLastParam()); + } - IRParam* getFirstParam() { return firstParam; } - IRParam* getLastParam() { return lastParam; } void addParam(IRParam* param); - // The parent function that contains this block - IRGlobalValueWithCode* parentFunc; - - IRGlobalValueWithCode* getParent() { return parentFunc; } - - void insertAfter(IRBlock* other); - void insertAfter(IRBlock* other, IRGlobalValueWithCode* func); - + // The parent of a basic block is assumed to be a + // value with code (e.g., a function, global variable + // with initializer, etc.). + IRGlobalValueWithCode* getParent() { return cast<IRGlobalValueWithCode>(IRInst::getParent()); } + + // The predecessor and successor lists of a block are needed + // when we want to work with the control flow graph (CFG) of + // a function. Rather than store these explicitly (and thus + // need to update them when transformations might change the + // CFG), we compute predecessors and successors in an + // implicit fashion using the use-def information for a + // block itself. + // + // To a first approximation, the predecessors of a block + // are the blocks where the IR value of the block is used. + // Similarly, the successors of a block are all values used + // by the terminator instruction of the block. + // The `getPredecessors()` and `getSuccessors()` functions + // make this more precise. + // struct PredecessorList { PredecessorList(IRUse* begin) : b(begin) {} @@ -465,6 +554,10 @@ struct IRBlock : IRValue PredecessorList getPredecessors(); SuccessorList getSuccessors(); + + // + + static bool isaImpl(IROp op) { return op == kIROp_Block; } }; // For right now, we will represent the type of @@ -474,21 +567,17 @@ struct IRBlock : IRValue // TODO: need to do this better. typedef FuncType IRFuncType; -struct IRGlobalValue : IRValue +// A "global value" is an instruction that might have +// linkage, so that it can be declared in one module +// and then resolved to a definition in another module. +struct IRGlobalValue : IRParentInst { - IRModule* parentModule; - // The mangled name, for a symbol that should have linkage, // or which might have multiple declarations. Name* mangledName = nullptr; - - IRGlobalValue* nextGlobalValue; - IRGlobalValue* prevGlobalValue; - - IRGlobalValue* getNextValue() { return nextGlobalValue; } - IRGlobalValue* getPrevValue() { return prevGlobalValue; } - +#if 0 + // TODO: these all belong on `IRInst` void insertBefore(IRGlobalValue* other); void insertBefore(IRGlobalValue* other, IRModule* module); void insertAtStart(IRModule* module); @@ -500,18 +589,26 @@ struct IRGlobalValue : IRValue void removeFromParent(); void moveToEnd(); +#endif + + static bool isaImpl(IROp op) + { + return (op >= kIROp_FirstGlobalValue) && (op <= kIROp_LastGlobalValue); + } }; /// @brief A global value that potentially holds executable code. /// struct IRGlobalValueWithCode : IRGlobalValue { - // The list of basic blocks in this function - IRBlock* firstBlock = nullptr; - IRBlock* lastBlock = nullptr; - - IRBlock* getFirstBlock() { return firstBlock; } - IRBlock* getLastBlock() { return lastBlock; } + // The children of a value with code will be the basic + // blocks of its definition. + IRBlock* getFirstBlock() { return cast<IRBlock>(getFirstChild()); } + IRBlock* getLastBlock() { return cast<IRBlock>(getLastChild()); } + IRInstList<IRBlock> getBlocks() + { + return IRInstList<IRBlock>(getChildren()); + } // Add a block to the end of this function. void addBlock(IRBlock* block); @@ -557,7 +654,18 @@ struct IRFunc : IRGlobalValueWithCode } }; -// A module is a parent to functions, global variables, types, etc. +// The IR module itself is represented as an instruction, which +// serves at the root of the tree of all instructions in the module. +struct IRModuleInst : IRParentInst +{ + // Pointer back to the non-instruction object that represents + // the module, so that we can get back to it in algorithms + // that need it. + IRModule* module; + + IRInstListBase getGlobalInsts() { return getChildren(); } +}; + struct IRModule : RefObject { // The compilation session in use. @@ -565,13 +673,10 @@ struct IRModule : RefObject MemoryPool memoryPool; List<IRObject*> irObjectsToFree; // list of ir objects to run destructor upon destruction - // A list of all the functions and other - // global values declared in this module. - IRGlobalValue* firstGlobalValue = nullptr; - IRGlobalValue* lastGlobalValue = nullptr; + IRModuleInst* moduleInst; + IRModuleInst* getModuleInst() { return moduleInst; } - IRGlobalValue* getFirstGlobalValue() { return firstGlobalValue; } - IRGlobalValue* getlastGlobalValue() { return lastGlobalValue; } + IRInstListBase getGlobalInsts() { return getModuleInst()->getChildren(); } ~IRModule() { diff --git a/source/slang/legalize-types.h b/source/slang/legalize-types.h index 0799e804d..8958c683d 100644 --- a/source/slang/legalize-types.h +++ b/source/slang/legalize-types.h @@ -278,9 +278,9 @@ struct LegalVal Flavor flavor = Flavor::none; RefPtr<RefObject> obj; - IRValue* irValue = nullptr; + IRInst* irValue = nullptr; - static LegalVal simple(IRValue* irValue) + static LegalVal simple(IRInst* irValue) { LegalVal result; result.flavor = Flavor::simple; @@ -288,7 +288,7 @@ struct LegalVal return result; } - IRValue* getSimple() + IRInst* getSimple() { assert(flavor == Flavor::simple); return irValue; diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index fde52d2e3..9508bb86d 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -82,7 +82,7 @@ struct BoundSubscriptInfo : ExtendedValueInfo { DeclRef<SubscriptDecl> declRef; RefPtr<Type> type; - List<IRValue*> args; + List<IRInst*> args; }; // Some cases of `ExtendedValueInfo` need to @@ -129,7 +129,7 @@ struct LoweredValInfo union { - IRValue* val; + IRInst* val; ExtendedValueInfo* ext; }; Flavor flavor; @@ -140,7 +140,7 @@ struct LoweredValInfo val = nullptr; } - static LoweredValInfo simple(IRValue* v) + static LoweredValInfo simple(IRInst* v) { LoweredValInfo info; info.flavor = Flavor::Simple; @@ -148,7 +148,7 @@ struct LoweredValInfo return info; } - static LoweredValInfo ptr(IRValue* v) + static LoweredValInfo ptr(IRInst* v) { LoweredValInfo info; info.flavor = Flavor::Ptr; @@ -334,7 +334,7 @@ LoweredValInfo maybeEmitSpecializeInst(IRGenContext* context, ); -IRValue* getSimpleVal(IRGenContext* context, LoweredValInfo lowered); +IRInst* getSimpleVal(IRGenContext* context, LoweredValInfo lowered); IROp getIntrinsicOp( Decl* decl, @@ -361,7 +361,7 @@ LoweredValInfo emitCallToVal( IRType* type, LoweredValInfo funcVal, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto builder = context->irBuilder; switch (funcVal.flavor) @@ -379,7 +379,7 @@ LoweredValInfo emitCompoundAssignOp( IRType* type, IROp op, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto builder = context->irBuilder; SLANG_UNREFERENCED_PARAMETER(argCount); @@ -389,7 +389,7 @@ LoweredValInfo emitCompoundAssignOp( auto leftVal = builder->emitLoad(leftPtr); - IRValue* innerArgs[] = { leftVal, rightVal }; + IRInst* innerArgs[] = { leftVal, rightVal }; auto innerOp = builder->emitIntrinsicInst(type, op, 2, innerArgs); builder->emitStore(leftPtr, innerOp); @@ -397,7 +397,7 @@ LoweredValInfo emitCompoundAssignOp( return LoweredValInfo::ptr(leftPtr); } -IRValue* getOneValOfType( +IRInst* getOneValOfType( IRGenContext* context, IRType* type) { @@ -429,7 +429,7 @@ LoweredValInfo emitPreOp( IRType* type, IROp op, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto builder = context->irBuilder; SLANG_UNREFERENCED_PARAMETER(argCount); @@ -438,9 +438,9 @@ LoweredValInfo emitPreOp( auto preVal = builder->emitLoad(argPtr); - IRValue* oneVal = getOneValOfType(context, type); + IRInst* oneVal = getOneValOfType(context, type); - IRValue* innerArgs[] = { preVal, oneVal }; + IRInst* innerArgs[] = { preVal, oneVal }; auto innerOp = builder->emitIntrinsicInst(type, op, 2, innerArgs); builder->emitStore(argPtr, innerOp); @@ -453,7 +453,7 @@ LoweredValInfo emitPostOp( IRType* type, IROp op, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto builder = context->irBuilder; SLANG_UNREFERENCED_PARAMETER(argCount); @@ -462,9 +462,9 @@ LoweredValInfo emitPostOp( auto preVal = builder->emitLoad(argPtr); - IRValue* oneVal = getOneValOfType(context, type); + IRInst* oneVal = getOneValOfType(context, type); - IRValue* innerArgs[] = { preVal, oneVal }; + IRInst* innerArgs[] = { preVal, oneVal }; auto innerOp = builder->emitIntrinsicInst(type, op, 2, innerArgs); builder->emitStore(argPtr, innerOp); @@ -472,7 +472,7 @@ LoweredValInfo emitPostOp( return LoweredValInfo::ptr(argPtr); } -IRValue* findWitnessTable( +IRInst* findWitnessTable( IRGenContext* context, DeclRef<Decl> declRef); @@ -494,7 +494,7 @@ LoweredValInfo emitWitnessTableRef( exprType = mbrExpr->BaseExpression->type; auto declRefType = exprType->GetCanonicalType()->AsDeclRefType(); SLANG_ASSERT(declRefType); - IRValue* witnessTableVal = nullptr; + IRInst* witnessTableVal = nullptr; DeclRef<Decl> srcDeclRef = declRefType->declRef; if (!declRefType->declRef.As<AssocTypeDecl>()) { @@ -579,7 +579,7 @@ LoweredValInfo emitCallToDeclRef( DeclRef<Decl> funcDeclRef, Expr* funcExpr, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto builder = context->irBuilder; @@ -743,7 +743,7 @@ LoweredValInfo emitCallToDeclRef( IRType* type, DeclRef<Decl> funcDeclRef, Expr* funcExpr, - List<IRValue*> const& args) + List<IRInst*> const& args) { return emitCallToDeclRef(context, type, funcDeclRef, funcExpr, args.Count(), args.Buffer()); } @@ -760,7 +760,7 @@ LoweredValInfo extractField( { default: { - IRValue* irBase = getSimpleVal(context, base); + IRInst* irBase = getSimpleVal(context, base); return LoweredValInfo::simple( builder->emitFieldExtract( fieldType, @@ -790,7 +790,7 @@ LoweredValInfo extractField( // We are "extracting" a field from an lvalue address, // which means we should just compute an lvalue // representing the field address. - IRValue* irBasePtr = base.val; + IRInst* irBasePtr = base.val; return LoweredValInfo::ptr( builder->emitFieldAddress( context->getSession()->getPtrType(fieldType), @@ -876,7 +876,7 @@ top: } -IRValue* getSimpleVal(IRGenContext* context, LoweredValInfo lowered) +IRInst* getSimpleVal(IRGenContext* context, LoweredValInfo lowered) { auto builder = context->irBuilder; @@ -944,7 +944,7 @@ LoweredValInfo lowerVal( IRGenContext* context, Val* val); -IRValue* lowerSimpleVal( +IRInst* lowerSimpleVal( IRGenContext* context, Val* val) { @@ -1061,7 +1061,7 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower return LoweredTypeInfo(type); } - void addGenericArgs(List<IRValue*>* ioArgs, DeclRefBase declRef) + void addGenericArgs(List<IRInst*>* ioArgs, DeclRefBase declRef) { auto subs = declRef.substitutions.genericSubstitutions; while(subs) @@ -1148,7 +1148,7 @@ LoweredValInfo createVar( void addArgs( IRGenContext* context, - List<IRValue*>* ioArgs, + List<IRInst*>* ioArgs, LoweredValInfo argInfo) { auto& args = *ioArgs; @@ -1262,7 +1262,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> // in order for a dereference to make senese, so we just // need to extract the value type from that pointer here. // - IRValue* loweredBaseVal = getSimpleVal(context, loweredBase); + IRInst* loweredBaseVal = getSimpleVal(context, loweredBase); RefPtr<Type> loweredBaseType = loweredBaseVal->getDataType(); if (loweredBaseType->As<PointerLikeType>() @@ -1296,7 +1296,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> { // Allocate a temporary of the given type RefPtr<Type> type = lowerSimpleType(context, expr->type); - List<IRValue*> args; + List<IRInst*> args; UInt argCount = expr->args.Count(); @@ -1417,7 +1417,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> // to the list of argument values for a call. void addDirectCallArgs( InvokeExpr* expr, - List<IRValue*>* ioArgs) + List<IRInst*>* ioArgs) { for( auto arg : expr->Arguments ) { @@ -1444,7 +1444,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> void addDirectCallArgs( InvokeExpr* expr, DeclRef<CallableDecl> funcDeclRef, - List<IRValue*>* ioArgs, + List<IRInst*>* ioArgs, List<OutArgumentFixup>* ioFixups) { UInt argCount = expr->Arguments.Count(); @@ -1530,7 +1530,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> void addDirectCallArgs( InvokeExpr* expr, DeclRef<Decl> funcDeclRef, - List<IRValue*>* ioArgs, + List<IRInst*>* ioArgs, List<OutArgumentFixup>* ioFixups) { if (auto callableDeclRef = funcDeclRef.As<CallableDecl>()) @@ -1546,7 +1546,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> void addFuncBaseArgs( LoweredValInfo funcVal, - List<IRValue*>* ioArgs) + List<IRInst*>* ioArgs) { switch (funcVal.flavor) { @@ -1651,7 +1651,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> // Along the way, we may end up collecting additional // arguments that will be part of the call. - List<IRValue*> irArgs; + List<IRInst*> irArgs; // We will also collect "fixup" actions that need // to be performed after teh call, in order to @@ -1715,7 +1715,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> LoweredValInfo subscriptValue( LoweredTypeInfo type, LoweredValInfo baseVal, - IRValue* indexVal) + IRInst* indexVal) { auto builder = getBuilder(); switch (baseVal.flavor) @@ -1823,7 +1823,7 @@ struct RValueExprLoweringVisitor : ExprLoweringVisitorBase<RValueExprLoweringVis auto irIntType = getIntType(context); UInt elementCount = (UInt)expr->elementCount; - IRValue* irElementIndices[4]; + IRInst* irElementIndices[4]; for (UInt ii = 0; ii < elementCount; ++ii) { irElementIndices[ii] = builder->getIntValue( @@ -1932,12 +1932,12 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> auto builder = getBuilder(); auto prevBlock = builder->curBlock; - auto parentFunc = prevBlock ? prevBlock->parentFunc : builder->curFunc; + auto parentFunc = prevBlock ? prevBlock->getParent() : builder->curFunc; // If the previous block doesn't already have // a terminator instruction, then be sure to // emit a branch to the new block. - if (prevBlock && !isTerminatorInst(prevBlock->lastInst)) + if (prevBlock && !prevBlock->getTerminator()) { builder->emitBranch(block); } @@ -2326,7 +2326,7 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> // The collected (value, label) pairs for // all the `case` statements. - List<IRValue*> cases; + List<IRInst*> cases; }; // We need a label to use for a `case` or `default` statement, @@ -2504,7 +2504,7 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> // that we can find it for nested statements. context->shared->breakLabels.Add(stmt, breakLabel); - builder->curFunc = initialBlock->parentFunc; + builder->curFunc = initialBlock->getParent(); builder->curBlock = nullptr; // Iterate over the body of the statement, looking @@ -2528,8 +2528,7 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> if(builder->curBlock != initialBlock) { // Is the block already terminated? - auto lastInst = builder->curBlock->lastInst; - if(!lastInst || !isTerminatorInst(lastInst)) + if(!builder->curBlock->getTerminator()) { // Not terminated, so add one. builder->emitBreak(breakLabel); @@ -2580,7 +2579,7 @@ static LoweredValInfo maybeMoveMutableTemp( default: { - IRValue* irVal = getSimpleVal(context, val); + IRInst* irVal = getSimpleVal(context, val); auto type = irVal->getDataType(); auto var = createVar(context, type); @@ -2656,8 +2655,8 @@ top: auto loweredBase = swizzleInfo->base; // Load from the base value: - IRValue* irLeftVal = getSimpleVal(context, loweredBase); - IRValue* irRightVal = getSimpleVal(context, right); + IRInst* irLeftVal = getSimpleVal(context, loweredBase); + IRInst* irRightVal = getSimpleVal(context, right); // Now apply the swizzle IRInst* irSwizzled = builder->emitSwizzleSet( @@ -2819,7 +2818,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> cpyTable->mangledName = cpyMangledName; context->irBuilder->createWitnessTableEntry(witnessTable, context->irBuilder->getDeclRefVal(subInheritanceDeclRef), cpyTable); - cpyTable->entries = witnessTable->entries; + + // HACK: we are re-using the entries in a pre-existing table here, + // which is not how things are supposed to work. + cpyTable->children = witnessTable->children; + witnessTablesDictionary.Add(cpyTable->mangledName, cpyTable); walkInheritanceHierarchyAndCreateWitnessTableCopies(witnessTable, subType, subInheritanceDeclRef.getDecl()); } @@ -2888,7 +2891,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> auto satisfyingMemberDeclRef = entry.Value; auto irRequirement = context->irBuilder->getDeclRefVal(requiredMemberDeclRef); - IRValue* irSatisfyingVal = nullptr; + IRInst* irSatisfyingVal = nullptr; if (satisfyingMemberDeclRef.As<GenericTypeConstraintDecl>()) irSatisfyingVal = context->irBuilder->getDeclRefVal(satisfyingMemberDeclRef); else @@ -3127,7 +3130,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> } // TODO: we currently store a Decl* in the witness table, which causes this function - // being invoked to translate the witness table entry into an IRValue. + // being invoked to translate the witness table entry into an IRInst. // We should really allow a witness table entry to represent a type and not having to // construct the type here. The current implementation will not work when the struct type // is defined in a generic parent (we lose the environmental substitutions). @@ -3787,7 +3790,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // We need to carefully add a terminator instruction to the end // of the body, in case the user didn't do so. - if (!isTerminatorInst(subContext->irBuilder->curBlock->lastInst)) + if (!subContext->irBuilder->curBlock->getTerminator()) { if (irResultType->Equals(context->getSession()->getVoidType())) { @@ -3940,11 +3943,11 @@ LoweredValInfo ensureDecl( return result; } -IRValue* findWitnessTable( +IRInst* findWitnessTable( IRGenContext* context, DeclRef<Decl> declRef) { - IRValue* irVal = getSimpleVal(context, emitDeclRef(context, declRef)); + IRInst* irVal = getSimpleVal(context, emitDeclRef(context, declRef)); if (!irVal) { SLANG_UNEXPECTED("expected a witness table"); @@ -3986,7 +3989,7 @@ RefPtr<Val> lowerSubstitutionArg( auto irWitnessTable = findWitnessTable(context, declaredSubtypeWitness->declRef); // We have an IR-level value, but we need to embed it into an AST-level - // type, so we will use a proxy `Val` that wraps up an `IRValue` as + // type, so we will use a proxy `Val` that wraps up an `IRInst` as // an AST-level value. // // TODO: This proxy value currently doesn't enter into use-def chaining, @@ -4174,47 +4177,6 @@ static void lowerEntryPointToIR( lowerType(context, arg); } -#if 0 -IRModule* lowerEntryPointToIR( - EntryPointRequest* entryPoint, - ProgramLayout* programLayout, - CodeGenTarget target) -{ - SharedIRGenContext sharedContextStorage; - SharedIRGenContext* sharedContext = &sharedContextStorage; - - sharedContext->entryPoint = entryPoint; - sharedContext->programLayout = programLayout; - sharedContext->target = target; - - IRGenContext contextStorage; - IRGenContext* context = &contextStorage; - - context->shared = sharedContext; - - SharedIRBuilder sharedBuilderStorage; - SharedIRBuilder* sharedBuilder = &sharedBuilderStorage; - sharedBuilder->module = nullptr; - sharedBuilder->session = entryPoint->compileRequest->mSession; - - IRBuilder builderStorage; - IRBuilder* builder = &builderStorage; - builder->shared = sharedBuilder; - - IRModule* module = builder->createModule(); - sharedBuilder->module = module; - - context->irBuilder = builder; - - auto entryPointLayout = findEntryPointLayout(sharedContext, entryPoint); - - lowerEntryPointToIR(context, entryPoint, entryPointLayout); - - return module; - -} -#endif - IRModule* generateIRForTranslationUnit( TranslationUnitRequest* translationUnit) { diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index 93979f473..1dd3b5ef5 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -77,83 +77,95 @@ <Item Name="[Val]">satisfyingVal</Item> </Expand> </Type> - <Type Name="Slang::IRValue"> + <Type Name="Slang::IRInst"> <DisplayString>{{{op}}}</DisplayString> <Expand> - <Item Name="[OpCode]">op</Item> - <Item Name="[Type]">type</Item> - <Item Name="[IRInst]">(Slang::IRInst*)this</Item> - <ExpandedItem Condition="op==kIROp_decl_ref">(Slang::IRDeclRef*)this</ExpandedItem> - <ExpandedItem Condition="op==kIROp_Func">(Slang::IRFunc*)this</ExpandedItem> - <ExpandedItem Condition="op==kIROp_Block">(Slang::IRBlock*)this</ExpandedItem> - <ExpandedItem Condition="op==kIROp_witness_table">(Slang::IRWitnessTable*)this</ExpandedItem> - <ExpandedItem Condition="op==kIROp_witness_table_entry">(Slang::IRWitnessTableEntry*)this</ExpandedItem> - <Item Name="====Uses====">"-------"</Item> - <LinkedListItems> - <HeadPointer>firstUse</HeadPointer> - <NextPointer>nextUse</NextPointer> - <ValueNode>user</ValueNode> - </LinkedListItems> - + <Item Name="[op]">op</Item> + <Item Name="[type]">type</Item> + <Synthetic Name="[operands]"> + <DisplayString>{{count = {operandCount}}}</DisplayString> + <Expand> + <Item Name="[count]">operandCount</Item> + <ArrayItems> + <Size>operandCount</Size> + <ValuePointer>(IRUse*)(this + 1)</ValuePointer> + </ArrayItems> + </Expand> + </Synthetic> + <Synthetic Name="[uses]"> + <Expand> + <LinkedListItems> + <HeadPointer>firstUse</HeadPointer> + <NextPointer>nextUse</NextPointer> + <ValueNode>user</ValueNode> + </LinkedListItems> + </Expand> + </Synthetic> </Expand> </Type> - <Type Name="Slang::IRUser"> + <Type Name="Slang::IRParentInst"> <DisplayString>{{{op}}}</DisplayString> <Expand> - <Item Name="[OpCode]">op</Item> - <Item Name="[ArgCount]">argCount</Item> - <ArrayItems> - <Size>argCount</Size> - <ValuePointer>(IRUse*)(this + 1)</ValuePointer> - </ArrayItems> - </Expand> - </Type> - <Type Name="Slang::IRBlock"> - <Expand> - <LinkedListItems> - <HeadPointer>firstInst</HeadPointer> - <NextPointer>(Slang::IRInst*)next</NextPointer> - <ValueNode>this</ValueNode> - </LinkedListItems> + <Item Name="[op]">op</Item> + <Item Name="[type]">type</Item> + <Synthetic Name="[children]"> + <Expand> + <LinkedListItems> + <HeadPointer>children.first</HeadPointer> + <NextPointer>next</NextPointer> + <ValueNode>this</ValueNode> + </LinkedListItems> + </Expand> + </Synthetic> + <Synthetic Name="[uses]"> + <Expand> + <LinkedListItems> + <HeadPointer>firstUse</HeadPointer> + <NextPointer>nextUse</NextPointer> + <ValueNode>user</ValueNode> + </LinkedListItems> + </Expand> + </Synthetic> </Expand> </Type> - <Type Name="Slang::IRFunc"> - <DisplayString>{{{mangledName}}}</DisplayString> + <Type Name="Slang::IRGlobalValue"> + <DisplayString>{{{op} "{mangledName}"}}</DisplayString> <Expand> - <Item Name="[Name]">mangledName</Item> - <Item Name="[ResultType]">(*(IRFuncType*)(type.pointer)).resultType</Item> - <Item Name="[ParameterTypes]">(*(IRFuncType*)(type.pointer)).paramTypes</Item> - <Item Name="[FirstBlock]">firstBlock</Item> - <Item Name="[SpecLevel]">specializedGenericLevel</Item> - <Item Name="genericDecls">genericDecls</Item> + <Item Name="[op]">op</Item> + <Item Name="[type]">type</Item> + <Synthetic Name="[children]"> + <Expand> + <LinkedListItems> + <HeadPointer>children.first</HeadPointer> + <NextPointer>next</NextPointer> + <ValueNode>this</ValueNode> + </LinkedListItems> + </Expand> + </Synthetic> + <Synthetic Name="[uses]"> + <Expand> + <LinkedListItems> + <HeadPointer>firstUse</HeadPointer> + <NextPointer>nextUse</NextPointer> + <ValueNode>user</ValueNode> + </LinkedListItems> + </Expand> + </Synthetic> </Expand> </Type> <Type Name="Slang::IRDeclRef"> <DisplayString>{{IRDeclRef {declRef}}}</DisplayString> <Expand> - <Item Name="[OpCode]">op</Item> + <Item Name="[op]">op</Item> + <Item Name="[type]">type</Item> <ExpandedItem>declRef</ExpandedItem> </Expand> </Type> <Type Name="Slang::IRUse"> <DisplayString>{{IRUse {usedValue}}}</DisplayString> <Expand> - <Item Name="[NextUse]">nextUse</Item> <ExpandedItem>usedValue</ExpandedItem> </Expand> </Type> - <Type Name="Slang::IRModule"> - <Expand> - <Item Name="session">session</Item> - <LinkedListItems> - <HeadPointer>firstGlobalValue</HeadPointer> - <NextPointer>nextGlobalValue</NextPointer> - <ValueNode>this</ValueNode> - </LinkedListItems> - </Expand> - </Type> - <Type Name="Slang::IRGlobalValue"> - <DisplayString>{{IRGlobalValue {op} {mangledName}}}</DisplayString> - </Type> </AutoVisualizer>
\ No newline at end of file diff --git a/source/slang/syntax.h b/source/slang/syntax.h index 32f57ce4c..0dbdd8238 100644 --- a/source/slang/syntax.h +++ b/source/slang/syntax.h @@ -12,7 +12,6 @@ namespace Slang { - struct IRValue; class Name; class Session; class Substitutions; |
