#include "slang-ir-lower-expand-type.h" #include "slang-ir-clone.h" #include "slang-ir-insts.h" #include "slang-ir-util.h" namespace Slang { IRInst* clonePatternVal(IRCloneEnv& cloneEnv, IRBuilder* builder, IRInst* val, IRInst* eachIndex); IRInst* clonePatternValImpl( IRCloneEnv& cloneEnv, IRBuilder* builder, IRInst* val, IRInst* eachIndex) { if (!val) return val; switch (val->getOp()) { case kIROp_ExpandTypeOrVal: return val; case kIROp_Each: { auto eachInst = as(val); auto packInst = eachInst->getElement(); auto type = (IRType*)clonePatternVal(cloneEnv, builder, packInst->getFullType(), eachIndex); packInst = clonePatternValImpl(cloneEnv, builder, packInst, eachIndex); auto result = builder->emitGetTupleElement(type, packInst, eachIndex); return result; } case kIROp_Specialize: case kIROp_LookupWitnessMethod: case kIROp_ExtractExistentialType: case kIROp_ExtractExistentialWitnessTable: break; default: // If the value is not a type, and it is not in a block, then it is some global inst // that shouldn't be deep copied into current block, such as a IRFunc. if (!as(val) && getBlock(val->getParent()) == nullptr) return val; break; } bool anyChange = false; ShortList operands; for (UInt i = 0; i < val->getOperandCount(); i++) { auto newOperand = clonePatternVal(cloneEnv, builder, val->getOperand(i), eachIndex); if (newOperand != val->getOperand(i)) anyChange = true; operands.add(newOperand); } auto newType = clonePatternVal(cloneEnv, builder, val->getFullType(), eachIndex); 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, builder->getModule(), val, newVal); } return newVal; } IRInst* clonePatternVal(IRCloneEnv& cloneEnv, IRBuilder* builder, IRInst* val, IRInst* eachIndex) { if (auto clonedVal = cloneEnv.mapOldValToNew.tryGetValue(val)) return *clonedVal; cloneEnv.mapOldValToNew[val] = val; auto result = clonePatternValImpl(cloneEnv, builder, val, eachIndex); cloneEnv.mapOldValToNew[val] = result; return result; } // Translate a `IRExpandType` into an `IRExpand` where the `PatternType` is defined // inside the `IRExpand` body. // IRInst* lowerExpandTypeImpl(IRExpandTypeOrVal* expandType) { // Turn `IRExpandType` into an `IRExpand` instruction. IRBuilder builder(expandType); builder.setInsertBefore(expandType); List capturedArgs; IRCloneEnv cloneEnv; for (UInt i = 0; i < expandType->getCaptureCount(); i++) { auto capturedArg = expandType->getCaptureType(i); capturedArgs.add(capturedArg); } auto result = builder.emitExpandInst( expandType->getFullType(), expandType->getCaptureCount(), capturedArgs.getBuffer()); builder.setInsertInto(result); builder.emitBlock(); auto eachIndex = builder.emitParam(builder.getIntType()); auto newPatternType = clonePatternVal(cloneEnv, &builder, expandType->getPatternType(), eachIndex); builder.emitYield(newPatternType); return result; } // Process the body of an `IRExpand` instruction, and replace the type of children insts if it // is an `IRExpandType`. // void processExpandVal(IRExpand* expandVal) { IRBuilder builder(expandVal); IRCloneEnv cloneEnv; auto eachIndex = expandVal->getFirstBlock()->getFirstParam(); for (auto block : expandVal->getBlocks()) { for (auto inst : block->getModifiableChildren()) { builder.setInsertBefore(inst); auto newType = clonePatternVal(cloneEnv, &builder, inst->getFullType(), eachIndex); if (newType != inst->getFullType()) { inst = builder.replaceOperand(&inst->typeUse, newType); } for (UInt i = 0; i < inst->getOperandCount(); i++) { auto oldOperand = inst->getOperand(i); if (!oldOperand) continue; if (isChildInstOf(oldOperand, expandVal)) continue; auto newOperand = clonePatternVal(cloneEnv, &builder, oldOperand, eachIndex); if (newOperand != inst->getOperand(i)) { inst = builder.replaceOperand(inst->getOperands() + i, newOperand); } } } } } void lowerExpandType(IRModule* module) { // Use a work list to process all instructions in the module, and lower any `IRExpandType` we // see along the way. List workList; for (auto type : module->getGlobalInsts()) { workList.add(type); } while (workList.getCount() != 0) { auto inst = workList.getLast(); workList.removeLast(); if (auto expandType = as(inst)) { inst = lowerExpandTypeImpl(expandType); if (inst != expandType) { expandType->replaceUsesWith(inst); expandType->removeAndDeallocate(); } } else if (auto expandVal = as(inst)) { processExpandVal(expandVal); } for (auto child : inst->getChildren()) { workList.add(child); } } } } // namespace Slang