Bit manipulation

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

View File

@@ -4,11 +4,19 @@ extern func puts(text: cstring)
func main(args: []cstring): i64 func main(args: []cstring): i64
{ {
let x: u32 = 23 let x: u32 = 23
test(x)
if x == 23 && true
{
puts("yes")
}
else
{
puts("no")
}
return 0 return 0
} }
func test(test: u32) func test(test: u32)
{ {
puts("test")
} }

View File

@@ -725,102 +725,162 @@ public class QBEGenerator
var outputName = TmpName(); 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}"); _writer.Indented($"{outputName} {QBEAssign(binaryExpression.Left.Type)} {instruction} {left}, {right}");
return outputName; 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 return op switch
{ {
BinaryOperator.GreaterThan => 'c' + sign + "gt" + suffix, BinaryOperator.RightShift => type switch
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
{ {
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.Plus => "add",
BinaryOperator.Minus => "sub", BinaryOperator.Minus => "sub",
BinaryOperator.Multiply => "mul", 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)) _ => throw new ArgumentOutOfRangeException(nameof(op))
}; };
} }

View File

@@ -348,16 +348,28 @@ public sealed class Parser
{ {
return operatorSyntax switch return operatorSyntax switch
{ {
BinaryOperatorSyntax.Multiply => 3, BinaryOperatorSyntax.Multiply => 6,
BinaryOperatorSyntax.Divide => 3, BinaryOperatorSyntax.Divide => 6,
BinaryOperatorSyntax.Plus => 2, BinaryOperatorSyntax.Modulo => 6,
BinaryOperatorSyntax.Minus => 2,
BinaryOperatorSyntax.GreaterThan => 1, BinaryOperatorSyntax.Plus => 5,
BinaryOperatorSyntax.GreaterThanOrEqual => 1, BinaryOperatorSyntax.Minus => 5,
BinaryOperatorSyntax.LessThan => 1,
BinaryOperatorSyntax.LessThanOrEqual => 1, BinaryOperatorSyntax.LeftShift => 4,
BinaryOperatorSyntax.Equal => 0, BinaryOperatorSyntax.RightShift => 4,
BinaryOperatorSyntax.NotEqual => 0,
BinaryOperatorSyntax.GreaterThan => 3,
BinaryOperatorSyntax.GreaterThanOrEqual => 3,
BinaryOperatorSyntax.LessThan => 3,
BinaryOperatorSyntax.LessThanOrEqual => 3,
BinaryOperatorSyntax.Equal => 2,
BinaryOperatorSyntax.NotEqual => 2,
BinaryOperatorSyntax.BitwiseAnd => 1,
BinaryOperatorSyntax.BitwiseXor => 0,
BinaryOperatorSyntax.BitwiseOr => -1,
_ => throw new ArgumentOutOfRangeException(nameof(operatorSyntax), operatorSyntax, null) _ => throw new ArgumentOutOfRangeException(nameof(operatorSyntax), operatorSyntax, null)
}; };
} }
@@ -396,6 +408,24 @@ public sealed class Parser
case Symbol.ForwardSlash: case Symbol.ForwardSlash:
binaryExpressionOperator = BinaryOperatorSyntax.Divide; binaryExpressionOperator = BinaryOperatorSyntax.Divide;
return true; return true;
case Symbol.Percent:
binaryExpressionOperator = BinaryOperatorSyntax.Modulo;
return true;
case Symbol.LeftShift:
binaryExpressionOperator = BinaryOperatorSyntax.LeftShift;
return true;
case Symbol.RightShift:
binaryExpressionOperator = BinaryOperatorSyntax.RightShift;
return true;
case Symbol.Ampersand:
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseAnd;
return true;
case Symbol.Pipe:
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseOr;
return true;
case Symbol.Caret:
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseXor;
return true;
default: default:
binaryExpressionOperator = null; binaryExpressionOperator = null;
return false; return false;

View File

@@ -19,14 +19,20 @@ public enum BinaryOperatorSyntax
Plus, Plus,
Minus, Minus,
Multiply, Multiply,
Divide Divide,
Modulo,
LeftShift,
RightShift,
BitwiseAnd,
BitwiseXor,
BitwiseOr
} }
public abstract record ExpressionSyntax(IEnumerable<Token> Tokens) : SyntaxNode(Tokens); public abstract record ExpressionSyntax(IEnumerable<Token> Tokens) : SyntaxNode(Tokens);
public record BinaryExpressionSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Left, BinaryOperatorSyntax OperatorSyntax, ExpressionSyntax Right) : ExpressionSyntax(Tokens); public record BinaryExpressionSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Left, BinaryOperatorSyntax Operator, ExpressionSyntax Right) : ExpressionSyntax(Tokens);
public record UnaryExpressionSyntax(IEnumerable<Token> Tokens, UnaryOperatorSyntax OperatorSyntax, ExpressionSyntax Operand) : ExpressionSyntax(Tokens); public record UnaryExpressionSyntax(IEnumerable<Token> Tokens, UnaryOperatorSyntax Operator, ExpressionSyntax Operand) : ExpressionSyntax(Tokens);
public record FuncCallSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Expression, IReadOnlyList<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens); public record FuncCallSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Expression, IReadOnlyList<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens);

View File

@@ -70,4 +70,8 @@ public enum Symbol
For, For,
Extern, Extern,
Semi, Semi,
Percent,
LeftShift,
RightShift,
Pipe,
} }

View File

@@ -28,6 +28,8 @@ public sealed class Tokenizer
[['!', '=']] = Symbol.NotEqual, [['!', '=']] = Symbol.NotEqual,
[['<', '=']] = Symbol.LessThanOrEqual, [['<', '=']] = Symbol.LessThanOrEqual,
[['>', '=']] = Symbol.GreaterThanOrEqual, [['>', '=']] = Symbol.GreaterThanOrEqual,
[['<', '<']] = Symbol.LeftShift,
[['>', '>']] = Symbol.RightShift,
[[':']] = Symbol.Colon, [[':']] = Symbol.Colon,
[['(']] = Symbol.OpenParen, [['(']] = Symbol.OpenParen,
[[')']] = Symbol.CloseParen, [[')']] = Symbol.CloseParen,
@@ -48,6 +50,8 @@ public sealed class Tokenizer
[['^']] = Symbol.Caret, [['^']] = Symbol.Caret,
[['&']] = Symbol.Ampersand, [['&']] = Symbol.Ampersand,
[[';']] = Symbol.Semi, [[';']] = Symbol.Semi,
[['%']] = Symbol.Percent,
[['|']] = Symbol.Pipe,
}; };
private static readonly (char[] Pattern, Symbol Symbol)[] OrderedSymbols = Symbols private static readonly (char[] Pattern, Symbol Symbol)[] OrderedSymbols = Symbols

View File

@@ -19,7 +19,13 @@ public enum BinaryOperator
Plus, Plus,
Minus, Minus,
Multiply, Multiply,
Divide Divide,
Modulo,
LeftShift,
RightShift,
BitwiseAnd,
BitwiseXor,
BitwiseOr
} }
public abstract record ExpressionNode(TypeNode Type) : Node; public abstract record ExpressionNode(TypeNode Type) : Node;

View File

@@ -345,7 +345,50 @@ public sealed class TypeChecker
{ {
var boundLeft = CheckExpression(expression.Left); var boundLeft = CheckExpression(expression.Left);
var boundRight = CheckExpression(expression.Right, boundLeft.Type); var boundRight = CheckExpression(expression.Right, boundLeft.Type);
return new BinaryExpressionNode(boundLeft.Type, boundLeft, CheckBinaryOperator(expression.OperatorSyntax), boundRight);
var op = expression.Operator switch
{
BinaryOperatorSyntax.Equal => BinaryOperator.Equal,
BinaryOperatorSyntax.NotEqual => BinaryOperator.NotEqual,
BinaryOperatorSyntax.GreaterThan => BinaryOperator.GreaterThan,
BinaryOperatorSyntax.GreaterThanOrEqual => BinaryOperator.GreaterThanOrEqual,
BinaryOperatorSyntax.LessThan => BinaryOperator.LessThan,
BinaryOperatorSyntax.LessThanOrEqual => BinaryOperator.LessThanOrEqual,
BinaryOperatorSyntax.Plus => BinaryOperator.Plus,
BinaryOperatorSyntax.Minus => BinaryOperator.Minus,
BinaryOperatorSyntax.Multiply => BinaryOperator.Multiply,
BinaryOperatorSyntax.Divide => BinaryOperator.Divide,
BinaryOperatorSyntax.Modulo => BinaryOperator.Modulo,
BinaryOperatorSyntax.LeftShift => BinaryOperator.LeftShift,
BinaryOperatorSyntax.RightShift => BinaryOperator.RightShift,
BinaryOperatorSyntax.BitwiseAnd => BinaryOperator.BitwiseAnd,
BinaryOperatorSyntax.BitwiseXor => BinaryOperator.BitwiseXor,
BinaryOperatorSyntax.BitwiseOr => BinaryOperator.BitwiseOr,
_ => throw new ArgumentOutOfRangeException(nameof(expression.Operator), expression.Operator, null)
};
var resultingType = op switch
{
BinaryOperator.Equal => new BoolTypeNode(),
BinaryOperator.NotEqual => new BoolTypeNode(),
BinaryOperator.GreaterThan => new BoolTypeNode(),
BinaryOperator.GreaterThanOrEqual => new BoolTypeNode(),
BinaryOperator.LessThan => new BoolTypeNode(),
BinaryOperator.LessThanOrEqual => new BoolTypeNode(),
BinaryOperator.Plus => boundLeft.Type,
BinaryOperator.Minus => boundLeft.Type,
BinaryOperator.Multiply => boundLeft.Type,
BinaryOperator.Divide => boundLeft.Type,
BinaryOperator.Modulo => boundLeft.Type,
BinaryOperator.LeftShift => boundLeft.Type,
BinaryOperator.RightShift => boundLeft.Type,
BinaryOperator.BitwiseAnd => boundLeft.Type,
BinaryOperator.BitwiseXor => boundLeft.Type,
BinaryOperator.BitwiseOr => boundLeft.Type,
_ => throw new ArgumentOutOfRangeException()
};
return new BinaryExpressionNode(resultingType, boundLeft, op, boundRight);
} }
private DereferenceNode CheckDereference(DereferenceSyntax expression) private DereferenceNode CheckDereference(DereferenceSyntax expression)
@@ -606,7 +649,7 @@ public sealed class TypeChecker
TypeNode? type = null; TypeNode? type = null;
switch (expression.OperatorSyntax) switch (expression.Operator)
{ {
case UnaryOperatorSyntax.Negate: case UnaryOperatorSyntax.Negate:
{ {
@@ -633,7 +676,14 @@ public sealed class TypeChecker
throw new TypeCheckerException(Diagnostic.Error($"Cannot perform unary operation {expression.Operand} on type {boundOperand.Type}").Build()); throw new TypeCheckerException(Diagnostic.Error($"Cannot perform unary operation {expression.Operand} on type {boundOperand.Type}").Build());
} }
return new UnaryExpressionNode(type, CheckUnaryOperator(expression.OperatorSyntax), boundOperand); var op = expression.Operator switch
{
UnaryOperatorSyntax.Negate => UnaryOperator.Negate,
UnaryOperatorSyntax.Invert => UnaryOperator.Invert,
_ => throw new ArgumentOutOfRangeException(nameof(expression.Operator), expression.Operator, null)
};
return new UnaryExpressionNode(type, op, boundOperand);
} }
private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax node) private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax node)
@@ -648,34 +698,6 @@ public sealed class TypeChecker
return new FuncSignatureNode(parameters, CheckType(node.ReturnType)); return new FuncSignatureNode(parameters, CheckType(node.ReturnType));
} }
private BinaryOperator CheckBinaryOperator(BinaryOperatorSyntax op)
{
return op switch
{
BinaryOperatorSyntax.Equal => BinaryOperator.Equal,
BinaryOperatorSyntax.NotEqual => BinaryOperator.NotEqual,
BinaryOperatorSyntax.GreaterThan => BinaryOperator.GreaterThan,
BinaryOperatorSyntax.GreaterThanOrEqual => BinaryOperator.GreaterThanOrEqual,
BinaryOperatorSyntax.LessThan => BinaryOperator.LessThan,
BinaryOperatorSyntax.LessThanOrEqual => BinaryOperator.LessThanOrEqual,
BinaryOperatorSyntax.Plus => BinaryOperator.Plus,
BinaryOperatorSyntax.Minus => BinaryOperator.Minus,
BinaryOperatorSyntax.Multiply => BinaryOperator.Multiply,
BinaryOperatorSyntax.Divide => BinaryOperator.Divide,
_ => throw new ArgumentOutOfRangeException(nameof(op), op, null)
};
}
private UnaryOperator CheckUnaryOperator(UnaryOperatorSyntax op)
{
return op switch
{
UnaryOperatorSyntax.Negate => UnaryOperator.Negate,
UnaryOperatorSyntax.Invert => UnaryOperator.Invert,
_ => throw new ArgumentOutOfRangeException(nameof(op), op, null)
};
}
private BlockNode CheckBlock(BlockSyntax node, Scope? scope = null) private BlockNode CheckBlock(BlockSyntax node, Scope? scope = null)
{ {
var statements = new List<StatementNode>(); var statements = new List<StatementNode>();