Bit manipulation
This commit is contained in:
@@ -725,102 +725,162 @@ public class QBEGenerator
|
||||
|
||||
var outputName = TmpName();
|
||||
|
||||
var instruction = EmitBinaryInstructionFor(binaryExpression.Operator, binaryExpression.Left.Type, left, right);
|
||||
var instruction = BinaryInstructionFor(binaryExpression.Operator, binaryExpression.Left.Type);
|
||||
|
||||
_writer.Indented($"{outputName} {QBEAssign(binaryExpression.Left.Type)} {instruction} {left}, {right}");
|
||||
return outputName;
|
||||
}
|
||||
|
||||
private string EmitBinaryInstructionFor(BinaryOperator op, TypeNode type, string left, string right)
|
||||
private string BinaryInstructionFor(BinaryOperator op, TypeNode type)
|
||||
{
|
||||
if (op is
|
||||
BinaryOperator.Equal or
|
||||
BinaryOperator.NotEqual or
|
||||
BinaryOperator.GreaterThan or
|
||||
BinaryOperator.GreaterThanOrEqual or
|
||||
BinaryOperator.LessThan or
|
||||
BinaryOperator.LessThanOrEqual)
|
||||
{
|
||||
char suffix;
|
||||
|
||||
if (!type.IsSimpleType(out var simpleType, out _))
|
||||
{
|
||||
throw new NotSupportedException("Binary operations is only supported for simple types.");
|
||||
}
|
||||
|
||||
switch (simpleType.StorageSize)
|
||||
{
|
||||
case StorageSize.I8:
|
||||
_writer.Indented($"{left} =w extsb {left}");
|
||||
_writer.Indented($"{right} =w extsb {right}");
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.U8:
|
||||
_writer.Indented($"{left} =w extub {left}");
|
||||
_writer.Indented($"{right} =w extub {right}");
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.I16:
|
||||
_writer.Indented($"{left} =w extsh {left}");
|
||||
_writer.Indented($"{right} =w extsh {right}");
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.U16:
|
||||
_writer.Indented($"{left} =w extuh {left}");
|
||||
_writer.Indented($"{right} =w extuh {right}");
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.I32 or StorageSize.U32:
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.I64 or StorageSize.U64:
|
||||
suffix = 'l';
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"Unsupported type '{simpleType}' for binary operator '{op}'");
|
||||
}
|
||||
|
||||
if (op is BinaryOperator.Equal)
|
||||
{
|
||||
return "ceq" + suffix;
|
||||
}
|
||||
|
||||
if (op is BinaryOperator.NotEqual)
|
||||
{
|
||||
return "cne" + suffix;
|
||||
}
|
||||
|
||||
string sign;
|
||||
|
||||
if (simpleType is IntTypeNode { Signed: true })
|
||||
{
|
||||
sign = "s";
|
||||
}
|
||||
else if (simpleType is IntTypeNode { Signed: false })
|
||||
{
|
||||
sign = "u";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"Unsupported type '{type}' for binary operator '{op}'");
|
||||
}
|
||||
|
||||
return op switch
|
||||
{
|
||||
BinaryOperator.GreaterThan => 'c' + sign + "gt" + suffix,
|
||||
BinaryOperator.GreaterThanOrEqual => 'c' + sign + "ge" + suffix,
|
||||
BinaryOperator.LessThan => 'c' + sign + "lt" + suffix,
|
||||
BinaryOperator.LessThanOrEqual => 'c' + sign + "le" + suffix,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(op), op, null)
|
||||
};
|
||||
}
|
||||
|
||||
return op switch
|
||||
{
|
||||
BinaryOperator.RightShift => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } => "sar",
|
||||
IntTypeNode { Signed: false } => "shr",
|
||||
_ => throw new NotSupportedException($"Right shift not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.BitwiseAnd => "and",
|
||||
BinaryOperator.BitwiseOr => "or",
|
||||
BinaryOperator.BitwiseXor => "xor",
|
||||
BinaryOperator.LeftShift => "shl",
|
||||
BinaryOperator.Divide => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } => "div",
|
||||
IntTypeNode { Signed: false } => "udiv",
|
||||
FloatTypeNode => "div",
|
||||
_ => throw new NotSupportedException($"Division not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.Modulo => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } => "rem",
|
||||
IntTypeNode { Signed: false } => "urem",
|
||||
_ => throw new NotSupportedException($"Modulo not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.Plus => "add",
|
||||
BinaryOperator.Minus => "sub",
|
||||
BinaryOperator.Multiply => "mul",
|
||||
BinaryOperator.Divide => "div",
|
||||
BinaryOperator.Equal => type switch
|
||||
{
|
||||
IntTypeNode intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "ceqw",
|
||||
64 => "ceql",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
{
|
||||
32 => "ceqs",
|
||||
64 => "ceqd",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new NotSupportedException($"Equality comparison not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.NotEqual => type switch
|
||||
{
|
||||
IntTypeNode intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cnew",
|
||||
64 => "cnel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
{
|
||||
32 => "cnes",
|
||||
64 => "cned",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new NotSupportedException($"Inequality comparison not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.LessThan => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "csltw",
|
||||
64 => "csltl",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
IntTypeNode { Signed: false } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cultw",
|
||||
64 => "cultl",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
{
|
||||
32 => "clts",
|
||||
64 => "cltd",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new NotSupportedException($"Less than comparison not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.LessThanOrEqual => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cslew",
|
||||
64 => "cslel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
IntTypeNode { Signed: false } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "culew",
|
||||
64 => "culel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
{
|
||||
32 => "cles",
|
||||
64 => "cled",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new NotSupportedException($"Less than or equal comparison not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.GreaterThan => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "csgtw",
|
||||
64 => "csgtl",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
IntTypeNode { Signed: false } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cugtw",
|
||||
64 => "cugtl",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
{
|
||||
32 => "cgts",
|
||||
64 => "cgtd",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new NotSupportedException($"Greater than comparison not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.GreaterThanOrEqual => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "csgew",
|
||||
64 => "csgel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
IntTypeNode { Signed: false } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cugew",
|
||||
64 => "cugel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
{
|
||||
32 => "cges",
|
||||
64 => "cged",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new NotSupportedException($"Greater than or equal comparison not supported for type '{type}'")
|
||||
},
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(op))
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user