Implement UMULH and SMULH, with new IR instructions
This commit is contained in:
parent
ab53424831
commit
c170e0f01c
8 changed files with 93 additions and 12 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> 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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,6 +35,8 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
LoadZx16,
|
||||
LoadZx8,
|
||||
Multiply,
|
||||
Multiply64HighSI,
|
||||
Multiply64HighUI,
|
||||
Negate,
|
||||
Return,
|
||||
RotateRight,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue