private static int GetConstOp(ref Operand baseOp) { Operation operation = GetAsgOpWithInst(baseOp, Instruction.Add); if (operation == null) { 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 64-bits constant, then we can't optimize it further, // as we can't encode a 64-bits immediate on the memory operand. if (CodeGenCommon.IsLongConst(constOp)) { return(0); } baseOp = otherOp; return(constOp.AsInt32()); }
private static void HandleConstantCopy(IntrusiveList <Node> nodes, Node node, Operation operation) { if (operation.SourcesCount == 0 || IsIntrinsic(operation.Instruction)) { return; } Instruction inst = operation.Instruction; Operand src1 = operation.GetSource(0); Operand src2; if (src1.Kind == OperandKind.Constant) { if (!src1.Type.IsInteger()) { // Handle non-integer types (FP32, FP64 and V128). // For instructions without an immediate operand, we do the following: // - Insert a copy with the constant value (as integer) to a GPR. // - Insert a copy from the GPR to a XMM register. // - Replace the constant use with the XMM register. src1 = AddXmmCopy(nodes, node, src1); operation.SetSource(0, src1); } else if (!HasConstSrc1(inst)) { // Handle integer types. // Most ALU instructions accepts a 32-bits immediate on the second operand. // We need to ensure the following: // - If the constant is on operand 1, we need to move it. // -- But first, we try to swap operand 1 and 2 if the instruction is commutative. // -- Doing so may allow us to encode the constant as operand 2 and avoid a copy. // - If the constant is on operand 2, we check if the instruction supports it, // if not, we also add a copy. 64-bits constants are usually not supported. if (IsCommutative(inst)) { src2 = operation.GetSource(1); Operand temp = src1; src1 = src2; src2 = temp; operation.SetSource(0, src1); operation.SetSource(1, src2); } if (src1.Kind == OperandKind.Constant) { src1 = AddCopy(nodes, node, src1); operation.SetSource(0, src1); } } } if (operation.SourcesCount < 2) { return; } src2 = operation.GetSource(1); if (src2.Kind == OperandKind.Constant) { if (!src2.Type.IsInteger()) { src2 = AddXmmCopy(nodes, node, src2); operation.SetSource(1, src2); } else if (!HasConstSrc2(inst) || CodeGenCommon.IsLongConst(src2)) { src2 = AddCopy(nodes, node, src2); operation.SetSource(1, src2); } } }
public static void RunPass(ControlFlowGraph cfg) { for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) { Node nextNode; for (Node node = block.Operations.First; node != null; node = nextNode) { nextNode = node.ListNext; if (!(node is Operation operation)) { continue; } // Insert copies for constants that can't fit on a 32-bits immediate. // Doing this early unblocks a few optimizations. if (operation.Instruction == Instruction.Add) { Operand src1 = operation.GetSource(0); Operand src2 = operation.GetSource(1); if (src1.Kind == OperandKind.Constant && (src1.Relocatable || CodeGenCommon.IsLongConst(src1))) { Operand temp = Local(src1.Type); Operation copyOp = Operation(Instruction.Copy, temp, src1); block.Operations.AddBefore(operation, copyOp); operation.SetSource(0, temp); } if (src2.Kind == OperandKind.Constant && (src2.Relocatable || CodeGenCommon.IsLongConst(src2))) { Operand temp = Local(src2.Type); Operation copyOp = Operation(Instruction.Copy, temp, src2); block.Operations.AddBefore(operation, copyOp); operation.SetSource(1, temp); } } // Try to fold something like: // shl rbx, 2 // add rax, rbx // add rax, 0xcafe // mov rax, [rax] // Into: // mov rax, [rax+rbx*4+0xcafe] if (IsMemoryLoadOrStore(operation.Instruction)) { OperandType type; if (operation.Destination != null) { type = operation.Destination.Type; } else { type = operation.GetSource(1).Type; } MemoryOperand memOp = GetMemoryOperandOrNull(operation.GetSource(0), type); if (memOp != null) { operation.SetSource(0, memOp); } } } } Optimizer.RemoveUnusedNodes(cfg); }
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-bits 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 || CodeGenCommon.IsLongConst(src1))) { node.SetSource(0, GetConstantCopy(block, node, src1)); } if (src2.Kind == OperandKind.Constant && (src2.Relocatable || CodeGenCommon.IsLongConst(src2))) { node.SetSource(1, GetConstantCopy(block, node, src2)); } } // Try to fold something like: // shl rbx, 2 // add rax, rbx // add rax, 0xcafe // mov rax, [rax] // Into: // mov rax, [rax+rbx*4+0xcafe] 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); }