public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode) { // Compute local register inputs and outputs used inside blocks. RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count]; for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { for (Operation node = block.Operations.First; node != default; node = node.ListNext) { for (int index = 0; index < node.SourcesCount; index++) { Operand source = node.GetSource(index); if (source.Kind == OperandKind.Register) { Register register = source.GetRegister(); localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index]; } } if (node.Destination != default && node.Destination.Kind == OperandKind.Register) { localOutputs[block.Index] |= GetMask(node.Destination.GetRegister()); } } } // Compute global register inputs and outputs used across blocks. RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] globalInputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count]; bool modified; bool firstPass = true; do { modified = false; // Compute register outputs. for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) { BasicBlock block = cfg.PostOrderBlocks[index]; if (block.Predecessors.Count != 0 && !HasContextLoad(block)) { BasicBlock predecessor = block.Predecessors[0]; RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index]; RegisterMask outputs = globalOutputs[predecessor.Index]; for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++) { predecessor = block.Predecessors[pIndex]; cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index]; outputs |= globalOutputs[predecessor.Index]; } globalInputs[block.Index] |= outputs & ~cmnOutputs; if (!firstPass) { cmnOutputs &= globalCmnOutputs[block.Index]; } modified |= Exchange(globalCmnOutputs, block.Index, cmnOutputs); outputs |= localOutputs[block.Index]; modified |= Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs); } else { modified |= Exchange(globalOutputs, block.Index, localOutputs[block.Index]); } } // Compute register inputs. for (int index = 0; index < cfg.PostOrderBlocks.Length; index++) { BasicBlock block = cfg.PostOrderBlocks[index]; RegisterMask inputs = localInputs[block.Index]; for (int i = 0; i < block.SuccessorsCount; i++) { inputs |= globalInputs[block.GetSuccessor(i).Index]; } inputs &= ~globalCmnOutputs[block.Index]; modified |= Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs); } firstPass = false; }while (modified); // Insert load and store context instructions where needed. for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { bool hasContextLoad = HasContextLoad(block); if (hasContextLoad) { block.Operations.Remove(block.Operations.First); } Operand arg = default; // The only block without any predecessor should be the entry block. // It always needs a context load as it is the first block to run. if (block.Predecessors.Count == 0 || hasContextLoad) { long vecMask = globalInputs[block.Index].VecMask; long intMask = globalInputs[block.Index].IntMask; if (vecMask != 0 || intMask != 0) { arg = Local(OperandType.I64); Operation loadArg = block.Operations.AddFirst(Operation(Instruction.LoadArgument, arg, Const(0))); LoadLocals(block, vecMask, RegisterType.Vector, mode, loadArg, arg); LoadLocals(block, intMask, RegisterType.Integer, mode, loadArg, arg); } } bool hasContextStore = HasContextStore(block); if (hasContextStore) { block.Operations.Remove(block.Operations.Last); } if (EndsWithReturn(block) || hasContextStore) { long vecMask = globalOutputs[block.Index].VecMask; long intMask = globalOutputs[block.Index].IntMask; if (vecMask != 0 || intMask != 0) { if (arg == default) { arg = Local(OperandType.I64); block.Append(Operation(Instruction.LoadArgument, arg, Const(0))); } StoreLocals(block, intMask, RegisterType.Integer, mode, arg); StoreLocals(block, vecMask, RegisterType.Vector, mode, arg); } } } }
public static void Construct(ControlFlowGraph cfg) { var globalDefs = new DefMap[cfg.Blocks.Count]; var localDefs = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount]; var dfPhiBlocks = new Queue <BasicBlock>(); for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { globalDefs[block.Index] = new DefMap(); } // First pass, get all defs and locals uses. for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { for (Operation node = block.Operations.First; node != default; node = node.ListNext) { for (int index = 0; index < node.SourcesCount; index++) { Operand src = node.GetSource(index); if (TryGetId(src, out int srcKey)) { Operand local = localDefs[srcKey]; if (local == default) { local = src; } node.SetSource(index, local); } } Operand dest = node.Destination; if (TryGetId(dest, out int destKey)) { Operand local = Local(dest.Type); localDefs[destKey] = local; node.Destination = local; } } for (int key = 0; key < localDefs.Length; key++) { Operand local = localDefs[key]; if (local == default) { continue; } globalDefs[block.Index].TryAddOperand(key, local); dfPhiBlocks.Enqueue(block); while (dfPhiBlocks.TryDequeue(out BasicBlock dfPhiBlock)) { foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers) { if (globalDefs[domFrontier.Index].AddPhi(key)) { dfPhiBlocks.Enqueue(domFrontier); } } } } Array.Clear(localDefs, 0, localDefs.Length); } // Second pass, rename variables with definitions on different blocks. for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { for (Operation node = block.Operations.First; node != default; node = node.ListNext) { for (int index = 0; index < node.SourcesCount; index++) { Operand src = node.GetSource(index); if (TryGetId(src, out int key)) { Operand local = localDefs[key]; if (local == default) { local = FindDef(globalDefs, block, src); localDefs[key] = local; } node.SetSource(index, local); } } } Array.Clear(localDefs, 0, localDefs.Length); } }
public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode) { // Compute local register inputs and outputs used inside blocks. RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count]; for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { for (Node node = block.Operations.First; node != null; node = node.ListNext) { Operation operation = node as Operation; for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++) { Operand source = operation.GetSource(srcIndex); if (source.Kind != OperandKind.Register) { continue; } Register register = source.GetRegister(); localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index]; } if (operation.Destination != null && operation.Destination.Kind == OperandKind.Register) { localOutputs[block.Index] |= GetMask(operation.Destination.GetRegister()); } } } // Compute global register inputs and outputs used across blocks. RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] globalInputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count]; bool modified; bool firstPass = true; do { modified = false; // Compute register outputs. for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) { BasicBlock block = cfg.PostOrderBlocks[index]; if (block.Predecessors.Count != 0 && !HasContextLoad(block)) { BasicBlock predecessor = block.Predecessors[0]; RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index]; RegisterMask outputs = globalOutputs[predecessor.Index]; for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++) { predecessor = block.Predecessors[pIndex]; cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index]; outputs |= globalOutputs[predecessor.Index]; } globalInputs[block.Index] |= outputs & ~cmnOutputs; if (!firstPass) { cmnOutputs &= globalCmnOutputs[block.Index]; } if (Exchange(globalCmnOutputs, block.Index, cmnOutputs)) { modified = true; } outputs |= localOutputs[block.Index]; if (Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs)) { modified = true; } } else if (Exchange(globalOutputs, block.Index, localOutputs[block.Index])) { modified = true; } } // Compute register inputs. for (int index = 0; index < cfg.PostOrderBlocks.Length; index++) { BasicBlock block = cfg.PostOrderBlocks[index]; RegisterMask inputs = localInputs[block.Index]; for (int i = 0; i < block.SuccessorCount; i++) { inputs |= globalInputs[block.GetSuccessor(i).Index]; } inputs &= ~globalCmnOutputs[block.Index]; if (Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs)) { modified = true; } } firstPass = false; }while (modified); // Insert load and store context instructions where needed. for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { bool hasContextLoad = HasContextLoad(block); if (hasContextLoad) { block.Operations.Remove(block.Operations.First); } // The only block without any predecessor should be the entry block. // It always needs a context load as it is the first block to run. if (block.Predecessors.Count == 0 || hasContextLoad) { LoadLocals(block, globalInputs[block.Index].VecMask, RegisterType.Vector, mode); LoadLocals(block, globalInputs[block.Index].IntMask, RegisterType.Integer, mode); } bool hasContextStore = HasContextStore(block); if (hasContextStore) { block.Operations.Remove(block.Operations.Last); } if (EndsWithReturn(block) || hasContextStore) { StoreLocals(block, globalOutputs[block.Index].IntMask, RegisterType.Integer, mode); StoreLocals(block, globalOutputs[block.Index].VecMask, RegisterType.Vector, mode); } } }
public static void Construct(ControlFlowGraph cfg) { DefMap[] globalDefs = new DefMap[cfg.Blocks.Count]; for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { globalDefs[block.Index] = new DefMap(); } Queue <BasicBlock> dfPhiBlocks = new Queue <BasicBlock>(); // First pass, get all defs and locals uses. for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; Node node = block.Operations.First; Operand RenameLocal(Operand operand) { if (operand != null && operand.Kind == OperandKind.Register) { Operand local = localDefs[GetIdFromRegister(operand.GetRegister())]; operand = local ?? operand; } return(operand); } while (node != null) { if (node is Operation operation) { for (int index = 0; index < operation.SourcesCount; index++) { operation.SetSource(index, RenameLocal(operation.GetSource(index))); } Operand dest = operation.Destination; if (dest != null && dest.Kind == OperandKind.Register) { Operand local = Local(dest.Type); localDefs[GetIdFromRegister(dest.GetRegister())] = local; operation.Destination = local; } } node = node.ListNext; } for (int index = 0; index < RegisterConsts.TotalCount; index++) { Operand local = localDefs[index]; if (local == null) { continue; } Register reg = GetRegisterFromId(index); globalDefs[block.Index].TryAddOperand(reg, local); dfPhiBlocks.Enqueue(block); while (dfPhiBlocks.TryDequeue(out BasicBlock dfPhiBlock)) { foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers) { if (globalDefs[domFrontier.Index].AddPhi(reg)) { dfPhiBlocks.Enqueue(domFrontier); } } } } } // Second pass, rename variables with definitions on different blocks. for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; Node node = block.Operations.First; Operand RenameGlobal(Operand operand) { if (operand != null && operand.Kind == OperandKind.Register) { int key = GetIdFromRegister(operand.GetRegister()); Operand local = localDefs[key]; if (local == null) { local = FindDef(globalDefs, block, operand); localDefs[key] = local; } operand = local; } return(operand); } while (node != null) { if (node is Operation operation) { for (int index = 0; index < operation.SourcesCount; index++) { operation.SetSource(index, RenameGlobal(operation.GetSource(index))); } } node = node.ListNext; } } }