Bit manipulation

This commit is contained in:
nub31
2025-09-09 16:15:40 +02:00
parent ab77588b72
commit 5fd4909f81
8 changed files with 272 additions and 132 deletions

View File

@@ -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))
};
}