Implement UMULH and SMULH, with new IR instructions

This commit is contained in:
gdkchan 2019-05-30 02:45:15 -03:00
commit c170e0f01c
8 changed files with 93 additions and 12 deletions

View file

@ -66,6 +66,7 @@ namespace ARMeilleure.CodeGen.X86
Add(X86Instruction.Div, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0600f7, InstFlags.None)); 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.Idiv, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0700f7, InstFlags.None));
Add(X86Instruction.Imul, new InstInfo(BadOp, 0x00006b, 0x000069, BadOp, 0x000faf, 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.Mov, new InstInfo(0x000089, BadOp, 0x0000c7, 0x0000b8, 0x00008b, InstFlags.None));
Add(X86Instruction.Mov16, new InstInfo(0x000089, BadOp, 0x0000c7, BadOp, 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)); 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.Movsx8, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fbe, InstFlags.None));
Add(X86Instruction.Movzx16, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fb7, 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.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.Neg, new InstInfo(0x0300f7, BadOp, BadOp, BadOp, BadOp, InstFlags.None));
Add(X86Instruction.Not, new InstInfo(0x0200f7, 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)); 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); WriteInstruction(null, source, X86Instruction.Idiv);
} }
public void Imul(Operand source)
{
WriteInstruction(null, source, X86Instruction.Imul128);
}
public void Imul(Operand dest, Operand source) public void Imul(Operand dest, Operand source)
{ {
if (source.Kind != OperandKind.Register) if (source.Kind != OperandKind.Register)
@ -272,6 +279,11 @@ namespace ARMeilleure.CodeGen.X86
WriteInstruction(dest, source, X86Instruction.Movzx8); WriteInstruction(dest, source, X86Instruction.Movzx8);
} }
public void Mul(Operand source)
{
WriteInstruction(null, source, X86Instruction.Mul128);
}
public void Neg(Operand dest) public void Neg(Operand dest)
{ {
WriteInstruction(dest, null, X86Instruction.Neg); WriteInstruction(dest, null, X86Instruction.Neg);

View file

@ -50,6 +50,8 @@ namespace ARMeilleure.CodeGen.X86
Add(Instruction.LoadZx16, GenerateLoadZx16); Add(Instruction.LoadZx16, GenerateLoadZx16);
Add(Instruction.LoadZx8, GenerateLoadZx8); Add(Instruction.LoadZx8, GenerateLoadZx8);
Add(Instruction.Multiply, GenerateMultiply); Add(Instruction.Multiply, GenerateMultiply);
Add(Instruction.Multiply64HighSI, GenerateMultiply64HighSI);
Add(Instruction.Multiply64HighUI, GenerateMultiply64HighUI);
Add(Instruction.Negate, GenerateNegate); Add(Instruction.Negate, GenerateNegate);
Add(Instruction.Return, GenerateReturn); Add(Instruction.Return, GenerateReturn);
Add(Instruction.RotateRight, GenerateRotateRight); 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) private static void GenerateNegate(CodeGenContext context, Operation operation)
{ {
context.Assembler.Neg(operation.Dest); context.Assembler.Neg(operation.Dest);

View file

@ -193,7 +193,9 @@ namespace ARMeilleure.CodeGen.X86
operation.SetSource(0, rax); 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); Operation destCopyOp = new Operation(Instruction.Copy, dest, rax);
@ -202,6 +204,32 @@ namespace ARMeilleure.CodeGen.X86
operation.Dest = rax; 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. //The only allowed shift register is CL.
if (inst.IsShift() && operation.GetSource(1).Kind == OperandKind.LocalVariable) if (inst.IsShift() && operation.GetSource(1).Kind == OperandKind.LocalVariable)
{ {
@ -262,15 +290,6 @@ namespace ARMeilleure.CodeGen.X86
return temp; return temp;
} }
private static void Clobber(LinkedListNode<Node> 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) private static bool IsLongConst(Operand operand)
{ {
long value = operand.Type == OperandType.I32 ? operand.AsInt32() long value = operand.Type == OperandType.I32 ? operand.AsInt32()

View file

@ -11,6 +11,7 @@ namespace ARMeilleure.CodeGen.X86
Div, Div,
Idiv, Idiv,
Imul, Imul,
Imul128,
Mov, Mov,
Mov16, Mov16,
Mov8, Mov8,
@ -19,6 +20,7 @@ namespace ARMeilleure.CodeGen.X86
Movsx8, Movsx8,
Movzx16, Movzx16,
Movzx8, Movzx8,
Mul128,
Neg, Neg,
Not, Not,
Or, Or,

View file

@ -158,7 +158,7 @@ namespace ARMeilleure.Decoders
SetA64("x0011010110xxxxx000011xxxxxxxxxx", InstName.Sdiv, InstEmit.Sdiv, typeof(OpCodeDiv)); SetA64("x0011010110xxxxx000011xxxxxxxxxx", InstName.Sdiv, InstEmit.Sdiv, typeof(OpCodeDiv));
SetA64("10011011001xxxxx0xxxxxxxxxxxxxxx", InstName.Smaddl, InstEmit.Smaddl, typeof(OpCodeMul)); SetA64("10011011001xxxxx0xxxxxxxxxxxxxxx", InstName.Smaddl, InstEmit.Smaddl, typeof(OpCodeMul));
SetA64("10011011001xxxxx1xxxxxxxxxxxxxxx", InstName.Smsubl, InstEmit.Smsubl, 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("xx001000100xxxxx1xxxxxxxxxxxxxxx", InstName.Stlr, null, typeof(OpCodeMemEx));
SetA64("1x001000001xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxp, null, typeof(OpCodeMemEx)); SetA64("1x001000001xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxp, null, typeof(OpCodeMemEx));
SetA64("xx001000000xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxr, 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("x0011010110xxxxx000010xxxxxxxxxx", InstName.Udiv, InstEmit.Udiv, typeof(OpCodeDiv));
SetA64("10011011101xxxxx0xxxxxxxxxxxxxxx", InstName.Umaddl, InstEmit.Umaddl, typeof(OpCodeMul)); SetA64("10011011101xxxxx0xxxxxxxxxxxxxxx", InstName.Umaddl, InstEmit.Umaddl, typeof(OpCodeMul));
SetA64("10011011101xxxxx1xxxxxxxxxxxxxxx", InstName.Umsubl, InstEmit.Umsubl, 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 //FP & SIMD
SetA64("0101111011100000101110xxxxxxxxxx", InstName.Abs_S, null, typeof(OpCodeSimd)); SetA64("0101111011100000101110xxxxxxxxxx", InstName.Abs_S, null, typeof(OpCodeSimd));

View file

@ -73,5 +73,29 @@ namespace ARMeilleure.Instructions
SetIntOrZR(context, op.Rd, res); 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);
}
} }
} }

View file

@ -35,6 +35,8 @@ namespace ARMeilleure.IntermediateRepresentation
LoadZx16, LoadZx16,
LoadZx8, LoadZx8,
Multiply, Multiply,
Multiply64HighSI,
Multiply64HighUI,
Negate, Negate,
Return, Return,
RotateRight, RotateRight,

View file

@ -211,6 +211,16 @@ namespace ARMeilleure.Translation
return Add(Instruction.LoadZx8, value, address); 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() public Operand Return()
{ {
return Add(Instruction.Return); return Add(Instruction.Return);