aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs')
-rw-r--r--ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs270
1 files changed, 0 insertions, 270 deletions
diff --git a/ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs b/ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs
deleted file mode 100644
index fdd4d024..00000000
--- a/ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs
+++ /dev/null
@@ -1,270 +0,0 @@
-using ARMeilleure.CodeGen.Optimizations;
-using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.Translation;
-using System.Collections.Generic;
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
-
-namespace ARMeilleure.CodeGen.Arm64
-{
- static class Arm64Optimizer
- {
- private const int MaxConstantUses = 10000;
-
- public static void RunPass(ControlFlowGraph cfg)
- {
- var constants = new Dictionary<ulong, Operand>();
-
- Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
- {
- // If the constant has many uses, we also force a new constant mov to be added, in order
- // to avoid overflow of the counts field (that is limited to 16 bits).
- if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
- {
- constant = Local(source.Type);
-
- Operation copyOp = Operation(Instruction.Copy, constant, source);
-
- block.Operations.AddBefore(operation, copyOp);
-
- constants[source.Value] = constant;
- }
-
- return constant;
- }
-
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- constants.Clear();
-
- Operation nextNode;
-
- for (Operation node = block.Operations.First; node != default; node = nextNode)
- {
- nextNode = node.ListNext;
-
- // Insert copies for constants that can't fit on a 32-bit immediate.
- // Doing this early unblocks a few optimizations.
- if (node.Instruction == Instruction.Add)
- {
- Operand src1 = node.GetSource(0);
- Operand src2 = node.GetSource(1);
-
- if (src1.Kind == OperandKind.Constant && (src1.Relocatable || ConstTooLong(src1, OperandType.I32)))
- {
- node.SetSource(0, GetConstantCopy(block, node, src1));
- }
-
- if (src2.Kind == OperandKind.Constant && (src2.Relocatable || ConstTooLong(src2, OperandType.I32)))
- {
- node.SetSource(1, GetConstantCopy(block, node, src2));
- }
- }
-
- // Try to fold something like:
- // lsl x1, x1, #2
- // add x0, x0, x1
- // ldr x0, [x0]
- // add x2, x2, #16
- // ldr x2, [x2]
- // Into:
- // ldr x0, [x0, x1, lsl #2]
- // ldr x2, [x2, #16]
- if (IsMemoryLoadOrStore(node.Instruction))
- {
- OperandType type;
-
- if (node.Destination != default)
- {
- type = node.Destination.Type;
- }
- else
- {
- type = node.GetSource(1).Type;
- }
-
- Operand memOp = GetMemoryOperandOrNull(node.GetSource(0), type);
-
- if (memOp != default)
- {
- node.SetSource(0, memOp);
- }
- }
- }
- }
-
- Optimizer.RemoveUnusedNodes(cfg);
- }
-
- private static Operand GetMemoryOperandOrNull(Operand addr, OperandType type)
- {
- Operand baseOp = addr;
-
- // First we check if the address is the result of a local X with immediate
- // addition. If that is the case, then the baseOp is X, and the memory operand immediate
- // becomes the addition immediate. Otherwise baseOp keeps being the address.
- int imm = GetConstOp(ref baseOp, type);
- if (imm != 0)
- {
- return MemoryOp(type, baseOp, default, Multiplier.x1, imm);
- }
-
- // Now we check if the baseOp is the result of a local Y with a local Z addition.
- // If that is the case, we now set baseOp to Y and indexOp to Z. We further check
- // if Z is the result of a left shift of local W by a value == 0 or == Log2(AccessSize),
- // if that is the case, we set indexOp to W and adjust the scale value of the memory operand
- // to match that of the left shift.
- // There is one missed case, which is the address being a shift result, but this is
- // probably not worth optimizing as it should never happen.
- (Operand indexOp, Multiplier scale) = GetIndexOp(ref baseOp, type);
-
- // If baseOp is still equal to address, then there's nothing that can be optimized.
- if (baseOp == addr)
- {
- return default;
- }
-
- return MemoryOp(type, baseOp, indexOp, scale, 0);
- }
-
- private static int GetConstOp(ref Operand baseOp, OperandType accessType)
- {
- Operation operation = GetAsgOpWithInst(baseOp, Instruction.Add);
-
- if (operation == default)
- {
- return 0;
- }
-
- Operand src1 = operation.GetSource(0);
- Operand src2 = operation.GetSource(1);
-
- Operand constOp;
- Operand otherOp;
-
- if (src1.Kind == OperandKind.Constant && src2.Kind == OperandKind.LocalVariable)
- {
- constOp = src1;
- otherOp = src2;
- }
- else if (src1.Kind == OperandKind.LocalVariable && src2.Kind == OperandKind.Constant)
- {
- constOp = src2;
- otherOp = src1;
- }
- else
- {
- return 0;
- }
-
- // If we have addition by a constant that we can't encode on the instruction,
- // then we can't optimize it further.
- if (ConstTooLong(constOp, accessType))
- {
- return 0;
- }
-
- baseOp = otherOp;
-
- return constOp.AsInt32();
- }
-
- private static (Operand, Multiplier) GetIndexOp(ref Operand baseOp, OperandType accessType)
- {
- Operand indexOp = default;
-
- Multiplier scale = Multiplier.x1;
-
- Operation addOp = GetAsgOpWithInst(baseOp, Instruction.Add);
-
- if (addOp == default)
- {
- return (indexOp, scale);
- }
-
- Operand src1 = addOp.GetSource(0);
- Operand src2 = addOp.GetSource(1);
-
- if (src1.Kind != OperandKind.LocalVariable || src2.Kind != OperandKind.LocalVariable)
- {
- return (indexOp, scale);
- }
-
- baseOp = src1;
- indexOp = src2;
-
- Operation shlOp = GetAsgOpWithInst(src1, Instruction.ShiftLeft);
-
- bool indexOnSrc2 = false;
-
- if (shlOp == default)
- {
- shlOp = GetAsgOpWithInst(src2, Instruction.ShiftLeft);
-
- indexOnSrc2 = true;
- }
-
- if (shlOp != default)
- {
- Operand shSrc = shlOp.GetSource(0);
- Operand shift = shlOp.GetSource(1);
-
- int maxShift = Assembler.GetScaleForType(accessType);
-
- if (shSrc.Kind == OperandKind.LocalVariable &&
- shift.Kind == OperandKind.Constant &&
- (shift.Value == 0 || shift.Value == (ulong)maxShift))
- {
- scale = shift.Value switch
- {
- 1 => Multiplier.x2,
- 2 => Multiplier.x4,
- 3 => Multiplier.x8,
- 4 => Multiplier.x16,
- _ => Multiplier.x1
- };
-
- baseOp = indexOnSrc2 ? src1 : src2;
- indexOp = shSrc;
- }
- }
-
- return (indexOp, scale);
- }
-
- private static Operation GetAsgOpWithInst(Operand op, Instruction inst)
- {
- // If we have multiple assignments, folding is not safe
- // as the value may be different depending on the
- // control flow path.
- if (op.AssignmentsCount != 1)
- {
- return default;
- }
-
- Operation asgOp = op.Assignments[0];
-
- if (asgOp.Instruction != inst)
- {
- return default;
- }
-
- return asgOp;
- }
-
- private static bool IsMemoryLoadOrStore(Instruction inst)
- {
- return inst == Instruction.Load || inst == Instruction.Store;
- }
-
- private static bool ConstTooLong(Operand constOp, OperandType accessType)
- {
- if ((uint)constOp.Value != constOp.Value)
- {
- return true;
- }
-
- return !CodeGenCommon.ConstFitsOnUImm12(constOp.AsInt32(), accessType);
- }
- }
-}