From e5f78fb1d44b825ee9195660f4387680055137dc Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 17 Feb 2020 18:30:54 -0300 Subject: [PATCH] Replace LinkedList by IntrusiveList to avoid allocations on JIT (#931) * Replace LinkedList by IntrusiveList to avoid allocations on JIT * Fix wrong replacements --- .../CodeGen/Optimizations/Optimizer.cs | 16 +- .../RegisterAllocators/HybridAllocator.cs | 12 +- .../RegisterAllocators/LinearScanAllocator.cs | 52 ++--- ARMeilleure/CodeGen/X86/CodeGenerator.cs | 4 +- ARMeilleure/CodeGen/X86/PreAllocator.cs | 146 +++++++------- ARMeilleure/Diagnostics/IRDumper.cs | 4 +- .../IntermediateRepresentation/BasicBlock.cs | 11 +- .../IIntrusiveListNode.cs | 8 + .../IntrusiveList.cs | 178 ++++++++++++++++++ .../IntermediateRepresentation/Node.cs | 33 ++-- .../IntermediateRepresentation/Operand.cs | 8 +- ARMeilleure/Translation/ControlFlowGraph.cs | 24 ++- ARMeilleure/Translation/Dominance.cs | 2 +- ARMeilleure/Translation/EmitterContext.cs | 11 +- ARMeilleure/Translation/RegisterToLocal.cs | 4 +- ARMeilleure/Translation/RegisterUsage.cs | 16 +- ARMeilleure/Translation/SsaConstruction.cs | 26 +-- ARMeilleure/Translation/SsaDeconstruction.cs | 8 +- 18 files changed, 365 insertions(+), 198 deletions(-) create mode 100644 ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs create mode 100644 ARMeilleure/IntermediateRepresentation/IntrusiveList.cs diff --git a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs index c01a8f1e7f..e3117d1f7e 100644 --- a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs +++ b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs @@ -16,17 +16,17 @@ namespace ARMeilleure.CodeGen.Optimizations { modified = false; - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { - LinkedListNode node = block.Operations.First; + Node node = block.Operations.First; while (node != null) { - LinkedListNode nextNode = node.Next; + Node nextNode = node.ListNext; - bool isUnused = IsUnused(node.Value); + bool isUnused = IsUnused(node); - if (!(node.Value is Operation operation) || isUnused) + if (!(node is Operation operation) || isUnused) { if (isUnused) { @@ -80,13 +80,11 @@ namespace ARMeilleure.CodeGen.Optimizations } } - private static void RemoveNode(BasicBlock block, LinkedListNode llNode) + private static void RemoveNode(BasicBlock block, Node node) { // Remove a node from the nodes list, and also remove itself // from all the use lists on the operands that this node uses. - block.Operations.Remove(llNode); - - Node node = llNode.Value; + block.Operations.Remove(node); for (int index = 0; index < node.SourcesCount; index++) { diff --git a/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs index 9a827420bb..ed0e1ae1ae 100644 --- a/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs +++ b/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs @@ -95,7 +95,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators bool hasCall = false; - foreach (Node node in block.Operations) + for (Node node = block.Operations.First; node != null; node = node.ListNext) { if (node is Operation operation && operation.Instruction == Instruction.Call) { @@ -176,10 +176,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators intLocalFreeRegisters &= ~(intSpillTempRegisters | intCallerSavedRegisters); vecLocalFreeRegisters &= ~(vecSpillTempRegisters | vecCallerSavedRegisters); - for (LinkedListNode llNode = block.Operations.First; llNode != null; llNode = llNode.Next) + for (Node node = block.Operations.First; node != null; node = node.ListNext) { - Node node = llNode.Value; - int intLocalUse = 0; int vecLocalUse = 0; @@ -232,7 +230,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators Operation fillOp = new Operation(Instruction.Fill, temp, Const(info.SpillOffset)); - block.Operations.AddBefore(llNode, fillOp); + block.Operations.AddBefore(node, fillOp); } } @@ -306,7 +304,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators Operation spillOp = new Operation(Instruction.Spill, null, Const(info.SpillOffset), temp); - llNode = block.Operations.AddAfter(llNode, spillOp); + block.Operations.AddAfter(node, spillOp); + + node = spillOp; } } diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs index 6d5ecc1416..1127ccd58b 100644 --- a/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs +++ b/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs @@ -28,7 +28,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators private LiveInterval[] _parentIntervals; - private List> _operationNodes; + private List<(IntrusiveList, Node)> _operationNodes; private int _operationsCount; @@ -583,15 +583,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators int splitPosition = kv.Key; - LinkedListNode node = GetOperationNode(splitPosition); + (IntrusiveList nodes, Node node) = GetOperationNode(splitPosition); Operation[] sequence = copyResolver.Sequence(); - node = node.List.AddBefore(node, sequence[0]); + nodes.AddBefore(node, sequence[0]); + + node = sequence[0]; for (int index = 1; index < sequence.Length; index++) { - node = node.List.AddAfter(node, sequence[index]); + nodes.AddAfter(node, sequence[index]); + + node = sequence[index]; } } } @@ -605,10 +609,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators return block.Index >= blocksCount; } - for (LinkedListNode node = cfg.Blocks.First; node != null; node = node.Next) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { - BasicBlock block = node.Value; - if (IsSplitEdgeBlock(block)) { continue; @@ -666,13 +668,17 @@ namespace ARMeilleure.CodeGen.RegisterAllocators } else if (successor.Predecessors.Count == 1) { - LinkedListNode prependNode = successor.Operations.AddFirst(sequence[0]); + successor.Operations.AddFirst(sequence[0]); + + Node prependNode = sequence[0]; for (int index = 1; index < sequence.Length; index++) { Operation operation = sequence[index]; - prependNode = successor.Operations.AddAfter(prependNode, operation); + successor.Operations.AddAfter(prependNode, operation); + + prependNode = operation; } } else @@ -695,7 +701,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators foreach (int usePosition in current.UsePositions()) { - Node operation = GetOperationNode(usePosition).Value; + (_, Node operation) = GetOperationNode(usePosition); for (int index = 0; index < operation.SourcesCount; index++) { @@ -729,14 +735,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators interval.Local.Type); } - private LinkedListNode GetOperationNode(int position) + private (IntrusiveList, Node) GetOperationNode(int position) { return _operationNodes[position / InstructionGap]; } private void NumberLocals(ControlFlowGraph cfg) { - _operationNodes = new List>(); + _operationNodes = new List<(IntrusiveList, Node)>(); _intervals = new List(); @@ -754,13 +760,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators { BasicBlock block = cfg.PostOrderBlocks[index]; - for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) + for (Node node = block.Operations.First; node != null; node = node.ListNext) { - _operationNodes.Add(node); + _operationNodes.Add((block.Operations, node)); - Node operation = node.Value; - - foreach (Operand dest in Destinations(operation)) + foreach (Operand dest in Destinations(node)) { if (dest.Kind == OperandKind.LocalVariable && visited.Add(dest)) { @@ -776,7 +780,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators if (block.Operations.Count == 0) { // Pretend we have a dummy instruction on the empty block. - _operationNodes.Add(null); + _operationNodes.Add((null, null)); _operationsCount += InstructionGap; } @@ -795,12 +799,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators BitMap[] blkLiveKill = new BitMap[cfg.Blocks.Count]; // Compute local live sets. - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { BitMap liveGen = new BitMap(mapSize); BitMap liveKill = new BitMap(mapSize); - foreach (Node node in block.Operations) + for (Node node = block.Operations.First; node != null; node = node.ListNext) { foreach (Operand source in Sources(node)) { @@ -979,13 +983,13 @@ namespace ARMeilleure.CodeGen.RegisterAllocators private static IEnumerable BottomOperations(BasicBlock block) { - LinkedListNode node = block.Operations.Last; + Node node = block.Operations.Last; - while (node != null && !(node.Value is PhiNode)) + while (node != null && !(node is PhiNode)) { - yield return node.Value; + yield return node; - node = node.Previous; + node = node.ListPrevious; } } diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs index 0268665cb0..d0cb77f81f 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -157,11 +157,11 @@ namespace ARMeilleure.CodeGen.X86 UnwindInfo unwindInfo = WritePrologue(context); - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { context.EnterBlock(block); - foreach (Node node in block.Operations) + for (Node node = block.Operations.First; node != null; node = node.ListNext) { if (node is Operation operation) { diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs index 034a87ac25..d250f5e883 100644 --- a/ARMeilleure/CodeGen/X86/PreAllocator.cs +++ b/ARMeilleure/CodeGen/X86/PreAllocator.cs @@ -8,8 +8,6 @@ using static ARMeilleure.IntermediateRepresentation.OperandHelper; namespace ARMeilleure.CodeGen.X86 { - using LLNode = LinkedListNode; - static class PreAllocator { public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs) @@ -20,24 +18,24 @@ namespace ARMeilleure.CodeGen.X86 Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()]; - foreach (BasicBlock block in cctx.Cfg.Blocks) + for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext) { - LLNode nextNode; + Node nextNode; - for (LLNode node = block.Operations.First; node != null; node = nextNode) + for (Node node = block.Operations.First; node != null; node = nextNode) { - nextNode = node.Next; + nextNode = node.ListNext; - if (!(node.Value is Operation operation)) + if (!(node is Operation operation)) { continue; } - HandleConstantCopy(node, operation); + HandleConstantCopy(block.Operations, node, operation); - HandleSameDestSrc1Copy(node, operation); + HandleSameDestSrc1Copy(block.Operations, node, operation); - HandleFixedRegisterCopy(node, operation); + HandleFixedRegisterCopy(block.Operations, node, operation); switch (operation.Instruction) { @@ -62,51 +60,51 @@ namespace ARMeilleure.CodeGen.X86 // being called, as mandated by the ABI. if (callConv == CallConvName.Windows) { - node = HandleCallWindowsAbi(stackAlloc, node, operation); + node = HandleCallWindowsAbi(block.Operations, stackAlloc, node, operation); } else /* if (callConv == CallConvName.SystemV) */ { - node = HandleCallSystemVAbi(node, operation); + node = HandleCallSystemVAbi(block.Operations, node, operation); } break; case Instruction.ConvertToFPUI: - HandleConvertToFPUI(node, operation); + HandleConvertToFPUI(block.Operations, node, operation); break; case Instruction.LoadArgument: if (callConv == CallConvName.Windows) { - HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation); + HandleLoadArgumentWindowsAbi(cctx, block.Operations, node, preservedArgs, operation); } else /* if (callConv == CallConvName.SystemV) */ { - HandleLoadArgumentSystemVAbi(cctx, node, preservedArgs, operation); + HandleLoadArgumentSystemVAbi(cctx, block.Operations, node, preservedArgs, operation); } break; case Instruction.Negate: if (!operation.GetSource(0).Type.IsInteger()) { - node = HandleNegate(node, operation); + node = HandleNegate(block.Operations, node, operation); } break; case Instruction.Return: if (callConv == CallConvName.Windows) { - HandleReturnWindowsAbi(cctx, node, preservedArgs, operation); + HandleReturnWindowsAbi(cctx, block.Operations, node, preservedArgs, operation); } else /* if (callConv == CallConvName.SystemV) */ { - HandleReturnSystemVAbi(node, operation); + HandleReturnSystemVAbi(block.Operations, node, operation); } break; case Instruction.VectorInsert8: if (!HardwareCapabilities.SupportsSse41) { - node = HandleVectorInsert8(node, operation); + node = HandleVectorInsert8(block.Operations, node, operation); } break; } @@ -114,7 +112,7 @@ namespace ARMeilleure.CodeGen.X86 } } - private static void HandleConstantCopy(LLNode node, Operation operation) + private static void HandleConstantCopy(IntrusiveList nodes, Node node, Operation operation) { if (operation.SourcesCount == 0 || IsIntrinsic(operation.Instruction)) { @@ -135,7 +133,7 @@ namespace ARMeilleure.CodeGen.X86 // - Insert a copy with the constant value (as integer) to a GPR. // - Insert a copy from the GPR to a XMM register. // - Replace the constant use with the XMM register. - src1 = AddXmmCopy(node, src1); + src1 = AddXmmCopy(nodes, node, src1); operation.SetSource(0, src1); } @@ -164,7 +162,7 @@ namespace ARMeilleure.CodeGen.X86 if (src1.Kind == OperandKind.Constant) { - src1 = AddCopy(node, src1); + src1 = AddCopy(nodes, node, src1); operation.SetSource(0, src1); } @@ -182,25 +180,23 @@ namespace ARMeilleure.CodeGen.X86 { if (!src2.Type.IsInteger()) { - src2 = AddXmmCopy(node, src2); + src2 = AddXmmCopy(nodes, node, src2); operation.SetSource(1, src2); } else if (!HasConstSrc2(inst) || IsLongConst(src2)) { - src2 = AddCopy(node, src2); + src2 = AddCopy(nodes, node, src2); operation.SetSource(1, src2); } } } - private static LLNode HandleFixedRegisterCopy(LLNode node, Operation operation) + private static Node HandleFixedRegisterCopy(IntrusiveList nodes, Node node, Operation operation) { Operand dest = operation.Destination; - LinkedList nodes = node.List; - switch (operation.Instruction) { case Instruction.CompareAndSwap128: @@ -359,7 +355,7 @@ namespace ARMeilleure.CodeGen.X86 return node; } - private static LLNode HandleSameDestSrc1Copy(LLNode node, Operation operation) + private static Node HandleSameDestSrc1Copy(IntrusiveList nodes, Node node, Operation operation) { if (operation.Destination == null || operation.SourcesCount == 0) { @@ -371,8 +367,6 @@ namespace ARMeilleure.CodeGen.X86 Operand dest = operation.Destination; Operand src1 = operation.GetSource(0); - LinkedList nodes = node.List; - // The multiply instruction (that maps to IMUL) is somewhat special, it has // a three operand form where the second source is a immediate value. bool threeOperandForm = inst == Instruction.Multiply && operation.GetSource(1).Kind == OperandKind.Constant; @@ -441,7 +435,7 @@ namespace ARMeilleure.CodeGen.X86 return node; } - private static LLNode HandleConvertToFPUI(LLNode node, Operation operation) + private static Node HandleConvertToFPUI(IntrusiveList nodes, Node node, Operation operation) { // Unsigned integer to FP conversions are not supported on X86. // We need to turn them into signed integer to FP conversions, and @@ -451,9 +445,7 @@ namespace ARMeilleure.CodeGen.X86 Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\"."); - LinkedList nodes = node.List; - - LLNode currentNode = node; + Node currentNode = node; if (source.Type == OperandType.I32) { @@ -494,12 +486,12 @@ namespace ARMeilleure.CodeGen.X86 node = nodes.AddAfter(node, new Operation(Instruction.Add, dest, dest, lsbF)); } - Delete(currentNode, operation); + Delete(nodes, currentNode, operation); return node; } - private static LLNode HandleNegate(LLNode node, Operation operation) + private static Node HandleNegate(IntrusiveList nodes, Node node, Operation operation) { // There's no SSE FP negate instruction, so we need to transform that into // a XOR of the value to be negated with a mask with the highest bit set. @@ -510,9 +502,7 @@ namespace ARMeilleure.CodeGen.X86 Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64, $"Invalid destination type \"{dest.Type}\"."); - LinkedList nodes = node.List; - - LLNode currentNode = node; + Node currentNode = node; Operand res = Local(dest.Type); @@ -531,12 +521,12 @@ namespace ARMeilleure.CodeGen.X86 node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, res)); - Delete(currentNode, operation); + Delete(nodes, currentNode, operation); return node; } - private static LLNode HandleVectorInsert8(LLNode node, Operation operation) + private static Node HandleVectorInsert8(IntrusiveList nodes, Node node, Operation operation) { // Handle vector insertion, when SSE 4.1 is not supported. Operand dest = operation.Destination; @@ -550,9 +540,7 @@ namespace ARMeilleure.CodeGen.X86 Debug.Assert(index < 16); - LinkedList nodes = node.List; - - LLNode currentNode = node; + Node currentNode = node; Operand temp1 = Local(OperandType.I32); Operand temp2 = Local(OperandType.I32); @@ -580,17 +568,15 @@ namespace ARMeilleure.CodeGen.X86 node = nodes.AddAfter(node, vinsOp); - Delete(currentNode, operation); + Delete(nodes, currentNode, operation); return node; } - private static LLNode HandleCallWindowsAbi(StackAllocator stackAlloc, LLNode node, Operation operation) + private static Node HandleCallWindowsAbi(IntrusiveList nodes, StackAllocator stackAlloc, Node node, Operation operation) { Operand dest = operation.Destination; - LinkedList nodes = node.List; - // Handle struct arguments. int retArgs = 0; @@ -661,7 +647,7 @@ namespace ARMeilleure.CodeGen.X86 Operation storeOp = new Operation(Instruction.Store, null, stackAddr, source); - HandleConstantCopy(nodes.AddBefore(node, storeOp), storeOp); + HandleConstantCopy(nodes, nodes.AddBefore(node, storeOp), storeOp); operation.SetSource(index, stackAddr); } @@ -687,7 +673,7 @@ namespace ARMeilleure.CodeGen.X86 Operation copyOp = new Operation(Instruction.Copy, argReg, source); - HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp); + HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp); sources[1 + retArgs + index] = argReg; } @@ -702,7 +688,7 @@ namespace ARMeilleure.CodeGen.X86 Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source); - HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp); + HandleConstantCopy(nodes, nodes.AddBefore(node, spillOp), spillOp); } if (dest != null) @@ -738,15 +724,14 @@ namespace ARMeilleure.CodeGen.X86 return node; } - private static LLNode HandleCallSystemVAbi(LLNode node, Operation operation) + private static Node HandleCallSystemVAbi(IntrusiveList nodes, Node node, Operation operation) { Operand dest = operation.Destination; - LinkedList nodes = node.List; - - List sources = new List(); - - sources.Add(operation.GetSource(0)); + List sources = new List + { + operation.GetSource(0) + }; int argsCount = operation.SourcesCount - 1; @@ -797,7 +782,7 @@ namespace ARMeilleure.CodeGen.X86 Operation copyOp = new Operation(Instruction.Copy, argReg, source); - HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp); + HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp); sources.Add(argReg); } @@ -807,7 +792,7 @@ namespace ARMeilleure.CodeGen.X86 Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source); - HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp); + HandleConstantCopy(nodes, nodes.AddBefore(node, spillOp), spillOp); stackOffset += source.Type.GetSizeInBytes(); } @@ -846,7 +831,8 @@ namespace ARMeilleure.CodeGen.X86 private static void HandleLoadArgumentWindowsAbi( CompilerContext cctx, - LLNode node, + IntrusiveList nodes, + Node node, Operand[] preservedArgs, Operation operation) { @@ -896,9 +882,9 @@ namespace ARMeilleure.CodeGen.X86 ? Instruction.Load : Instruction.Copy, dest, preservedArgs[index]); - node.List.AddBefore(node, argCopyOp); + nodes.AddBefore(node, argCopyOp); - Delete(node, operation); + Delete(nodes, node, operation); } else { @@ -908,7 +894,8 @@ namespace ARMeilleure.CodeGen.X86 private static void HandleLoadArgumentSystemVAbi( CompilerContext cctx, - LLNode node, + IntrusiveList nodes, + Node node, Operand[] preservedArgs, Operation operation) { @@ -994,9 +981,9 @@ namespace ARMeilleure.CodeGen.X86 Operation argCopyOp = new Operation(Instruction.Copy, dest, preservedArgs[index]); - node.List.AddBefore(node, argCopyOp); + nodes.AddBefore(node, argCopyOp); - Delete(node, operation); + Delete(nodes, node, operation); } else { @@ -1006,7 +993,8 @@ namespace ARMeilleure.CodeGen.X86 private static void HandleReturnWindowsAbi( CompilerContext cctx, - LLNode node, + IntrusiveList nodes, + Node node, Operand[] preservedArgs, Operation operation) { @@ -1049,19 +1037,19 @@ namespace ARMeilleure.CodeGen.X86 { Operation retStoreOp = new Operation(Instruction.Store, null, retReg, source); - node.List.AddBefore(node, retStoreOp); + nodes.AddBefore(node, retStoreOp); } else { Operation retCopyOp = new Operation(Instruction.Copy, retReg, source); - node.List.AddBefore(node, retCopyOp); + nodes.AddBefore(node, retCopyOp); } operation.SetSources(new Operand[0]); } - private static void HandleReturnSystemVAbi(LLNode node, Operation operation) + private static void HandleReturnSystemVAbi(IntrusiveList nodes, Node node, Operation operation) { if (operation.SourcesCount == 0) { @@ -1075,8 +1063,8 @@ namespace ARMeilleure.CodeGen.X86 Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64); - node.List.AddBefore(node, new Operation(Instruction.VectorExtract, retLReg, source, Const(0))); - node.List.AddBefore(node, new Operation(Instruction.VectorExtract, retHReg, source, Const(1))); + nodes.AddBefore(node, new Operation(Instruction.VectorExtract, retLReg, source, Const(0))); + nodes.AddBefore(node, new Operation(Instruction.VectorExtract, retHReg, source, Const(1))); } else { @@ -1086,30 +1074,30 @@ namespace ARMeilleure.CodeGen.X86 Operation retCopyOp = new Operation(Instruction.Copy, retReg, source); - node.List.AddBefore(node, retCopyOp); + nodes.AddBefore(node, retCopyOp); } } - private static Operand AddXmmCopy(LLNode node, Operand source) + private static Operand AddXmmCopy(IntrusiveList nodes, Node node, Operand source) { Operand temp = Local(source.Type); - Operand intConst = AddCopy(node, GetIntConst(source)); + Operand intConst = AddCopy(nodes, node, GetIntConst(source)); Operation copyOp = new Operation(Instruction.VectorCreateScalar, temp, intConst); - node.List.AddBefore(node, copyOp); + nodes.AddBefore(node, copyOp); return temp; } - private static Operand AddCopy(LLNode node, Operand source) + private static Operand AddCopy(IntrusiveList nodes, Node node, Operand source) { Operand temp = Local(source.Type); Operation copyOp = new Operation(Instruction.Copy, temp, source); - node.List.AddBefore(node, copyOp); + nodes.AddBefore(node, copyOp); return temp; } @@ -1142,7 +1130,7 @@ namespace ARMeilleure.CodeGen.X86 return value == (int)value; } - private static void Delete(LLNode node, Operation operation) + private static void Delete(IntrusiveList nodes, Node node, Operation operation) { operation.Destination = null; @@ -1151,7 +1139,7 @@ namespace ARMeilleure.CodeGen.X86 operation.SetSource(index, null); } - node.List.Remove(node); + nodes.Remove(node); } private static Operand Gpr(X86Register register, OperandType type) diff --git a/ARMeilleure/Diagnostics/IRDumper.cs b/ARMeilleure/Diagnostics/IRDumper.cs index 55d5b493e3..c3e99dfab8 100644 --- a/ARMeilleure/Diagnostics/IRDumper.cs +++ b/ARMeilleure/Diagnostics/IRDumper.cs @@ -35,7 +35,7 @@ namespace ARMeilleure.Diagnostics IncreaseIndentation(); - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { string blockName = GetBlockName(block); @@ -55,7 +55,7 @@ namespace ARMeilleure.Diagnostics IncreaseIndentation(); - foreach (Node node in block.Operations) + for (Node node = block.Operations.First; node != null; node = node.ListNext) { string[] sources = new string[node.SourcesCount]; diff --git a/ARMeilleure/IntermediateRepresentation/BasicBlock.cs b/ARMeilleure/IntermediateRepresentation/BasicBlock.cs index 06839f309f..ac48ac8eb2 100644 --- a/ARMeilleure/IntermediateRepresentation/BasicBlock.cs +++ b/ARMeilleure/IntermediateRepresentation/BasicBlock.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; namespace ARMeilleure.IntermediateRepresentation { - class BasicBlock + class BasicBlock : IIntrusiveListNode { public int Index { get; set; } - public LinkedListNode Node { get; set; } + public BasicBlock ListPrevious { get; set; } + public BasicBlock ListNext { get; set; } - public LinkedList Operations { get; } + public IntrusiveList Operations { get; } private BasicBlock _next; private BasicBlock _branch; @@ -33,7 +34,7 @@ namespace ARMeilleure.IntermediateRepresentation public BasicBlock() { - Operations = new LinkedList(); + Operations = new IntrusiveList(); Predecessors = new List(); @@ -77,7 +78,7 @@ namespace ARMeilleure.IntermediateRepresentation public Node GetLastOp() { - return Operations.Last?.Value; + return Operations.Last; } } } \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs b/ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs new file mode 100644 index 0000000000..797e789177 --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs @@ -0,0 +1,8 @@ +namespace ARMeilleure.IntermediateRepresentation +{ + interface IIntrusiveListNode where T : class + { + T ListPrevious { get; set; } + T ListNext { get; set; } + } +} diff --git a/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs b/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs new file mode 100644 index 0000000000..a7b0f7a7e3 --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs @@ -0,0 +1,178 @@ +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace ARMeilleure.IntermediateRepresentation +{ + /// + /// Represents a efficient linked list that stores the pointer on the object directly and does not allocate. + /// + /// Type of the list items + class IntrusiveList where T : class, IIntrusiveListNode + { + /// + /// First item of the list, or null if empty. + /// + public T First { get; private set; } + + /// + /// Last item of the list, or null if empty. + /// + public T Last { get; private set; } + + /// + /// Total number of items on the list. + /// + public int Count { get; private set; } + + /// + /// Adds a item as the first item of the list. + /// + /// Item to be added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddFirst(T newNode) + { + if (First != null) + { + AddBefore(First, newNode); + } + else + { + Debug.Assert(newNode.ListPrevious == null); + Debug.Assert(newNode.ListNext == null); + Debug.Assert(Last == null); + + First = newNode; + Last = newNode; + + Debug.Assert(Count == 0); + + Count = 1; + } + } + + /// + /// Adds a item as the last item of the list. + /// + /// Item to be added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddLast(T newNode) + { + if (Last != null) + { + AddAfter(Last, newNode); + } + else + { + Debug.Assert(newNode.ListPrevious == null); + Debug.Assert(newNode.ListNext == null); + Debug.Assert(First == null); + + First = newNode; + Last = newNode; + + Debug.Assert(Count == 0); + + Count = 1; + } + } + + /// + /// Adds a item before a existing item on the list. + /// + /// Item on the list that will succeed the new item + /// Item to be added + /// New item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T AddBefore(T node, T newNode) + { + Debug.Assert(newNode.ListPrevious == null); + Debug.Assert(newNode.ListNext == null); + + newNode.ListPrevious = node.ListPrevious; + newNode.ListNext = node; + + node.ListPrevious = newNode; + + if (newNode.ListPrevious != null) + { + newNode.ListPrevious.ListNext = newNode; + } + + if (First == node) + { + First = newNode; + } + + Count++; + + return newNode; + } + + /// + /// Adds a item after a existing item on the list. + /// + /// Item on the list that will preceed the new item + /// Item to be added + /// New item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T AddAfter(T node, T newNode) + { + Debug.Assert(newNode.ListPrevious == null); + Debug.Assert(newNode.ListNext == null); + + newNode.ListPrevious = node; + newNode.ListNext = node.ListNext; + + node.ListNext = newNode; + + if (newNode.ListNext != null) + { + newNode.ListNext.ListPrevious = newNode; + } + + if (Last == node) + { + Last = newNode; + } + + Count++; + + return newNode; + } + + /// + /// Removes a item from the list. + /// + /// The item to be removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Remove(T node) + { + if (node.ListPrevious != null) + { + node.ListPrevious.ListNext = node.ListNext; + } + else + { + Debug.Assert(First == node); + + First = node.ListNext; + } + + if (node.ListNext != null) + { + node.ListNext.ListPrevious = node.ListPrevious; + } + else + { + Debug.Assert(Last == node); + + Last = node.ListPrevious; + } + + node.ListPrevious = null; + node.ListNext = null; + + Count--; + } + } +} diff --git a/ARMeilleure/IntermediateRepresentation/Node.cs b/ARMeilleure/IntermediateRepresentation/Node.cs index 167acd0721..e1f8b11bb1 100644 --- a/ARMeilleure/IntermediateRepresentation/Node.cs +++ b/ARMeilleure/IntermediateRepresentation/Node.cs @@ -1,10 +1,12 @@ using System; -using System.Collections.Generic; namespace ARMeilleure.IntermediateRepresentation { - class Node + class Node : IIntrusiveListNode { + public Node ListPrevious { get; set; } + public Node ListNext { get; set; } + public Operand Destination { get @@ -27,9 +29,6 @@ namespace ARMeilleure.IntermediateRepresentation private Operand[] _destinations; private Operand[] _sources; - private LinkedListNode[] _asgUseNodes; - private LinkedListNode[] _srcUseNodes; - public int DestinationsCount => _destinations.Length; public int SourcesCount => _sources.Length; @@ -38,8 +37,6 @@ namespace ARMeilleure.IntermediateRepresentation Destination = destination; _sources = new Operand[sourcesCount]; - - _srcUseNodes = new LinkedListNode[sourcesCount]; } public Node(Operand[] destinations, int sourcesCount) @@ -47,8 +44,6 @@ namespace ARMeilleure.IntermediateRepresentation SetDestinations(destinations ?? throw new ArgumentNullException(nameof(destinations))); _sources = new Operand[sourcesCount]; - - _srcUseNodes = new LinkedListNode[sourcesCount]; } public Operand GetDestination(int index) @@ -67,12 +62,12 @@ namespace ARMeilleure.IntermediateRepresentation if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable) { - oldOp.Assignments.Remove(_asgUseNodes[index]); + oldOp.Assignments.Remove(this); } if (destination != null && destination.Kind == OperandKind.LocalVariable) { - _asgUseNodes[index] = destination.Assignments.AddLast(this); + destination.Assignments.Add(this); } _destinations[index] = destination; @@ -84,12 +79,12 @@ namespace ARMeilleure.IntermediateRepresentation if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable) { - oldOp.Uses.Remove(_srcUseNodes[index]); + oldOp.Uses.Remove(this); } if (source != null && source.Kind == OperandKind.LocalVariable) { - _srcUseNodes[index] = source.Uses.AddLast(this); + source.Uses.Add(this); } _sources[index] = source; @@ -105,7 +100,7 @@ namespace ARMeilleure.IntermediateRepresentation if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable) { - oldOp.Assignments.Remove(_asgUseNodes[index]); + oldOp.Assignments.Remove(this); } } @@ -116,8 +111,6 @@ namespace ARMeilleure.IntermediateRepresentation _destinations = new Operand[destinations.Length]; } - _asgUseNodes = new LinkedListNode[destinations.Length]; - for (int index = 0; index < destinations.Length; index++) { Operand newOp = destinations[index]; @@ -126,7 +119,7 @@ namespace ARMeilleure.IntermediateRepresentation if (newOp.Kind == OperandKind.LocalVariable) { - _asgUseNodes[index] = newOp.Assignments.AddLast(this); + newOp.Assignments.Add(this); } } } @@ -139,14 +132,12 @@ namespace ARMeilleure.IntermediateRepresentation if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable) { - oldOp.Uses.Remove(_srcUseNodes[index]); + oldOp.Uses.Remove(this); } } _sources = new Operand[sources.Length]; - _srcUseNodes = new LinkedListNode[sources.Length]; - for (int index = 0; index < sources.Length; index++) { Operand newOp = sources[index]; @@ -155,7 +146,7 @@ namespace ARMeilleure.IntermediateRepresentation if (newOp.Kind == OperandKind.LocalVariable) { - _srcUseNodes[index] = newOp.Uses.AddLast(this); + newOp.Uses.Add(this); } } } diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs index 2df6256fc6..fe5bf0732c 100644 --- a/ARMeilleure/IntermediateRepresentation/Operand.cs +++ b/ARMeilleure/IntermediateRepresentation/Operand.cs @@ -11,13 +11,13 @@ namespace ARMeilleure.IntermediateRepresentation public ulong Value { get; private set; } - public LinkedList Assignments { get; } - public LinkedList Uses { get; } + public List Assignments { get; } + public List Uses { get; } private Operand() { - Assignments = new LinkedList(); - Uses = new LinkedList(); + Assignments = new List(); + Uses = new List(); } public Operand(OperandKind kind, OperandType type = OperandType.None) : this() diff --git a/ARMeilleure/Translation/ControlFlowGraph.cs b/ARMeilleure/Translation/ControlFlowGraph.cs index 758f1f968a..37613eb495 100644 --- a/ARMeilleure/Translation/ControlFlowGraph.cs +++ b/ARMeilleure/Translation/ControlFlowGraph.cs @@ -9,13 +9,13 @@ namespace ARMeilleure.Translation { public BasicBlock Entry { get; } - public LinkedList Blocks { get; } + public IntrusiveList Blocks { get; } public BasicBlock[] PostOrderBlocks { get; } public int[] PostOrderMap { get; } - public ControlFlowGraph(BasicBlock entry, LinkedList blocks) + public ControlFlowGraph(BasicBlock entry, IntrusiveList blocks) { Entry = entry; Blocks = blocks; @@ -57,7 +57,7 @@ namespace ARMeilleure.Translation } } - private void RemoveUnreachableBlocks(LinkedList blocks) + private void RemoveUnreachableBlocks(IntrusiveList blocks) { HashSet visited = new HashSet(); @@ -87,25 +87,23 @@ namespace ARMeilleure.Translation // Remove unreachable blocks and renumber. int index = 0; - for (LinkedListNode node = blocks.First; node != null;) + for (BasicBlock block = blocks.First; block != null;) { - LinkedListNode nextNode = node.Next; - - BasicBlock block = node.Value; + BasicBlock nextBlock = block.ListNext; if (!visited.Contains(block)) { - block.Next = null; + block.Next = null; block.Branch = null; - blocks.Remove(node); + blocks.Remove(block); } else { block.Index = index++; } - node = nextNode; + block = nextBlock; } } } @@ -130,7 +128,7 @@ namespace ARMeilleure.Translation } // Insert the new block on the list of blocks. - BasicBlock succPrev = successor.Node.Previous?.Value; + BasicBlock succPrev = successor.ListPrevious; if (succPrev != null && succPrev != predecessor && succPrev.Next == successor) { @@ -145,12 +143,12 @@ namespace ARMeilleure.Translation splitBlock2.Operations.AddLast(new Operation(Instruction.Branch, null)); - Blocks.AddBefore(successor.Node, splitBlock2); + Blocks.AddBefore(successor, splitBlock2); } splitBlock.Next = successor; - Blocks.AddBefore(successor.Node, splitBlock); + Blocks.AddBefore(successor, splitBlock); return splitBlock; } diff --git a/ARMeilleure/Translation/Dominance.cs b/ARMeilleure/Translation/Dominance.cs index bb55169ed0..b9b961d15f 100644 --- a/ARMeilleure/Translation/Dominance.cs +++ b/ARMeilleure/Translation/Dominance.cs @@ -71,7 +71,7 @@ namespace ARMeilleure.Translation public static void FindDominanceFrontiers(ControlFlowGraph cfg) { - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { if (block.Predecessors.Count < 2) { diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs index 13cf677c77..a125a715da 100644 --- a/ARMeilleure/Translation/EmitterContext.cs +++ b/ARMeilleure/Translation/EmitterContext.cs @@ -12,7 +12,7 @@ namespace ARMeilleure.Translation { private Dictionary _irLabels; - private LinkedList _irBlocks; + private IntrusiveList _irBlocks; private BasicBlock _irBlock; @@ -22,7 +22,7 @@ namespace ARMeilleure.Translation { _irLabels = new Dictionary(); - _irBlocks = new LinkedList(); + _irBlocks = new IntrusiveList(); _needsNewBlock = true; } @@ -508,7 +508,8 @@ namespace ARMeilleure.Translation if (_irLabels.TryGetValue(label, out BasicBlock nextBlock)) { nextBlock.Index = _irBlocks.Count; - nextBlock.Node = _irBlocks.AddLast(nextBlock); + + _irBlocks.AddLast(nextBlock); NextBlock(nextBlock); } @@ -524,7 +525,7 @@ namespace ARMeilleure.Translation { BasicBlock block = new BasicBlock(_irBlocks.Count); - block.Node = _irBlocks.AddLast(block); + _irBlocks.AddLast(block); NextBlock(block); } @@ -556,7 +557,7 @@ namespace ARMeilleure.Translation public ControlFlowGraph GetControlFlowGraph() { - return new ControlFlowGraph(_irBlocks.First.Value, _irBlocks); + return new ControlFlowGraph(_irBlocks.First, _irBlocks); } } } \ No newline at end of file diff --git a/ARMeilleure/Translation/RegisterToLocal.cs b/ARMeilleure/Translation/RegisterToLocal.cs index aa91801824..088cec7ef3 100644 --- a/ARMeilleure/Translation/RegisterToLocal.cs +++ b/ARMeilleure/Translation/RegisterToLocal.cs @@ -25,9 +25,9 @@ namespace ARMeilleure.Translation return local; } - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { - foreach (Node node in block.Operations) + for (Node node = block.Operations.First; node != null; node = node.ListNext) { Operand dest = node.Destination; diff --git a/ARMeilleure/Translation/RegisterUsage.cs b/ARMeilleure/Translation/RegisterUsage.cs index 4164786b90..becaa24cd9 100644 --- a/ARMeilleure/Translation/RegisterUsage.cs +++ b/ARMeilleure/Translation/RegisterUsage.cs @@ -74,9 +74,9 @@ namespace ARMeilleure.Translation RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count]; - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { - foreach (Node node in block.Operations) + for (Node node = block.Operations.First; node != null; node = node.ListNext) { Operation operation = node as Operation; @@ -192,13 +192,13 @@ namespace ARMeilleure.Translation while (modified); // Insert load and store context instructions where needed. - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { bool hasContextLoad = HasContextLoad(block); if (hasContextLoad) { - block.Operations.RemoveFirst(); + block.Operations.Remove(block.Operations.First); } // The only block without any predecessor should be the entry block. @@ -213,7 +213,7 @@ namespace ARMeilleure.Translation if (hasContextStore) { - block.Operations.RemoveLast(); + block.Operations.Remove(block.Operations.Last); } if (EndsWithReturn(block) || hasContextStore) @@ -226,7 +226,7 @@ namespace ARMeilleure.Translation private static bool HasContextLoad(BasicBlock block) { - return StartsWith(block, Instruction.LoadFromContext) && block.Operations.First.Value.SourcesCount == 0; + return StartsWith(block, Instruction.LoadFromContext) && block.Operations.First.SourcesCount == 0; } private static bool HasContextStore(BasicBlock block) @@ -241,7 +241,7 @@ namespace ARMeilleure.Translation return false; } - return block.Operations.First.Value is Operation operation && operation.Instruction == inst; + return block.Operations.First is Operation operation && operation.Instruction == inst; } private static bool EndsWith(BasicBlock block, Instruction inst) @@ -251,7 +251,7 @@ namespace ARMeilleure.Translation return false; } - return block.Operations.Last.Value is Operation operation && operation.Instruction == inst; + return block.Operations.Last is Operation operation && operation.Instruction == inst; } private static RegisterMask GetMask(Register register) diff --git a/ARMeilleure/Translation/SsaConstruction.cs b/ARMeilleure/Translation/SsaConstruction.cs index ccf5259154..292e74e36b 100644 --- a/ARMeilleure/Translation/SsaConstruction.cs +++ b/ARMeilleure/Translation/SsaConstruction.cs @@ -47,7 +47,7 @@ namespace ARMeilleure.Translation { DefMap[] globalDefs = new DefMap[cfg.Blocks.Count]; - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { globalDefs[block.Index] = new DefMap(); } @@ -55,11 +55,11 @@ namespace ARMeilleure.Translation Queue dfPhiBlocks = new Queue(); // First pass, get all defs and locals uses. - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; - LinkedListNode node = block.Operations.First; + Node node = block.Operations.First; Operand RenameLocal(Operand operand) { @@ -75,7 +75,7 @@ namespace ARMeilleure.Translation while (node != null) { - if (node.Value is Operation operation) + if (node is Operation operation) { for (int index = 0; index < operation.SourcesCount; index++) { @@ -94,7 +94,7 @@ namespace ARMeilleure.Translation } } - node = node.Next; + node = node.ListNext; } for (int index = 0; index < RegisterConsts.TotalCount; index++) @@ -126,11 +126,11 @@ namespace ARMeilleure.Translation } // Second pass, rename variables with definitions on different blocks. - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; - LinkedListNode node = block.Operations.First; + Node node = block.Operations.First; Operand RenameGlobal(Operand operand) { @@ -155,7 +155,7 @@ namespace ARMeilleure.Translation while (node != null) { - if (node.Value is Operation operation) + if (node is Operation operation) { for (int index = 0; index < operation.SourcesCount; index++) { @@ -163,7 +163,7 @@ namespace ARMeilleure.Translation } } - node = node.Next; + node = node.ListNext; } } } @@ -238,17 +238,17 @@ namespace ARMeilleure.Translation private static void AddPhi(BasicBlock block, PhiNode phi) { - LinkedListNode node = block.Operations.First; + Node node = block.Operations.First; if (node != null) { - while (node.Next?.Value is PhiNode) + while (node.ListNext is PhiNode) { - node = node.Next; + node = node.ListNext; } } - if (node?.Value is PhiNode) + if (node is PhiNode) { block.Operations.AddAfter(node, phi); } diff --git a/ARMeilleure/Translation/SsaDeconstruction.cs b/ARMeilleure/Translation/SsaDeconstruction.cs index 2ba78bdf43..37d616252d 100644 --- a/ARMeilleure/Translation/SsaDeconstruction.cs +++ b/ARMeilleure/Translation/SsaDeconstruction.cs @@ -9,13 +9,13 @@ namespace ARMeilleure.Translation { public static void Deconstruct(ControlFlowGraph cfg) { - foreach (BasicBlock block in cfg.Blocks) + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { - LinkedListNode node = block.Operations.First; + Node node = block.Operations.First; - while (node?.Value is PhiNode phi) + while (node is PhiNode phi) { - LinkedListNode nextNode = node.Next; + Node nextNode = node.ListNext; Operand local = Local(phi.Destination.Type);