diff options
Diffstat (limited to 'source/slang/slang-ir.cpp')
| -rw-r--r-- | source/slang/slang-ir.cpp | 359 |
1 files changed, 160 insertions, 199 deletions
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 81b554c3b..27eb1adfb 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -702,12 +702,8 @@ namespace Slang auto irModule = func->getModule(); SLANG_ASSERT(irModule); - SharedIRBuilder sharedBuilder; - sharedBuilder.module = irModule; - - IRBuilder builder; - builder.sharedBuilder = &sharedBuilder; - + SharedIRBuilder sharedBuilder(irModule); + IRBuilder builder(sharedBuilder); builder.setInsertBefore(func); List<IRType*> paramTypes; @@ -1121,16 +1117,33 @@ namespace Slang // - IRBlock* IRBuilder::getBlock() + IRInst* IRInsertLoc::getParent() const + { + auto inst = getInst(); + switch(getMode()) + { + default: + case Mode::None: + return nullptr; + case Mode::Before: + case Mode::After: + return inst->getParent(); + case Mode::AtStart: + case Mode::AtEnd: + return inst; + } + } + + IRBlock* IRInsertLoc::getBlock() const { - return as<IRBlock>(insertIntoParent); + return as<IRBlock>(getParent()); } // Get the current function (or other value with code) // that we are inserting into (if any). - IRGlobalValueWithCode* IRBuilder::getFunc() + IRGlobalValueWithCode* IRInsertLoc::getFunc() const { - auto pp = insertIntoParent; + auto pp = getParent(); if (auto block = as<IRBlock>(pp)) { pp = pp->getParent(); @@ -1138,37 +1151,11 @@ namespace Slang return as<IRGlobalValueWithCode>(pp); } - - void IRBuilder::setInsertInto(IRInst* insertInto) - { - insertIntoParent = insertInto; - insertBeforeInst = nullptr; - } - - void IRBuilder::setInsertBefore(IRInst* insertBefore) - { - SLANG_ASSERT(insertBefore); - insertIntoParent = insertBefore->parent; - insertBeforeInst = insertBefore; - } - - // Add an instruction into the current scope void IRBuilder::addInst( IRInst* inst) { - if(insertBeforeInst) - { - inst->insertBefore(insertBeforeInst); - } - else if (insertIntoParent) - { - inst->insertAtEnd(insertIntoParent); - } - else - { - // Don't append the instruction anywhere - } + inst->insertAt(m_insertLoc); } // Given two parent instructions, pick the better one to use as as @@ -1313,33 +1300,34 @@ namespace Slang return parent; } - IRInst* createEmptyInst( - IRModule* module, - IROp op, - int totalArgCount) + IRInst* IRModule::_allocateInst( + IROp op, + Int operandCount, + size_t minSizeInBytes) { - size_t size = sizeof(IRInst) + (totalArgCount) * sizeof(IRUse); - - SLANG_ASSERT(module); - IRInst* inst = (IRInst*)module->memoryArena.allocateAndZero(size); - - inst->operandCount = uint32_t(totalArgCount); - inst->m_op = op; - - return inst; - } + // There are two basic cases for instructions that affect how we compute size: + // + // * The default case is that an instruction's state is fully defined by the fields + // in the `IRInst` base type, along with the trailing operand list (a tail-allocated + // array of `IRUse`s. Almost all instructions need space allocated this way. + // + // * A small number of cases (currently `IRConstant`s and the `IRModule` type) have + // *zero* operands but include additional state beyond the fields in `IRInst`. + // For these cases we want to ensure that at least `sizeof(T)` bytes are allocated, + // based on the specific leaf type `T`. + // + // We handle the combination of the two cases by just taking the maximum of the two + // different sizes. + // + size_t defaultSize = sizeof(IRInst) + (operandCount) * sizeof(IRUse); + size_t totalSize = minSizeInBytes > defaultSize ? minSizeInBytes : defaultSize; - IRInst* createEmptyInstWithSize( - IRModule* module, - IROp op, - size_t totalSizeInBytes) - { - SLANG_ASSERT(totalSizeInBytes >= sizeof(IRInst)); + IRInst* inst = (IRInst*) m_memoryArena.allocateAndZero(totalSize); - SLANG_ASSERT(module); - IRInst* inst = (IRInst*)module->memoryArena.allocateAndZero(totalSizeInBytes); + // TODO: Is it actually important to run a constructor here? + new(inst) IRInst(); - inst->operandCount = 0; + inst->operandCount = uint32_t(operandCount); inst->m_op = op; return inst; @@ -1561,14 +1549,10 @@ namespace Slang } } - static void maybeSetSourceLoc( - IRBuilder* builder, - IRInst* value) + void IRBuilder::_maybeSetSourceLoc( + IRInst* inst) { - if(!builder) - return; - - auto sourceLocInfo = builder->sourceLocInfo; + auto sourceLocInfo = getSourceLocInfo(); if(!sourceLocInfo) return; @@ -1584,7 +1568,7 @@ namespace Slang sourceLocInfo = sourceLocInfo->next; } - value->sourceLoc = sourceLocInfo->sourceLoc; + inst->sourceLoc = sourceLocInfo->sourceLoc; } #if SLANG_ENABLE_IR_BREAK_ALLOC @@ -1606,56 +1590,39 @@ namespace Slang } #endif - // Create an IR instruction/value and initialize it. - // - // In this case `argCount` and `args` represent the - // arguments *after* the type (which is a mandatory - // argument for all instructions). - template<typename T> - static T* createInstImpl( - IRModule* module, - IRBuilder* builder, - IROp op, - IRType* type, - UInt fixedArgCount, - IRInst* const* fixedArgs, - UInt varArgListCount, - UInt const* listArgCounts, + IRInst* IRBuilder::_createInst( + size_t minSizeInBytes, + IRType* type, + IROp op, + Int fixedArgCount, + IRInst* const* fixedArgs, + Int varArgListCount, + Int const* listArgCounts, IRInst* const* const* listArgs) { - UInt varArgCount = 0; - for (UInt ii = 0; ii < varArgListCount; ++ii) + Int varArgCount = 0; + for (Int ii = 0; ii < varArgListCount; ++ii) { varArgCount += listArgCounts[ii]; } - UInt size = sizeof(IRInst) + (fixedArgCount + varArgCount) * sizeof(IRUse); - if (sizeof(T) > size) - { - size = sizeof(T); - } + Int totalOperandCount = fixedArgCount + varArgCount; + auto module = getModule(); SLANG_ASSERT(module); - T* inst = (T*)module->memoryArena.allocateAndZero(size); - - // TODO: Do we need to run ctor after zeroing? - new(inst)T(); + IRInst* inst = module->_allocateInst(op, totalOperandCount, minSizeInBytes); #if SLANG_ENABLE_IR_BREAK_ALLOC inst->_debugUID = _debugGetAndIncreaseInstCounter(); #endif - inst->operandCount = (uint32_t)(fixedArgCount + varArgCount); - - inst->m_op = op; - inst->typeUse.init(inst, type); - maybeSetSourceLoc(builder, inst); + _maybeSetSourceLoc(inst); auto operand = inst->getOperands(); - for( UInt aa = 0; aa < fixedArgCount; ++aa ) + for( Int aa = 0; aa < fixedArgCount; ++aa ) { if (fixedArgs) { @@ -1668,10 +1635,10 @@ namespace Slang operand++; } - for (UInt ii = 0; ii < varArgListCount; ++ii) + for (Int ii = 0; ii < varArgListCount; ++ii) { - UInt listArgCount = listArgCounts[ii]; - for (UInt jj = 0; jj < listArgCount; ++jj) + Int listArgCount = listArgCounts[ii]; + for (Int jj = 0; jj < listArgCount; ++jj) { if (listArgs[ii]) { @@ -1687,52 +1654,31 @@ namespace Slang return inst; } - static IRInst* createInstWithSizeImpl( - IRBuilder* builder, - IROp op, - IRType* type, - size_t sizeInBytes) - { - auto module = builder->getModule(); - IRInst* inst = (IRInst*)module->memoryArena.allocate(sizeInBytes); - // Zero only the 'type' - memset(inst, 0, sizeof(IRInst)); - // TODO: Do we need to run ctor after zeroing? - new (inst) IRInst; - -#if SLANG_ENABLE_IR_BREAK_ALLOC - inst->_debugUID = _debugGetAndIncreaseInstCounter(); -#endif - - inst->m_op = op; - if (type) - { - inst->typeUse.init(inst, type); - } - maybeSetSourceLoc(builder, inst); - return inst; - } - + // Create an IR instruction/value and initialize it. + // + // In this case `argCount` and `args` represent the + // arguments *after* the type (which is a mandatory + // argument for all instructions). template<typename T> static T* createInstImpl( - IRBuilder* builder, - IROp op, - IRType* type, - UInt fixedArgCount, - IRInst* const* fixedArgs, - UInt varArgCount = 0, - IRInst* const* varArgs = nullptr) + IRBuilder* builder, + IROp op, + IRType* type, + Int fixedArgCount, + IRInst* const* fixedArgs, + Int varArgListCount, + Int const* listArgCounts, + IRInst* const* const* listArgs) { - return createInstImpl<T>( - builder->getModule(), - builder, - op, + return (T*) builder->_createInst( + sizeof(T), type, + op, fixedArgCount, fixedArgs, - 1, - &varArgCount, - &varArgs); + varArgListCount, + listArgCounts, + listArgs); } template<typename T> @@ -1740,22 +1686,20 @@ namespace Slang IRBuilder* builder, IROp op, IRType* type, - UInt fixedArgCount, + Int fixedArgCount, IRInst* const* fixedArgs, - UInt varArgListCount, - UInt const* listArgCount, - IRInst* const* const* listArgs) + Int varArgCount = 0, + IRInst* const* varArgs = nullptr) { return createInstImpl<T>( - builder->getModule(), builder, op, type, fixedArgCount, fixedArgs, - varArgListCount, - listArgCount, - listArgs); + 1, + &varArgCount, + &varArgs); } template<typename T> @@ -1763,8 +1707,8 @@ namespace Slang IRBuilder* builder, IROp op, IRType* type, - UInt argCount, - IRInst* const* args) + Int argCount, + IRInst* const* args) { return createInstImpl<T>( builder, @@ -1825,8 +1769,8 @@ namespace Slang IRBuilder* builder, IROp op, IRType* type, - UInt argCount, - IRInst* const* args) + Int argCount, + IRInst* const* args) { return createInstImpl<T>( builder, @@ -1841,9 +1785,9 @@ namespace Slang IRBuilder* builder, IROp op, IRType* type, - UInt fixedArgCount, + Int fixedArgCount, IRInst* const* fixedArgs, - UInt varArgCount, + Int varArgCount, IRInst* const* varArgs) { return createInstImpl<T>( @@ -1862,7 +1806,7 @@ namespace Slang IROp op, IRType* type, IRInst* arg1, - UInt varArgCount, + Int varArgCount, IRInst* const* varArgs) { IRInst* fixedArgs[] = { arg1 }; @@ -2038,8 +1982,7 @@ namespace Slang } } - static IRConstant* findOrEmitConstant( - IRBuilder* builder, + IRConstant* IRBuilder::_findOrEmitConstant( IRConstant& keyInst) { // We now know where we want to insert, but there might @@ -2054,7 +1997,7 @@ namespace Slang key.inst = &keyInst; IRConstant* irValue = nullptr; - if( builder->sharedBuilder->constantMap.TryGetValue(key, irValue) ) + if( getSharedBuilder()->getConstantMap().TryGetValue(key, irValue) ) { // We found a match, so just use that. return irValue; @@ -2072,19 +2015,22 @@ namespace Slang case kIROp_BoolLit: case kIROp_IntLit: { - irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.getOp(), keyInst.getFullType(), prefixSize + sizeof(IRIntegerValue))); + const size_t instSize = prefixSize + sizeof(IRIntegerValue); + irValue = static_cast<IRConstant*>(_createInst(instSize, keyInst.getFullType(), keyInst.getOp())); irValue->value.intVal = keyInst.value.intVal; break; } case kIROp_FloatLit: { - irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.getOp(), keyInst.getFullType(), prefixSize + sizeof(IRFloatingPointValue))); + const size_t instSize = prefixSize + sizeof(IRFloatingPointValue); + irValue = static_cast<IRConstant*>(_createInst(instSize, keyInst.getFullType(), keyInst.getOp())); irValue->value.floatVal = keyInst.value.floatVal; break; } case kIROp_PtrLit: { - irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.getOp(), keyInst.getFullType(), prefixSize + sizeof(void*))); + const size_t instSize = prefixSize + sizeof(void*); + irValue = static_cast<IRConstant*>(_createInst(instSize, keyInst.getFullType(), keyInst.getOp())); irValue->value.ptrVal = keyInst.value.ptrVal; break; } @@ -2095,7 +2041,7 @@ namespace Slang const size_t sliceSize = slice.getLength(); const size_t instSize = prefixSize + offsetof(IRConstant::StringValue, chars) + sliceSize; - irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.getOp(), keyInst.getFullType(), instSize)); + irValue = static_cast<IRConstant*>(_createInst(instSize, keyInst.getFullType(), keyInst.getOp())); IRConstant::StringValue& dstString = irValue->value.stringVal; @@ -2110,9 +2056,9 @@ namespace Slang } key.inst = irValue; - builder->sharedBuilder->constantMap.Add(key, irValue); + getSharedBuilder()->getConstantMap().Add(key, irValue); - addHoistableInst(builder, irValue); + addHoistableInst(this, irValue); return irValue; } @@ -2126,7 +2072,7 @@ namespace Slang keyInst.m_op = kIROp_BoolLit; keyInst.typeUse.usedValue = getBoolType(); keyInst.value.intVal = IRIntegerValue(inValue); - return findOrEmitConstant(this, keyInst); + return _findOrEmitConstant(keyInst); } IRInst* IRBuilder::getIntValue(IRType* type, IRIntegerValue inValue) @@ -2136,7 +2082,7 @@ namespace Slang keyInst.m_op = kIROp_IntLit; keyInst.typeUse.usedValue = type; keyInst.value.intVal = inValue; - return findOrEmitConstant(this, keyInst); + return _findOrEmitConstant(keyInst); } IRInst* IRBuilder::getFloatValue(IRType* type, IRFloatingPointValue inValue) @@ -2146,7 +2092,7 @@ namespace Slang keyInst.m_op = kIROp_FloatLit; keyInst.typeUse.usedValue = type; keyInst.value.floatVal = inValue; - return findOrEmitConstant(this, keyInst); + return _findOrEmitConstant(keyInst); } IRStringLit* IRBuilder::getStringValue(const UnownedStringSlice& inSlice) @@ -2167,7 +2113,7 @@ namespace Slang dstSlice.chars = const_cast<char*>(inSlice.begin()); dstSlice.numChars = uint32_t(inSlice.getLength()); - return static_cast<IRStringLit*>(findOrEmitConstant(this, keyInst)); + return static_cast<IRStringLit*>(_findOrEmitConstant(keyInst)); } IRPtrLit* IRBuilder::getPtrValue(void* value) @@ -2179,7 +2125,7 @@ namespace Slang keyInst.m_op = kIROp_PtrLit; keyInst.typeUse.usedValue = type; keyInst.value.ptrVal = value; - return (IRPtrLit*) findOrEmitConstant(this, keyInst); + return (IRPtrLit*) _findOrEmitConstant(keyInst); } IRInst* IRBuilder::getCapabilityValue(CapabilitySet const& caps) @@ -2226,7 +2172,7 @@ namespace Slang operandCount += listOperandCounts[ii]; } - auto& memoryArena = getModule()->memoryArena; + auto& memoryArena = getModule()->getMemoryArena(); void* cursor = memoryArena.getCursor(); // We are going to create a 'dummy' instruction on the memoryArena @@ -2266,7 +2212,7 @@ namespace Slang IRInstKey key = { inst }; // Ideally we would add if not found, else return if was found instead of testing & then adding. - IRInst** found = sharedBuilder->globalValueNumberingMap.TryGetValueOrAdd(key, inst); + IRInst** found = getSharedBuilder()->getGlobalValueNumberingMap().TryGetValueOrAdd(key, inst); SLANG_ASSERT(endCursor == memoryArena.getCursor()); // If it's found, just return, and throw away the instruction if (found) @@ -2285,7 +2231,7 @@ namespace Slang inst->typeUse.init(inst, type); } - maybeSetSourceLoc(this, inst); + _maybeSetSourceLoc(inst); IRUse*const operands = inst->getOperands(); for (UInt i = 0; i < operandCount; ++i) @@ -2316,7 +2262,7 @@ namespace Slang operandCount += listOperandCounts[ii]; } - auto& memoryArena = getModule()->memoryArena; + auto& memoryArena = getModule()->getMemoryArena(); void* cursor = memoryArena.getCursor(); // We are going to create a 'dummy' instruction on the memoryArena @@ -2356,7 +2302,7 @@ namespace Slang IRInstKey key = { inst }; // Ideally we would add if not found, else return if was found instead of testing & then adding. - IRInst** found = sharedBuilder->globalValueNumberingMap.TryGetValueOrAdd(key, inst); + IRInst** found = getSharedBuilder()->getGlobalValueNumberingMap().TryGetValueOrAdd(key, inst); SLANG_ASSERT(endCursor == memoryArena.getCursor()); // If it's found, just return, and throw away the instruction if (found) @@ -2375,7 +2321,7 @@ namespace Slang inst->typeUse.init(inst, type); } - maybeSetSourceLoc(this, inst); + _maybeSetSourceLoc(inst); IRUse*const operands = inst->getOperands(); for (UInt i = 0; i < operandCount; ++i) @@ -3216,22 +3162,13 @@ namespace Slang return inst; } - IRModule* IRBuilder::createModule() + RefPtr<IRModule> IRModule::create(Session* session) { - auto module = new IRModule(); - module->session = getSession(); + RefPtr<IRModule> module = new IRModule(session); - auto moduleInst = createInstImpl<IRModuleInst>( - module, - this, - kIROp_Module, - nullptr, - 0, - nullptr, - 0, - nullptr, - nullptr); - module->moduleInst = moduleInst; + auto moduleInst = module->_allocateInst<IRModuleInst>(kIROp_Module, 0); + + module->m_moduleInst = moduleInst; moduleInst->module = module; return module; @@ -3248,7 +3185,9 @@ namespace Slang // parent instruction for the builder, and // possibly work our way up. // - auto parent = builder->insertIntoParent; + auto defaultInsertLoc = builder->getInsertLoc(); + auto defaultParent = defaultInsertLoc.getParent(); + auto parent = defaultParent; while(parent) { // Inserting into the top level of a module? @@ -3281,10 +3220,9 @@ namespace Slang // current "insert into" parent for the builder, then // we need to respect its "insert before" setting // as well. - if (parent == builder->insertIntoParent - && builder->insertBeforeInst) + if (parent == defaultParent) { - value->insertBefore(builder->insertBeforeInst); + value->insertAt(defaultInsertLoc); } else { @@ -3298,7 +3236,7 @@ namespace Slang this, kIROp_Func, nullptr); - maybeSetSourceLoc(this, rsFunc); + _maybeSetSourceLoc(rsFunc); addGlobalValue(this, rsFunc); return rsFunc; } @@ -3311,7 +3249,7 @@ namespace Slang this, kIROp_GlobalVar, ptrType); - maybeSetSourceLoc(this, globalVar); + _maybeSetSourceLoc(globalVar); addGlobalValue(this, globalVar); return globalVar; } @@ -3323,7 +3261,7 @@ namespace Slang this, kIROp_GlobalParam, valueType); - maybeSetSourceLoc(this, inst); + _maybeSetSourceLoc(inst); addGlobalValue(this, inst); return inst; } @@ -5581,6 +5519,29 @@ namespace Slang insertAtEnd(p); } + void IRInst::insertAt(IRInsertLoc const& loc) + { + removeFromParent(); + IRInst* other = loc.getInst(); + switch(loc.getMode()) + { + case IRInsertLoc::Mode::None: + break; + case IRInsertLoc::Mode::Before: + insertBefore(other); + break; + case IRInsertLoc::Mode::After: + insertAfter(other); + break; + case IRInsertLoc::Mode::AtStart: + insertAtStart(other); + break; + case IRInsertLoc::Mode::AtEnd: + insertAtEnd(other); + break; + } + } + // Remove this instruction from its parent block, // and then destroy it (it had better have no uses!) void IRInst::removeFromParent() |
