From c170e0f01c964d9d0569222621814c46fcdfd586 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Thu, 30 May 2019 02:45:15 -0300 Subject: [PATCH] Implement UMULH and SMULH, with new IR instructions --- ARMeilleure/CodeGen/X86/Assembler.cs | 12 ++++++ ARMeilleure/CodeGen/X86/CodeGenerator.cs | 12 ++++++ ARMeilleure/CodeGen/X86/PreAllocator.cs | 39 ++++++++++++++----- ARMeilleure/CodeGen/X86/X86Instruction.cs | 2 + ARMeilleure/Decoders/OpCodeTable.cs | 4 +- ARMeilleure/Instructions/InstEmitMul.cs | 24 ++++++++++++ .../IntermediateRepresentation/Instruction.cs | 2 + ARMeilleure/Translation/EmitterContext.cs | 10 +++++ 8 files changed, 93 insertions(+), 12 deletions(-) diff --git a/ARMeilleure/CodeGen/X86/Assembler.cs b/ARMeilleure/CodeGen/X86/Assembler.cs index e9eb4d1a71..848a4d3bfa 100644 --- a/ARMeilleure/CodeGen/X86/Assembler.cs +++ b/ARMeilleure/CodeGen/X86/Assembler.cs @@ -66,6 +66,7 @@ namespace ARMeilleure.CodeGen.X86 Add(X86Instruction.Div, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0600f7, InstFlags.None)); Add(X86Instruction.Idiv, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0700f7, InstFlags.None)); Add(X86Instruction.Imul, new InstInfo(BadOp, 0x00006b, 0x000069, BadOp, 0x000faf, InstFlags.None)); + Add(X86Instruction.Imul128, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0500f7, InstFlags.None)); Add(X86Instruction.Mov, new InstInfo(0x000089, BadOp, 0x0000c7, 0x0000b8, 0x00008b, InstFlags.None)); Add(X86Instruction.Mov16, new InstInfo(0x000089, BadOp, 0x0000c7, BadOp, 0x00008b, InstFlags.None)); Add(X86Instruction.Mov8, new InstInfo(0x000088, 0x0000c6, BadOp, BadOp, 0x00008a, InstFlags.None)); @@ -74,6 +75,7 @@ namespace ARMeilleure.CodeGen.X86 Add(X86Instruction.Movsx8, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fbe, InstFlags.None)); Add(X86Instruction.Movzx16, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fb7, InstFlags.None)); Add(X86Instruction.Movzx8, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fb6, InstFlags.None)); + Add(X86Instruction.Mul128, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0400f7, InstFlags.None)); Add(X86Instruction.Neg, new InstInfo(0x0300f7, BadOp, BadOp, BadOp, BadOp, InstFlags.None)); Add(X86Instruction.Not, new InstInfo(0x0200f7, BadOp, BadOp, BadOp, BadOp, InstFlags.None)); Add(X86Instruction.Or, new InstInfo(0x000009, 0x010083, 0x010081, BadOp, 0x00000b, InstFlags.None)); @@ -152,6 +154,11 @@ namespace ARMeilleure.CodeGen.X86 WriteInstruction(null, source, X86Instruction.Idiv); } + public void Imul(Operand source) + { + WriteInstruction(null, source, X86Instruction.Imul128); + } + public void Imul(Operand dest, Operand source) { if (source.Kind != OperandKind.Register) @@ -272,6 +279,11 @@ namespace ARMeilleure.CodeGen.X86 WriteInstruction(dest, source, X86Instruction.Movzx8); } + public void Mul(Operand source) + { + WriteInstruction(null, source, X86Instruction.Mul128); + } + public void Neg(Operand dest) { WriteInstruction(dest, null, X86Instruction.Neg); diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs index 6b2bff4321..f43d59e0c8 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -50,6 +50,8 @@ namespace ARMeilleure.CodeGen.X86 Add(Instruction.LoadZx16, GenerateLoadZx16); Add(Instruction.LoadZx8, GenerateLoadZx8); Add(Instruction.Multiply, GenerateMultiply); + Add(Instruction.Multiply64HighSI, GenerateMultiply64HighSI); + Add(Instruction.Multiply64HighUI, GenerateMultiply64HighUI); Add(Instruction.Negate, GenerateNegate); Add(Instruction.Return, GenerateReturn); Add(Instruction.RotateRight, GenerateRotateRight); @@ -410,6 +412,16 @@ namespace ARMeilleure.CodeGen.X86 } } + private static void GenerateMultiply64HighSI(CodeGenContext context, Operation operation) + { + context.Assembler.Imul(operation.GetSource(1)); + } + + private static void GenerateMultiply64HighUI(CodeGenContext context, Operation operation) + { + context.Assembler.Mul(operation.GetSource(1)); + } + private static void GenerateNegate(CodeGenContext context, Operation operation) { context.Assembler.Neg(operation.Dest); diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs index 2a348b6ce7..1fc9a1dc24 100644 --- a/ARMeilleure/CodeGen/X86/PreAllocator.cs +++ b/ARMeilleure/CodeGen/X86/PreAllocator.cs @@ -193,7 +193,9 @@ namespace ARMeilleure.CodeGen.X86 operation.SetSource(0, rax); - Clobber(node, X86Register.Rdx); + Operation clobberCopyOp = new Operation(Instruction.Copy, rdx, rdx); + + node.List.AddBefore(node, clobberCopyOp); Operation destCopyOp = new Operation(Instruction.Copy, dest, rax); @@ -202,6 +204,32 @@ namespace ARMeilleure.CodeGen.X86 operation.Dest = rax; } + //Handle the many restrictions of the i64 * i64 = i128 multiply instructions: + //- The multiplicand is always in RAX. + //- The lower 64-bits of the result is always in RAX. + //- The higher 64-bits of the result is always in RDX. + if (inst == Instruction.Multiply64HighSI || inst == Instruction.Multiply64HighUI) + { + Operand rax = Gpr(X86Register.Rax, src1.Type); + Operand rdx = Gpr(X86Register.Rdx, src1.Type); + + Operation srcCopyOp = new Operation(Instruction.Copy, rax, src1); + + node.List.AddBefore(node, srcCopyOp); + + operation.SetSource(0, rax); + + Operation destCopyOp = new Operation(Instruction.Copy, dest, rdx); + + node.List.AddAfter(node, destCopyOp); + + Operation clobberCopyOp = new Operation(Instruction.Copy, rax, rax); + + node.List.AddAfter(node, clobberCopyOp); + + operation.Dest = rdx; + } + //The only allowed shift register is CL. if (inst.IsShift() && operation.GetSource(1).Kind == OperandKind.LocalVariable) { @@ -262,15 +290,6 @@ namespace ARMeilleure.CodeGen.X86 return temp; } - private static void Clobber(LinkedListNode node, X86Register register) - { - Operand reg = Gpr(register, OperandType.I32); - - Operation copyOp = new Operation(Instruction.Copy, reg, reg); - - node.List.AddBefore(node, copyOp); - } - private static bool IsLongConst(Operand operand) { long value = operand.Type == OperandType.I32 ? operand.AsInt32() diff --git a/ARMeilleure/CodeGen/X86/X86Instruction.cs b/ARMeilleure/CodeGen/X86/X86Instruction.cs index 26d016c179..872adc67f2 100644 --- a/ARMeilleure/CodeGen/X86/X86Instruction.cs +++ b/ARMeilleure/CodeGen/X86/X86Instruction.cs @@ -11,6 +11,7 @@ namespace ARMeilleure.CodeGen.X86 Div, Idiv, Imul, + Imul128, Mov, Mov16, Mov8, @@ -19,6 +20,7 @@ namespace ARMeilleure.CodeGen.X86 Movsx8, Movzx16, Movzx8, + Mul128, Neg, Not, Or, diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index 08f9ade886..cc198c7c8f 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -158,7 +158,7 @@ namespace ARMeilleure.Decoders SetA64("x0011010110xxxxx000011xxxxxxxxxx", InstName.Sdiv, InstEmit.Sdiv, typeof(OpCodeDiv)); SetA64("10011011001xxxxx0xxxxxxxxxxxxxxx", InstName.Smaddl, InstEmit.Smaddl, typeof(OpCodeMul)); SetA64("10011011001xxxxx1xxxxxxxxxxxxxxx", InstName.Smsubl, InstEmit.Smsubl, typeof(OpCodeMul)); - SetA64("10011011010xxxxx0xxxxxxxxxxxxxxx", InstName.Smulh, null, typeof(OpCodeMul)); + SetA64("10011011010xxxxx0xxxxxxxxxxxxxxx", InstName.Smulh, InstEmit.Smulh, typeof(OpCodeMul)); SetA64("xx001000100xxxxx1xxxxxxxxxxxxxxx", InstName.Stlr, null, typeof(OpCodeMemEx)); SetA64("1x001000001xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxp, null, typeof(OpCodeMemEx)); SetA64("xx001000000xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxr, null, typeof(OpCodeMemEx)); @@ -187,7 +187,7 @@ namespace ARMeilleure.Decoders SetA64("x0011010110xxxxx000010xxxxxxxxxx", InstName.Udiv, InstEmit.Udiv, typeof(OpCodeDiv)); SetA64("10011011101xxxxx0xxxxxxxxxxxxxxx", InstName.Umaddl, InstEmit.Umaddl, typeof(OpCodeMul)); SetA64("10011011101xxxxx1xxxxxxxxxxxxxxx", InstName.Umsubl, InstEmit.Umsubl, typeof(OpCodeMul)); - SetA64("10011011110xxxxx0xxxxxxxxxxxxxxx", InstName.Umulh, null, typeof(OpCodeMul)); + SetA64("10011011110xxxxx0xxxxxxxxxxxxxxx", InstName.Umulh, InstEmit.Umulh, typeof(OpCodeMul)); //FP & SIMD SetA64("0101111011100000101110xxxxxxxxxx", InstName.Abs_S, null, typeof(OpCodeSimd)); diff --git a/ARMeilleure/Instructions/InstEmitMul.cs b/ARMeilleure/Instructions/InstEmitMul.cs index 5a46251988..4fce120273 100644 --- a/ARMeilleure/Instructions/InstEmitMul.cs +++ b/ARMeilleure/Instructions/InstEmitMul.cs @@ -73,5 +73,29 @@ namespace ARMeilleure.Instructions SetIntOrZR(context, op.Rd, res); } + + public static void Smulh(EmitterContext context) + { + OpCodeMul op = (OpCodeMul)context.CurrOp; + + Operand n = GetIntOrZR(op, op.Rn); + Operand m = GetIntOrZR(op, op.Rm); + + Operand d = context.Multiply64HighSI(n, m); + + SetIntOrZR(context, op.Rd, d); + } + + public static void Umulh(EmitterContext context) + { + OpCodeMul op = (OpCodeMul)context.CurrOp; + + Operand n = GetIntOrZR(op, op.Rn); + Operand m = GetIntOrZR(op, op.Rm); + + Operand d = context.Multiply64HighUI(n, m); + + SetIntOrZR(context, op.Rd, d); + } } } \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Instruction.cs b/ARMeilleure/IntermediateRepresentation/Instruction.cs index 8f26d5096d..70b3a13f5f 100644 --- a/ARMeilleure/IntermediateRepresentation/Instruction.cs +++ b/ARMeilleure/IntermediateRepresentation/Instruction.cs @@ -35,6 +35,8 @@ namespace ARMeilleure.IntermediateRepresentation LoadZx16, LoadZx8, Multiply, + Multiply64HighSI, + Multiply64HighUI, Negate, Return, RotateRight, diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs index 45d701fadb..0bfda56794 100644 --- a/ARMeilleure/Translation/EmitterContext.cs +++ b/ARMeilleure/Translation/EmitterContext.cs @@ -211,6 +211,16 @@ namespace ARMeilleure.Translation return Add(Instruction.LoadZx8, value, address); } + public Operand Multiply64HighSI(Operand a, Operand b) + { + return Add(Instruction.Multiply64HighSI, Local(OperandType.I64), a, b); + } + + public Operand Multiply64HighUI(Operand a, Operand b) + { + return Add(Instruction.Multiply64HighUI, Local(OperandType.I64), a, b); + } + public Operand Return() { return Add(Instruction.Return);