...
This commit is contained in:
@@ -10,7 +10,7 @@ public class QBEGenerator
|
||||
|
||||
private readonly QBEWriter _writer;
|
||||
private readonly List<DefinitionNode> _definitions;
|
||||
private readonly HashSet<StructTypeNode> _structTypes;
|
||||
private readonly HashSet<NubStructType> _structTypes;
|
||||
|
||||
private readonly List<CStringLiteral> _cStringLiterals = [];
|
||||
private readonly List<StringLiteral> _stringLiterals = [];
|
||||
@@ -24,7 +24,7 @@ public class QBEGenerator
|
||||
|
||||
private Scope Scope => _scopes.Peek();
|
||||
|
||||
public QBEGenerator(List<DefinitionNode> definitions, HashSet<StructTypeNode> structTypes)
|
||||
public QBEGenerator(List<DefinitionNode> definitions, HashSet<NubStructType> structTypes)
|
||||
{
|
||||
_definitions = definitions;
|
||||
_structTypes = structTypes;
|
||||
@@ -142,72 +142,72 @@ public class QBEGenerator
|
||||
return _writer.ToString();
|
||||
}
|
||||
|
||||
private static string QBEAssign(TypeNode type)
|
||||
private static string QBEAssign(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
IntTypeNode { Width: <= 32 } => "=w",
|
||||
IntTypeNode { Width: 64 } => "=l",
|
||||
FloatTypeNode { Width: 32 } => "=s",
|
||||
FloatTypeNode { Width: 64 } => "=d",
|
||||
BoolTypeNode => "=w",
|
||||
PointerTypeNode => "=l",
|
||||
FuncTypeNode => "=l",
|
||||
CStringTypeNode => "=l",
|
||||
StringTypeNode => "=l",
|
||||
ArrayTypeNode => "=l",
|
||||
StructTypeNode => throw new InvalidOperationException("Structs are not loaded/stored directly"),
|
||||
VoidTypeNode => throw new InvalidOperationException("Void has no assignment"),
|
||||
NubIntType { Width: <= 32 } => "=w",
|
||||
NubIntType { Width: 64 } => "=l",
|
||||
NubFloatType { Width: 32 } => "=s",
|
||||
NubFloatType { Width: 64 } => "=d",
|
||||
NubBoolType => "=w",
|
||||
NubPointerType => "=l",
|
||||
NubFuncType => "=l",
|
||||
NubCStringType => "=l",
|
||||
NubStringType => "=l",
|
||||
NubArrayType => "=l",
|
||||
NubStructType => throw new InvalidOperationException("Structs are not loaded/stored directly"),
|
||||
NubVoidType => throw new InvalidOperationException("Void has no assignment"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unknown type {type.GetType()}")
|
||||
};
|
||||
}
|
||||
|
||||
private void EmitStore(TypeNode type, string value, string destination)
|
||||
private void EmitStore(NubType type, string value, string destination)
|
||||
{
|
||||
var store = type switch
|
||||
{
|
||||
BoolTypeNode => "storeb",
|
||||
IntTypeNode { Width: 8 } => "storeb",
|
||||
IntTypeNode { Width: 16 } => "storeh",
|
||||
IntTypeNode { Width: 32 } => "storew",
|
||||
IntTypeNode { Width: 64 } => "storel",
|
||||
FloatTypeNode { Width: 32 } => "stores",
|
||||
FloatTypeNode { Width: 64 } => "stored",
|
||||
PointerTypeNode => "storel",
|
||||
FuncTypeNode => "storel",
|
||||
CStringTypeNode => "storel",
|
||||
StringTypeNode => "storel",
|
||||
ArrayTypeNode => "storel",
|
||||
StructTypeNode => throw new InvalidOperationException("Struct stores must use blit/memcpy"),
|
||||
VoidTypeNode => throw new InvalidOperationException("Cannot store void"),
|
||||
NubBoolType => "storeb",
|
||||
NubIntType { Width: 8 } => "storeb",
|
||||
NubIntType { Width: 16 } => "storeh",
|
||||
NubIntType { Width: 32 } => "storew",
|
||||
NubIntType { Width: 64 } => "storel",
|
||||
NubFloatType { Width: 32 } => "stores",
|
||||
NubFloatType { Width: 64 } => "stored",
|
||||
NubPointerType => "storel",
|
||||
NubFuncType => "storel",
|
||||
NubCStringType => "storel",
|
||||
NubStringType => "storel",
|
||||
NubArrayType => "storel",
|
||||
NubStructType => throw new InvalidOperationException("Struct stores must use blit/memcpy"),
|
||||
NubVoidType => throw new InvalidOperationException("Cannot store void"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unknown type {type.GetType()}")
|
||||
};
|
||||
|
||||
_writer.Indented($"{store} {value}, {destination}");
|
||||
}
|
||||
|
||||
private string EmitLoad(TypeNode type, string from)
|
||||
private string EmitLoad(NubType type, string from)
|
||||
{
|
||||
string load = type switch
|
||||
{
|
||||
BoolTypeNode => "loadub",
|
||||
IntTypeNode { Signed: true, Width: 8 } => "loadsb",
|
||||
IntTypeNode { Signed: true, Width: 16 } => "loadsh",
|
||||
IntTypeNode { Signed: true, Width: 32 } => "loadw",
|
||||
IntTypeNode { Signed: true, Width: 64 } => "loadl",
|
||||
IntTypeNode { Signed: false, Width: 8 } => "loadsb",
|
||||
IntTypeNode { Signed: false, Width: 16 } => "loadsh",
|
||||
IntTypeNode { Signed: false, Width: 32 } => "loadw",
|
||||
IntTypeNode { Signed: false, Width: 64 } => "loadl",
|
||||
FloatTypeNode { Width: 32 } => "loads",
|
||||
FloatTypeNode { Width: 64 } => "loadd",
|
||||
PointerTypeNode => "loadl",
|
||||
FuncTypeNode => "loadl",
|
||||
CStringTypeNode => "loadl",
|
||||
StringTypeNode => "loadl",
|
||||
ArrayTypeNode => "loadl",
|
||||
StructTypeNode => throw new InvalidOperationException("Struct loads must use blit/memcpy"),
|
||||
VoidTypeNode => throw new InvalidOperationException("Cannot load void"),
|
||||
NubBoolType => "loadub",
|
||||
NubIntType { Signed: true, Width: 8 } => "loadsb",
|
||||
NubIntType { Signed: true, Width: 16 } => "loadsh",
|
||||
NubIntType { Signed: true, Width: 32 } => "loadw",
|
||||
NubIntType { Signed: true, Width: 64 } => "loadl",
|
||||
NubIntType { Signed: false, Width: 8 } => "loadsb",
|
||||
NubIntType { Signed: false, Width: 16 } => "loadsh",
|
||||
NubIntType { Signed: false, Width: 32 } => "loadw",
|
||||
NubIntType { Signed: false, Width: 64 } => "loadl",
|
||||
NubFloatType { Width: 32 } => "loads",
|
||||
NubFloatType { Width: 64 } => "loadd",
|
||||
NubPointerType => "loadl",
|
||||
NubFuncType => "loadl",
|
||||
NubCStringType => "loadl",
|
||||
NubStringType => "loadl",
|
||||
NubArrayType => "loadl",
|
||||
NubStructType => throw new InvalidOperationException("Struct loads must use blit/memcpy"),
|
||||
NubVoidType => throw new InvalidOperationException("Cannot load void"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unknown type {type.GetType()}")
|
||||
};
|
||||
|
||||
@@ -217,48 +217,48 @@ public class QBEGenerator
|
||||
}
|
||||
|
||||
|
||||
private static string StructDefQBEType(TypeNode type)
|
||||
private static string StructDefQBEType(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
BoolTypeNode => "b",
|
||||
IntTypeNode { Width: 8 } => "b",
|
||||
IntTypeNode { Width: 16 } => "h",
|
||||
IntTypeNode { Width: 32 } => "w",
|
||||
IntTypeNode { Width: 64 } => "l",
|
||||
FloatTypeNode { Width: 32 } => "s",
|
||||
FloatTypeNode { Width: 64 } => "d",
|
||||
PointerTypeNode => "l",
|
||||
FuncTypeNode => "l",
|
||||
CStringTypeNode => "l",
|
||||
StringTypeNode => "l",
|
||||
ArrayTypeNode => "l",
|
||||
StructTypeNode st => StructTypeName(st.Module, st.Name),
|
||||
VoidTypeNode => throw new InvalidOperationException("Void has no QBE type"),
|
||||
NubBoolType => "b",
|
||||
NubIntType { Width: 8 } => "b",
|
||||
NubIntType { Width: 16 } => "h",
|
||||
NubIntType { Width: 32 } => "w",
|
||||
NubIntType { Width: 64 } => "l",
|
||||
NubFloatType { Width: 32 } => "s",
|
||||
NubFloatType { Width: 64 } => "d",
|
||||
NubPointerType => "l",
|
||||
NubFuncType => "l",
|
||||
NubCStringType => "l",
|
||||
NubStringType => "l",
|
||||
NubArrayType => "l",
|
||||
NubStructType st => StructTypeName(st.Module, st.Name),
|
||||
NubVoidType => throw new InvalidOperationException("Void has no QBE type"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unknown type: {type.GetType()}")
|
||||
};
|
||||
}
|
||||
|
||||
private string FuncQBETypeName(TypeNode type)
|
||||
private string FuncQBETypeName(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
BoolTypeNode => "ub",
|
||||
IntTypeNode { Signed: true, Width: 8 } => "sb",
|
||||
IntTypeNode { Signed: true, Width: 16 } => "sh",
|
||||
IntTypeNode { Signed: false, Width: 8 } => "ub",
|
||||
IntTypeNode { Signed: false, Width: 16 } => "uh",
|
||||
IntTypeNode { Width: 32 } => "w",
|
||||
IntTypeNode { Width: 64 } => "l",
|
||||
FloatTypeNode { Width: 32 } => "s",
|
||||
FloatTypeNode { Width: 64 } => "d",
|
||||
PointerTypeNode => "l",
|
||||
FuncTypeNode => "l",
|
||||
CStringTypeNode => "l",
|
||||
StringTypeNode => "l",
|
||||
ArrayTypeNode => "l",
|
||||
StructTypeNode st => StructTypeName(st.Module, st.Name),
|
||||
VoidTypeNode => throw new InvalidOperationException("Void has no QBE type"),
|
||||
NubBoolType => "ub",
|
||||
NubIntType { Signed: true, Width: 8 } => "sb",
|
||||
NubIntType { Signed: true, Width: 16 } => "sh",
|
||||
NubIntType { Signed: false, Width: 8 } => "ub",
|
||||
NubIntType { Signed: false, Width: 16 } => "uh",
|
||||
NubIntType { Width: 32 } => "w",
|
||||
NubIntType { Width: 64 } => "l",
|
||||
NubFloatType { Width: 32 } => "s",
|
||||
NubFloatType { Width: 64 } => "d",
|
||||
NubPointerType => "l",
|
||||
NubFuncType => "l",
|
||||
NubCStringType => "l",
|
||||
NubStringType => "l",
|
||||
NubArrayType => "l",
|
||||
NubStructType st => StructTypeName(st.Module, st.Name),
|
||||
NubVoidType => throw new InvalidOperationException("Void has no QBE type"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unknown type: {type.GetType()}")
|
||||
};
|
||||
}
|
||||
@@ -309,7 +309,7 @@ public class QBEGenerator
|
||||
var value = EmitExpression(source);
|
||||
_writer.Indented($"blit {value}, {destinationAddress}, {SizeOf(source.Type)}");
|
||||
|
||||
if (source.Type is StructTypeNode structType)
|
||||
if (source.Type is NubStructType structType)
|
||||
{
|
||||
var copyFunc = structType.Functions.FirstOrDefault(x => x.Hook == "oncopy");
|
||||
if (copyFunc != null)
|
||||
@@ -323,7 +323,7 @@ public class QBEGenerator
|
||||
|
||||
switch (source.Type)
|
||||
{
|
||||
case CStringTypeNode:
|
||||
case NubCStringType:
|
||||
{
|
||||
var value = EmitExpression(source);
|
||||
var size = EmitCStringSizeInBytes(value);
|
||||
@@ -333,7 +333,7 @@ public class QBEGenerator
|
||||
EmitStore(source.Type, buffer, destinationAddress);
|
||||
return;
|
||||
}
|
||||
case StringTypeNode:
|
||||
case NubStringType:
|
||||
{
|
||||
var value = EmitExpression(source);
|
||||
var size = EmitStringSizeInBytes(value);
|
||||
@@ -343,14 +343,14 @@ public class QBEGenerator
|
||||
EmitStore(source.Type, buffer, destinationAddress);
|
||||
return;
|
||||
}
|
||||
case VoidTypeNode:
|
||||
case NubVoidType:
|
||||
throw new InvalidOperationException("Cannot copy void");
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(source.Type), $"Unknown type {source.Type}");
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitStructType(StructTypeNode structType)
|
||||
private void EmitStructType(NubStructType structType)
|
||||
{
|
||||
// todo(nub31): qbe expects structs to be declared in order. We must Check the dependencies of the struct to see if a type need to be declared before this one
|
||||
// qbe allows multiple declarations of the same struct, but we should keep track and only emit an new one if necessary
|
||||
@@ -374,7 +374,7 @@ public class QBEGenerator
|
||||
{
|
||||
if (field.Value.TryGetValue(out var value))
|
||||
{
|
||||
var offset = OffsetOf(structDef.StructType, field.Name);
|
||||
var offset = OffsetOf(TypeOfStruct(structDef), field.Name);
|
||||
var destination = TmpName();
|
||||
_writer.Indented($"{destination} =l add %struct, {offset}");
|
||||
EmitCopyInto(value, destination);
|
||||
@@ -393,7 +393,7 @@ public class QBEGenerator
|
||||
|
||||
_writer.Write("export function ");
|
||||
|
||||
if (function.Signature.ReturnType is not VoidTypeNode)
|
||||
if (function.Signature.ReturnType is not NubVoidType)
|
||||
{
|
||||
_writer.Write(FuncQBETypeName(function.Signature.ReturnType) + ' ');
|
||||
}
|
||||
@@ -418,7 +418,7 @@ public class QBEGenerator
|
||||
EmitBlock(function.Body, scope);
|
||||
|
||||
// Implicit return for void functions if no explicit return has been set
|
||||
if (function.Signature.ReturnType is VoidTypeNode && function.Body.Statements.LastOrDefault() is not ReturnNode)
|
||||
if (function.Signature.ReturnType is NubVoidType && function.Body.Statements.LastOrDefault() is not ReturnNode)
|
||||
{
|
||||
_writer.Indented("ret");
|
||||
}
|
||||
@@ -437,7 +437,7 @@ public class QBEGenerator
|
||||
|
||||
_writer.Write(funcDef.ExternSymbol != null ? "export function " : "function ");
|
||||
|
||||
if (funcDef.Signature.ReturnType is not VoidTypeNode)
|
||||
if (funcDef.Signature.ReturnType is not NubVoidType)
|
||||
{
|
||||
_writer.Write(FuncQBETypeName(funcDef.Signature.ReturnType) + ' ');
|
||||
}
|
||||
@@ -533,7 +533,7 @@ public class QBEGenerator
|
||||
|
||||
while (Scope.Variables.TryPop(out var variable))
|
||||
{
|
||||
if (variable.Type is StructTypeNode structType)
|
||||
if (variable.Type is NubStructType structType)
|
||||
{
|
||||
var destroyFunc = structType.Functions.FirstOrDefault(x => x.Hook == "ondestroy");
|
||||
if (destroyFunc != null)
|
||||
@@ -643,7 +643,7 @@ public class QBEGenerator
|
||||
var elementAddress = TmpName();
|
||||
_writer.Indented($"{elementAddress} =l add {arrayStart}, {arrayOffset}");
|
||||
|
||||
if (forArray.ArrayType.ElementType is StructTypeNode)
|
||||
if (forArray.ArrayType.ElementType is NubStructType)
|
||||
{
|
||||
_writer.Indented($"%{forArray.ElementIdent} =l copy {elementAddress}");
|
||||
}
|
||||
@@ -689,7 +689,7 @@ public class QBEGenerator
|
||||
ConvertIntNode expr => EmitConvertInt(expr),
|
||||
FuncCallNode expr => EmitFuncCall(expr),
|
||||
FuncIdentifierNode expr => FuncName(expr.Module, expr.Name, expr.ExternSymbol),
|
||||
FuncParameterIdentifierNode expr => $"%{expr.Name}",
|
||||
RValueIdentifierNode expr => $"%{expr.Name}",
|
||||
StructFuncCallNode expr => EmitStructFuncCall(expr),
|
||||
StructInitializerNode expr => EmitStructInitializer(expr),
|
||||
UnaryExpressionNode expr => EmitUnaryExpression(expr),
|
||||
@@ -789,7 +789,7 @@ public class QBEGenerator
|
||||
ArrayIndexAccessNode arrayIndexAccess => EmitAddressOfArrayIndexAccess(arrayIndexAccess),
|
||||
DereferenceNode dereference => EmitExpression(dereference.Expression),
|
||||
StructFieldAccessNode structFieldAccess => EmitAddressOfStructFieldAccess(structFieldAccess),
|
||||
VariableIdentifierNode variableIdent => $"%{variableIdent.Name}",
|
||||
LValueIdentifierNode variableIdent => $"%{variableIdent.Name}",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(lval))
|
||||
};
|
||||
}
|
||||
@@ -799,7 +799,7 @@ public class QBEGenerator
|
||||
var array = EmitExpression(arrayIndexAccess.Target);
|
||||
var index = EmitExpression(arrayIndexAccess.Index);
|
||||
|
||||
var elementType = ((ArrayTypeNode)arrayIndexAccess.Target.Type).ElementType;
|
||||
var elementType = ((NubArrayType)arrayIndexAccess.Target.Type).ElementType;
|
||||
|
||||
var offset = TmpName();
|
||||
_writer.Indented($"{offset} =l mul {index}, {SizeOf(elementType)}");
|
||||
@@ -810,8 +810,9 @@ public class QBEGenerator
|
||||
|
||||
private string EmitAddressOfStructFieldAccess(StructFieldAccessNode structFieldAccess)
|
||||
{
|
||||
var structType = (NubStructType)structFieldAccess.Target.Type;
|
||||
var target = EmitExpression(structFieldAccess.Target);
|
||||
var offset = OffsetOf(structFieldAccess.StructType, structFieldAccess.Field);
|
||||
var offset = OffsetOf(structType, structFieldAccess.Field);
|
||||
|
||||
var address = TmpName();
|
||||
_writer.Indented($"{address} =l add {target}, {offset}");
|
||||
@@ -831,15 +832,15 @@ public class QBEGenerator
|
||||
return outputName;
|
||||
}
|
||||
|
||||
private static string EmitBinaryInstructionForOperator(BinaryOperator op, TypeNode type)
|
||||
private static string EmitBinaryInstructionForOperator(BinaryOperator op, NubType type)
|
||||
{
|
||||
// todo(nub31): Add support for string concatenation. Currently this expects ints or floats and will treat strings as ints
|
||||
return op switch
|
||||
{
|
||||
BinaryOperator.RightShift => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } => "sar",
|
||||
IntTypeNode { Signed: false } => "shr",
|
||||
NubIntType { Signed: true } => "sar",
|
||||
NubIntType { Signed: false } => "shr",
|
||||
_ => throw new NotSupportedException($"Right shift not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.BitwiseAnd => "and",
|
||||
@@ -848,15 +849,15 @@ public class QBEGenerator
|
||||
BinaryOperator.LeftShift => "shl",
|
||||
BinaryOperator.Divide => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } => "div",
|
||||
IntTypeNode { Signed: false } => "udiv",
|
||||
FloatTypeNode => "div",
|
||||
NubIntType { Signed: true } => "div",
|
||||
NubIntType { Signed: false } => "udiv",
|
||||
NubFloatType => "div",
|
||||
_ => throw new NotSupportedException($"Division not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.Modulo => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } => "rem",
|
||||
IntTypeNode { Signed: false } => "urem",
|
||||
NubIntType { Signed: true } => "rem",
|
||||
NubIntType { Signed: false } => "urem",
|
||||
_ => throw new NotSupportedException($"Modulo not supported for type '{type}'")
|
||||
},
|
||||
BinaryOperator.Plus => "add",
|
||||
@@ -864,13 +865,13 @@ public class QBEGenerator
|
||||
BinaryOperator.Multiply => "mul",
|
||||
BinaryOperator.Equal => type switch
|
||||
{
|
||||
IntTypeNode intType => intType.Width switch
|
||||
NubIntType intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "ceqw",
|
||||
64 => "ceql",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "ceqs",
|
||||
64 => "ceqd",
|
||||
@@ -880,13 +881,13 @@ public class QBEGenerator
|
||||
},
|
||||
BinaryOperator.NotEqual => type switch
|
||||
{
|
||||
IntTypeNode intType => intType.Width switch
|
||||
NubIntType intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cnew",
|
||||
64 => "cnel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "cnes",
|
||||
64 => "cned",
|
||||
@@ -896,19 +897,19 @@ public class QBEGenerator
|
||||
},
|
||||
BinaryOperator.LessThan => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } intType => intType.Width switch
|
||||
NubIntType { Signed: true } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "csltw",
|
||||
64 => "csltl",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
IntTypeNode { Signed: false } intType => intType.Width switch
|
||||
NubIntType { Signed: false } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cultw",
|
||||
64 => "cultl",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "clts",
|
||||
64 => "cltd",
|
||||
@@ -918,19 +919,19 @@ public class QBEGenerator
|
||||
},
|
||||
BinaryOperator.LessThanOrEqual => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } intType => intType.Width switch
|
||||
NubIntType { Signed: true } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cslew",
|
||||
64 => "cslel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
IntTypeNode { Signed: false } intType => intType.Width switch
|
||||
NubIntType { Signed: false } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "culew",
|
||||
64 => "culel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "cles",
|
||||
64 => "cled",
|
||||
@@ -940,19 +941,19 @@ public class QBEGenerator
|
||||
},
|
||||
BinaryOperator.GreaterThan => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } intType => intType.Width switch
|
||||
NubIntType { Signed: true } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "csgtw",
|
||||
64 => "csgtl",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
IntTypeNode { Signed: false } intType => intType.Width switch
|
||||
NubIntType { Signed: false } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cugtw",
|
||||
64 => "cugtl",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "cgts",
|
||||
64 => "cgtd",
|
||||
@@ -962,19 +963,19 @@ public class QBEGenerator
|
||||
},
|
||||
BinaryOperator.GreaterThanOrEqual => type switch
|
||||
{
|
||||
IntTypeNode { Signed: true } intType => intType.Width switch
|
||||
NubIntType { Signed: true } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "csgew",
|
||||
64 => "csgel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
IntTypeNode { Signed: false } intType => intType.Width switch
|
||||
NubIntType { Signed: false } intType => intType.Width switch
|
||||
{
|
||||
<= 32 => "cugew",
|
||||
64 => "cugel",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
FloatTypeNode floatType => floatType.Width switch
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "cges",
|
||||
64 => "cged",
|
||||
@@ -1027,16 +1028,16 @@ public class QBEGenerator
|
||||
{
|
||||
switch (unaryExpression.Operand.Type)
|
||||
{
|
||||
case IntTypeNode { Signed: true, Width: 64 }:
|
||||
case NubIntType { Signed: true, Width: 64 }:
|
||||
_writer.Indented($"{outputName} =l neg {operand}");
|
||||
return outputName;
|
||||
case IntTypeNode { Signed: true, Width: 8 or 16 or 32 }:
|
||||
case NubIntType { Signed: true, Width: 8 or 16 or 32 }:
|
||||
_writer.Indented($"{outputName} =w neg {operand}");
|
||||
return outputName;
|
||||
case FloatTypeNode { Width: 64 }:
|
||||
case NubFloatType { Width: 64 }:
|
||||
_writer.Indented($"{outputName} =d neg {operand}");
|
||||
return outputName;
|
||||
case FloatTypeNode { Width: 32 }:
|
||||
case NubFloatType { Width: 32 }:
|
||||
_writer.Indented($"{outputName} =s neg {operand}");
|
||||
return outputName;
|
||||
}
|
||||
@@ -1047,7 +1048,7 @@ public class QBEGenerator
|
||||
{
|
||||
switch (unaryExpression.Operand.Type)
|
||||
{
|
||||
case BoolTypeNode:
|
||||
case NubBoolType:
|
||||
_writer.Indented($"{outputName} =w xor {operand}, 1");
|
||||
return outputName;
|
||||
}
|
||||
@@ -1065,7 +1066,7 @@ public class QBEGenerator
|
||||
|
||||
private string EmitStructFuncCall(StructFuncCallNode structFuncCall)
|
||||
{
|
||||
var func = StructFuncName(structFuncCall.StructType.Module, structFuncCall.StructType.Name, structFuncCall.Name);
|
||||
var func = StructFuncName(structFuncCall.Module, structFuncCall.StructName, structFuncCall.FuncName);
|
||||
|
||||
var thisParameter = EmitExpression(structFuncCall.StructExpression);
|
||||
|
||||
@@ -1075,7 +1076,7 @@ public class QBEGenerator
|
||||
{
|
||||
var value = EmitExpression(parameter);
|
||||
|
||||
if (parameter.Type is StructTypeNode structType)
|
||||
if (parameter.Type is NubStructType structType)
|
||||
{
|
||||
var copyFunc = structType.Functions.FirstOrDefault(x => x.Hook == "oncopy");
|
||||
if (copyFunc != null)
|
||||
@@ -1087,7 +1088,7 @@ public class QBEGenerator
|
||||
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {value}");
|
||||
}
|
||||
|
||||
if (structFuncCall.Type is VoidTypeNode)
|
||||
if (structFuncCall.Type is NubVoidType)
|
||||
{
|
||||
_writer.Indented($"call {func}({string.Join(", ", parameterStrings)})");
|
||||
return string.Empty;
|
||||
@@ -1163,7 +1164,7 @@ public class QBEGenerator
|
||||
{
|
||||
var value = EmitExpression(parameter);
|
||||
|
||||
if (parameter.Type is StructTypeNode structType)
|
||||
if (parameter.Type is NubStructType structType)
|
||||
{
|
||||
var copyFunc = structType.Functions.FirstOrDefault(x => x.Hook == "oncopy");
|
||||
if (copyFunc != null)
|
||||
@@ -1175,7 +1176,7 @@ public class QBEGenerator
|
||||
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {value}");
|
||||
}
|
||||
|
||||
if (funcCall.Type is VoidTypeNode)
|
||||
if (funcCall.Type is NubVoidType)
|
||||
{
|
||||
_writer.Indented($"call {funcPointer}({string.Join(", ", parameterStrings)})");
|
||||
return string.Empty;
|
||||
@@ -1188,25 +1189,25 @@ public class QBEGenerator
|
||||
}
|
||||
}
|
||||
|
||||
private static int SizeOf(TypeNode type)
|
||||
private static int SizeOf(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
IntTypeNode intType => intType.Width / 8,
|
||||
FloatTypeNode fType => fType.Width / 8,
|
||||
BoolTypeNode => 1,
|
||||
PointerTypeNode => PTR_SIZE,
|
||||
FuncTypeNode => PTR_SIZE,
|
||||
StructTypeNode structType => CalculateStructSize(structType),
|
||||
VoidTypeNode => throw new InvalidOperationException("Void type has no size"),
|
||||
CStringTypeNode => PTR_SIZE,
|
||||
StringTypeNode => PTR_SIZE,
|
||||
ArrayTypeNode => PTR_SIZE,
|
||||
NubIntType intType => intType.Width / 8,
|
||||
NubFloatType fType => fType.Width / 8,
|
||||
NubBoolType => 1,
|
||||
NubPointerType => PTR_SIZE,
|
||||
NubFuncType => PTR_SIZE,
|
||||
NubStructType structType => CalculateStructSize(structType),
|
||||
NubVoidType => throw new InvalidOperationException("Void type has no size"),
|
||||
NubCStringType => PTR_SIZE,
|
||||
NubStringType => PTR_SIZE,
|
||||
NubArrayType => PTR_SIZE,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unknown type: {type.GetType()}")
|
||||
};
|
||||
}
|
||||
|
||||
private static int CalculateStructSize(StructTypeNode structType)
|
||||
private static int CalculateStructSize(NubStructType structType)
|
||||
{
|
||||
var offset = 0;
|
||||
|
||||
@@ -1221,26 +1222,26 @@ public class QBEGenerator
|
||||
return AlignTo(offset, structAlignment);
|
||||
}
|
||||
|
||||
private static int AlignmentOf(TypeNode type)
|
||||
private static int AlignmentOf(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
IntTypeNode intType => intType.Width / 8,
|
||||
FloatTypeNode fType => fType.Width / 8,
|
||||
BoolTypeNode => 1,
|
||||
PointerTypeNode => PTR_SIZE,
|
||||
FuncTypeNode => PTR_SIZE,
|
||||
StructTypeNode st => CalculateStructAlignment(st),
|
||||
CStringTypeNode => PTR_SIZE,
|
||||
StringTypeNode => PTR_SIZE,
|
||||
ArrayTypeNode => PTR_SIZE,
|
||||
VoidTypeNode => throw new InvalidOperationException("Void has no alignment"),
|
||||
NubIntType intType => intType.Width / 8,
|
||||
NubFloatType fType => fType.Width / 8,
|
||||
NubBoolType => 1,
|
||||
NubPointerType => PTR_SIZE,
|
||||
NubFuncType => PTR_SIZE,
|
||||
NubStructType st => CalculateStructAlignment(st),
|
||||
NubCStringType => PTR_SIZE,
|
||||
NubStringType => PTR_SIZE,
|
||||
NubArrayType => PTR_SIZE,
|
||||
NubVoidType => throw new InvalidOperationException("Void has no alignment"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unknown type: {type.GetType()}")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private static int CalculateStructAlignment(StructTypeNode structType)
|
||||
private static int CalculateStructAlignment(NubStructType structType)
|
||||
{
|
||||
var maxAlignment = 1;
|
||||
|
||||
@@ -1258,7 +1259,7 @@ public class QBEGenerator
|
||||
return (offset + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
private static int OffsetOf(StructTypeNode type, string member)
|
||||
private static int OffsetOf(NubStructType type, string member)
|
||||
{
|
||||
var offset = 0;
|
||||
|
||||
@@ -1278,6 +1279,27 @@ public class QBEGenerator
|
||||
throw new UnreachableException($"Member '{member}' not found in struct");
|
||||
}
|
||||
|
||||
private NubStructType TypeOfStruct(StructNode definition)
|
||||
{
|
||||
var fieldTypes = definition.Fields
|
||||
.Select(x => new NubStructFieldType(x.Name, x.Type, x.Value.HasValue))
|
||||
.ToList();
|
||||
|
||||
var functionTypes = new List<NubStructFuncType>();
|
||||
foreach (var function in definition.Functions)
|
||||
{
|
||||
var parameters = function.Signature.Parameters.Select(x => x.Type).ToList();
|
||||
functionTypes.Add(new NubStructFuncType(function.Name, function.Hook, parameters, function.Signature.ReturnType));
|
||||
}
|
||||
|
||||
return new NubStructType(definition.Module, definition.Name, fieldTypes, functionTypes);
|
||||
}
|
||||
|
||||
private NubFuncType TypeOfFunc(FuncSignatureNode signature)
|
||||
{
|
||||
var parameters = signature.Parameters.Select(x => x.Type).ToList();
|
||||
return new NubFuncType(parameters, signature.ReturnType);
|
||||
}
|
||||
|
||||
private string TmpName()
|
||||
{
|
||||
@@ -1332,7 +1354,7 @@ public class Scope(Scope? parent = null)
|
||||
}
|
||||
}
|
||||
|
||||
public record Variable(string Name, TypeNode Type);
|
||||
public record Variable(string Name, NubType Type);
|
||||
|
||||
public class StringLiteral(string value, string name)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user