diff --git a/example/src/main.nub b/example/src/main.nub index 03b53d0..20a3676 100644 --- a/example/src/main.nub +++ b/example/src/main.nub @@ -8,7 +8,18 @@ struct Human export func main(args: []cstring): i64 { - c::puts("john") + let x: i64 + + x = 23 + + if (x == 23) + { + c::printf("true\n") + } + else + { + c::printf("false\n") + } return 0 } diff --git a/src/compiler/CLI/assets/libruntime_x64.a b/src/compiler/CLI/assets/libruntime_x64.a index dfd438d..d43a568 100644 Binary files a/src/compiler/CLI/assets/libruntime_x64.a and b/src/compiler/CLI/assets/libruntime_x64.a differ diff --git a/src/compiler/Generation/QBE/QBEGenerator.cs b/src/compiler/Generation/QBE/QBEGenerator.cs index ab2ccd0..b2bff8c 100644 --- a/src/compiler/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/Generation/QBE/QBEGenerator.cs @@ -264,7 +264,7 @@ public static class QBEGenerator throw new ArgumentOutOfRangeException(nameof(type)); } } - + private static string EmitCopy(NubType type, string source) { var destination = VarName(); @@ -301,8 +301,7 @@ public static class QBEGenerator case NubPointerType: case NubPrimitiveType: { - _builder.AppendLine($" {destination} {QBEAssign(type)} {source}"); - break; + return source; } case NubVoidType: case NubFuncType: @@ -311,7 +310,7 @@ public static class QBEGenerator default: throw new ArgumentOutOfRangeException(nameof(type)); } - + return destination; } @@ -649,7 +648,7 @@ public static class QBEGenerator { var destination = EmitExpression(assignment.Expression); Debug.Assert(destination.Kind == ValKind.Pointer); - + var source = EmitUnwrap(EmitExpression(assignment.Value)); EmitCopyInto(assignment.Value.Type, source, destination.Name); } @@ -857,214 +856,117 @@ public static class QBEGenerator { var left = EmitUnwrap(EmitExpression(binaryExpression.Left)); var right = EmitUnwrap(EmitExpression(binaryExpression.Right)); + var outputName = VarName(); - var output = new Val(outputName, binaryExpression.Type, ValKind.Direct); - switch (binaryExpression.Operator) + var instruction = EmitBinaryInstructionFor(binaryExpression.Operator, binaryExpression.Left.Type, left, right); + + _builder.AppendLine($" {outputName} {QBEAssign(binaryExpression.Left.Type)} {instruction} {left}, {right}"); + return new Val(outputName, binaryExpression.Type, ValKind.Direct); + } + + private static string EmitBinaryInstructionFor(BinaryExpressionOperator op, NubType type, string left, string right) + { + if (op is + BinaryExpressionOperator.Equal or + BinaryExpressionOperator.NotEqual or + BinaryExpressionOperator.GreaterThan or + BinaryExpressionOperator.GreaterThanOrEqual or + BinaryExpressionOperator.LessThan or + BinaryExpressionOperator.LessThanOrEqual) { - case BinaryExpressionOperator.Equal: + char suffix; + + if (type.Is8BitInteger) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) + if (type.IsSignedInteger) { - _builder.AppendLine($" {outputName} =w ceql {left}, {right}"); - return output; + _builder.AppendLine($" {left} =w extsb {left}"); + _builder.AppendLine($" {right} =w extsb {right}"); + } + else + { + _builder.AppendLine($" {left} =w extub {left}"); + _builder.AppendLine($" {right} =w extub {right}"); } - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w ceqw {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool)) - { - _builder.AppendLine($" {outputName} =w ceqw {left}, {right}"); - return output; - } - - break; + suffix = 'w'; } - case BinaryExpressionOperator.NotEqual: + else if (type.Is16BitInteger) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) + if (type.IsSignedInteger) { - _builder.AppendLine($" {outputName} =w cnel {left}, {right}"); - return output; + _builder.AppendLine($" {left} =w extsh {left}"); + _builder.AppendLine($" {right} =w extsh {right}"); + } + else + { + _builder.AppendLine($" {left} =w extuh {left}"); + _builder.AppendLine($" {right} =w extuh {right}"); } - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w cnew {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool)) - { - _builder.AppendLine($" {outputName} =w cnew {left}, {right}"); - return output; - } - - break; + suffix = 'w'; } - case BinaryExpressionOperator.GreaterThan: + else if (type.Is32BitInteger) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) - { - _builder.AppendLine($" {outputName} =w csgtl {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w csgtw {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool)) - { - _builder.AppendLine($" {outputName} =w csgtw {left}, {right}"); - return output; - } - - break; + suffix = 'w'; } - case BinaryExpressionOperator.GreaterThanOrEqual: + else if (type.Is64BitInteger) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) - { - _builder.AppendLine($" {outputName} =w csgel {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w csgew {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool)) - { - _builder.AppendLine($" {outputName} =w csgew {left}, {right}"); - return output; - } - - break; + suffix = 'l'; } - case BinaryExpressionOperator.LessThan: + else { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) - { - _builder.AppendLine($" {outputName} =w csltl {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w csltw {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool)) - { - _builder.AppendLine($" {outputName} =w csltw {left}, {right}"); - return output; - } - - break; + throw new NotSupportedException($"Unsupported type '{type}' for binary operator '{op}'"); } - case BinaryExpressionOperator.LessThanOrEqual: + + if (op is BinaryExpressionOperator.Equal) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) - { - _builder.AppendLine($" {outputName} =w cslel {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w cslew {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool)) - { - _builder.AppendLine($" {outputName} =w cslew {left}, {right}"); - return output; - } - - break; + return "ceq" + suffix; } - case BinaryExpressionOperator.Plus: + + if (op is BinaryExpressionOperator.NotEqual) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) - { - _builder.AppendLine($" {outputName} =l add {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w add {left}, {right}"); - return output; - } - - break; + return "cne" + suffix; } - case BinaryExpressionOperator.Minus: + + string sign; + + if (type.IsSignedInteger) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) - { - _builder.AppendLine($" {outputName} =l sub {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w sub {left}, {right}"); - return output; - } - - break; + sign = "s"; } - case BinaryExpressionOperator.Multiply: + else if (type.IsUnsignedInteger) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) - { - _builder.AppendLine($" {outputName} =l mul {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w mul {left}, {right}"); - return output; - } - - break; + sign = "u"; } - case BinaryExpressionOperator.Divide: + else if (type.IsFloat) { - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64)) - { - _builder.AppendLine($" {outputName} =l div {left}, {right}"); - return output; - } - - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32)) - { - _builder.AppendLine($" {outputName} =w div {left}, {right}"); - return output; - } - - break; + sign = ""; } - default: + else { - throw new ArgumentOutOfRangeException(); + throw new NotSupportedException($"Unsupported type '{type}' for binary operator '{op}'"); } + + return op switch + { + BinaryExpressionOperator.GreaterThan => 'c' + sign + "gt" + suffix, + BinaryExpressionOperator.GreaterThanOrEqual => 'c' + sign + "ge" + suffix, + BinaryExpressionOperator.LessThan => 'c' + sign + "lt" + suffix, + BinaryExpressionOperator.LessThanOrEqual => 'c' + sign + "le" + suffix, + _ => throw new ArgumentOutOfRangeException(nameof(op), op, null) + }; } - throw new NotSupportedException($"Binary operator {binaryExpression.Operator} for types {binaryExpression.Left.Type} and {binaryExpression.Right.Type} not supported"); + return op switch + { + BinaryExpressionOperator.Plus => "add", + BinaryExpressionOperator.Minus => "sub", + BinaryExpressionOperator.Multiply => "mul", + BinaryExpressionOperator.Divide => "div", + _ => throw new ArgumentOutOfRangeException(nameof(op)) + }; } private static Val EmitIdentifier(BoundIdentifierNode identifier) diff --git a/src/compiler/Syntax/Typing/NubType.cs b/src/compiler/Syntax/Typing/NubType.cs index 48a5e9c..5cd508a 100644 --- a/src/compiler/Syntax/Typing/NubType.cs +++ b/src/compiler/Syntax/Typing/NubType.cs @@ -4,42 +4,25 @@ namespace Syntax.Typing; public abstract class NubType { - public abstract bool ValueIsPointer { get; } - - public bool IsInteger => this is NubPrimitiveType - { - Kind: PrimitiveTypeKind.I8 - or PrimitiveTypeKind.I16 - or PrimitiveTypeKind.I32 - or PrimitiveTypeKind.I64 - or PrimitiveTypeKind.U8 - or PrimitiveTypeKind.U16 - or PrimitiveTypeKind.U32 - or PrimitiveTypeKind.U64 - }; - - public bool IsFloat32 => this is NubPrimitiveType - { - Kind: PrimitiveTypeKind.F32 - }; - - public bool IsFloat64 => this is NubPrimitiveType - { - Kind: PrimitiveTypeKind.F64 - }; + public bool Is8BitInteger => this is NubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 }; + public bool Is16BitInteger => this is NubPrimitiveType { Kind: PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 }; + public bool Is32BitInteger => this is NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 }; + public bool Is64BitInteger => this is NubPrimitiveType { Kind: PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 }; - public bool IsNumber => IsFloat32 || IsFloat64 || IsInteger; + public bool IsSignedInteger => this is NubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I32 or PrimitiveTypeKind.I64 }; + public bool IsUnsignedInteger => this is NubPrimitiveType { Kind: PrimitiveTypeKind.U8 or PrimitiveTypeKind.U16 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.U64 }; + public bool IsInteger => IsSignedInteger || IsUnsignedInteger; + + public bool IsFloat32 => this is NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }; + public bool IsFloat64 => this is NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }; + public bool IsFloat => IsFloat32 || IsFloat64; + + public bool IsNumber => IsFloat || IsInteger; public bool IsVoid => this is NubVoidType; - public bool IsString => this is NubStringType; - public bool IsCString => this is NubCStringType; - - public bool IsBool => this is NubPrimitiveType - { - Kind: PrimitiveTypeKind.Bool - }; + public bool IsBool => this is NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }; public abstract override bool Equals(object? obj); public abstract override int GetHashCode(); @@ -48,8 +31,6 @@ public abstract class NubType public class NubCStringType : NubType { - public override bool ValueIsPointer => true; - public override bool Equals(object? obj) { return obj is NubCStringType; @@ -68,8 +49,6 @@ public class NubCStringType : NubType public class NubStringType : NubType { - public override bool ValueIsPointer => true; - public override bool Equals(object? obj) { return obj is NubStringType; @@ -88,8 +67,6 @@ public class NubStringType : NubType public class NubFuncType(NubType returnType, List parameters) : NubType { - public override bool ValueIsPointer => false; - public NubType ReturnType { get; } = returnType; public List Parameters { get; } = parameters; @@ -111,8 +88,6 @@ public class NubFuncType(NubType returnType, List parameters) : NubType public class NubStructType(string @namespace, string name) : NubType { - public override bool ValueIsPointer => true; - public string Namespace { get; } = @namespace; public string Name { get; } = name; @@ -134,10 +109,8 @@ public class NubStructType(string @namespace, string name) : NubType public class NubPointerType(NubType baseType) : NubType { - public override bool ValueIsPointer => false; - public NubType BaseType { get; } = baseType; - + public override bool Equals(object? obj) { return obj is NubPointerType other && BaseType.Equals(other.BaseType); @@ -156,8 +129,6 @@ public class NubPointerType(NubType baseType) : NubType public class NubArrayType(NubType elementType) : NubType { - public override bool ValueIsPointer => true; - public NubType ElementType { get; } = elementType; public override bool Equals(object? obj) @@ -166,6 +137,7 @@ public class NubArrayType(NubType elementType) : NubType { return ElementType.Equals(other.ElementType); } + return false; } @@ -182,10 +154,8 @@ public class NubArrayType(NubType elementType) : NubType public class NubAnyType : NubType { - public override bool ValueIsPointer => false; - public override string ToString() => "any"; - + public override bool Equals(object? obj) { return obj is NubAnyType; @@ -199,10 +169,8 @@ public class NubAnyType : NubType public class NubVoidType : NubType { - public override bool ValueIsPointer => false; - public override string ToString() => "void"; - + public override bool Equals(object? obj) { return obj is NubVoidType; @@ -216,23 +184,21 @@ public class NubVoidType : NubType public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType { - public override bool ValueIsPointer => false; - public PrimitiveTypeKind Kind { get; } = kind; public static NubPrimitiveType I64 => new(PrimitiveTypeKind.I64); public static NubPrimitiveType I32 => new(PrimitiveTypeKind.I32); public static NubPrimitiveType I16 => new(PrimitiveTypeKind.I16); public static NubPrimitiveType I8 => new(PrimitiveTypeKind.I8); - + public static NubPrimitiveType U64 => new(PrimitiveTypeKind.U64); public static NubPrimitiveType U32 => new(PrimitiveTypeKind.U32); public static NubPrimitiveType U16 => new(PrimitiveTypeKind.U16); public static NubPrimitiveType U8 => new(PrimitiveTypeKind.U8); - + public static NubPrimitiveType F64 => new(PrimitiveTypeKind.F64); public static NubPrimitiveType F32 => new(PrimitiveTypeKind.F32); - + public static NubPrimitiveType Bool => new(PrimitiveTypeKind.Bool); public static bool TryParse(string s, [NotNullWhen(true)] out PrimitiveTypeKind? kind) @@ -274,15 +240,15 @@ public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType PrimitiveTypeKind.I16 => "i16", PrimitiveTypeKind.I32 => "i32", PrimitiveTypeKind.I64 => "i64", - + PrimitiveTypeKind.U8 => "u8", PrimitiveTypeKind.U16 => "u16", PrimitiveTypeKind.U32 => "u32", PrimitiveTypeKind.U64 => "u64", - + PrimitiveTypeKind.F32 => "f32", PrimitiveTypeKind.F64 => "f64", - + PrimitiveTypeKind.Bool => "bool", _ => throw new ArgumentOutOfRangeException(nameof(kind), Kind, null) }; diff --git a/src/runtime/targets/x64.s b/src/runtime/targets/x64.s index 4e6cd53..f55a1d0 100644 --- a/src/runtime/targets/x64.s +++ b/src/runtime/targets/x64.s @@ -5,5 +5,6 @@ _start: mov rdi, rsp call main + mov rdi, rax mov rax, 60 syscall