diff --git a/compiler/NubLang/Generation/LlvmGenerator.cs b/compiler/NubLang/Generation/LlvmGenerator.cs index d1a2828..bdd0249 100644 --- a/compiler/NubLang/Generation/LlvmGenerator.cs +++ b/compiler/NubLang/Generation/LlvmGenerator.cs @@ -91,7 +91,7 @@ public class LlvmGenerator _labelIndex = 0; var parameters = funcNode.Prototype.Parameters.Select(x => $"{MapType(x.Type)} %{x.NameToken.Value}"); - writer.WriteLine($"define {MapType(funcNode.Prototype.ReturnType)} @{FuncName(funcNode.Prototype)}({string.Join(", ", parameters)}) {{"); + writer.WriteLine($"define {MapType(funcNode.Prototype.ReturnType)} @{FuncName(_module, funcNode.Prototype.NameToken.Value, funcNode.Prototype.ExternSymbolToken?.Value)}({string.Join(", ", parameters)}) {{"); using (writer.Indent()) { @@ -127,10 +127,10 @@ public class LlvmGenerator EmitBlock(writer, blockNode); break; case BreakNode breakNode: - EmitBreak(writer, breakNode); + EmitBreak(writer); break; case ContinueNode continueNode: - EmitContinue(writer, continueNode); + EmitContinue(writer); break; case DeferNode deferNode: EmitDefer(writer, deferNode); @@ -176,13 +176,13 @@ public class LlvmGenerator } } - private void EmitBreak(IndentedTextWriter writer, BreakNode breakNode) + private void EmitBreak(IndentedTextWriter writer) { var (breakLabel, _) = _loopStack.Peek(); writer.WriteLine($"br label %{breakLabel}"); } - private void EmitContinue(IndentedTextWriter writer, ContinueNode continueNode) + private void EmitContinue(IndentedTextWriter writer) { var (_, continueLabel) = _loopStack.Peek(); writer.WriteLine($"br label %{continueLabel}"); @@ -301,8 +301,43 @@ public class LlvmGenerator { return expressionNode switch { - RValue rValue => EmitRValue(writer, rValue), - LValue lValue => EmitLValue(writer, lValue), + AddressOfNode addressOfNode => EmitAddressOf(writer, addressOfNode), + DereferenceNode dereferenceNode => EmitDereference(writer, dereferenceNode), + + UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(writer, unaryExpressionNode), + BinaryExpressionNode binaryExpressionNode => EmitBinaryExpression(writer, binaryExpressionNode), + + ConstArrayInitializerNode constArrayInitializerNode => EmitConstArrayInitializer(writer, constArrayInitializerNode), + StructInitializerNode structInitializerNode => EmitStructInitializer(writer, structInitializerNode), + + ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(writer, constArrayIndexAccessNode), + ArrayIndexAccessNode arrayIndexAccessNode => EmitArrayIndexAccess(writer, arrayIndexAccessNode), + SliceIndexAccessNode sliceIndexAccessNode => EmitSliceIndexAccess(writer, sliceIndexAccessNode), + + StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(writer, structFieldAccessNode), + + CStringLiteralNode cStringLiteralNode => EmitCStringLiteral(writer, cStringLiteralNode), + StringLiteralNode stringLiteralNode => EmitStringLiteral(writer, stringLiteralNode), + BoolLiteralNode boolLiteralNode => EmitBoolLiteral(boolLiteralNode), + Float32LiteralNode float32LiteralNode => EmitFloat32Literal(float32LiteralNode), + Float64LiteralNode float64LiteralNode => EmitFloat64Literal(float64LiteralNode), + U8LiteralNode u8LiteralNode => EmitU8Literal(u8LiteralNode), + U16LiteralNode u16LiteralNode => EmitU16Literal(u16LiteralNode), + U32LiteralNode u32LiteralNode => EmitU32Literal(u32LiteralNode), + U64LiteralNode u64LiteralNode => EmitU64Literal(u64LiteralNode), + I8LiteralNode i8LiteralNode => EmitI8Literal(i8LiteralNode), + I16LiteralNode i16LiteralNode => EmitI16Literal(i16LiteralNode), + I32LiteralNode i32LiteralNode => EmitI32Literal(i32LiteralNode), + I64LiteralNode i64LiteralNode => EmitI64Literal(i64LiteralNode), + + LocalFuncIdentifierNode localFuncIdentifierNode => EmitLocalFuncIdentifier(writer, localFuncIdentifierNode), + ModuleFuncIdentifierNode moduleFuncIdentifierNode => EmitModuleFuncIdentifier(writer, moduleFuncIdentifierNode), + VariableIdentifierNode variableIdentifierNode => EmitVariableIdentifier(writer, variableIdentifierNode), + + FuncCallNode funcCallNode => EmitFuncCall(writer, funcCallNode), + SizeNode sizeNode => EmitSize(sizeNode), + CastNode castNode => EmitCast(writer, castNode), + _ => throw new ArgumentOutOfRangeException(nameof(expressionNode)) }; } @@ -337,67 +372,52 @@ public class LlvmGenerator } } - private Tmp EmitRValue(IndentedTextWriter writer, RValue rValue) - { - return rValue switch - { - AddressOfNode addressOfNode => EmitAddressOf(writer, addressOfNode), - BinaryExpressionNode binaryExpressionNode => EmitBinaryExpression(writer, binaryExpressionNode), - BoolLiteralNode boolLiteralNode => EmitBoolLiteral(writer, boolLiteralNode), - CastNode castNode => EmitCast(writer, castNode), - ConstArrayInitializerNode constArrayInitializerNode => EmitConstArrayInitializer(writer, constArrayInitializerNode), - CStringLiteralNode cStringLiteralNode => EmitCStringLiteral(writer, cStringLiteralNode), - Float32LiteralNode float32LiteralNode => EmitFloat32Literal(writer, float32LiteralNode), - Float64LiteralNode float64LiteralNode => EmitFloat64Literal(writer, float64LiteralNode), - FuncCallNode funcCallNode => EmitFuncCall(writer, funcCallNode), - ModuleFuncIdentifierNode moduleFuncIdentifierNode => EmitModuleFuncIdentifier(writer, moduleFuncIdentifierNode), - LocalFuncIdentifierNode localFuncIdentifierNode => EmitLocalFuncIdentifier(writer, localFuncIdentifierNode), - I16LiteralNode i16LiteralNode => EmitI16Literal(writer, i16LiteralNode), - I32LiteralNode i32LiteralNode => EmitI32Literal(writer, i32LiteralNode), - I64LiteralNode i64LiteralNode => EmitI64Literal(writer, i64LiteralNode), - I8LiteralNode i8LiteralNode => EmitI8Literal(writer, i8LiteralNode), - SizeNode sizeNode => EmitSize(writer, sizeNode), - StringLiteralNode stringLiteralNode => EmitStringLiteral(writer, stringLiteralNode), - StructInitializerNode structInitializerNode => EmitStructInitializer(writer, structInitializerNode), - U16LiteralNode u16LiteralNode => EmitU16Literal(writer, u16LiteralNode), - U32LiteralNode u32LiteralNode => EmitU32Literal(writer, u32LiteralNode), - U64LiteralNode u64LiteralNode => EmitU64Literal(writer, u64LiteralNode), - U8LiteralNode u8LiteralNode => EmitU8Literal(writer, u8LiteralNode), - UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(writer, unaryExpressionNode), - _ => throw new ArgumentOutOfRangeException(nameof(rValue), rValue, null) - }; - } - - private Tmp EmitLValue(IndentedTextWriter writer, LValue lValue) - { - return lValue switch - { - ArrayIndexAccessNode arrayIndexAccessNode => EmitArrayIndexAccess(writer, arrayIndexAccessNode), - ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(writer, constArrayIndexAccessNode), - DereferenceNode dereferenceNode => EmitDereference(writer, dereferenceNode), - SliceIndexAccessNode sliceIndexAccessNode => EmitSliceIndexAccess(writer, sliceIndexAccessNode), - StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(writer, structFieldAccessNode), - VariableIdentifierNode variableIdentifierNode => EmitVariableIdentifier(writer, variableIdentifierNode), - _ => throw new ArgumentOutOfRangeException(nameof(lValue), lValue, null) - }; - } - private Tmp EmitAddressOf(IndentedTextWriter writer, AddressOfNode addressOfNode) { var target = EmitExpression(writer, addressOfNode.Target); return new Tmp(target.Ident, addressOfNode.Type, false); } - private Tmp EmitArrayIndexAccess(IndentedTextWriter writer, ArrayIndexAccessNode arrayIndexAccessNode) + private Tmp EmitDereference(IndentedTextWriter writer, DereferenceNode dereferenceNode) { - var arrayPtr = Unwrap(writer, EmitExpression(writer, arrayIndexAccessNode.Target)); - var index = Unwrap(writer, EmitExpression(writer, arrayIndexAccessNode.Index)); + throw new NotImplementedException(); + } - var elementType = ((NubArrayType)arrayIndexAccessNode.Target.Type).ElementType; - var ptrTmp = NewTmp("array.element"); - writer.WriteLine($"{ptrTmp} = getelementptr {MapType(elementType)}, ptr {arrayPtr}, {MapType(arrayIndexAccessNode.Index.Type)} {index}"); + private Tmp EmitUnaryExpression(IndentedTextWriter writer, UnaryExpressionNode unaryExpressionNode) + { + var operand = Unwrap(writer, EmitExpression(writer, unaryExpressionNode.Operand)); + var result = NewTmp("unary"); - return new Tmp(ptrTmp, arrayIndexAccessNode.Type, true); + switch (unaryExpressionNode.Operator) + { + case UnaryOperator.Negate: + { + switch (unaryExpressionNode.Operand.Type) + { + case NubIntType intType: + writer.WriteLine($"{result} = sub {MapType(intType)} 0, {operand}"); + break; + case NubFloatType floatType: + writer.WriteLine($"{result} = fneg {MapType(floatType)} {operand}"); + break; + default: + throw new UnreachableException(); + } + + break; + } + case UnaryOperator.Invert: + { + writer.WriteLine($"{result} = xor i1 {operand}, true"); + break; + } + default: + { + throw new ArgumentOutOfRangeException(); + } + } + + return new Tmp(result, unaryExpressionNode.Type, false); } private Tmp EmitBinaryExpression(IndentedTextWriter writer, BinaryExpressionNode binaryExpressionNode) @@ -557,7 +577,7 @@ public class LlvmGenerator }; } - private string GenerateBoolComparison(BinaryOperator op) + private static string GenerateBoolComparison(BinaryOperator op) { return op switch { @@ -567,7 +587,7 @@ public class LlvmGenerator }; } - private string GeneratePointerComparison(BinaryOperator op) + private static string GeneratePointerComparison(BinaryOperator op) { return op switch { @@ -581,11 +601,279 @@ public class LlvmGenerator }; } - private Tmp EmitBoolLiteral(IndentedTextWriter writer, BoolLiteralNode boolLiteralNode) + #region Initializers + + private Tmp EmitConstArrayInitializer(IndentedTextWriter writer, ConstArrayInitializerNode constArrayInitializerNode, string? destination = null) + { + var arrayType = (NubConstArrayType)constArrayInitializerNode.Type; + + if (destination == null) + { + destination = NewTmp("array"); + writer.WriteLine($"{destination} = alloca {MapType(arrayType)}"); + } + + for (var i = 0; i < constArrayInitializerNode.Values.Count; i++) + { + var value = constArrayInitializerNode.Values[i]; + var indexTmp = NewTmp("array.element"); + writer.WriteLine($"{indexTmp} = getelementptr {MapType(arrayType)}, ptr {destination}, i32 0, i32 {i}"); + EmitExpressionInto(writer, value, indexTmp); + } + + return new Tmp(destination, constArrayInitializerNode.Type, false); + } + + private Tmp EmitStructInitializer(IndentedTextWriter writer, StructInitializerNode structInitializerNode, string? destination = null) + { + if (destination == null) + { + destination = NewTmp("struct"); + writer.WriteLine($"{destination} = alloca {MapType(structInitializerNode.Type)}"); + } + + var structType = (NubStructType)structInitializerNode.Type; + + writer.WriteLine($"call void @{StructName(structType.Module, structType.Name)}.new(ptr {destination})"); + + foreach (var (name, value) in structInitializerNode.Initializers) + { + var index = structType.GetFieldIndex(name.Value); + var fieldTmp = NewTmp($"struct.field.{name}"); + writer.WriteLine($"{fieldTmp} = getelementptr %{StructName(structType.Module, structType.Name)}, ptr {destination}, i32 0, i32 {index}"); + + EmitExpressionInto(writer, value, fieldTmp); + } + + return new Tmp(destination, structInitializerNode.Type, false); + } + + #endregion + + #region Array indexing + + private Tmp EmitConstArrayIndexAccess(IndentedTextWriter writer, ConstArrayIndexAccessNode constArrayIndexAccessNode) + { + var arrayPtr = Unwrap(writer, EmitExpression(writer, constArrayIndexAccessNode.Target)); + var index = Unwrap(writer, EmitExpression(writer, constArrayIndexAccessNode.Index)); + + var elementType = ((NubConstArrayType)constArrayIndexAccessNode.Target.Type).ElementType; + var ptrTmp = NewTmp("array.element"); + writer.WriteLine($"{ptrTmp} = getelementptr {MapType(elementType)}, ptr {arrayPtr}, {MapType(constArrayIndexAccessNode.Index.Type)} {index}"); + + return new Tmp(ptrTmp, constArrayIndexAccessNode.Type, true); + } + + private Tmp EmitArrayIndexAccess(IndentedTextWriter writer, ArrayIndexAccessNode arrayIndexAccessNode) + { + var arrayPtr = Unwrap(writer, EmitExpression(writer, arrayIndexAccessNode.Target)); + var index = Unwrap(writer, EmitExpression(writer, arrayIndexAccessNode.Index)); + + var elementType = ((NubArrayType)arrayIndexAccessNode.Target.Type).ElementType; + var ptrTmp = NewTmp("array.element"); + writer.WriteLine($"{ptrTmp} = getelementptr {MapType(elementType)}, ptr {arrayPtr}, {MapType(arrayIndexAccessNode.Index.Type)} {index}"); + + return new Tmp(ptrTmp, arrayIndexAccessNode.Type, true); + } + + private Tmp EmitSliceIndexAccess(IndentedTextWriter writer, SliceIndexAccessNode sliceIndexAccessNode) + { + throw new NotImplementedException(); + } + + #endregion + + private Tmp EmitStructFieldAccess(IndentedTextWriter writer, StructFieldAccessNode structFieldAccessNode) + { + var target = Unwrap(writer, EmitExpression(writer, structFieldAccessNode.Target)); + + var structType = (NubStructType)structFieldAccessNode.Target.Type; + var index = structType.GetFieldIndex(structFieldAccessNode.FieldToken.Value); + + var ptrTmp = NewTmp($"struct.field.{structFieldAccessNode.FieldToken.Value}"); + writer.WriteLine($"{ptrTmp} = getelementptr %{StructName(structType.Module, structType.Name)}, ptr {target}, i32 0, i32 {index}"); + + return new Tmp(ptrTmp, structFieldAccessNode.Type, true); + } + + #region Literals + + private Tmp EmitCStringLiteral(IndentedTextWriter writer, CStringLiteralNode cStringLiteralNode) + { + var escaped = new StringBuilder(); + foreach (var c in cStringLiteralNode.Value) + { + switch (c) + { + case '\0': + escaped.Append("\\00"); + break; + case '\n': + escaped.Append("\\0A"); + break; + case '\r': + escaped.Append("\\0D"); + break; + case '\t': + escaped.Append("\\09"); + break; + case '\\': + escaped.Append("\\\\"); + break; + case '"': + escaped.Append("\\22"); + break; + default: + { + if (c < 32 || c > 126) + escaped.Append($"\\{(int)c:X2}"); + else + escaped.Append(c); + + break; + } + } + } + + var stringWithNull = cStringLiteralNode.Value + "\0"; + var length = stringWithNull.Length; + + var globalName = $"@.str.{_stringLiterals.Count}"; + + _stringLiterals.Add((globalName, length, escaped.ToString())); + + var gepTmp = NewTmp("str.ptr"); + writer.WriteLine($"{gepTmp} = getelementptr [{length} x i8], ptr {globalName}, i32 0, i32 0"); + + return new Tmp(gepTmp, cStringLiteralNode.Type, false); + } + + private static Tmp EmitStringLiteral(IndentedTextWriter writer, StringLiteralNode stringLiteralNode) + { + throw new NotImplementedException(); + } + + private static Tmp EmitBoolLiteral(BoolLiteralNode boolLiteralNode) { return new Tmp(boolLiteralNode.Value ? "1" : "0", boolLiteralNode.Type, false); } + private static Tmp EmitFloat32Literal(Float32LiteralNode float32LiteralNode) + { + var literal = ((double)float32LiteralNode.Value).ToString("R", System.Globalization.CultureInfo.InvariantCulture); + if (!literal.Contains('.')) + { + literal += ".0"; + } + + return new Tmp(literal, float32LiteralNode.Type, false); + } + + private static Tmp EmitFloat64Literal(Float64LiteralNode float64LiteralNode) + { + var literal = float64LiteralNode.Value.ToString("R", System.Globalization.CultureInfo.InvariantCulture); + if (!literal.Contains('.')) + { + literal += ".0"; + } + + return new Tmp(literal, float64LiteralNode.Type, false); + } + + private static Tmp EmitU8Literal(U8LiteralNode u8LiteralNode) + { + return new Tmp(u8LiteralNode.Value.ToString(), u8LiteralNode.Type, false); + } + + private static Tmp EmitU16Literal(U16LiteralNode u16LiteralNode) + { + return new Tmp(u16LiteralNode.Value.ToString(), u16LiteralNode.Type, false); + } + + private static Tmp EmitU32Literal(U32LiteralNode u32LiteralNode) + { + return new Tmp(u32LiteralNode.Value.ToString(), u32LiteralNode.Type, false); + } + + private static Tmp EmitU64Literal(U64LiteralNode u64LiteralNode) + { + return new Tmp(u64LiteralNode.Value.ToString(), u64LiteralNode.Type, false); + } + + private static Tmp EmitI8Literal(I8LiteralNode i8LiteralNode) + { + return new Tmp(i8LiteralNode.Value.ToString(), i8LiteralNode.Type, false); + } + + private static Tmp EmitI16Literal(I16LiteralNode i16LiteralNode) + { + return new Tmp(i16LiteralNode.Value.ToString(), i16LiteralNode.Type, false); + } + + private static Tmp EmitI32Literal(I32LiteralNode i32LiteralNode) + { + return new Tmp(i32LiteralNode.Value.ToString(), i32LiteralNode.Type, false); + } + + private static Tmp EmitI64Literal(I64LiteralNode i64LiteralNode) + { + return new Tmp(i64LiteralNode.Value.ToString(), i64LiteralNode.Type, false); + } + + #endregion + + #region Identifiers + + private Tmp EmitLocalFuncIdentifier(IndentedTextWriter writer, LocalFuncIdentifierNode localFuncIdentifierNode) + { + var name = FuncName(_module, localFuncIdentifierNode.NameToken.Value, localFuncIdentifierNode.ExternSymbolToken?.Value); + return new Tmp($"@{name}", localFuncIdentifierNode.Type, false); + } + + private Tmp EmitModuleFuncIdentifier(IndentedTextWriter writer, ModuleFuncIdentifierNode moduleFuncIdentifierNode) + { + var name = FuncName(moduleFuncIdentifierNode.ModuleToken.Value, moduleFuncIdentifierNode.NameToken.Value, moduleFuncIdentifierNode.ExternSymbolToken?.Value); + return new Tmp($"@{name}", moduleFuncIdentifierNode.Type, false); + } + + private Tmp EmitVariableIdentifier(IndentedTextWriter writer, VariableIdentifierNode variableIdentifierNode) + { + return new Tmp($"%{variableIdentifierNode.NameToken.Value}", variableIdentifierNode.Type, true); + } + + #endregion + + private Tmp EmitFuncCall(IndentedTextWriter writer, FuncCallNode funcCallNode) + { + var result = NewTmp(); + + var parameterStrings = new List(); + + foreach (var parameter in funcCallNode.Parameters) + { + var value = Unwrap(writer, EmitExpression(writer, parameter)); + parameterStrings.Add($"{MapType(parameter.Type)} {value}"); + } + + var functionPtr = Unwrap(writer, EmitExpression(writer, funcCallNode.Expression)); + + if (funcCallNode.Type is NubVoidType) + { + writer.WriteLine($"call {MapType(funcCallNode.Type)} {functionPtr}({string.Join(", ", parameterStrings)})"); + } + else + { + writer.WriteLine($"{result} = call {MapType(funcCallNode.Type)} {functionPtr}({string.Join(", ", parameterStrings)})"); + } + + return new Tmp(result, funcCallNode.Type, false); + } + + private static Tmp EmitSize(SizeNode sizeNode) + { + return new Tmp(sizeNode.TargetType.GetSize().ToString(), sizeNode.Type, false); + } + private Tmp EmitCast(IndentedTextWriter writer, CastNode castNode) { var source = Unwrap(writer, EmitExpression(writer, castNode.Value)); @@ -664,281 +952,6 @@ public class LlvmGenerator return new Tmp(result, castNode.Type, false); } - private Tmp EmitConstArrayIndexAccess(IndentedTextWriter writer, ConstArrayIndexAccessNode constArrayIndexAccessNode) - { - var arrayPtr = Unwrap(writer, EmitExpression(writer, constArrayIndexAccessNode.Target)); - var index = Unwrap(writer, EmitExpression(writer, constArrayIndexAccessNode.Index)); - - var elementType = ((NubConstArrayType)constArrayIndexAccessNode.Target.Type).ElementType; - var ptrTmp = NewTmp("array.element"); - writer.WriteLine($"{ptrTmp} = getelementptr {MapType(elementType)}, ptr {arrayPtr}, {MapType(constArrayIndexAccessNode.Index.Type)} {index}"); - - return new Tmp(ptrTmp, constArrayIndexAccessNode.Type, true); - } - - private Tmp EmitConstArrayInitializer(IndentedTextWriter writer, ConstArrayInitializerNode constArrayInitializerNode, string? destination = null) - { - var arrayType = (NubConstArrayType)constArrayInitializerNode.Type; - - if (destination == null) - { - destination = NewTmp("array"); - writer.WriteLine($"{destination} = alloca {MapType(arrayType)}"); - } - - for (var i = 0; i < constArrayInitializerNode.Values.Count; i++) - { - var value = constArrayInitializerNode.Values[i]; - var indexTmp = NewTmp("array.element"); - writer.WriteLine($"{indexTmp} = getelementptr {MapType(arrayType)}, ptr {destination}, i32 0, i32 {i}"); - EmitExpressionInto(writer, value, indexTmp); - } - - return new Tmp(destination, constArrayInitializerNode.Type, false); - } - - private Tmp EmitCStringLiteral(IndentedTextWriter writer, CStringLiteralNode cStringLiteralNode) - { - var escaped = EscapeStringForLLVM(cStringLiteralNode.Value); - - var stringWithNull = cStringLiteralNode.Value + "\0"; - var length = stringWithNull.Length; - - var globalName = $"@.str.{_stringLiterals.Count}"; - - _stringLiterals.Add((globalName, length, escaped)); - - var gepTmp = NewTmp("str.ptr"); - writer.WriteLine($"{gepTmp} = getelementptr [{length} x i8], ptr {globalName}, i32 0, i32 0"); - - return new Tmp(gepTmp, cStringLiteralNode.Type, false); - } - - private string EscapeStringForLLVM(string input) - { - var result = new StringBuilder(); - foreach (var c in input) - { - if (c == '\0') - result.Append("\\00"); - else if (c == '\n') - result.Append("\\0A"); - else if (c == '\r') - result.Append("\\0D"); - else if (c == '\t') - result.Append("\\09"); - else if (c == '\\') - result.Append("\\\\"); - else if (c == '"') - result.Append("\\22"); - else if (c < 32 || c > 126) - result.Append($"\\{(int)c:X2}"); - else - result.Append(c); - } - - return result.ToString(); - } - - private Tmp EmitDereference(IndentedTextWriter writer, DereferenceNode dereferenceNode) - { - throw new NotImplementedException(); - } - - private Tmp EmitFloat32Literal(IndentedTextWriter writer, Float32LiteralNode float32LiteralNode) - { - var literal = ((double)float32LiteralNode.Value).ToString("R", System.Globalization.CultureInfo.InvariantCulture); - if (!literal.Contains('.')) - { - literal += ".0"; - } - - return new Tmp(literal, float32LiteralNode.Type, false); - } - - private Tmp EmitFloat64Literal(IndentedTextWriter writer, Float64LiteralNode float64LiteralNode) - { - var literal = float64LiteralNode.Value.ToString("R", System.Globalization.CultureInfo.InvariantCulture); - if (!literal.Contains('.')) - { - literal += ".0"; - } - - return new Tmp(literal, float64LiteralNode.Type, false); - } - - private Tmp EmitFuncCall(IndentedTextWriter writer, FuncCallNode funcCallNode) - { - var result = NewTmp(); - - var parameterStrings = new List(); - - foreach (var parameter in funcCallNode.Parameters) - { - var value = Unwrap(writer, EmitExpression(writer, parameter)); - parameterStrings.Add($"{MapType(parameter.Type)} {value}"); - } - - var functionPtr = Unwrap(writer, EmitExpression(writer, funcCallNode.Expression)); - - if (funcCallNode.Type is NubVoidType) - { - writer.WriteLine($"call {MapType(funcCallNode.Type)} {functionPtr}({string.Join(", ", parameterStrings)})"); - } - else - { - writer.WriteLine($"{result} = call {MapType(funcCallNode.Type)} {functionPtr}({string.Join(", ", parameterStrings)})"); - } - - return new Tmp(result, funcCallNode.Type, false); - } - - private Tmp EmitModuleFuncIdentifier(IndentedTextWriter writer, ModuleFuncIdentifierNode moduleFuncIdentifierNode) - { - var name = FuncName(moduleFuncIdentifierNode.ModuleToken.Value, moduleFuncIdentifierNode.NameToken.Value, moduleFuncIdentifierNode.ExternSymbolToken?.Value); - return new Tmp($"@{name}", moduleFuncIdentifierNode.Type, false); - } - - private Tmp EmitLocalFuncIdentifier(IndentedTextWriter writer, LocalFuncIdentifierNode localFuncIdentifierNode) - { - var name = FuncName(_module, localFuncIdentifierNode.NameToken.Value, localFuncIdentifierNode.ExternSymbolToken?.Value); - return new Tmp($"@{name}", localFuncIdentifierNode.Type, false); - } - - private Tmp EmitI16Literal(IndentedTextWriter writer, I16LiteralNode i16LiteralNode) - { - return new Tmp(i16LiteralNode.Value.ToString(), i16LiteralNode.Type, false); - } - - private Tmp EmitI32Literal(IndentedTextWriter writer, I32LiteralNode i32LiteralNode) - { - return new Tmp(i32LiteralNode.Value.ToString(), i32LiteralNode.Type, false); - } - - private Tmp EmitI64Literal(IndentedTextWriter writer, I64LiteralNode i64LiteralNode) - { - return new Tmp(i64LiteralNode.Value.ToString(), i64LiteralNode.Type, false); - } - - private Tmp EmitI8Literal(IndentedTextWriter writer, I8LiteralNode i8LiteralNode) - { - return new Tmp(i8LiteralNode.Value.ToString(), i8LiteralNode.Type, false); - } - - private Tmp EmitSize(IndentedTextWriter writer, SizeNode sizeNode) - { - return new Tmp(sizeNode.TargetType.GetSize().ToString(), sizeNode.Type, false); - } - - private Tmp EmitSliceIndexAccess(IndentedTextWriter writer, SliceIndexAccessNode sliceIndexAccessNode) - { - throw new NotImplementedException(); - } - - private Tmp EmitStringLiteral(IndentedTextWriter writer, StringLiteralNode stringLiteralNode) - { - throw new NotImplementedException(); - } - - private Tmp EmitStructFieldAccess(IndentedTextWriter writer, StructFieldAccessNode structFieldAccessNode) - { - var target = Unwrap(writer, EmitExpression(writer, structFieldAccessNode.Target)); - - var structType = (NubStructType)structFieldAccessNode.Target.Type; - var index = structType.GetFieldIndex(structFieldAccessNode.FieldToken.Value); - - var ptrTmp = NewTmp($"struct.field.{structFieldAccessNode.FieldToken.Value}"); - writer.WriteLine($"{ptrTmp} = getelementptr %{StructName(structType.Module, structType.Name)}, ptr {target}, i32 0, i32 {index}"); - - return new Tmp(ptrTmp, structFieldAccessNode.Type, true); - } - - private Tmp EmitStructInitializer(IndentedTextWriter writer, StructInitializerNode structInitializerNode, string? destination = null) - { - if (destination == null) - { - destination = NewTmp("struct"); - writer.WriteLine($"{destination} = alloca {MapType(structInitializerNode.Type)}"); - } - - var structType = (NubStructType)structInitializerNode.Type; - - writer.WriteLine($"call void @{StructName(structType.Module, structType.Name)}.new(ptr {destination})"); - - foreach (var (name, value) in structInitializerNode.Initializers) - { - var index = structType.GetFieldIndex(name.Value); - var fieldTmp = NewTmp($"struct.field.{name}"); - writer.WriteLine($"{fieldTmp} = getelementptr %{StructName(structType.Module, structType.Name)}, ptr {destination}, i32 0, i32 {index}"); - - EmitExpressionInto(writer, value, fieldTmp); - } - - return new Tmp(destination, structInitializerNode.Type, false); - } - - private Tmp EmitU16Literal(IndentedTextWriter writer, U16LiteralNode u16LiteralNode) - { - return new Tmp(u16LiteralNode.Value.ToString(), u16LiteralNode.Type, false); - } - - private Tmp EmitU32Literal(IndentedTextWriter writer, U32LiteralNode u32LiteralNode) - { - return new Tmp(u32LiteralNode.Value.ToString(), u32LiteralNode.Type, false); - } - - private Tmp EmitU64Literal(IndentedTextWriter writer, U64LiteralNode u64LiteralNode) - { - return new Tmp(u64LiteralNode.Value.ToString(), u64LiteralNode.Type, false); - } - - private Tmp EmitU8Literal(IndentedTextWriter writer, U8LiteralNode u8LiteralNode) - { - return new Tmp(u8LiteralNode.Value.ToString(), u8LiteralNode.Type, false); - } - - private Tmp EmitUnaryExpression(IndentedTextWriter writer, UnaryExpressionNode unaryExpressionNode) - { - var operand = Unwrap(writer, EmitExpression(writer, unaryExpressionNode.Operand)); - var result = NewTmp("unary"); - - switch (unaryExpressionNode.Operator) - { - case UnaryOperator.Negate: - { - switch (unaryExpressionNode.Operand.Type) - { - case NubIntType intType: - writer.WriteLine($"{result} = sub {MapType(intType)} 0, {operand}"); - break; - case NubFloatType floatType: - writer.WriteLine($"{result} = fneg {MapType(floatType)} {operand}"); - break; - default: - throw new UnreachableException(); - } - - break; - } - case UnaryOperator.Invert: - { - writer.WriteLine($"{result} = xor i1 {operand}, true"); - break; - } - default: - { - throw new ArgumentOutOfRangeException(); - } - } - - return new Tmp(result, unaryExpressionNode.Type, false); - } - - private Tmp EmitVariableIdentifier(IndentedTextWriter writer, VariableIdentifierNode variableIdentifierNode) - { - return new Tmp($"%{variableIdentifierNode.NameToken.Value}", variableIdentifierNode.Type, true); - } - private string StructName(StructNode structNode) { return StructName(_module, structNode.NameToken.Value); @@ -949,11 +962,6 @@ public class LlvmGenerator return $"struct.{module}.{name}"; } - private string FuncName(FuncPrototypeNode funcNodePrototype) - { - return FuncName(_module, funcNodePrototype.NameToken.Value, funcNodePrototype.ExternSymbolToken?.Value); - } - private string FuncName(string module, string name, string? externSymbol) { if (externSymbol != null)