private static void StoreLocals(BasicBlock block, long outputs, RegisterType baseType, ExecutionMode mode) { Operand arg0 = Local(OperandType.I64); Operation loadArg0 = Operation(Instruction.LoadArgument, arg0, Const(0)); block.Append(loadArg0); for (int bit = 0; bit < 64; bit++) { long mask = 1L << bit; if ((outputs & mask) == 0) { continue; } Operand source = GetRegFromBit(bit, baseType, mode); long offset = NativeContext.GetRegisterOffset(source.GetRegister()); Operand addr = Local(OperandType.I64); Operation calcOffsOp = Operation(Instruction.Add, addr, arg0, Const(offset)); block.Append(calcOffsOp); Operation storeOp = Operation(Instruction.Store, null, addr, source); block.Append(storeOp); } }
public static void Deconstruct(ControlFlowGraph cfg) { foreach (BasicBlock block in cfg.Blocks) { LinkedListNode <Node> node = block.Operations.First; while (node?.Value is PhiNode phi) { LinkedListNode <Node> nextNode = node.Next; Operand local = Local(phi.Destination.Type); for (int index = 0; index < phi.SourcesCount; index++) { BasicBlock predecessor = phi.GetBlock(index); Operand source = phi.GetSource(index); predecessor.Append(new Operation(Instruction.Copy, local, source)); phi.SetSource(index, null); } Operation copyOp = new Operation(Instruction.Copy, phi.Destination, local); block.Operations.AddBefore(node, copyOp); phi.Destination = null; block.Operations.Remove(node); node = nextNode; } } }
private static void StoreLocals(BasicBlock block, long outputs, RegisterType baseType, bool isCompleteFunction) { if (Optimizations.AssumeStrictAbiCompliance && isCompleteFunction) { if (baseType == RegisterType.Integer || baseType == RegisterType.Flag) { outputs = ClearCallerSavedIntRegs(outputs); } else /* if (baseType == RegisterType.Vector) */ { outputs = ClearCallerSavedVecRegs(outputs); } } Operand arg0 = Local(OperandType.I64); Operation loadArg0 = new Operation(Instruction.LoadArgument, arg0, Const(0)); block.Append(loadArg0); for (int bit = 0; bit < 64; bit++) { long mask = 1L << bit; if ((outputs & mask) == 0) { continue; } Operand source = GetRegFromBit(bit, baseType); long offset = NativeContext.GetRegisterOffset(source.GetRegister()); Operand addr = Local(OperandType.I64); Operation calcOffsOp = new Operation(Instruction.Add, addr, arg0, Const(offset)); block.Append(calcOffsOp); Operation storeOp = new Operation(Instruction.Store, null, addr, source); block.Append(storeOp); } }
public static void Deconstruct(ControlFlowGraph cfg) { for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { Operation operation = block.Operations.First; while (operation != default && operation.Instruction == Instruction.Phi) { Operation nextNode = operation.ListNext; Operand local = Local(operation.Destination.Type); PhiOperation phi = operation.AsPhi(); for (int index = 0; index < phi.SourcesCount; index++) { BasicBlock predecessor = phi.GetBlock(cfg, index); Operand source = phi.GetSource(index); predecessor.Append(Operation(Instruction.Copy, local, source)); phi.SetSource(index, default); } Operation copyOp = Operation(Instruction.Copy, operation.Destination, local); block.Operations.AddBefore(operation, copyOp); operation.Destination = default; block.Operations.Remove(operation); operation = nextNode; } } }
public static void Remove(BasicBlock[] blocks) { for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) { BasicBlock block = blocks[blkIndex]; LinkedListNode <INode> node = block.Operations.First; while (node != null) { LinkedListNode <INode> nextNode = node.Next; if (node.Value is not PhiNode phi) { node = nextNode; continue; } for (int index = 0; index < phi.SourcesCount; index++) { Operand src = phi.GetSource(index); BasicBlock srcBlock = phi.GetBlock(index); Operation copyOp = new Operation(Instruction.Copy, phi.Dest, src); srcBlock.Append(copyOp); } block.Operations.Remove(node); node = nextNode; } } }
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) { arg = Local(OperandType.I64); Operation loadArg = block.Operations.AddFirst(Operation(Instruction.LoadArgument, arg, Const(0))); LoadLocals(block, globalInputs[block.Index].VecMask, RegisterType.Vector, mode, loadArg, arg); LoadLocals(block, globalInputs[block.Index].IntMask, RegisterType.Integer, mode, loadArg, arg); } bool hasContextStore = HasContextStore(block); if (hasContextStore) { block.Operations.Remove(block.Operations.Last); } if (EndsWithReturn(block) || hasContextStore) { if (arg == default) { arg = Local(OperandType.I64); block.Append(Operation(Instruction.LoadArgument, arg, Const(0))); } StoreLocals(block, globalOutputs[block.Index].IntMask, RegisterType.Integer, mode, arg); StoreLocals(block, globalOutputs[block.Index].VecMask, RegisterType.Vector, mode, arg); } } }
private void InsertSplitCopiesAtEdges(ControlFlowGraph cfg) { int blocksCount = cfg.Blocks.Count; bool IsSplitEdgeBlock(BasicBlock block) { return(block.Index >= blocksCount); } for (LinkedListNode <BasicBlock> node = cfg.Blocks.First; node != null; node = node.Next) { BasicBlock block = node.Value; if (IsSplitEdgeBlock(block)) { continue; } bool hasSingleOrNoSuccessor = block.Next == null || block.Branch == null; foreach (BasicBlock successor in Successors(block)) { int succIndex = successor.Index; // If the current node is a split node, then the actual successor node // (the successor before the split) should be right after it. if (IsSplitEdgeBlock(successor)) { succIndex = Successors(successor).First().Index; } CopyResolver copyResolver = new CopyResolver(); foreach (int iIndex in _blockLiveIn[succIndex]) { LiveInterval interval = _parentIntervals[iIndex]; if (!interval.IsSplit) { continue; } int lEnd = _blockRanges[block.Index].End - 1; int rStart = _blockRanges[succIndex].Start; LiveInterval left = interval.GetSplitChild(lEnd); LiveInterval right = interval.GetSplitChild(rStart); if (left != null && right != null && left != right) { copyResolver.AddSplit(left, right); } } if (!copyResolver.HasCopy) { continue; } Operation[] sequence = copyResolver.Sequence(); if (hasSingleOrNoSuccessor) { foreach (Operation operation in sequence) { block.Append(operation); } } else if (successor.Predecessors.Count == 1) { LinkedListNode <Node> prependNode = successor.Operations.AddFirst(sequence[0]); for (int index = 1; index < sequence.Length; index++) { Operation operation = sequence[index]; prependNode = successor.Operations.AddAfter(prependNode, operation); } } else { // Split the critical edge. BasicBlock splitBlock = cfg.SplitEdge(block, successor); foreach (Operation operation in sequence) { splitBlock.Append(operation); } } } } }