Add CLZ support and fix CLS implementation

This commit is contained in:
gdkchan 2019-05-29 15:45:22 -03:00
parent 7d29ae0c4c
commit 316d2cdace
5 changed files with 75 additions and 5 deletions

View file

@ -50,6 +50,7 @@ namespace ARMeilleure.CodeGen.X86
// Name RM/R RM/I8 RM/I32 R/I64 R/RM Opers
Add(X86Instruction.Add, new InstInfo(0x000001, 0x000083, 0x000081, BadOp, 0x000003, 2));
Add(X86Instruction.And, new InstInfo(0x000021, 0x040083, 0x040081, BadOp, 0x000023, 2));
Add(X86Instruction.Bsr, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fbd, 2));
Add(X86Instruction.Cmp, new InstInfo(0x000039, 0x070083, 0x070081, BadOp, 0x00003b, 2));
Add(X86Instruction.Idiv, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0700f7, 1));
Add(X86Instruction.Imul, new InstInfo(BadOp, 0x00006b, 0x000069, BadOp, 0x000faf, 2));
@ -95,6 +96,11 @@ namespace ARMeilleure.CodeGen.X86
WriteInstruction(dest, source, X86Instruction.And);
}
public void Bsr(Operand dest, Operand source)
{
WriteInstruction(dest, source, X86Instruction.Bsr);
}
public void Cdq()
{
WriteByte(0x99);

View file

@ -1,6 +1,7 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace ARMeilleure.CodeGen.X86
@ -60,6 +61,10 @@ namespace ARMeilleure.CodeGen.X86
private List<Jump> _jumps;
private X86Condition _jNearCondition;
private long _jNearPosition;
private int _jNearLength;
public CodeGenContext(Stream stream, RAReport raReport, int blocksCount)
{
_stream = stream;
@ -94,6 +99,30 @@ namespace ARMeilleure.CodeGen.X86
WritePadding(ReservedBytesForJump);
}
public void JumpToNear(X86Condition condition)
{
_jNearCondition = condition;
_jNearPosition = _stream.Position;
_jNearLength = Assembler.GetJccLength(0);
_stream.Seek(_jNearLength, SeekOrigin.Current);
}
public void JumpHere()
{
long currentPosition = _stream.Position;
_stream.Seek(_jNearPosition, SeekOrigin.Begin);
long offset = currentPosition - (_jNearPosition + _jNearLength);
Debug.Assert(_jNearLength == Assembler.GetJccLength(offset), "Relative offset doesn't fit on near jump.");
Assembler.Jcc(_jNearCondition, offset);
_stream.Seek(currentPosition, SeekOrigin.Begin);
}
private void WritePadding(int size)
{
while (size-- > 0)

View file

@ -36,6 +36,7 @@ namespace ARMeilleure.CodeGen.X86
Add(Instruction.CompareLessUI, GenerateCompareLessUI);
Add(Instruction.CompareNotEqual, GenerateCompareNotEqual);
Add(Instruction.ConditionalSelect, GenerateConditionalSelect);
Add(Instruction.CountLeadingZeros, GenerateCountLeadingZeros);
Add(Instruction.Copy, GenerateCopy);
Add(Instruction.Divide, GenerateDivide);
Add(Instruction.Fill, GenerateFill);
@ -228,6 +229,34 @@ namespace ARMeilleure.CodeGen.X86
context.Assembler.Cmovcc(operation.Dest, operation.GetSource(1), X86Condition.NotEqual);
}
private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
{
Operand dest = operation.Dest;
Operand dest32 = Get32BitsRegister(dest.GetRegister());
context.Assembler.Bsr(dest, operation.GetSource(0));
int operandSize = dest.Type == OperandType.I32 ? 32 : 64;
int operandMask = operandSize - 1;
//When the input operand is 0, the result is undefined, however the
//ZF flag is set. We are supposed to return the operand size on that
//case. So, add an additional jump to handle that case, by moving the
//operand size constant to the destination register.
context.JumpToNear(X86Condition.NotEqual);
context.Assembler.Mov(dest32, new Operand(operandSize | operandMask));
context.JumpHere();
//BSR returns the zero based index of the last bit set on the operand,
//starting from the least significant bit. However we are supposed to
//return the number of 0 bits on the high end. So, we invert the result
//of the BSR using XOR to get the correct value.
context.Assembler.Xor(dest32, new Operand(operandMask));
}
private static void GenerateCopy(CodeGenContext context, Operation operation)
{
Operand dest = operation.Dest;

View file

@ -4,6 +4,7 @@ namespace ARMeilleure.CodeGen.X86
{
Add,
And,
Bsr,
Cmp,
Idiv,
Imul,

View file

@ -103,14 +103,19 @@ namespace ARMeilleure.Instructions
Operand n = GetIntOrZR(op, op.Rn);
ulong mask = ulong.MaxValue >> ((64 - op.GetBitsCount()) + 1);
Operand nHigh = context.ShiftRightUI(n, Const(1));
n = context.BitwiseExclusiveOr(context.BitwiseAnd(n, Const(mask << 1)),
context.BitwiseAnd(n, Const(mask)));
bool is32Bits = op.RegisterSize == RegisterSize.Int32;
Operand d = context.CountLeadingZeros(n);
Operand mask = is32Bits ? Const(int.MaxValue) : Const(long.MaxValue);
SetAluDOrZR(context, d);
Operand nLow = context.BitwiseAnd(n, mask);
Operand res = context.CountLeadingZeros(context.BitwiseExclusiveOr(nHigh, nLow));
res = context.ISubtract(res, Const(res.Type, 1));
SetAluDOrZR(context, res);
}
public static void Clz(EmitterContext context)