summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-ir-specialize.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-ir-specialize.cpp')
-rw-r--r--source/slang/slang-ir-specialize.cpp255
1 files changed, 253 insertions, 2 deletions
diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp
index c86906b2d..2eb16112f 100644
--- a/source/slang/slang-ir-specialize.cpp
+++ b/source/slang/slang-ir-specialize.cpp
@@ -1,6 +1,6 @@
// slang-ir-specialize.cpp
#include "slang-ir-specialize.h"
-
+#include "slang-ir-peephole.h"
#include "slang-ir.h"
#include "slang-ir-clone.h"
#include "slang-ir-insts.h"
@@ -585,6 +585,15 @@ struct SpecializationContext
case kIROp_BindExistentialsType:
return maybeSpecializeBindExistentialsType(as<IRBindExistentialsType>(inst));
+
+ case kIROp_Expand:
+ return maybeSpecializeExpand(as<IRExpand>(inst));
+
+ case kIROp_ExpandTypeOrVal:
+ return maybeSpecializeExpandTypeOrVal(as<IRExpandType>(inst));
+
+ case kIROp_GetTupleElement:
+ return maybeSpecializeFoldableInst(inst);
}
}
@@ -597,7 +606,7 @@ struct SpecializationContext
{
// Note: While we currently have named the instruction
// `lookup_witness_method`, the `method` part is a misnomer
- // and the same instruction can look up *any* interface
+ // and the same instruction can look up *any* interfacemay
// requirement based on the witness table that provides
// a conformance, and the "key" that indicates the interface
// requirement.
@@ -609,7 +618,9 @@ struct SpecializationContext
//
auto witnessTable = as<IRWitnessTable>(lookupInst->getWitnessTable());
if (!witnessTable)
+ {
return false;
+ }
// Because we have a concrete witness table, we can
// use it to look up the IR value that satisfies
@@ -642,6 +653,19 @@ struct SpecializationContext
return true;
}
+ bool maybeSpecializeFoldableInst(IRInst* inst)
+ {
+ auto firstUse = inst->firstUse;
+ bool instChanged = peepholeOptimizeInst(targetProgram, module, inst);
+
+ for (auto use = firstUse; use; use = use->nextUse)
+ {
+ auto user = use->getUser();
+ addToWorkList(user);
+ }
+ return instChanged;
+ }
+
// The above subroutine needed a way to look up
// the satisfying value for a given requirement
// key in a concrete witness table, so let's
@@ -2208,6 +2232,233 @@ struct SpecializationContext
return false;
}
+ IRInst* specializeExpandChildInst(IRCloneEnv& cloneEnv, IRBuilder* builder, IRInst* childInst, UInt index)
+ {
+ IRCloneEnv freshEnv;
+ IRCloneEnv* subEnv = &cloneEnv;
+ switch (childInst->getOp())
+ {
+ case kIROp_Expand:
+ {
+ subEnv = &freshEnv;
+ break;
+ }
+ }
+ auto type = clonePatternVal(*subEnv, builder, childInst->getFullType(), index);
+ for (UInt i = 0; i < childInst->getOperandCount(); i++)
+ {
+ clonePatternVal(*subEnv, builder, childInst->getOperand(i), index);
+ }
+ auto newInst = cloneInst(subEnv, builder, childInst);
+ newInst = builder->replaceOperand(&newInst->typeUse, type);
+ subEnv->mapOldValToNew[childInst] = newInst;
+ IRBuilder subBuilder(*builder);
+ subBuilder.setInsertInto(newInst);
+ for (auto child : childInst->getChildren())
+ {
+ specializeExpandChildInst(*subEnv, &subBuilder, child, index);
+ }
+ return newInst;
+ }
+
+ bool maybeSpecializeExpand(IRExpand* expandInst)
+ {
+ if (expandInst->getCaptureCount() == 0)
+ return false;
+
+ for (UInt i = 0; i < expandInst->getCaptureCount(); i++)
+ {
+ if (!as<IRTupleType>(expandInst->getCapture(i)))
+ return false;
+ }
+
+ IRBuilder builder(expandInst);
+ builder.setInsertBefore(expandInst);
+ List<IRInst*> elements;
+ UInt elementCount = 0;
+ if (auto firstTupleType = as<IRTupleType>(expandInst->getCapture(0)))
+ {
+ elementCount = firstTupleType->getOperandCount();
+ }
+ if (elementCount == 0)
+ {
+ auto resultTuple = builder.emitMakeTuple(0, (IRInst*const*)nullptr);
+ expandInst->replaceUsesWith(resultTuple);
+ expandInst->removeAndDeallocate();
+ addUsersToWorkList(resultTuple);
+ return true;
+ }
+
+ for (UInt i = 0; i < elementCount; i++)
+ {
+ IRCloneEnv cloneEnv;
+ IRBlock* firstBlock = nullptr;
+ IRBuilder subBuilder = builder;
+ for (auto childBlock : expandInst->getBlocks())
+ {
+ auto newBlock = subBuilder.emitBlock();
+ if (!firstBlock)
+ firstBlock = newBlock;
+ cloneEnv.mapOldValToNew[childBlock] = newBlock;
+ }
+ auto indexParam = expandInst->getFirstBlock()->getFirstParam();
+ SLANG_ASSERT(indexParam);
+ cloneEnv.mapOldValToNew[indexParam] = subBuilder.getIntValue(subBuilder.getIntType(), i);
+
+ builder.emitBranch(firstBlock);
+
+ IRBlock* mergeBlock = subBuilder.emitBlock();
+ builder.setInsertInto(mergeBlock);
+
+ for (auto childBlock : expandInst->getBlocks())
+ {
+ auto newBlock = cloneEnv.mapOldValToNew[childBlock];
+ subBuilder.setInsertInto(newBlock);
+ for (auto child : childBlock->getChildren())
+ {
+ if (as<IRYield>(child))
+ {
+ elements.add(cloneEnv.mapOldValToNew[child->getOperand(0)]);
+ subBuilder.emitBranch(mergeBlock);
+ continue;
+ }
+ specializeExpandChildInst(cloneEnv, &subBuilder, child, i);
+ addToWorkList(childBlock);
+ }
+ }
+
+ }
+ auto resultTuple = builder.emitMakeTuple(elements);
+ auto currentBlock = builder.getBlock();
+ for (auto nextInst = expandInst->next; nextInst;)
+ {
+ auto next = nextInst->next;
+ nextInst->insertAtEnd(currentBlock);
+ nextInst = next;
+ }
+ addUsersToWorkList(expandInst);
+ expandInst->replaceUsesWith(resultTuple);
+ expandInst->removeAndDeallocate();
+ return true;
+ }
+
+ IRInst* clonePatternValImpl(IRCloneEnv& cloneEnv, IRBuilder* builder, IRInst* val, UInt indexInPack)
+ {
+ if (!val)
+ return val;
+
+ switch (val->getOp())
+ {
+ case kIROp_ExpandTypeOrVal:
+ return val;
+ case kIROp_Each:
+ {
+ auto eachInst = as<IREach>(val);
+ auto packInst = eachInst->getElement();
+ if (auto tuple = as<IRTupleType>(packInst))
+ {
+ SLANG_RELEASE_ASSERT(indexInPack < tuple->getOperandCount());
+ return tuple->getOperand(indexInPack);
+ }
+ else if (auto makeTuple = as<IRMakeTuple>(packInst))
+ {
+ SLANG_RELEASE_ASSERT(indexInPack < makeTuple->getOperandCount());
+ return makeTuple->getOperand(indexInPack);
+ }
+ else if (!as<IRTypeKind>(packInst->getDataType()))
+ {
+ auto type = clonePatternVal(cloneEnv, builder, val, indexInPack);
+ return builder->emitGetTupleElement((IRType*)type, packInst, indexInPack);
+ }
+ return val;
+ }
+ default:
+ break;
+ }
+ bool anyChange = false;
+ ShortList<IRInst*> operands;
+ for (UInt i = 0; i < val->getOperandCount(); i++)
+ {
+ auto newOperand = clonePatternVal(cloneEnv, builder, val->getOperand(i), indexInPack);
+ if (newOperand != val->getOperand(i))
+ anyChange = true;
+ operands.add(newOperand);
+ }
+ auto newType = clonePatternVal(cloneEnv, builder, val->getFullType(), indexInPack);
+ if (newType != val->getFullType())
+ anyChange = true;
+ if (!anyChange)
+ return val;
+
+ auto newVal = builder->emitIntrinsicInst((IRType*)newType, val->getOp(), operands.getCount(), operands.getArrayView().getBuffer());
+ if (newVal != val)
+ {
+ cloneInstDecorationsAndChildren(&cloneEnv, module, val, newVal);
+ }
+ return newVal;
+ }
+
+ IRInst* clonePatternVal(IRCloneEnv& cloneEnv, IRBuilder* builder, IRInst* val, UInt indexInPack)
+ {
+ if (auto clonedVal = cloneEnv.mapOldValToNew.tryGetValue(val))
+ return *clonedVal;
+ cloneEnv.mapOldValToNew[val] = val;
+ auto result = clonePatternValImpl(cloneEnv, builder, val, indexInPack);
+ cloneEnv.mapOldValToNew[val] = result;
+ return result;
+ }
+
+ bool maybeSpecializeExpandTypeOrVal(IRExpandType* expandInst)
+ {
+ if (expandInst->getCaptureCount() == 0)
+ return false;
+
+ bool anyAbstractPack = false;
+ for (UInt i = 0; i < expandInst->getCaptureCount(); i++)
+ {
+ if (!as<IRTupleType>(expandInst->getCaptureType(i)))
+ {
+ anyAbstractPack = true;
+ break;
+ }
+ }
+ if (anyAbstractPack)
+ return false;
+ IRBuilder builder(expandInst);
+ builder.setInsertBefore(expandInst);
+ List<IRInst*> elements;
+ UInt elementCount = 0;
+ if (auto firstTupleType = as<IRTupleType>(expandInst->getCaptureType(0)))
+ {
+ elementCount = firstTupleType->getOperandCount();
+ }
+ for (UInt i = 0; i < elementCount; i++)
+ {
+ IRCloneEnv cloneEnv;
+ auto element = clonePatternVal(cloneEnv, &builder, expandInst->getPatternType(), i);
+ elements.add(element);
+ }
+ addUsersToWorkList(expandInst);
+ if (as<IRWitnessTableType>(expandInst->getDataType()))
+ {
+ List<IRType*> types;
+ for (auto element : elements)
+ types.add(element->getDataType());
+ auto newTupleType = builder.getTupleType(types);
+ auto result = builder.emitMakeWitnessPack(newTupleType, elements.getArrayView());
+ expandInst->replaceUsesWith(result);
+ expandInst->removeAndDeallocate();
+ return true;
+ }
+ else
+ {
+ auto newTupleType = builder.getTupleType(elements.getCount(), (IRType*const*)elements.getBuffer());
+ expandInst->replaceUsesWith(newTupleType);
+ expandInst->removeAndDeallocate();
+ return true;
+ }
+ }
+
// The handling of specialization for global generic type
// parameters involves searching for all `bind_global_generic_param`
// instructions in the input module.