diff --git a/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs b/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
index 65901e80cc..417f3bae68 100644
--- a/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
+++ b/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
@@ -2,6 +2,9 @@ using ARMeilleure.IntermediateRepresentation;
 using System;
 using System.Collections.Generic;
 
+using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.OperationHelper;
+
 namespace ARMeilleure.CodeGen.RegisterAllocators
 {
     class CopyResolver
@@ -133,14 +136,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
             private static void EmitCopy(List<Operation> sequence, Operand x, Operand y)
             {
-                sequence.Add(new Operation(Instruction.Copy, x, y));
+                sequence.Add(Operation(Instruction.Copy, x, y));
             }
 
             private static void EmitXorSwap(List<Operation> sequence, Operand x, Operand y)
             {
-                sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, x, x, y));
-                sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, y, y, x));
-                sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, x, x, y));
+                sequence.Add(Operation(Instruction.BitwiseExclusiveOr, x, x, y));
+                sequence.Add(Operation(Instruction.BitwiseExclusiveOr, y, y, x));
+                sequence.Add(Operation(Instruction.BitwiseExclusiveOr, x, x, y));
             }
         }
 
@@ -194,20 +197,20 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
         {
             Operand register = GetRegister(right.Register, type);
 
-            Operand offset = new Operand(left.SpillOffset);
+            Operand offset = Const(left.SpillOffset);
 
-            _fillQueue.Enqueue(new Operation(Instruction.Fill, register, offset));
+            _fillQueue.Enqueue(Operation(Instruction.Fill, register, offset));
 
             HasCopy = true;
         }
 
         private void AddSplitSpill(LiveInterval left, LiveInterval right, OperandType type)
         {
-            Operand offset = new Operand(right.SpillOffset);
+            Operand offset = Const(right.SpillOffset);
 
             Operand register = GetRegister(left.Register, type);
 
-            _spillQueue.Enqueue(new Operation(Instruction.Spill, null, offset, register));
+            _spillQueue.Enqueue(Operation(Instruction.Spill, null, offset, register));
 
             HasCopy = true;
         }
@@ -240,7 +243,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
         private static Operand GetRegister(Register reg, OperandType type)
         {
-            return new Operand(reg.Index, reg.Type, type);
+            return Register(reg.Index, reg.Type, type);
         }
     }
 }
\ No newline at end of file
diff --git a/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
index ce7936f916..21470a663b 100644
--- a/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
+++ b/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
@@ -1,10 +1,11 @@
-using ARMeilleure.Common;
 using ARMeilleure.IntermediateRepresentation;
 using ARMeilleure.Translation;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Numerics;
 
 using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.OperationHelper;
 
 namespace ARMeilleure.CodeGen.RegisterAllocators
 {
@@ -265,7 +266,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                                 node.SetSource(srcIndex, temp);
                             }
 
-                            Operation fillOp = new Operation(Instruction.Fill, temp, Const(info.SpillOffset));
+                            Operation fillOp = Operation(Instruction.Fill, temp, Const(info.SpillOffset));
 
                             block.Operations.AddBefore(node, fillOp);
                         }
@@ -317,7 +318,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
                             if (info.IsBlockLocal && mask != 0)
                             {
-                                int selectedReg = BitUtils.LowestBitSet(mask);
+                                int selectedReg = BitOperations.TrailingZeroCount(mask);
 
                                 info.Register = selectedReg;
 
@@ -363,7 +364,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
                             node.SetDestination(dstIndex, temp);
 
-                            Operation spillOp = new Operation(Instruction.Spill, null, Const(info.SpillOffset), temp);
+                            Operation spillOp = Operation(Instruction.Spill, null, Const(info.SpillOffset), temp);
 
                             block.Operations.AddAfter(node, spillOp);
 
@@ -415,7 +416,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
         private static Operand GetSpillTemp(Operand local, int freeMask, ref int useMask)
         {
-            int selectedReg = BitUtils.LowestBitSet(freeMask & ~useMask);
+            int selectedReg = BitOperations.TrailingZeroCount(freeMask & ~useMask);
 
             useMask |= 1 << selectedReg;
 
diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
index 1dc6ad7372..01bb9554d5 100644
--- a/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
+++ b/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
@@ -5,6 +5,7 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
+using System.Numerics;
 
 namespace ARMeilleure.CodeGen.RegisterAllocators
 {
@@ -32,7 +33,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
         private int _operationsCount;
 
-        private class AllocationContext
+        private class AllocationContext : IDisposable
         {
             public RegisterMasks Masks { get; }
 
@@ -49,8 +50,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                 StackAlloc = stackAlloc;
                 Masks      = masks;
 
-                Active   = new BitMap(intervalsCount);
-                Inactive = new BitMap(intervalsCount);
+                Active   = BitMapPool.Allocate(intervalsCount);
+                Inactive = BitMapPool.Allocate(intervalsCount);
             }
 
             public void MoveActiveToInactive(int bit)
@@ -69,6 +70,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
                 dest.Set(bit);
             }
+
+            public void Dispose()
+            {
+                BitMapPool.Release();
+            }
         }
 
         public AllocationResult RunPass(
@@ -121,10 +127,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
             InsertSplitCopies();
             InsertSplitCopiesAtEdges(cfg);
 
-            return new AllocationResult(
+            AllocationResult result = new AllocationResult(
                 context.IntUsedRegisters,
                 context.VecUsedRegisters,
                 context.StackAlloc.TotalSize);
+
+            context.Dispose();
+
+            return result;
         }
 
         private void AllocateInterval(AllocationContext context, LiveInterval current, int cIndex)
@@ -618,15 +628,22 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
                 bool hasSingleOrNoSuccessor = block.Next == null || block.Branch == null;
 
-                foreach (BasicBlock successor in Successors(block))
+                for (int i = 0; i < 2; i++)
                 {
+                    // This used to use an enumerable, but it ended up generating a lot of garbage, so now it is a loop.
+                    BasicBlock successor = (i == 0) ? block.Next : block.Branch;
+                    if (successor == null)
+                    {
+                        continue;
+                    }
+
                     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;
+                        succIndex = FirstSuccessor(successor).Index;
                     }
 
                     CopyResolver copyResolver = new CopyResolver();
@@ -699,8 +716,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
         {
             Operand register = GetRegister(current);
 
-            foreach (int usePosition in current.UsePositions())
+            IList<int> usePositions = current.UsePositions();
+            for (int i = usePositions.Count - 1; i >= 0; i--)
             {
+                int usePosition = -usePositions[i];
                 (_, Node operation) = GetOperationNode(usePosition);
 
                 for (int index = 0; index < operation.SourcesCount; index++)
@@ -743,7 +762,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
         {
             Debug.Assert(!interval.IsSpilled, "Spilled intervals are not allowed.");
 
-            return new Operand(
+            return OperandHelper.Register(
                 interval.Register.Index,
                 interval.Register.Type,
                 interval.Local.Type);
@@ -778,8 +797,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                 {
                     _operationNodes.Add((block.Operations, node));
 
-                    foreach (Operand dest in Destinations(node))
+                    for (int i = 0; i < node.DestinationsCount; i++)
                     {
+                        Operand dest = node.GetDestination(i);
                         if (dest.Kind == OperandKind.LocalVariable && visited.Add(dest))
                         {
                             dest.NumberLocal(_intervals.Count);
@@ -815,12 +835,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
             // Compute local live sets.
             for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
             {
-                BitMap liveGen  = new BitMap(mapSize);
-                BitMap liveKill = new BitMap(mapSize);
+                BitMap liveGen  = BitMapPool.Allocate(mapSize);
+                BitMap liveKill = BitMapPool.Allocate(mapSize);
 
                 for (Node node = block.Operations.First; node != null; node = node.ListNext)
                 {
-                    foreach (Operand source in Sources(node))
+                    Sources(node, (source) =>
                     {
                         int id = GetOperandId(source);
 
@@ -828,10 +848,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                         {
                             liveGen.Set(id);
                         }
-                    }
+                    });
 
-                    foreach (Operand dest in Destinations(node))
+                    for (int i = 0; i < node.DestinationsCount; i++)
                     {
+                        Operand dest = node.GetDestination(i);
                         liveKill.Set(GetOperandId(dest));
                     }
                 }
@@ -846,8 +867,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
             for (int index = 0; index < cfg.Blocks.Count; index++)
             {
-                blkLiveIn [index] = new BitMap(mapSize);
-                blkLiveOut[index] = new BitMap(mapSize);
+                blkLiveIn [index] = BitMapPool.Allocate(mapSize);
+                blkLiveOut[index] = BitMapPool.Allocate(mapSize);
             }
 
             bool modified;
@@ -862,12 +883,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
                     BitMap liveOut = blkLiveOut[block.Index];
 
-                    foreach (BasicBlock successor in Successors(block))
+                    if ((block.Next != null && liveOut.Set(blkLiveIn[block.Next.Index])) || 
+                        (block.Branch != null && liveOut.Set(blkLiveIn[block.Branch.Index])))
                     {
-                        if (liveOut.Set(blkLiveIn[successor.Index]))
-                        {
-                            modified = true;
-                        }
+                        modified = true;
                     }
 
                     BitMap liveIn = blkLiveIn[block.Index];
@@ -920,21 +939,22 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                 {
                     operationPos -= InstructionGap;
 
-                    foreach (Operand dest in Destinations(node))
+                    for (int i = 0; i < node.DestinationsCount; i++)
                     {
+                        Operand dest = node.GetDestination(i);
                         LiveInterval interval = _intervals[GetOperandId(dest)];
 
                         interval.SetStart(operationPos + 1);
                         interval.AddUsePosition(operationPos + 1);
                     }
 
-                    foreach (Operand source in Sources(node))
+                    Sources(node, (source) =>
                     {
                         LiveInterval interval = _intervals[GetOperandId(source)];
 
                         interval.AddRange(blockStart, operationPos + 1);
                         interval.AddUsePosition(operationPos);
-                    }
+                    });
 
                     if (node is Operation operation && operation.Instruction == Instruction.Call)
                     {
@@ -949,7 +969,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
         {
             while (mask != 0)
             {
-                int regIndex = BitUtils.LowestBitSet(mask);
+                int regIndex = BitOperations.TrailingZeroCount(mask);
 
                 Register callerSavedReg = new Register(regIndex, regType);
 
@@ -982,17 +1002,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
             return (register.Index << 1) | (register.Type == RegisterType.Vector ? 1 : 0);
         }
 
-        private static IEnumerable<BasicBlock> Successors(BasicBlock block)
+        private static BasicBlock FirstSuccessor(BasicBlock block)
         {
-            if (block.Next != null)
-            {
-                yield return block.Next;
-            }
-
-            if (block.Branch != null)
-            {
-                yield return block.Branch;
-            }
+            return block.Next ?? block.Branch;
         }
 
         private static IEnumerable<Node> BottomOperations(BasicBlock block)
@@ -1007,15 +1019,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
             }
         }
 
-        private static IEnumerable<Operand> Destinations(Node node)
-        {
-            for (int index = 0; index < node.DestinationsCount; index++)
-            {
-                yield return node.GetDestination(index);
-            }
-        }
-
-        private static IEnumerable<Operand> Sources(Node node)
+        private static void Sources(Node node, Action<Operand> action)
         {
             for (int index = 0; index < node.SourcesCount; index++)
             {
@@ -1023,7 +1027,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
                 if (IsLocalOrRegister(source.Kind))
                 {
-                    yield return source;
+                    action(source);
                 }
                 else if (source.Kind == OperandKind.Memory)
                 {
@@ -1031,12 +1035,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
                     if (memOp.BaseAddress != null)
                     {
-                        yield return memOp.BaseAddress;
+                        action(memOp.BaseAddress);
                     }
 
                     if (memOp.Index != null)
                     {
-                        yield return memOp.Index;
+                        action(memOp.Index);
                     }
                 }
             }
diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs b/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs
index 18858a7689..6e786061a1 100644
--- a/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs
+++ b/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Common;
 using ARMeilleure.IntermediateRepresentation;
 using System;
 using System.Collections.Generic;
@@ -12,7 +13,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
         private LiveInterval _parent;
 
-        private SortedSet<int> _usePositions;
+        private SortedIntegerList _usePositions;
 
         public int UsesCount => _usePositions.Count;
 
@@ -38,7 +39,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
             Local   = local;
             _parent = parent ?? this;
 
-            _usePositions = new SortedSet<int>();
+            _usePositions = new SortedIntegerList();
 
             _ranges = new List<LiveRange>();
 
@@ -196,7 +197,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 
         public void AddUsePosition(int position)
         {
-            _usePositions.Add(position);
+            // Inserts are in descending order, but ascending is faster for SortedIntegerList<>.
+            // We flip the ordering, then iterate backwards when using the final list.
+            _usePositions.Add(-position);
         }
 
         public bool Overlaps(int position)
@@ -247,9 +250,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
             return _childs.Values;
         }
 
-        public IEnumerable<int> UsePositions()
+        public IList<int> UsePositions()
         {
-            return _usePositions;
+            return _usePositions.GetList();
         }
 
         public int FirstUse()
@@ -259,20 +262,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                 return NotFound;
             }
 
-            return _usePositions.First();
+            return -_usePositions.Last();
         }
 
         public int NextUseAfter(int position)
         {
-            foreach (int usePosition in _usePositions)
-            {
-                if (usePosition >= position)
-                {
-                    return usePosition;
-                }
-            }
+            int index = _usePositions.FindLessEqualIndex(-position);
+            return (index >= 0) ? -_usePositions[index] : NotFound;
+        }
 
-            return NotFound;
+        public void RemoveAfter(int position)
+        {
+            int index = _usePositions.FindLessEqualIndex(-position);
+            _usePositions.RemoveRange(0, index + 1);
         }
 
         public LiveInterval Split(int position)
@@ -311,12 +313,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
                 _ranges.RemoveRange(splitIndex, count);
             }
 
-            foreach (int usePosition in _usePositions.Where(x => x >= position))
+            int addAfter = _usePositions.FindLessEqualIndex(-position);
+            for (int index = addAfter; index >= 0; index--)
             {
+                int usePosition = _usePositions[index];
                 right._usePositions.Add(usePosition);
             }
 
-            _usePositions.RemoveWhere(x => x >= position);
+            RemoveAfter(position);
 
             Debug.Assert(_ranges.Count != 0, "Left interval is empty after split.");
 
diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs
index 1d0a4c12ff..1bcab736fd 100644
--- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs
+++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs
@@ -9,6 +9,9 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
+using System.Numerics;
+
+using static ARMeilleure.IntermediateRepresentation.OperandHelper;
 
 namespace ARMeilleure.CodeGen.X86
 {
@@ -550,7 +553,7 @@ namespace ARMeilleure.CodeGen.X86
 
             if (operation.SourcesCount == 5) // CompareAndSwap128 has 5 sources, compared to CompareAndSwap64/32's 3.
             {
-                MemoryOperand memOp = new MemoryOperand(OperandType.I64, src1);
+                MemoryOperand memOp = MemoryOp(OperandType.I64, src1);
 
                 context.Assembler.Cmpxchg16b(memOp);
             }
@@ -561,7 +564,7 @@ namespace ARMeilleure.CodeGen.X86
 
                 EnsureSameType(src2, src3);
 
-                MemoryOperand memOp = new MemoryOperand(src3.Type, src1);
+                MemoryOperand memOp = MemoryOp(src3.Type, src1);
 
                 context.Assembler.Cmpxchg(memOp, src3);
             }
@@ -751,7 +754,7 @@ namespace ARMeilleure.CodeGen.X86
             // operand size constant to the destination register.
             context.JumpToNear(X86Condition.NotEqual);
 
-            context.Assembler.Mov(dest, new Operand(operandSize | operandMask), OperandType.I32);
+            context.Assembler.Mov(dest, Const(operandSize | operandMask), OperandType.I32);
 
             context.JumpHere();
 
@@ -759,7 +762,7 @@ namespace ARMeilleure.CodeGen.X86
             // starting from the least significant bit. However we are supposed to
             // return the number of 0 bits on the high end. So, we invert the result
             // of the BSR using XOR to get the correct value.
-            context.Assembler.Xor(dest, new Operand(operandMask), OperandType.I32);
+            context.Assembler.Xor(dest, Const(operandMask), OperandType.I32);
         }
 
         private static void GenerateCpuId(CodeGenContext context, Operation operation)
@@ -828,7 +831,7 @@ namespace ARMeilleure.CodeGen.X86
 
             Operand rsp = Register(X86Register.Rsp);
 
-            MemoryOperand memOp = new MemoryOperand(dest.Type, rsp, null, Multiplier.x1, offs);
+            MemoryOperand memOp = MemoryOp(dest.Type, rsp, null, Multiplier.x1, offs);
 
             GenerateLoad(context, memOp, dest);
         }
@@ -1027,7 +1030,7 @@ namespace ARMeilleure.CodeGen.X86
 
             Operand rsp = Register(X86Register.Rsp);
 
-            MemoryOperand memOp = new MemoryOperand(source.Type, rsp, null, Multiplier.x1, offs);
+            MemoryOperand memOp = MemoryOp(source.Type, rsp, null, Multiplier.x1, offs);
 
             GenerateStore(context, memOp, source);
         }
@@ -1043,7 +1046,7 @@ namespace ARMeilleure.CodeGen.X86
 
             Operand rsp = Register(X86Register.Rsp);
 
-            MemoryOperand memOp = new MemoryOperand(OperandType.I64, rsp, null, Multiplier.x1, offs);
+            MemoryOperand memOp = MemoryOp(OperandType.I64, rsp, null, Multiplier.x1, offs);
 
             context.Assembler.Lea(dest, memOp, OperandType.I64);
         }
@@ -1247,7 +1250,7 @@ namespace ARMeilleure.CodeGen.X86
 
                 if ((index & 1) != 0)
                 {
-                    context.Assembler.Shr(dest, new Operand(8), OperandType.I32);
+                    context.Assembler.Shr(dest, Const(8), OperandType.I32);
                 }
                 else
                 {
@@ -1286,7 +1289,7 @@ namespace ARMeilleure.CodeGen.X86
                     context.Assembler.Pinsrw(dest, dest, src2, (byte)(index * words + word));
 
                     // Move next word down.
-                    context.Assembler.Ror(src2, new Operand(16), src2.Type);
+                    context.Assembler.Ror(src2, Const(16), src2.Type);
                 }
             }
 
@@ -1594,7 +1597,7 @@ namespace ARMeilleure.CodeGen.X86
 
             while (mask != 0)
             {
-                int bit = BitUtils.LowestBitSet(mask);
+                int bit = BitOperations.TrailingZeroCount(mask);
 
                 context.Assembler.Push(Register((X86Register)bit));
 
@@ -1614,7 +1617,7 @@ namespace ARMeilleure.CodeGen.X86
 
             if (reservedStackSize != 0)
             {
-                context.Assembler.Sub(rsp, new Operand(reservedStackSize), OperandType.I64);
+                context.Assembler.Sub(rsp, Const(reservedStackSize), OperandType.I64);
             }
 
             int offset = reservedStackSize;
@@ -1623,11 +1626,11 @@ namespace ARMeilleure.CodeGen.X86
 
             while (mask != 0)
             {
-                int bit = BitUtils.LowestBitSet(mask);
+                int bit = BitOperations.TrailingZeroCount(mask);
 
                 offset -= 16;
 
-                MemoryOperand memOp = new MemoryOperand(OperandType.V128, rsp, null, Multiplier.x1, offset);
+                MemoryOperand memOp = MemoryOp(OperandType.V128, rsp, null, Multiplier.x1, offset);
 
                 context.Assembler.Movdqu(memOp, Xmm((X86Register)bit));
 
@@ -1653,11 +1656,11 @@ namespace ARMeilleure.CodeGen.X86
 
             while (mask != 0)
             {
-                int bit = BitUtils.LowestBitSet(mask);
+                int bit = BitOperations.TrailingZeroCount(mask);
 
                 offset -= 16;
 
-                MemoryOperand memOp = new MemoryOperand(OperandType.V128, rsp, null, Multiplier.x1, offset);
+                MemoryOperand memOp = MemoryOp(OperandType.V128, rsp, null, Multiplier.x1, offset);
 
                 context.Assembler.Movdqu(Xmm((X86Register)bit), memOp);
 
@@ -1666,7 +1669,7 @@ namespace ARMeilleure.CodeGen.X86
 
             if (reservedStackSize != 0)
             {
-                context.Assembler.Add(rsp, new Operand(reservedStackSize), OperandType.I64);
+                context.Assembler.Add(rsp, Const(reservedStackSize), OperandType.I64);
             }
 
             mask = CallingConvention.GetIntCalleeSavedRegisters() & context.AllocResult.IntUsedRegisters;
@@ -1698,7 +1701,7 @@ namespace ARMeilleure.CodeGen.X86
 
             for (int offset = PageSize; offset < size; offset += PageSize)
             {
-                Operand memOp = new MemoryOperand(OperandType.I32, rsp, null, Multiplier.x1, -offset);
+                Operand memOp = MemoryOp(OperandType.I32, rsp, null, Multiplier.x1, -offset);
 
                 context.Assembler.Mov(temp, memOp, OperandType.I32);
             }
@@ -1711,17 +1714,17 @@ namespace ARMeilleure.CodeGen.X86
                 return operand as MemoryOperand;
             }
 
-            return new MemoryOperand(type, operand);
+            return MemoryOp(type, operand);
         }
 
         private static Operand Register(X86Register register, OperandType type = OperandType.I64)
         {
-            return new Operand((int)register, RegisterType.Integer, type);
+            return OperandHelper.Register((int)register, RegisterType.Integer, type);
         }
 
         private static Operand Xmm(X86Register register)
         {
-            return new Operand((int)register, RegisterType.Vector, OperandType.V128);
+            return OperandHelper.Register((int)register, RegisterType.Vector, OperandType.V128);
         }
     }
 }
\ No newline at end of file
diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs
index e20fca9d60..7c1193491b 100644
--- a/ARMeilleure/CodeGen/X86/PreAllocator.cs
+++ b/ARMeilleure/CodeGen/X86/PreAllocator.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
 using System.Diagnostics;
 
 using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.OperationHelper;
 
 namespace ARMeilleure.CodeGen.X86
 {
@@ -223,8 +224,8 @@ namespace ARMeilleure.CodeGen.X86
                         // - The value at the memory location is loaded to RDX:RAX.
                         void SplitOperand(Operand source, Operand lr, Operand hr)
                         {
-                            nodes.AddBefore(node, new Operation(Instruction.VectorExtract, lr, source, Const(0)));
-                            nodes.AddBefore(node, new Operation(Instruction.VectorExtract, hr, source, Const(1)));
+                            nodes.AddBefore(node, Operation(Instruction.VectorExtract, lr, source, Const(0)));
+                            nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1)));
                         }
 
                         Operand rax = Gpr(X86Register.Rax, OperandType.I64);
@@ -235,8 +236,8 @@ namespace ARMeilleure.CodeGen.X86
                         SplitOperand(operation.GetSource(1), rax, rdx);
                         SplitOperand(operation.GetSource(2), rbx, rcx);
 
-                        node = nodes.AddAfter(node, new Operation(Instruction.VectorCreateScalar, dest, rax));
-                        node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert,       dest, dest, rdx, Const(1)));
+                        node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, rax));
+                        node = nodes.AddAfter(node, Operation(Instruction.VectorInsert,       dest, dest, rdx, Const(1)));
 
                         operation.SetDestinations(new Operand[] { rdx, rax });
 
@@ -252,11 +253,11 @@ namespace ARMeilleure.CodeGen.X86
 
                         Operand rax = Gpr(X86Register.Rax, expected.Type);
 
-                        nodes.AddBefore(node, new Operation(Instruction.Copy, rax, expected));
+                        nodes.AddBefore(node, Operation(Instruction.Copy, rax, expected));
 
                         operation.SetSources(new Operand[] { operation.GetSource(0), rax, operation.GetSource(2) });
 
-                        node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rax));
+                        node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
 
                         operation.Destination = rax;
                     }
@@ -278,16 +279,16 @@ namespace ARMeilleure.CodeGen.X86
                     Operand edx = Gpr(X86Register.Rdx, OperandType.I32);
 
                     // Value 0x01 = Version, family and feature information.
-                    nodes.AddBefore(node, new Operation(Instruction.Copy, eax, Const(1)));
+                    nodes.AddBefore(node, Operation(Instruction.Copy, eax, Const(1)));
 
                     // Copy results to the destination register.
                     // The values are split into 2 32-bits registers, we merge them
                     // into a single 64-bits register.
                     Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
 
-                    node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend32, dest, edx));
-                    node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft,    dest, dest, Const(32)));
-                    node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr,    dest, dest, rcx));
+                    node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, dest, edx));
+                    node = nodes.AddAfter(node, Operation(Instruction.ShiftLeft,    dest, dest, Const(32)));
+                    node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr,    dest, dest, rcx));
 
                     operation.SetDestinations(new Operand[] { eax, ebx, ecx, edx });
 
@@ -310,10 +311,10 @@ namespace ARMeilleure.CodeGen.X86
                         Operand rax = Gpr(X86Register.Rax, src1.Type);
                         Operand rdx = Gpr(X86Register.Rdx, src1.Type);
 
-                        nodes.AddBefore(node, new Operation(Instruction.Copy,    rax, src1));
-                        nodes.AddBefore(node, new Operation(Instruction.Clobber, rdx));
+                        nodes.AddBefore(node, Operation(Instruction.Copy,    rax, src1));
+                        nodes.AddBefore(node, Operation(Instruction.Clobber, rdx));
 
-                        node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rax));
+                        node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
 
                         operation.SetDestinations(new Operand[] { rdx, rax });
 
@@ -337,7 +338,7 @@ namespace ARMeilleure.CodeGen.X86
                     {
                         Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);
 
-                        nodes.AddBefore(node, new Operation(Instruction.Copy, xmm0, operation.GetSource(2)));
+                        nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, operation.GetSource(2)));
 
                         operation.SetSource(2, xmm0);
                     }
@@ -357,11 +358,11 @@ namespace ARMeilleure.CodeGen.X86
                     Operand rax = Gpr(X86Register.Rax, src1.Type);
                     Operand rdx = Gpr(X86Register.Rdx, src1.Type);
 
-                    nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));
+                    nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
 
                     operation.SetSource(0, rax);
 
-                    node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rdx));
+                    node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
 
                     operation.SetDestinations(new Operand[] { rdx, rax });
 
@@ -378,7 +379,7 @@ namespace ARMeilleure.CodeGen.X86
                     {
                         Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);
 
-                        nodes.AddBefore(node, new Operation(Instruction.Copy, rcx, operation.GetSource(1)));
+                        nodes.AddBefore(node, Operation(Instruction.Copy, rcx, operation.GetSource(1)));
 
                         operation.SetSource(1, rcx);
                     }
@@ -427,17 +428,17 @@ namespace ARMeilleure.CodeGen.X86
                     // local would be overwritten.
                     Operand temp = Local(dest.Type);
 
-                    nodes.AddBefore(node, new Operation(Instruction.Copy, temp, src1));
+                    nodes.AddBefore(node, Operation(Instruction.Copy, temp, src1));
 
                     operation.SetSource(0, temp);
 
-                    node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, temp));
+                    node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
 
                     operation.Destination = temp;
                 }
                 else
                 {
-                    nodes.AddBefore(node, new Operation(Instruction.Copy, dest, src1));
+                    nodes.AddBefore(node, Operation(Instruction.Copy, dest, src1));
 
                     operation.SetSource(0, dest);
                 }
@@ -451,17 +452,17 @@ namespace ARMeilleure.CodeGen.X86
                 {
                     Operand temp = Local(dest.Type);
 
-                    nodes.AddBefore(node, new Operation(Instruction.Copy, temp, src3));
+                    nodes.AddBefore(node, Operation(Instruction.Copy, temp, src3));
 
                     operation.SetSource(2, temp);
 
-                    node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, temp));
+                    node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
 
                     operation.Destination = temp;
                 }
                 else
                 {
-                    nodes.AddBefore(node, new Operation(Instruction.Copy, dest, src3));
+                    nodes.AddBefore(node, Operation(Instruction.Copy, dest, src3));
 
                     operation.SetSource(2, dest);
                 }
@@ -488,8 +489,8 @@ namespace ARMeilleure.CodeGen.X86
                 // and then use the 64-bits signed conversion instructions.
                 Operand zex = Local(OperandType.I64);
 
-                node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend32, zex,  source));
-                node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP,  dest, zex));
+                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex,  source));
+                node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP,  dest, zex));
             }
             else /* if (source.Type == OperandType.I64) */
             {
@@ -508,17 +509,17 @@ namespace ARMeilleure.CodeGen.X86
 
                 Operand lsbF = Local(dest.Type);
 
-                node = nodes.AddAfter(node, new Operation(Instruction.Copy, lsb,  source));
-                node = nodes.AddAfter(node, new Operation(Instruction.Copy, half, source));
+                node = nodes.AddAfter(node, Operation(Instruction.Copy, lsb,  source));
+                node = nodes.AddAfter(node, Operation(Instruction.Copy, half, source));
 
-                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseAnd,   lsb,  lsb,  Const(1L)));
-                node = nodes.AddAfter(node, new Operation(Instruction.ShiftRightUI, half, half, Const(1)));
+                node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd,   lsb,  lsb,  Const(1L)));
+                node = nodes.AddAfter(node, Operation(Instruction.ShiftRightUI, half, half, Const(1)));
 
-                node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP, lsbF, lsb));
-                node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP, dest, half));
+                node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, lsbF, lsb));
+                node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, half));
 
-                node = nodes.AddAfter(node, new Operation(Instruction.Add, dest, dest, dest));
-                node = nodes.AddAfter(node, new Operation(Instruction.Add, dest, dest, lsbF));
+                node = nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, dest));
+                node = nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, lsbF));
             }
 
             Delete(nodes, currentNode, operation);
@@ -541,7 +542,7 @@ namespace ARMeilleure.CodeGen.X86
 
             Operand res = Local(dest.Type);
 
-            node = nodes.AddAfter(node, new Operation(Instruction.VectorOne, res));
+            node = nodes.AddAfter(node, Operation(Instruction.VectorOne, res));
 
             if (dest.Type == OperandType.FP32)
             {
@@ -554,7 +555,7 @@ namespace ARMeilleure.CodeGen.X86
 
             node = nodes.AddAfter(node, new IntrinsicOperation(Intrinsic.X86Xorps, res, res, source));
 
-            node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, res));
+            node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, res));
 
             Delete(nodes, currentNode, operation);
 
@@ -580,26 +581,26 @@ namespace ARMeilleure.CodeGen.X86
             Operand temp1 = Local(OperandType.I32);
             Operand temp2 = Local(OperandType.I32);
 
-            node = nodes.AddAfter(node, new Operation(Instruction.Copy, temp2, src2));
+            node = nodes.AddAfter(node, Operation(Instruction.Copy, temp2, src2));
 
-            Operation vextOp = new Operation(Instruction.VectorExtract16, temp1, src1, Const(index >> 1));
+            Operation vextOp = Operation(Instruction.VectorExtract16, temp1, src1, Const(index >> 1));
 
             node = nodes.AddAfter(node, vextOp);
 
             if ((index & 1) != 0)
             {
-                node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend8, temp1, temp1));
-                node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft,   temp2, temp2, Const(8)));
-                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr,   temp1, temp1, temp2));
+                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp1, temp1));
+                node = nodes.AddAfter(node, Operation(Instruction.ShiftLeft,   temp2, temp2, Const(8)));
+                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr,   temp1, temp1, temp2));
             }
             else
             {
-                node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend8, temp2, temp2));
-                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseAnd,  temp1, temp1, Const(0xff00)));
-                node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr,   temp1, temp1, temp2));
+                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp2, temp2));
+                node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd,  temp1, temp1, Const(0xff00)));
+                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr,   temp1, temp1, temp2));
             }
 
-            Operation vinsOp = new Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));
+            Operation vinsOp = Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));
 
             node = nodes.AddAfter(node, vinsOp);
 
@@ -643,7 +644,7 @@ namespace ARMeilleure.CodeGen.X86
 
                 arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
 
-                Operation allocOp = new Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
+                Operation allocOp = Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
 
                 nodes.AddBefore(node, allocOp);
 
@@ -678,9 +679,9 @@ namespace ARMeilleure.CodeGen.X86
 
                     int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
 
-                    nodes.AddBefore(node, new Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
+                    nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
 
-                    Operation storeOp = new Operation(Instruction.Store, null, stackAddr, source);
+                    Operation storeOp = Operation(Instruction.Store, null, stackAddr, source);
 
                     HandleConstantCopy(nodes, nodes.AddBefore(node, storeOp), storeOp);
 
@@ -706,7 +707,7 @@ namespace ARMeilleure.CodeGen.X86
                     argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
                 }
 
-                Operation copyOp = new Operation(Instruction.Copy, argReg, source);
+                Operation copyOp = Operation(Instruction.Copy, argReg, source);
 
                 HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
 
@@ -719,9 +720,9 @@ namespace ARMeilleure.CodeGen.X86
             {
                 Operand source = operation.GetSource(index + 1);
 
-                Operand offset = new Operand((index + retArgs) * 8);
+                Operand offset = Const((index + retArgs) * 8);
 
-                Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);
+                Operation spillOp = Operation(Instruction.SpillArg, null, offset, source);
 
                 HandleConstantCopy(nodes, nodes.AddBefore(node, spillOp), spillOp);
             }
@@ -732,9 +733,9 @@ namespace ARMeilleure.CodeGen.X86
                 {
                     Operand retValueAddr = Local(OperandType.I64);
 
-                    nodes.AddBefore(node, new Operation(Instruction.Copy, retValueAddr, arg0Reg));
+                    nodes.AddBefore(node, Operation(Instruction.Copy, retValueAddr, arg0Reg));
 
-                    Operation loadOp = new Operation(Instruction.Load, dest, retValueAddr);
+                    Operation loadOp = Operation(Instruction.Load, dest, retValueAddr);
 
                     node = nodes.AddAfter(node, loadOp);
 
@@ -746,7 +747,7 @@ namespace ARMeilleure.CodeGen.X86
                         ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
                         : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
 
-                    Operation copyOp = new Operation(Instruction.Copy, dest, retReg);
+                    Operation copyOp = Operation(Instruction.Copy, dest, retReg);
 
                     node = nodes.AddAfter(node, copyOp);
 
@@ -803,8 +804,8 @@ namespace ARMeilleure.CodeGen.X86
                     Operand argReg  = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
                     Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 
-                    nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg,  source, Const(0)));
-                    nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
+                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg,  source, Const(0)));
+                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
 
                     continue;
                 }
@@ -815,7 +816,7 @@ namespace ARMeilleure.CodeGen.X86
                         ? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
                         : Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
 
-                    Operation copyOp = new Operation(Instruction.Copy, argReg, source);
+                    Operation copyOp = Operation(Instruction.Copy, argReg, source);
 
                     HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
 
@@ -823,9 +824,9 @@ namespace ARMeilleure.CodeGen.X86
                 }
                 else
                 {
-                    Operand offset = new Operand(stackOffset);
+                    Operand offset = Const(stackOffset);
 
-                    Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);
+                    Operation spillOp = Operation(Instruction.SpillArg, null, offset, source);
 
                     HandleConstantCopy(nodes, nodes.AddBefore(node, spillOp), spillOp);
 
@@ -840,8 +841,8 @@ namespace ARMeilleure.CodeGen.X86
                     Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(),     OperandType.I64);
                     Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 
-                    node = nodes.AddAfter(node, new Operation(Instruction.VectorCreateScalar, dest, retLReg));
-                    node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert,       dest, dest, retHReg, Const(1)));
+                    node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
+                    node = nodes.AddAfter(node, Operation(Instruction.VectorInsert,       dest, dest, retHReg, Const(1)));
 
                     operation.Destination = null;
                 }
@@ -851,7 +852,7 @@ namespace ARMeilleure.CodeGen.X86
                         ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
                         : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
 
-                    Operation copyOp = new Operation(Instruction.Copy, dest, retReg);
+                    Operation copyOp = Operation(Instruction.Copy, dest, retReg);
 
                     node = nodes.AddAfter(node, copyOp);
 
@@ -900,8 +901,8 @@ namespace ARMeilleure.CodeGen.X86
                     Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
                     Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 
-                    nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg, source, Const(0)));
-                    nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
+                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
+                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
 
                     continue;
                 }
@@ -912,7 +913,7 @@ namespace ARMeilleure.CodeGen.X86
                         ? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
                         : Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
 
-                    Operation copyOp = new Operation(Instruction.Copy, argReg, source);
+                    Operation copyOp = Operation(Instruction.Copy, argReg, source);
 
                     HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
 
@@ -929,7 +930,7 @@ namespace ARMeilleure.CodeGen.X86
             // callee saved register (which would be trashed on the epilogue).
             Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
 
-            Operation addrCopyOp = new Operation(Instruction.Copy, retReg, operation.GetSource(0));
+            Operation addrCopyOp = Operation(Instruction.Copy, retReg, operation.GetSource(0));
 
             nodes.AddBefore(node, addrCopyOp);
 
@@ -960,7 +961,7 @@ namespace ARMeilleure.CodeGen.X86
                     ? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
                     : Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
 
-                Operation copyOp = new Operation(Instruction.Copy, argReg, source);
+                Operation copyOp = Operation(Instruction.Copy, argReg, source);
 
                 HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
 
@@ -972,7 +973,7 @@ namespace ARMeilleure.CodeGen.X86
             // callee saved register (which would be trashed on the epilogue).
             Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
 
-            Operation addrCopyOp = new Operation(Instruction.Copy, retReg, operation.GetSource(0));
+            Operation addrCopyOp = Operation(Instruction.Copy, retReg, operation.GetSource(0));
 
             nodes.AddBefore(node, addrCopyOp);
 
@@ -1023,14 +1024,14 @@ namespace ARMeilleure.CodeGen.X86
                         pArg = Local(dest.Type);
                     }
 
-                    Operation copyOp = new Operation(Instruction.Copy, pArg, argReg);
+                    Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
 
                     cctx.Cfg.Entry.Operations.AddFirst(copyOp);
 
                     preservedArgs[index] = pArg;
                 }
 
-                Operation argCopyOp = new Operation(dest.Type == OperandType.V128
+                Operation argCopyOp = Operation(dest.Type == OperandType.V128
                     ? Instruction.Load
                     : Instruction.Copy, dest, preservedArgs[index]);
 
@@ -1107,8 +1108,8 @@ namespace ARMeilleure.CodeGen.X86
                         Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount),     OperandType.I64);
                         Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
 
-                        Operation copyL = new Operation(Instruction.VectorCreateScalar, pArg, argLReg);
-                        Operation copyH = new Operation(Instruction.VectorInsert,       pArg, pArg, argHReg, Const(1));
+                        Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
+                        Operation copyH = Operation(Instruction.VectorInsert,       pArg, pArg, argHReg, Const(1));
 
                         cctx.Cfg.Entry.Operations.AddFirst(copyH);
                         cctx.Cfg.Entry.Operations.AddFirst(copyL);
@@ -1123,7 +1124,7 @@ namespace ARMeilleure.CodeGen.X86
                             ? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
                             : Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
 
-                        Operation copyOp = new Operation(Instruction.Copy, pArg, argReg);
+                        Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
 
                         cctx.Cfg.Entry.Operations.AddFirst(copyOp);
 
@@ -1131,7 +1132,7 @@ namespace ARMeilleure.CodeGen.X86
                     }
                 }
 
-                Operation argCopyOp = new Operation(Instruction.Copy, dest, preservedArgs[index]);
+                Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
 
                 nodes.AddBefore(node, argCopyOp);
 
@@ -1171,7 +1172,7 @@ namespace ARMeilleure.CodeGen.X86
 
                     Operand arg0 = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
 
-                    Operation copyOp = new Operation(Instruction.Copy, preservedArg, arg0);
+                    Operation copyOp = Operation(Instruction.Copy, preservedArg, arg0);
 
                     cctx.Cfg.Entry.Operations.AddFirst(copyOp);
 
@@ -1187,18 +1188,18 @@ namespace ARMeilleure.CodeGen.X86
 
             if (source.Type == OperandType.V128)
             {
-                Operation retStoreOp = new Operation(Instruction.Store, null, retReg, source);
+                Operation retStoreOp = Operation(Instruction.Store, null, retReg, source);
 
                 nodes.AddBefore(node, retStoreOp);
             }
             else
             {
-                Operation retCopyOp = new Operation(Instruction.Copy, retReg, source);
+                Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
 
                 nodes.AddBefore(node, retCopyOp);
             }
 
-            operation.SetSources(System.Array.Empty<Operand>());
+            operation.SetSources(Array.Empty<Operand>());
         }
 
         private static void HandleReturnSystemVAbi(IntrusiveList<Node> nodes, Node node, Operation operation)
@@ -1215,8 +1216,8 @@ namespace ARMeilleure.CodeGen.X86
                 Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(),     OperandType.I64);
                 Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 
-                nodes.AddBefore(node, new Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
-                nodes.AddBefore(node, new Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
+                nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
+                nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
             }
             else
             {
@@ -1224,7 +1225,7 @@ namespace ARMeilleure.CodeGen.X86
                     ? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
                     : Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
 
-                Operation retCopyOp = new Operation(Instruction.Copy, retReg, source);
+                Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
 
                 nodes.AddBefore(node, retCopyOp);
             }
@@ -1236,7 +1237,7 @@ namespace ARMeilleure.CodeGen.X86
 
             Operand intConst = AddCopy(nodes, node, GetIntConst(source));
 
-            Operation copyOp = new Operation(Instruction.VectorCreateScalar, temp, intConst);
+            Operation copyOp = Operation(Instruction.VectorCreateScalar, temp, intConst);
 
             nodes.AddBefore(node, copyOp);
 
@@ -1247,7 +1248,7 @@ namespace ARMeilleure.CodeGen.X86
         {
             Operand temp = Local(source.Type);
 
-            Operation copyOp = new Operation(Instruction.Copy, temp, source);
+            Operation copyOp = Operation(Instruction.Copy, temp, source);
 
             nodes.AddBefore(node, copyOp);
 
diff --git a/ARMeilleure/CodeGen/X86/X86Optimizer.cs b/ARMeilleure/CodeGen/X86/X86Optimizer.cs
index c52541ca99..30fd6c714f 100644
--- a/ARMeilleure/CodeGen/X86/X86Optimizer.cs
+++ b/ARMeilleure/CodeGen/X86/X86Optimizer.cs
@@ -3,6 +3,7 @@ using ARMeilleure.IntermediateRepresentation;
 using ARMeilleure.Translation;
 
 using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.OperationHelper;
 
 namespace ARMeilleure.CodeGen.X86
 {
@@ -34,7 +35,7 @@ namespace ARMeilleure.CodeGen.X86
                         {
                             Operand temp = Local(src1.Type);
 
-                            Operation copyOp = new Operation(Instruction.Copy, temp, src1);
+                            Operation copyOp = Operation(Instruction.Copy, temp, src1);
 
                             block.Operations.AddBefore(operation, copyOp);
 
@@ -45,7 +46,7 @@ namespace ARMeilleure.CodeGen.X86
                         {
                             Operand temp = Local(src2.Type);
 
-                            Operation copyOp = new Operation(Instruction.Copy, temp, src2);
+                            Operation copyOp = Operation(Instruction.Copy, temp, src2);
 
                             block.Operations.AddBefore(operation, copyOp);
 
@@ -110,7 +111,7 @@ namespace ARMeilleure.CodeGen.X86
                 return null;
             }
 
-            return new MemoryOperand(type, baseOp, indexOp, scale, imm);
+            return MemoryOp(type, baseOp, indexOp, scale, imm);
         }
 
         private static int GetConstOp(ref Operand baseOp)
diff --git a/ARMeilleure/Common/BitMap.cs b/ARMeilleure/Common/BitMap.cs
index 9dff271b4c..3510053602 100644
--- a/ARMeilleure/Common/BitMap.cs
+++ b/ARMeilleure/Common/BitMap.cs
@@ -1,20 +1,50 @@
 using System.Collections;
 using System.Collections.Generic;
+using System.Numerics;
 
 namespace ARMeilleure.Common
 {
-    class BitMap : IEnumerable<int>
+    class BitMap : IEnumerator<int>
     {
-        private const int IntSize = 32;
+        private const int IntSize = 64;
         private const int IntMask = IntSize - 1;
 
-        private List<int> _masks;
+        private List<long> _masks;
+
+        private int _enumIndex;
+        private long _enumMask;
+        private int _enumBit;
+
+        public int Current => _enumIndex * IntSize + _enumBit;
+        object IEnumerator.Current => Current;
+
+        public BitMap()
+        {
+            _masks = new List<long>(0);
+        }
 
         public BitMap(int initialCapacity)
         {
             int count = (initialCapacity + IntMask) / IntSize;
 
-            _masks = new List<int>(count);
+            _masks = new List<long>(count);
+
+            while (count-- > 0)
+            {
+                _masks.Add(0);
+            }
+        }
+
+        public void Reset(int initialCapacity)
+        {
+            int count = (initialCapacity + IntMask) / IntSize;
+
+            if (count > _masks.Capacity)
+            {
+                _masks.Capacity = count;
+            }
+
+            _masks.Clear();
 
             while (count-- > 0)
             {
@@ -29,7 +59,7 @@ namespace ARMeilleure.Common
             int wordIndex = bit / IntSize;
             int wordBit   = bit & IntMask;
 
-            int wordMask = 1 << wordBit;
+            long wordMask = 1L << wordBit;
 
             if ((_masks[wordIndex] & wordMask) != 0)
             {
@@ -48,7 +78,7 @@ namespace ARMeilleure.Common
             int wordIndex = bit / IntSize;
             int wordBit   = bit & IntMask;
 
-            int wordMask = 1 << wordBit;
+            long wordMask = 1L << wordBit;
 
             _masks[wordIndex] &= ~wordMask;
         }
@@ -60,7 +90,7 @@ namespace ARMeilleure.Common
             int wordIndex = bit / IntSize;
             int wordBit   = bit & IntMask;
 
-            return (_masks[wordIndex] & (1 << wordBit)) != 0;
+            return (_masks[wordIndex] & (1L << wordBit)) != 0;
         }
 
         public bool Set(BitMap map)
@@ -71,7 +101,7 @@ namespace ARMeilleure.Common
 
             for (int index = 0; index < _masks.Count; index++)
             {
-                int newValue = _masks[index] | map._masks[index];
+                long newValue = _masks[index] | map._masks[index];
 
                 if (_masks[index] != newValue)
                 {
@@ -92,7 +122,7 @@ namespace ARMeilleure.Common
 
             for (int index = 0; index < _masks.Count; index++)
             {
-                int newValue = _masks[index] & ~map._masks[index];
+                long newValue = _masks[index] & ~map._masks[index];
 
                 if (_masks[index] != newValue)
                 {
@@ -105,6 +135,10 @@ namespace ARMeilleure.Common
             return modified;
         }
 
+ #region IEnumerable<long> Methods
+
+        // Note: The bit enumerator is embedded in this class to avoid creating garbage when enumerating.
+
         private void EnsureCapacity(int size)
         {
             while (_masks.Count * IntSize < size)
@@ -115,24 +149,37 @@ namespace ARMeilleure.Common
 
         public IEnumerator<int> GetEnumerator()
         {
-            for (int index = 0; index < _masks.Count; index++)
-            {
-                int mask = _masks[index];
-
-                while (mask != 0)
-                {
-                    int bit = BitUtils.LowestBitSet(mask);
-
-                    mask &= ~(1 << bit);
-
-                    yield return index * IntSize + bit;
-                }
-            }
+            Reset();
+            return this;
         }
 
-        IEnumerator IEnumerable.GetEnumerator()
+        public bool MoveNext()
         {
-            return GetEnumerator();
+            if (_enumMask != 0)
+            {
+                _enumMask &= ~(1L << _enumBit);
+            }
+            while (_enumMask == 0)
+            {
+                if (++_enumIndex >= _masks.Count)
+                {
+                    return false;
+                }
+                _enumMask = _masks[_enumIndex];
+            }
+            _enumBit = BitOperations.TrailingZeroCount(_enumMask);
+            return true;
         }
+
+        public void Reset()
+        {
+            _enumIndex = -1;
+            _enumMask = 0;
+            _enumBit = 0;
+        }
+
+        public void Dispose() { }
+
+#endregion
     }
 }
\ No newline at end of file
diff --git a/ARMeilleure/Common/BitMapPool.cs b/ARMeilleure/Common/BitMapPool.cs
new file mode 100644
index 0000000000..caba231716
--- /dev/null
+++ b/ARMeilleure/Common/BitMapPool.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace ARMeilleure.Common
+{
+    static class BitMapPool
+    {
+        public static BitMap Allocate(int initialCapacity)
+        {
+            BitMap result = ThreadStaticPool<BitMap>.Instance.Allocate();
+            result.Reset(initialCapacity);
+            return result;
+        }
+
+        public static void Release()
+        {
+            ThreadStaticPool<BitMap>.Instance.Clear();
+        }
+    }
+}
diff --git a/ARMeilleure/Common/BitUtils.cs b/ARMeilleure/Common/BitUtils.cs
index 7a29dcff7f..00fc6e5ba8 100644
--- a/ARMeilleure/Common/BitUtils.cs
+++ b/ARMeilleure/Common/BitUtils.cs
@@ -1,24 +1,13 @@
+using System.Numerics;
+
 namespace ARMeilleure.Common
 {
     static class BitUtils
     {
-        private const int DeBrujinSequence = 0x77cb531;
-
-        private static readonly int[] DeBrujinLbsLut;
-
         private static readonly sbyte[] HbsNibbleLut;
 
         static BitUtils()
         {
-            DeBrujinLbsLut = new int[32];
-
-            for (int index = 0; index < DeBrujinLbsLut.Length; index++)
-            {
-                uint lutIndex = (uint)(DeBrujinSequence * (1 << index)) >> 27;
-
-                DeBrujinLbsLut[lutIndex] = index;
-            }
-
             HbsNibbleLut = new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
         }
 
@@ -43,20 +32,7 @@ namespace ARMeilleure.Common
 
         public static int HighestBitSet(int value)
         {
-            if (value == 0)
-            {
-                return -1;
-            }
-
-            for (int bit = 31; bit >= 0; bit--)
-            {
-                if (((value >> bit) & 1) != 0)
-                {
-                    return bit;
-                }
-            }
-
-            return -1;
+            return 31 - BitOperations.LeadingZeroCount((uint)value);
         }
 
         public static int HighestBitSetNibble(int value)
@@ -64,18 +40,6 @@ namespace ARMeilleure.Common
             return HbsNibbleLut[value];
         }
 
-        public static int LowestBitSet(int value)
-        {
-            if (value == 0)
-            {
-                return -1;
-            }
-
-            int lsb = value & -value;
-
-            return DeBrujinLbsLut[(uint)(DeBrujinSequence * lsb) >> 27];
-        }
-
         public static long Replicate(long bits, int size)
         {
             long output = 0;
diff --git a/ARMeilleure/Common/SortedIntegerList.cs b/ARMeilleure/Common/SortedIntegerList.cs
new file mode 100644
index 0000000000..cceab62bfb
--- /dev/null
+++ b/ARMeilleure/Common/SortedIntegerList.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+
+namespace ARMeilleure.Common
+{
+    public class SortedIntegerList
+    {
+        private List<int> _items;
+
+        public int Count => _items.Count;
+
+        public int this[int index]
+        {
+            get
+            {
+                return _items[index];
+            }
+            set
+            {
+                _items[index] = value;
+            }
+        }
+
+        public SortedIntegerList()
+        {
+            _items = new List<int>();
+        }
+
+        public bool Add(int value)
+        {
+            if (_items.Count == 0 || value > Last())
+            {
+                _items.Add(value);
+                return true;
+            }
+            else
+            {
+                int index = _items.BinarySearch(value);
+                if (index >= 0)
+                {
+                    return false;
+                }
+
+                _items.Insert(-1 - index, value);
+                return true;
+            }
+        }
+
+        public int FindLessEqualIndex(int value)
+        {
+            int index = _items.BinarySearch(value);
+            return (index < 0) ? (-2 - index) : index;
+        }
+
+        public void RemoveRange(int index, int count)
+        {
+            if (count > 0)
+            {
+                _items.RemoveRange(index, count);
+            }
+        }
+
+        public int Last()
+        {
+            return _items[Count - 1];
+        }
+
+        public List<int> GetList()
+        {
+            return _items;
+        }
+    }
+}
diff --git a/ARMeilleure/Common/ThreadStaticPool.cs b/ARMeilleure/Common/ThreadStaticPool.cs
new file mode 100644
index 0000000000..cf3a7bb4d4
--- /dev/null
+++ b/ARMeilleure/Common/ThreadStaticPool.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace ARMeilleure.Common
+{
+    internal class ThreadStaticPool<T> where T : class, new()
+    {
+        private const int PoolSizeIncrement = 200;
+
+        [ThreadStatic]
+        private static ThreadStaticPool<T> _instance;
+        public static ThreadStaticPool<T> Instance
+        {
+            get
+            {
+                if (_instance == null)
+                {
+                    PreparePool(0); // So that we can still use a pool when blindly initializing one.
+                }
+                return _instance;
+            }
+        }
+
+        private static ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>> _pools = new ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>>();
+
+        private static Stack<ThreadStaticPool<T>> GetPools(int groupId)
+        {
+            return _pools.GetOrAdd(groupId, x => new Stack<ThreadStaticPool<T>>());
+        }
+
+        public static void PreparePool(int groupId)
+        {
+            // Prepare the pool for this thread, ideally using an existing one from the specified group.
+            if (_instance == null)
+            {
+                Stack<ThreadStaticPool<T>> pools = GetPools(groupId);
+                lock (pools)
+                {
+                    _instance = (pools.Count != 0) ? pools.Pop() : new ThreadStaticPool<T>(PoolSizeIncrement * 2);
+                }
+            }
+        }
+
+        public static void ReturnPool(int groupId)
+        {
+            // Reset and return the pool for this thread to the specified group.
+            Stack<ThreadStaticPool<T>> pools = GetPools(groupId);
+            lock (pools)
+            {
+                _instance.Clear();
+                pools.Push(_instance);
+                _instance = null;
+            }
+        }
+
+        private T[] _pool;
+        private int _poolUsed = -1;
+        private int _poolSize;
+
+        public ThreadStaticPool(int initialSize)
+        {
+            _pool = new T[initialSize];
+
+            for (int i = 0; i < initialSize; i++)
+            {
+                _pool[i] = new T();
+            }
+
+            _poolSize = initialSize;
+        }
+
+        public T Allocate()
+        {
+            int index = Interlocked.Increment(ref _poolUsed);
+            if (index >= _poolSize)
+            {
+                IncreaseSize();
+            }
+            return _pool[index];
+        }
+
+        private void IncreaseSize()
+        {
+            _poolSize += PoolSizeIncrement;
+
+            T[] newArray = new T[_poolSize];
+            Array.Copy(_pool, 0, newArray, 0, _pool.Length);
+
+            for (int i = _pool.Length; i < _poolSize; i++)
+            {
+                newArray[i] = new T();
+            }
+
+            Interlocked.Exchange(ref _pool, newArray);
+        }
+
+        public void Clear()
+        {
+            _poolUsed = -1;
+        }
+    }
+}
diff --git a/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs b/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs
index 742842fa72..56d07288a0 100644
--- a/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs
+++ b/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs
@@ -5,21 +5,25 @@ namespace ARMeilleure.IntermediateRepresentation
         public Operand BaseAddress { get; set; }
         public Operand Index       { get; set; }
 
-        public Multiplier Scale { get; }
+        public Multiplier Scale { get; private set; }
 
-        public int Displacement { get; }
+        public int Displacement { get; private set; }
 
-        public MemoryOperand(
+        public MemoryOperand() { }
+
+        public MemoryOperand With(
             OperandType type,
             Operand     baseAddress,
             Operand     index        = null,
             Multiplier  scale        = Multiplier.x1,
-            int         displacement = 0) : base(OperandKind.Memory, type)
+            int         displacement = 0)
         {
+            With(OperandKind.Memory, type);
             BaseAddress  = baseAddress;
             Index        = index;
             Scale        = scale;
             Displacement = displacement;
+            return this;
         }
     }
 }
\ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/Node.cs b/ARMeilleure/IntermediateRepresentation/Node.cs
index 37647c5600..9ce78c0955 100644
--- a/ARMeilleure/IntermediateRepresentation/Node.cs
+++ b/ARMeilleure/IntermediateRepresentation/Node.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 
 namespace ARMeilleure.IntermediateRepresentation
 {
@@ -11,39 +12,80 @@ namespace ARMeilleure.IntermediateRepresentation
         {
             get
             {
-                return _destinations.Length != 0 ? GetDestination(0) : null;
+                return _destinations.Count != 0 ? GetDestination(0) : null;
             }
             set
             {
                 if (value != null)
                 {
-                    SetDestinations(new Operand[] { value });
+                    SetDestination(value);
                 }
                 else
                 {
-                    SetDestinations(new Operand[0]);
+                    _destinations.Clear();
                 }
             }
         }
 
-        private Operand[] _destinations;
-        private Operand[] _sources;
+        private List<Operand> _destinations;
+        private List<Operand> _sources;
+        private bool _clearedDest;
 
-        public int DestinationsCount => _destinations.Length;
-        public int SourcesCount      => _sources.Length;
+        public int DestinationsCount => _destinations.Count;
+        public int SourcesCount      => _sources.Count;
 
-        public Node(Operand destination, int sourcesCount)
+        private void Resize(List<Operand> list, int size)
+        {
+            if (list.Count > size)
+            {
+                list.RemoveRange(size, list.Count - size);
+            } 
+            else
+            {
+                while (list.Count < size)
+                {
+                    list.Add(null);
+                }
+            }
+        }
+
+        public Node()
+        {
+            _destinations = new List<Operand>();
+            _sources = new List<Operand>();
+        }
+
+        public Node(Operand destination, int sourcesCount) : this()
         {
             Destination = destination;
 
-            _sources = new Operand[sourcesCount];
+            Resize(_sources, sourcesCount);
         }
 
-        public Node(Operand[] destinations, int sourcesCount)
+        private void Reset(int sourcesCount)
         {
+            _clearedDest = true;
+            _sources.Clear();
+            ListPrevious = null;
+            ListNext = null;
+
+            Resize(_sources, sourcesCount);
+        }
+
+        public Node With(Operand destination, int sourcesCount)
+        {
+            Reset(sourcesCount);
+            Destination = destination;
+
+            return this;
+        }
+
+        public Node With(Operand[] destinations, int sourcesCount)
+        {
+            Reset(sourcesCount);
             SetDestinations(destinations ?? throw new ArgumentNullException(nameof(destinations)));
 
-            _sources = new Operand[sourcesCount];
+            return this;
         }
 
         public Operand GetDestination(int index)
@@ -58,10 +100,15 @@ namespace ARMeilleure.IntermediateRepresentation
 
         public void SetDestination(int index, Operand destination)
         {
-            RemoveAssignment(_destinations[index]);
+            if (!_clearedDest) 
+            {
+                RemoveAssignment(_destinations[index]);
+            }
 
             AddAssignment(destination);
 
+            _clearedDest = false;
+
             _destinations[index] = destination;
         }
 
@@ -74,21 +121,37 @@ namespace ARMeilleure.IntermediateRepresentation
             _sources[index] = source;
         }
 
-        public void SetDestinations(Operand[] destinations)
+        private void RemoveOldDestinations()
         {
-            if (_destinations != null)
+            if (_destinations != null && !_clearedDest)
             {
-                for (int index = 0; index < _destinations.Length; index++)
+                for (int index = 0; index < _destinations.Count; index++)
                 {
                     RemoveAssignment(_destinations[index]);
                 }
+            }
+            _clearedDest = false;
+        }
 
-                _destinations = destinations;
-            }
-            else
+        public void SetDestination(Operand destination)
+        {
+            RemoveOldDestinations();
+
+            Resize(_destinations, 1);
+
+            _destinations[0] = destination;
+
+            if (destination.Kind == OperandKind.LocalVariable)
             {
-                _destinations = new Operand[destinations.Length];
+                destination.Assignments.Add(this);
             }
+        }
+
+        public void SetDestinations(Operand[] destinations)
+        {
+            RemoveOldDestinations();
+
+            Resize(_destinations, destinations.Length);
 
             for (int index = 0; index < destinations.Length; index++)
             {
@@ -100,14 +163,33 @@ namespace ARMeilleure.IntermediateRepresentation
             }
         }
 
-        public void SetSources(Operand[] sources)
+        private void RemoveOldSources()
         {
-            for (int index = 0; index < _sources.Length; index++)
+            for (int index = 0; index < _sources.Count; index++)
             {
                 RemoveUse(_sources[index]);
             }
+        }
 
-            _sources = new Operand[sources.Length];
+        public void SetSource(Operand source)
+        {
+            RemoveOldSources();
+
+            Resize(_sources, 1);
+
+            _sources[0] = source;
+
+            if (source.Kind == OperandKind.LocalVariable)
+            {
+                source.Uses.Add(this);
+            }
+        }
+
+        public void SetSources(Operand[] sources)
+        {
+            RemoveOldSources();
+
+            Resize(_sources, sources.Length);
 
             for (int index = 0; index < sources.Length; index++)
             {
diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs
index fe5bf0732c..2d5e762acb 100644
--- a/ARMeilleure/IntermediateRepresentation/Operand.cs
+++ b/ARMeilleure/IntermediateRepresentation/Operand.cs
@@ -5,16 +5,16 @@ namespace ARMeilleure.IntermediateRepresentation
 {
     class Operand
     {
-        public OperandKind Kind { get; }
+        public OperandKind Kind { get; private set; }
 
-        public OperandType Type { get; }
+        public OperandType Type { get; private set; }
 
         public ulong Value { get; private set; }
 
         public List<Node> Assignments { get; }
         public List<Node> Uses        { get; }
 
-        private Operand()
+        public Operand()
         {
             Assignments = new List<Node>();
             Uses        = new List<Node>();
@@ -26,42 +26,50 @@ namespace ARMeilleure.IntermediateRepresentation
             Type = type;
         }
 
-        public Operand(int value) : this(OperandKind.Constant, OperandType.I32)
+        public Operand With(OperandKind kind, OperandType type = OperandType.None, ulong value = 0)
         {
-            Value = (uint)value;
-        }
-
-        public Operand(uint value) : this(OperandKind.Constant, OperandType.I32)
-        {
-            Value = (uint)value;
-        }
-
-        public Operand(long value) : this(OperandKind.Constant, OperandType.I64)
-        {
-            Value = (ulong)value;
-        }
-
-        public Operand(ulong value) : this(OperandKind.Constant, OperandType.I64)
-        {
-            Value = value;
-        }
-
-        public Operand(float value) : this(OperandKind.Constant, OperandType.FP32)
-        {
-            Value = (ulong)BitConverter.SingleToInt32Bits(value);
-        }
-
-        public Operand(double value) : this(OperandKind.Constant, OperandType.FP64)
-        {
-            Value = (ulong)BitConverter.DoubleToInt64Bits(value);
-        }
-
-        public Operand(int index, RegisterType regType, OperandType type) : this()
-        {
-            Kind = OperandKind.Register;
+            Kind = kind;
             Type = type;
+            Value = value;
 
-            Value = (ulong)((int)regType << 24 | index);
+            Assignments.Clear();
+            Uses.Clear();
+            return this;
+        }
+
+        public Operand With(int value)
+        {
+            return With(OperandKind.Constant, OperandType.I32, (uint)value);
+        }
+
+        public Operand With(uint value)
+        {
+            return With(OperandKind.Constant, OperandType.I32, value);
+        }
+
+        public Operand With(long value)
+        {
+            return With(OperandKind.Constant, OperandType.I64, (ulong)value);
+        }
+
+        public Operand With(ulong value)
+        {
+            return With(OperandKind.Constant, OperandType.I64, value);
+        }
+
+        public Operand With(float value)
+        {
+            return With(OperandKind.Constant, OperandType.FP32, (ulong)BitConverter.SingleToInt32Bits(value));
+        }
+
+        public Operand With(double value)
+        {
+            return With(OperandKind.Constant, OperandType.FP64, (ulong)BitConverter.DoubleToInt64Bits(value));
+        }
+
+        public Operand With(int index, RegisterType regType, OperandType type)
+        {
+            return With(OperandKind.Register, type, (ulong)((int)regType << 24 | index));
         }
 
         public Register GetRegister()
diff --git a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs
index 4a930e03f4..cfdb32d988 100644
--- a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs
+++ b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs
@@ -1,68 +1,99 @@
-using ARMeilleure.State;
-using System;
+using ARMeilleure.Common;
 
 namespace ARMeilleure.IntermediateRepresentation
 {
     static class OperandHelper
     {
+        private static MemoryOperand MemoryOperand()
+        {
+            return ThreadStaticPool<MemoryOperand>.Instance.Allocate();
+        }
+
+        private static Operand Operand()
+        {
+            return ThreadStaticPool<Operand>.Instance.Allocate();
+        }
+
         public static Operand Const(OperandType type, long value)
         {
-            return type == OperandType.I32 ? new Operand((int)value) : new Operand(value);
+            return type == OperandType.I32 ? Operand().With((int)value) : Operand().With(value);
         }
 
         public static Operand Const(bool value)
         {
-            return new Operand(value ? 1 : 0);
+            return Operand().With(value ? 1 : 0);
         }
 
         public static Operand Const(int value)
         {
-            return new Operand(value);
+            return Operand().With(value);
         }
 
         public static Operand Const(uint value)
         {
-            return new Operand(value);
+            return Operand().With(value);
         }
 
         public static Operand Const(long value)
         {
-            return new Operand(value);
+            return Operand().With(value);
         }
 
         public static Operand Const(ulong value)
         {
-            return new Operand(value);
+            return Operand().With(value);
         }
 
         public static Operand ConstF(float value)
         {
-            return new Operand(value);
+            return Operand().With(value);
         }
 
         public static Operand ConstF(double value)
         {
-            return new Operand(value);
+            return Operand().With(value);
         }
 
         public static Operand Label()
         {
-            return new Operand(OperandKind.Label);
+            return Operand().With(OperandKind.Label);
         }
 
         public static Operand Local(OperandType type)
         {
-            return new Operand(OperandKind.LocalVariable, type);
+            return Operand().With(OperandKind.LocalVariable, type);
         }
 
         public static Operand Register(int index, RegisterType regType, OperandType type)
         {
-            return new Operand(index, regType, type);
+            return Operand().With(index, regType, type);
         }
 
         public static Operand Undef()
         {
-            return new Operand(OperandKind.Undefined);
+            return Operand().With(OperandKind.Undefined);
+        }
+
+        public static MemoryOperand MemoryOp(
+            OperandType type,
+            Operand baseAddress,
+            Operand index = null,
+            Multiplier scale = Multiplier.x1,
+            int displacement = 0)
+        {
+            return MemoryOperand().With(type, baseAddress, index, scale, displacement);
+        }
+
+        public static void PrepareOperandPool(bool highCq)
+        {
+            ThreadStaticPool<Operand>.PreparePool(highCq ? 1 : 0);
+            ThreadStaticPool<MemoryOperand>.PreparePool(highCq ? 1 : 0);
+        }
+
+        public static void ResetOperandPool(bool highCq)
+        {
+            ThreadStaticPool<Operand>.ReturnPool(highCq ? 1 : 0);
+            ThreadStaticPool<MemoryOperand>.ReturnPool(highCq ? 1 : 0);
         }
     }
 }
\ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/Operation.cs b/ARMeilleure/IntermediateRepresentation/Operation.cs
index 620bf3f6e2..4cdbe3261a 100644
--- a/ARMeilleure/IntermediateRepresentation/Operation.cs
+++ b/ARMeilleure/IntermediateRepresentation/Operation.cs
@@ -4,10 +4,12 @@ namespace ARMeilleure.IntermediateRepresentation
     {
         public Instruction Instruction { get; private set; }
 
+        public Operation() : base() { }
+
         public Operation(
             Instruction instruction,
             Operand destination,
-            params Operand[] sources) : base(destination, sources.Length)
+            Operand[] sources) : base(destination, sources.Length)
         {
             Instruction = instruction;
 
@@ -17,24 +19,78 @@ namespace ARMeilleure.IntermediateRepresentation
             }
         }
 
-        public Operation(
-            Instruction instruction,
-            Operand[] destinations,
-            Operand[] sources) : base(destinations, sources.Length)
+        public Operation With(Instruction instruction, Operand destination)
         {
+            With(destination, 0);
+            Instruction = instruction;
+            return this;
+        }
+
+        public Operation With(Instruction instruction, Operand destination, Operand[] sources)
+        {
+            With(destination, sources.Length);
             Instruction = instruction;
 
             for (int index = 0; index < sources.Length; index++)
             {
                 SetSource(index, sources[index]);
             }
+            return this;
+        }
+
+        public Operation With(Instruction instruction, Operand destination, 
+            Operand source0)
+        {
+            With(destination, 1);
+            Instruction = instruction;
+
+            SetSource(0, source0);
+            return this;
+        }
+
+        public Operation With(Instruction instruction, Operand destination,
+            Operand source0, Operand source1)
+        {
+            With(destination, 2);
+            Instruction = instruction;
+
+            SetSource(0, source0);
+            SetSource(1, source1);
+            return this;
+        }
+
+        public Operation With(Instruction instruction, Operand destination, 
+            Operand source0, Operand source1, Operand source2)
+        {
+            With(destination, 3);
+            Instruction = instruction;
+
+            SetSource(0, source0);
+            SetSource(1, source1);
+            SetSource(2, source2);
+            return this;
+        }
+
+        public Operation With(
+            Instruction instruction,
+            Operand[] destinations,
+            Operand[] sources)
+        {
+            With(destinations, sources.Length);
+            Instruction = instruction;
+
+            for (int index = 0; index < sources.Length; index++)
+            {
+                SetSource(index, sources[index]);
+            }
+            return this;
         }
 
         public void TurnIntoCopy(Operand source)
         {
             Instruction = Instruction.Copy;
 
-            SetSources(new Operand[] { source });
+            SetSource(source);
         }
     }
 }
\ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/OperationHelper.cs b/ARMeilleure/IntermediateRepresentation/OperationHelper.cs
new file mode 100644
index 0000000000..20c7d4efb8
--- /dev/null
+++ b/ARMeilleure/IntermediateRepresentation/OperationHelper.cs
@@ -0,0 +1,59 @@
+using ARMeilleure.Common;
+
+namespace ARMeilleure.IntermediateRepresentation
+{
+    static class OperationHelper
+    {
+        public static Operation Operation()
+        {
+            return ThreadStaticPool<Operation>.Instance.Allocate();
+        }
+
+        public static Operation Operation(Instruction instruction, Operand destination)
+        {
+            return Operation().With(instruction, destination);
+        }
+
+        public static Operation Operation(Instruction instruction, Operand destination,
+            Operand[] sources)
+        {
+            return Operation().With(instruction, destination, sources);
+        }
+
+        public static Operation Operation(Instruction instruction, Operand destination, 
+            Operand source0)
+        {
+            return Operation().With(instruction, destination, source0);
+        }
+
+        public static Operation Operation(Instruction instruction, Operand destination, 
+            Operand source0, Operand source1)
+        {
+            return Operation().With(instruction, destination, source0, source1);
+        }
+
+        public static Operation Operation(Instruction instruction, Operand destination,
+            Operand source0, Operand source1, Operand source2)
+        {
+            return Operation().With(instruction, destination, source0, source1, source2);
+        }
+
+        public static Operation Operation(
+            Instruction instruction,
+            Operand[] destinations,
+            Operand[] sources)
+        {
+            return Operation().With(instruction, destinations, sources);
+        }
+
+        public static void PrepareOperationPool(bool highCq)
+        {
+            ThreadStaticPool<Operation>.PreparePool(highCq ? 1 : 0);
+        }
+
+        public static void ResetOperationPool(bool highCq)
+        {
+            ThreadStaticPool<Operation>.ReturnPool(highCq ? 1 : 0);
+        }
+    }
+}
diff --git a/ARMeilleure/Translation/ControlFlowGraph.cs b/ARMeilleure/Translation/ControlFlowGraph.cs
index 37613eb495..16b406ab0d 100644
--- a/ARMeilleure/Translation/ControlFlowGraph.cs
+++ b/ARMeilleure/Translation/ControlFlowGraph.cs
@@ -141,7 +141,7 @@ namespace ARMeilleure.Translation
 
                 splitBlock2.Branch = successor;
 
-                splitBlock2.Operations.AddLast(new Operation(Instruction.Branch, null));
+                splitBlock2.Operations.AddLast(OperationHelper.Operation(Instruction.Branch, null));
 
                 Blocks.AddBefore(successor, splitBlock2);
             }
diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs
index a11d25a6db..d9e0a4edee 100644
--- a/ARMeilleure/Translation/EmitterContext.cs
+++ b/ARMeilleure/Translation/EmitterContext.cs
@@ -459,14 +459,63 @@ namespace ARMeilleure.Translation
             return Add(Instruction.ZeroExtend8, Local(type), op1);
         }
 
-        private Operand Add(Instruction inst, Operand dest = null, params Operand[] sources)
+        private void NewNextBlockIfNeeded()
         {
             if (_needsNewBlock)
             {
                 NewNextBlock();
             }
+        }
 
-            Operation operation = new Operation(inst, dest, sources);
+        private Operand Add(Instruction inst, Operand dest = null)
+        {
+            NewNextBlockIfNeeded();
+
+            Operation operation = OperationHelper.Operation(inst, dest);
+
+            _irBlock.Operations.AddLast(operation);
+
+            return dest;
+        }
+
+        private Operand Add(Instruction inst, Operand dest, Operand[] sources)
+        {
+            NewNextBlockIfNeeded();
+
+            Operation operation = OperationHelper.Operation(inst, dest, sources);
+
+            _irBlock.Operations.AddLast(operation);
+
+            return dest;
+        }
+
+        private Operand Add(Instruction inst, Operand dest, Operand source0)
+        {
+            NewNextBlockIfNeeded();
+
+            Operation operation = OperationHelper.Operation(inst, dest, source0);
+
+            _irBlock.Operations.AddLast(operation);
+
+            return dest;
+        }
+
+        private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1)
+        {
+            NewNextBlockIfNeeded();
+
+            Operation operation = OperationHelper.Operation(inst, dest, source0, source1);
+
+            _irBlock.Operations.AddLast(operation);
+
+            return dest;
+        }
+
+        private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1, Operand source2)
+        {
+            NewNextBlockIfNeeded();
+
+            Operation operation = OperationHelper.Operation(inst, dest, source0, source1, source2);
 
             _irBlock.Operations.AddLast(operation);
 
diff --git a/ARMeilleure/Translation/PriorityQueue.cs b/ARMeilleure/Translation/PriorityQueue.cs
index ab593dc07f..000a5009f4 100644
--- a/ARMeilleure/Translation/PriorityQueue.cs
+++ b/ARMeilleure/Translation/PriorityQueue.cs
@@ -4,28 +4,28 @@ namespace ARMeilleure.Translation
 {
     class PriorityQueue<T>
     {
-        private ConcurrentQueue<T>[] _queues;
+        private ConcurrentStack<T>[] _queues;
 
         public PriorityQueue(int priorities)
         {
-            _queues = new ConcurrentQueue<T>[priorities];
+            _queues = new ConcurrentStack<T>[priorities];
 
             for (int index = 0; index < priorities; index++)
             {
-                _queues[index] = new ConcurrentQueue<T>();
+                _queues[index] = new ConcurrentStack<T>();
             }
         }
 
         public void Enqueue(int priority, T value)
         {
-            _queues[priority].Enqueue(value);
+            _queues[priority].Push(value);
         }
 
         public bool TryDequeue(out T value)
         {
             for (int index = 0; index < _queues.Length; index++)
             {
-                if (_queues[index].TryDequeue(out value))
+                if (_queues[index].TryPop(out value))
                 {
                     return true;
                 }
diff --git a/ARMeilleure/Translation/RegisterUsage.cs b/ARMeilleure/Translation/RegisterUsage.cs
index 84dfce7b57..d512428564 100644
--- a/ARMeilleure/Translation/RegisterUsage.cs
+++ b/ARMeilleure/Translation/RegisterUsage.cs
@@ -3,6 +3,7 @@ using ARMeilleure.State;
 using System;
 
 using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.OperationHelper;
 
 namespace ARMeilleure.Translation
 {
@@ -299,16 +300,16 @@ namespace ARMeilleure.Translation
 
                 Operand addr = Local(OperandType.I64);
 
-                Operation loadOp = new Operation(Instruction.Load, dest, addr);
+                Operation loadOp = Operation(Instruction.Load, dest, addr);
 
                 block.Operations.AddFirst(loadOp);
 
-                Operation calcOffsOp = new Operation(Instruction.Add, addr, arg0, Const(offset));
+                Operation calcOffsOp = Operation(Instruction.Add, addr, arg0, Const(offset));
 
                 block.Operations.AddFirst(calcOffsOp);
             }
 
-            Operation loadArg0 = new Operation(Instruction.LoadArgument, arg0, Const(0));
+            Operation loadArg0 = Operation(Instruction.LoadArgument, arg0, Const(0));
 
             block.Operations.AddFirst(loadArg0);
         }
@@ -329,7 +330,7 @@ namespace ARMeilleure.Translation
 
             Operand arg0 = Local(OperandType.I64);
 
-            Operation loadArg0 = new Operation(Instruction.LoadArgument, arg0, Const(0));
+            Operation loadArg0 = Operation(Instruction.LoadArgument, arg0, Const(0));
 
             block.Append(loadArg0);
 
@@ -348,11 +349,11 @@ namespace ARMeilleure.Translation
 
                 Operand addr = Local(OperandType.I64);
 
-                Operation calcOffsOp = new Operation(Instruction.Add, addr, arg0, Const(offset));
+                Operation calcOffsOp = Operation(Instruction.Add, addr, arg0, Const(offset));
 
                 block.Append(calcOffsOp);
 
-                Operation storeOp = new Operation(Instruction.Store, null, addr, source);
+                Operation storeOp = Operation(Instruction.Store, null, addr, source);
 
                 block.Append(storeOp);
             }
@@ -362,15 +363,15 @@ namespace ARMeilleure.Translation
         {
             if (bit < RegsCount)
             {
-                return new Operand(bit, baseType, GetOperandType(baseType, mode));
+                return OperandHelper.Register(bit, baseType, GetOperandType(baseType, mode));
             }
             else if (baseType == RegisterType.Integer)
             {
-                return new Operand(bit & RegsMask, RegisterType.Flag, OperandType.I32);
+                return OperandHelper.Register(bit & RegsMask, RegisterType.Flag, OperandType.I32);
             }
             else if (baseType == RegisterType.Vector)
             {
-                return new Operand(bit & RegsMask, RegisterType.FpFlag, OperandType.I32);
+                return OperandHelper.Register(bit & RegsMask, RegisterType.FpFlag, OperandType.I32);
             }
             else
             {
diff --git a/ARMeilleure/Translation/SsaDeconstruction.cs b/ARMeilleure/Translation/SsaDeconstruction.cs
index 37d616252d..c3bcaf8c1c 100644
--- a/ARMeilleure/Translation/SsaDeconstruction.cs
+++ b/ARMeilleure/Translation/SsaDeconstruction.cs
@@ -2,6 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
 using System.Collections.Generic;
 
 using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.OperationHelper;
 
 namespace ARMeilleure.Translation
 {
@@ -25,12 +26,12 @@ namespace ARMeilleure.Translation
 
                         Operand source = phi.GetSource(index);
 
-                        predecessor.Append(new Operation(Instruction.Copy, local, source));
+                        predecessor.Append(Operation(Instruction.Copy, local, source));
 
                         phi.SetSource(index, null);
                     }
 
-                    Operation copyOp = new Operation(Instruction.Copy, phi.Destination, local);
+                    Operation copyOp = Operation(Instruction.Copy, phi.Destination, local);
 
                     block.Operations.AddBefore(node, copyOp);
 
diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs
index 9d534d58dd..053c7328f9 100644
--- a/ARMeilleure/Translation/Translator.cs
+++ b/ARMeilleure/Translation/Translator.cs
@@ -73,7 +73,7 @@ namespace ARMeilleure.Translation
                 // If we only have one rejit thread, it should be normal priority as highCq code is performance critical.
                 // TODO: Use physical cores rather than logical. This only really makes sense for processors with hyperthreading. Requires OS specific code.
                 int unboundedThreadCount = Math.Max(1, (Environment.ProcessorCount - 6) / 3);
-                int threadCount = Math.Min(3, unboundedThreadCount);
+                int threadCount = Math.Min(4, unboundedThreadCount);
                 for (int i = 0; i < threadCount; i++)
                 {
                     bool last = i != 0 && i == unboundedThreadCount - 1;
@@ -146,6 +146,9 @@ namespace ARMeilleure.Translation
         {
             ArmEmitterContext context = new ArmEmitterContext(_memory, _jumpTable, (long)address, highCq, Aarch32Mode.User);
 
+            OperandHelper.PrepareOperandPool(highCq);
+            OperationHelper.PrepareOperationPool(highCq);
+
             Logger.StartPass(PassName.Decoding);
 
             Block[] blocks = AlwaysTranslateFunctions
@@ -181,6 +184,9 @@ namespace ARMeilleure.Translation
 
             GuestFunction func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options);
 
+            OperandHelper.ResetOperandPool(highCq);
+            OperationHelper.ResetOperationPool(highCq);
+
             return new TranslatedFunction(func, rejit: !highCq);
         }