From 41dc26b9ef501e23563bdb0705ceecb15fd6c18d Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 1 Mar 2018 13:11:24 -0800 Subject: IR: "everything is an instruction" (#432) * IR: "everything is an instruction" This change tries to streamline the representation of the IR in the following ways: * Every IR value is an instruction (there is no `IRValue` type any more) * All IR values that can contain other values share a single base (`IRParentInstruction`) * Dynamic casts to specific IR instruction types can be accomplished with a new `as(inst)` operation, that uses the IR opcode to implement casts. The biggest change in terms of number of lines is getting rid of `IRValue`. The diff here could probably be smaller if I'd just done `typedef IRInst IRValue;`. Along the way I also renamed the `getArg`/`getArgs`/`getArgCount` combination over to `getOperand`/`getOperands`/`getOperandCount` to avoid being confusing when we have something like a `call` instruction where the "arguments" of the call don't line up with the operands of the instruction. I also tried to clean up the representation of lists of child instructions to try to make it easier to iterate over them with C++ range-based `for` loops. Developers still need to be careful about mutating the contents of a block while iterating over it in this fashion (e.g. if you remove the "current" element, the iteration will end prematurely). Probably the thorniest change here is that parameters are now just represented as the first N instructions in a block, which means: * We need to perform a linear search to find the end of the parameter list. This is probably not often a problem, because usually you would be iterating over the parameters anyway, and that will be linear in the number of parameters. * Algorithms that iterate over a block either need to ignore parameters, treat parameters just like other instructions, or somehow cleave the list into the range of parameters, and the range of "ordinary" instructions (which involves the same linear search above). * When inserting into a block, we need to be careful not to insert instructions at invalid locations (e.g., insert a temporary before the parameters, or insert a parameter in the middle of the code). I can't pretend that I've handled the details of that here. (This is no different than having to make the same adjustments for phi nodes in a typical SSA representation) * One possible future-proof approach is to implement a pass that sorts the instructions in a block so that parameters always come first. That would let us implement passes without caring about this detail, and then clean up right before any pass that cares about the relative order of parameters and other instructions. The current change is missing any work to make literals and other instructions that used to be `IRValue`s properly nest inside of their parent module. Right now these instructions are just left unparented, and may actually end up being shared between distinct modules. Fixing that will need a follow-up change. The biggest challenge there is that it introduces instructions at the global scope that aren't `IRGlobalValue`s. This change doesn't try to take advantage of any of the new flexibility (e.g., by nesting `specialize` instructions inside of witness tables). The goal is to do exactly what we were doing before, just with a different representation. * Warning fix --- source/slang/bytecode.cpp | 101 ++-- source/slang/emit.cpp | 190 +++--- source/slang/ir-constexpr.cpp | 63 +- source/slang/ir-inst-defs.h | 54 +- source/slang/ir-insts.h | 174 +++--- source/slang/ir-legalize-types.cpp | 152 ++--- source/slang/ir-ssa.cpp | 58 +- source/slang/ir.cpp | 1152 +++++++++++++++--------------------- source/slang/ir.h | 463 +++++++++------ source/slang/legalize-types.h | 6 +- source/slang/lower-to-ir.cpp | 144 ++--- source/slang/slang.natvis | 122 ++-- source/slang/syntax.h | 1 - 13 files changed, 1292 insertions(+), 1388 deletions(-) (limited to 'source/slang') 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 mapValueToGlobal; + Dictionary mapValueToGlobal; // Types that have been emitted List> bcTypes; @@ -111,7 +111,7 @@ struct SharedBytecodeGenerationContext // Compile-time constant values that need // to be emitted... - List constants; + List constants; }; struct BytecodeGenerationContext @@ -131,7 +131,7 @@ struct BytecodeGenerationContext // Map an instruction to its ID for use local // to the current context - Dictionary mapInstToLocalID; + Dictionary mapInstToLocalID; }; template @@ -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 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 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 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 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 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(ii); + if (!gv) + continue; + Int globalID = Int(symbolCount++); // Ensure that local code inside functions can see these symbols @@ -986,8 +975,12 @@ BytecodeGenerationPtr 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(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 mapIRValueToID; + Dictionary mapIRValueToID; Dictionary mapDeclToID; HashSet 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()) { 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(); 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(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(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(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 + INST(unconditionalBranch, unconditionalBranch, 1, 0) -// unconditionalBranch -INST(unconditionalBranch, unconditionalBranch, 1, 0) + // loop + INST(loop, loop, 3, 0) -// loop -INST(loop, loop, 3, 0) + // conditionalBranch + INST(conditionalBranch, conditionalBranch, 3, 0) -// conditionalBranch -INST(conditionalBranch, conditionalBranch, 3, 0) + // ifElse + INST(ifElse, ifElse, 4, 0) -// ifElse -INST(ifElse, ifElse, 4, 0) + // switch ... + INST(switch, switch, 3, 0) -// switch ... -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 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 getEntries() + { + return IRInstList(getChildren()); + } + RefPtr genericDecl; DeclRef subTypeDeclRef, supTypeDeclRef; - IRValueList 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 specDeclRef); - IRValue* emitLookupInterfaceMethodInst( + IRInst* emitLookupInterfaceMethodInst( IRType* type, - IRValue* witnessTableVal, - IRValue* interfaceMethodVal); + IRInst* witnessTableVal, + IRInst* interfaceMethodVal); - IRValue* emitLookupInterfaceMethodInst( + IRInst* emitLookupInterfaceMethodInst( IRType* type, DeclRef witnessTableDeclRef, DeclRef interfaceMethodDeclRef); - IRValue* emitLookupInterfaceMethodInst( + IRInst* emitLookupInterfaceMethodInst( IRType* type, - IRValue* witnessTableVal, + IRInst* witnessTableVal, DeclRef interfaceMethodDeclRef); - IRValue* emitFindWitnessTable( + IRInst* emitFindWitnessTable( DeclRef 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 - 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 - T* addDecoration(IRValue* value) + T* addDecoration(IRInst* value) { return addDecoration(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 mapValToLegalVal; + Dictionary 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 oldLocalVars; + List replacedInstructions; }; static void registerLegalizedValue( IRTypeLegalizationContext* context, - IRValue* irValue, + IRInst* irValue, LegalVal const& legalVal) { context->mapValToLegalVal.Add(irValue, legalVal); @@ -165,7 +166,7 @@ static RefPtr 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 & instArgs, + List & 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 instArgs; - for (auto i = 1u; i < callInst->argCount; i++) - getArgumentValues(instArgs, legalizeOperand(context, callInst->getArg(i))); + List 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 findVarLayout(IRValue* value) +RefPtr findVarLayout(IRInst* value) { if (auto layoutDecoration = value->findDecoration()) return layoutDecoration->layout.As(); @@ -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(inst)); + + case kIROp_Param: + return legalizeParam(context, cast(inst)); + + default: + break; + } // Need to legalize all the operands. - auto argCount = inst->getArgCount(); + auto argCount = inst->getOperandCount(); List 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(inst->getParent()); builder->insertBeforeInst = inst->getNextInst(); LegalVal legalVal = legalizeInst( @@ -795,47 +835,15 @@ static void legalizeFunc( addParamType(newFuncType, legalParamType); } irFunc->type = newFuncType; - List paramVals; - List 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(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 valueForVar; + Dictionary 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 successorArgs; + List 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 operandValues; + List 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 newArgs; + List 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(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(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 - begin = args + 0; + begin = operands + 0; end = begin + 1; break; case kIROp_conditionalBranch: case kIROp_ifElse: // conditionalBranch - begin = args + 1; + begin = operands + 1; end = begin + 2; break; case kIROp_switch: // switch ... - 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 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 + 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( + builder->getModule(), + builder, + size, + op, + type, + fixedArgCount, + fixedArgs, + varArgCount, + varArgs); + } + template static T* createInst( IRBuilder* builder, IROp op, IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { return createInstImpl( builder, @@ -647,7 +596,7 @@ namespace Slang IRBuilder* builder, IROp op, IRType* type, - IRValue* arg) + IRInst* arg) { return createInstImpl( 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( builder, sizeof(T), @@ -682,7 +631,7 @@ namespace Slang IROp op, IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { return createInstImpl( 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( 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( @@ -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( + auto irValue = createValue( 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( this, @@ -920,9 +869,9 @@ namespace Slang return inst; } - IRValue* IRBuilder::emitSpecializeInst( + IRInst* IRBuilder::emitSpecializeInst( Type* type, - IRValue* genericVal, + IRInst* genericVal, DeclRef 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( this, @@ -951,7 +900,7 @@ namespace Slang return inst; } - IRValue* IRBuilder::emitLookupInterfaceMethodInst( + IRInst* IRBuilder::emitLookupInterfaceMethodInst( IRType* type, DeclRef witnessTableDeclRef, DeclRef 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 interfaceMethodDeclRef) { DeclRef removeSubstDeclRef = interfaceMethodDeclRef; @@ -974,7 +923,7 @@ namespace Slang return emitLookupInterfaceMethodInst(type, witnessTableVal, interfaceMethodVal); } - IRValue* IRBuilder::emitFindWitnessTable( + IRInst* IRBuilder::emitFindWitnessTable( DeclRef 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( this, @@ -1012,7 +961,7 @@ namespace Slang IRType* type, IROp op, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto inst = createInstWithTrailingArgs( this, @@ -1027,7 +976,7 @@ namespace Slang IRInst* IRBuilder::emitConstructorInst( IRType* type, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto inst = createInstWithTrailingArgs( 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( + 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( 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( 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( 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( 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( this, @@ -1458,8 +1287,8 @@ namespace Slang IRInst* IRBuilder::emitElementAddress( IRType* type, - IRValue* basePtr, - IRValue* index) + IRInst* basePtr, + IRInst* index) { auto inst = createInst( 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( 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( @@ -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( 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( @@ -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( @@ -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( @@ -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( @@ -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(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(inst); decoration->layout = layout; @@ -1732,7 +1561,7 @@ namespace Slang int indent = 0; UInt idCounter = 1; - Dictionary mapValueToID; + Dictionary 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(inst)) { dump(context, "(\n"); context->indent += 2; - for (auto pp = block->getFirstParam(); pp; pp = pp->getNextParam()) + + for(;;) { - if (pp != block->getFirstParam()) + auto param = as(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, ""); - 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(); - 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, ""); + 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(); + 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()) return rateQualifiedType->rate; @@ -2603,7 +2311,7 @@ namespace Slang return nullptr; } - Type* IRValue::getDataType() + Type* IRInst::getDataType() { if(auto rateQualifiedType = type->As()) 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)(); @@ -2694,61 +2396,147 @@ namespace Slang // Insert this instruction into the same basic block // 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 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 arrayElementVals; + List 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 elementVals; + List 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 ClonedValueDictionary; + typedef Dictionary 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()); @@ -4437,9 +4223,9 @@ namespace Slang } } - IRValue* cloneValue( + IRInst* cloneValue( IRSpecContextBase* context, - IRValue* originalValue); + IRInst* originalValue); RefPtr 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(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( 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(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 maybeCloneType(Type* originalType) override; virtual RefPtr 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 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(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(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 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(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 witnessTables; - for (auto gv = module->getFirstGlobalValue(); - gv; - gv = gv->getNextValue()) + for(auto ii : module->getGlobalInsts()) { + auto gv = as(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(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 @@ -55,6 +53,13 @@ enum IROp : int16_t #define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) /* empty */ #define PSEUDO_INST(ID) kIRPseudoOp_##ID, +#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; + // 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* 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 +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 -struct IRValueList : IRValueListBase +T* cast(IRInst* inst, T* /* */ = nullptr) { - T* getFirst() { return (T*)first; } - T* getLast() { return (T*)last; } + SLANG_ASSERT(!inst || as(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 +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(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(getPrevInst()); } + IRBlock* getNextBlock() { return cast(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(getFirstInst()); } + IRParam* getLastParam(); + IRInstList getParams() + { + return IRInstList( + 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(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(getFirstChild()); } + IRBlock* getLastBlock() { return cast(getLastChild()); } + IRInstList getBlocks() + { + return IRInstList(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 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 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 declRef; RefPtr type; - List args; + List 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 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 srcDeclRef = declRefType->declRef; if (!declRefType->declRef.As()) { @@ -579,7 +579,7 @@ LoweredValInfo emitCallToDeclRef( DeclRef funcDeclRef, Expr* funcExpr, UInt argCount, - IRValue* const* args) + IRInst* const* args) { auto builder = context->irBuilder; @@ -743,7 +743,7 @@ LoweredValInfo emitCallToDeclRef( IRType* type, DeclRef funcDeclRef, Expr* funcExpr, - List const& args) + List 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* ioArgs, DeclRefBase declRef) + void addGenericArgs(List* ioArgs, DeclRefBase declRef) { auto subs = declRef.substitutions.genericSubstitutions; while(subs) @@ -1148,7 +1148,7 @@ LoweredValInfo createVar( void addArgs( IRGenContext* context, - List* ioArgs, + List* ioArgs, LoweredValInfo argInfo) { auto& args = *ioArgs; @@ -1262,7 +1262,7 @@ struct ExprLoweringVisitorBase : ExprVisitor // 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 loweredBaseType = loweredBaseVal->getDataType(); if (loweredBaseType->As() @@ -1296,7 +1296,7 @@ struct ExprLoweringVisitorBase : ExprVisitor { // Allocate a temporary of the given type RefPtr type = lowerSimpleType(context, expr->type); - List args; + List args; UInt argCount = expr->args.Count(); @@ -1417,7 +1417,7 @@ struct ExprLoweringVisitorBase : ExprVisitor // to the list of argument values for a call. void addDirectCallArgs( InvokeExpr* expr, - List* ioArgs) + List* ioArgs) { for( auto arg : expr->Arguments ) { @@ -1444,7 +1444,7 @@ struct ExprLoweringVisitorBase : ExprVisitor void addDirectCallArgs( InvokeExpr* expr, DeclRef funcDeclRef, - List* ioArgs, + List* ioArgs, List* ioFixups) { UInt argCount = expr->Arguments.Count(); @@ -1530,7 +1530,7 @@ struct ExprLoweringVisitorBase : ExprVisitor void addDirectCallArgs( InvokeExpr* expr, DeclRef funcDeclRef, - List* ioArgs, + List* ioArgs, List* ioFixups) { if (auto callableDeclRef = funcDeclRef.As()) @@ -1546,7 +1546,7 @@ struct ExprLoweringVisitorBase : ExprVisitor void addFuncBaseArgs( LoweredValInfo funcVal, - List* ioArgs) + List* ioArgs) { switch (funcVal.flavor) { @@ -1651,7 +1651,7 @@ struct ExprLoweringVisitorBase : ExprVisitor // Along the way, we may end up collecting additional // arguments that will be part of the call. - List irArgs; + List 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 LoweredValInfo subscriptValue( LoweredTypeInfo type, LoweredValInfo baseVal, - IRValue* indexVal) + IRInst* indexVal) { auto builder = getBuilder(); switch (baseVal.flavor) @@ -1823,7 +1823,7 @@ struct RValueExprLoweringVisitor : ExprLoweringVisitorBaseelementCount; - IRValue* irElementIndices[4]; + IRInst* irElementIndices[4]; for (UInt ii = 0; ii < elementCount; ++ii) { irElementIndices[ii] = builder->getIntValue( @@ -1932,12 +1932,12 @@ struct StmtLoweringVisitor : StmtVisitor 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 // The collected (value, label) pairs for // all the `case` statements. - List cases; + List cases; }; // We need a label to use for a `case` or `default` statement, @@ -2504,7 +2504,7 @@ struct StmtLoweringVisitor : StmtVisitor // 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 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 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 auto satisfyingMemberDeclRef = entry.Value; auto irRequirement = context->irBuilder->getDeclRefVal(requiredMemberDeclRef); - IRValue* irSatisfyingVal = nullptr; + IRInst* irSatisfyingVal = nullptr; if (satisfyingMemberDeclRef.As()) irSatisfyingVal = context->irBuilder->getDeclRefVal(satisfyingMemberDeclRef); else @@ -3127,7 +3130,7 @@ struct DeclLoweringVisitor : DeclVisitor } // 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 // 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 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 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 @@ satisfyingVal - + {{{op}}} - op - type - (Slang::IRInst*)this - (Slang::IRDeclRef*)this - (Slang::IRFunc*)this - (Slang::IRBlock*)this - (Slang::IRWitnessTable*)this - (Slang::IRWitnessTableEntry*)this - "-------" - - firstUse - nextUse - user - - + op + type + + {{count = {operandCount}}} + + operandCount + + operandCount + (IRUse*)(this + 1) + + + + + + + firstUse + nextUse + user + + + - + {{{op}}} - op - argCount - - argCount - (IRUse*)(this + 1) - - - - - - - firstInst - (Slang::IRInst*)next - this - + op + type + + + + children.first + next + this + + + + + + + firstUse + nextUse + user + + + - - {{{mangledName}}} + + {{{op} "{mangledName}"}} - mangledName - (*(IRFuncType*)(type.pointer)).resultType - (*(IRFuncType*)(type.pointer)).paramTypes - firstBlock - specializedGenericLevel - genericDecls + op + type + + + + children.first + next + this + + + + + + + firstUse + nextUse + user + + + {{IRDeclRef {declRef}}} - op + op + type declRef {{IRUse {usedValue}}} - nextUse usedValue - - - session - - firstGlobalValue - nextGlobalValue - this - - - - - {{IRGlobalValue {op} {mangledName}}} - \ 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; -- cgit v1.2.3