Lookahead cleanup. Start work on throws. Fix try expressions. Beginning work on initializer. Some fixes on LLVM types. Moving more target info into C3. Moving alignment into types Introducing a meta type (incomplete). Start work on macros. Splitting '@' from macro name.

This commit is contained in:
Christoffer Lerno
2020-02-14 11:15:35 +01:00
parent ae683d2811
commit ebbea2ac42
51 changed files with 7227 additions and 497 deletions

View File

@@ -310,11 +310,6 @@ void parse_arguments(int argc, const char *argv[])
exit(EXIT_SUCCESS);
}
build_options.cshort_size = sizeof(short);
build_options.cint_size = sizeof(int);
build_options.clong_size = sizeof(long);
build_options.clonglong_size = sizeof(long long);
build_options.pointer_size = sizeof(void *);
build_options.path = ".";
build_options.emit_llvm = false;
build_options.emit_bitcode = true;

View File

@@ -100,12 +100,6 @@ typedef struct
uint32_t symtab_size;
CompileOption compile_option;
DiagnosticsSeverity severity[DIAG_END_SENTINEL];
int pointer_size;
int cshort_size;
int cint_size;
int clong_size;
int clonglong_size;
int clongdouble_size;
OptimizationLevel optimization_level;
SizeOptimizationLevel size_optimization_level;
bool debug_info;

View File

@@ -16,6 +16,7 @@ Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility)
return decl;
}
Type poisoned_type = { .type_kind = TYPE_POISONED };
TypeInfo poisoned_type_info = { .kind = TYPE_INFO_POISON };
@@ -174,8 +175,18 @@ Type* type_get_unsigned(Type *type)
*/
bool func_return_value_as_out(FunctionSignature *func_sig)
{
Type *return_type = func_sig->rtype->type->canonical;
if (return_type->type_kind == TYPE_VOID) return false;
if (func_has_error_return(func_sig)) return true;
// TODO improve
return type_size(return_type) > 8 * 4;
}
BinaryOp binary_op[256] = {
BinaryOp binary_op[TOKEN_LAST + 1] = {
[TOKEN_STAR] = BINARYOP_MULT,
[TOKEN_MULT_MOD] = BINARYOP_MULT_MOD,
[TOKEN_DIV] = BINARYOP_DIV,
@@ -214,7 +225,7 @@ BinaryOp binary_op[256] = {
};
static BinaryOp assign_binop[256] = {
static BinaryOp assign_binop[BINARYOP_LAST + 1] = {
[BINARYOP_MULT_ASSIGN] = BINARYOP_MULT,
[BINARYOP_MULT_MOD_ASSIGN] = BINARYOP_MULT_MOD,
[BINARYOP_ADD_ASSIGN] = BINARYOP_ADD,
@@ -237,10 +248,7 @@ BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op)
return assign_binop[(int)assign_binary_op];
}
AssignOp assign_op[256] = {
};
UnaryOp unary_op[256] = {
UnaryOp unary_op[TOKEN_LAST + 1] = {
[TOKEN_STAR] = UNARYOP_DEREF,
[TOKEN_AMP] = UNARYOP_ADDR,
[TOKEN_BIT_NOT] = UNARYOP_BITNEG,
@@ -250,25 +258,13 @@ UnaryOp unary_op[256] = {
[TOKEN_MINUSMINUS] = UNARYOP_DEC,
};
PostUnaryOp post_unary_op[256] = {
PostUnaryOp post_unary_op[TOKEN_LAST + 1] = {
[TOKEN_PLUSPLUS] = POSTUNARYOP_INC,
[TOKEN_MINUSMINUS] = POSTUNARYOP_DEC,
};
AssignOp assignop_from_token(TokenType type)
{
return assign_op[type];
}
TokenType assignop_to_token(AssignOp type)
{
for (unsigned i = 0; i < 256; i++)
{
if (assign_op[i] == type) return (TokenType)i;
}
return TOKEN_INVALID_TOKEN;
}
BinaryOp binaryop_from_token(TokenType type)
{
@@ -277,7 +273,7 @@ BinaryOp binaryop_from_token(TokenType type)
TokenType binaryop_to_token(BinaryOp type)
{
for (unsigned i = 0; i < 256; i++)
for (unsigned i = 0; i <= TOKEN_LAST; i++)
{
if (binary_op[i] == type) return (TokenType)i;
}
@@ -291,7 +287,7 @@ UnaryOp unaryop_from_token(TokenType type)
TokenType unaryop_to_token(UnaryOp type)
{
for (unsigned i = 0; i < 256; i++)
for (unsigned i = 0; i <= TOKEN_LAST; i++)
{
if (unary_op[i] == type) return (TokenType)i;
}
@@ -305,7 +301,7 @@ PostUnaryOp post_unaryop_from_token(TokenType type)
TokenType postunaryop_to_token(PostUnaryOp type)
{
for (unsigned i = 0; i < 256; i++)
for (unsigned i = 0; i <= TOKEN_LAST; i++)
{
if (post_unary_op[i] == type) return (TokenType)i;
}
@@ -348,6 +344,10 @@ void fprint_type_recursive(FILE *file, Type *type, int indent)
case TYPE_POISONED:
fprintf_indented(file, indent, "(type poison)\n");
return;
case TYPE_META_TYPE:
fprintf_indented(file, indent, "(meta-type");
fprint_type_recursive(file, type->child, indent + 1);
fprint_endparen(file, indent);
case TYPE_FUNC:
fprintf_indented(file, indent, "(type-func %s)\n", type->func.signature->mangled_signature);
return;
@@ -675,9 +675,16 @@ void fprint_func_signature(FILE *file, FunctionSignature *signature, int indent)
fprintf_indented(file, indent, "(params\n");
fprint_decl_list(file, signature->params, indent + 1);
fprint_endparen(file, indent);
fprintf_indented(file, indent, "(throws\n");
fprint_decl_list(file, signature->throws, indent + 1);
fprint_endparen(file, indent);
if (signature->throw_any)
{
fprintf_indented(file, indent, "(throws any)\n");
}
else
{
fprintf_indented(file, indent, "(throws\n");
fprint_decl_list(file, signature->throws, indent + 1);
fprint_endparen(file, indent);
}
}
void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
{
@@ -1039,7 +1046,7 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
break;
case AST_THROW_STMT:
fprintf(file, "(throw\n");
fprint_expr_recursive(file, ast->throw_stmt, indent + 1);
fprint_expr_recursive(file, ast->throw_stmt.throw_value, indent + 1);
break;
case AST_TRY_STMT:
TODO

View File

@@ -38,7 +38,7 @@ static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type)
break;
}
SEMA_ERROR(expr, "Cannot %s '%s' to '%s'", action, type_to_error_string(expr->type), type_to_error_string(type));
SEMA_ERROR(expr, "Cannot %s '%s' to '%s'.", action, type_to_error_string(expr->type), type_to_error_string(type));
return false;
}
@@ -580,6 +580,7 @@ CastKind cast_to_bool_kind(Type *type)
case TYPE_ARRAY:
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
case TYPE_META_TYPE:
// Improve consider vararray / subarray conversion to boolean.
return CAST_ERROR;
case TYPE_BOOL:
@@ -614,6 +615,7 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
{
case TYPE_POISONED:
case TYPE_VOID:
case TYPE_META_TYPE:
break;
case TYPE_BOOL:
if (type_is_integer(canonical)) return boxi(expr, from_type, canonical, to_type, cast_type);

View File

@@ -36,7 +36,6 @@ static void compiler_lex(BuildTarget *target)
void compiler_parse(BuildTarget *target)
{
builtin_setup();
VECEACH(target->sources, i)
{
bool loaded = false;
@@ -149,7 +148,6 @@ void compile_files(BuildTarget *target)
}
target_expand_source_names(target);
target_setup();
builtin_setup();
if (!vec_size(target->sources)) error_exit("No files to compile.");
switch (build_options.compile_option)

View File

@@ -9,6 +9,7 @@
#include "../build/build_options.h"
#include "compiler.h"
#include "enums.h"
#include "target.h"
typedef uint32_t SourceLoc;
#define INVALID_LOC UINT32_MAX
@@ -18,6 +19,9 @@ typedef uint32_t SourceLoc;
#define MAX_SCOPE_DEPTH 0xFF
#define MAX_PATH 1024
#define MAX_DEFERS 0xFFFF
#define MAX_FUNCTION_SIGNATURE_SIZE 2048
#define MAX_PARAMS 512
#define MAX_ERRORS 0xFFFF
typedef struct _Ast Ast;
typedef struct _Decl Decl;
@@ -102,8 +106,10 @@ typedef struct _Path
typedef struct
{
unsigned bitsize : 16;
unsigned char bitsize;
unsigned char bytesize;
unsigned char min_alignment;
unsigned char pref_alignment;
} TypeBuiltin;
typedef struct
@@ -128,7 +134,7 @@ struct _Type
TypeKind type_kind : 8;
struct _Type *canonical;
const char *name;
struct _Type **ptr_cache;
struct _Type **type_cache;
void *backend_type;
void *backend_debug_type;
union
@@ -138,6 +144,7 @@ struct _Type
TypeArray array;
TypeFunc func;
Type *pointer;
Type *child;
};
};
@@ -183,6 +190,8 @@ typedef struct
typedef struct
{
uint32_t alignment;
uint64_t size;
Decl **members;
} StructDecl;
@@ -230,6 +239,7 @@ typedef struct _FunctionSignature
{
CallConvention convention : 4;
bool variadic : 1;
bool throw_any : 1;
TypeInfo *rtype;
Decl** params;
Decl** throws;
@@ -339,6 +349,7 @@ typedef struct _Decl
CtIfDecl ct_elif_decl;
Decl** ct_else_decl;
Expr *incr_array_decl;
TypeInfo *throws;
};
} Decl;
@@ -474,6 +485,7 @@ struct _Expr
ExprStructValue struct_value_expr;
ExprTypeRef type_access;
ExprTry try_expr;
Expr* macro_expr;
ExprBinary binary_expr;
ExprTernary ternary_expr;
ExprUnary unary_expr;
@@ -651,6 +663,12 @@ typedef struct
DeferList defers;
} AstNextStmt;
typedef struct
{
Expr *throw_value;
DeferList defers;
} AstThrowStmt;
typedef struct _Ast
{
SourceRange span;
@@ -663,9 +681,9 @@ typedef struct _Ast
AstCompoundStmt function_block_stmt;
Decl *declare_stmt;
Expr *expr_stmt;
Expr *throw_stmt;
struct _Ast *volatile_stmt;
struct _Ast *try_stmt;
AstThrowStmt throw_stmt;
Ast *volatile_stmt;
Ast *try_stmt;
AstLabelStmt label_stmt;
AstReturnStmt return_stmt;
AstWhileStmt while_stmt;
@@ -764,6 +782,12 @@ typedef struct _Context
Token *next_lead_comment;
DynamicScope *current_scope;
Decl *evaluating_macro;
// Error handling
struct
{
Decl **errors;
int try_nesting;
};
Type *rtype;
int in_volatile_section;
Decl *locals[MAX_LOCALS];
@@ -780,7 +804,7 @@ typedef struct _Context
Token next_tok;
struct
{
bool has_stored;
bool in_lookahead;
const char *current;
const char *start;
Token tok;
@@ -788,7 +812,6 @@ typedef struct _Context
Token *lead_comment;
Token *trailing_comment;
Token *next_lead_comment;
unsigned comments;
} stored;
} Context;
@@ -859,7 +882,7 @@ static inline Ast *extend_ast_with_prev_token(Context *context, Ast *ast)
}
void builtin_setup();
void builtin_setup(Target *target);
static inline bool builtin_may_negate(Type *canonical)
{
@@ -915,6 +938,8 @@ CastKind cast_to_bool_kind(Type *type);
bool cast_to_runtime(Expr *expr);
void llvm_codegen(Context *context);
void llvm_set_struct_size_alignment(Decl *decl);
bool sema_analyse_expr(Context *context, Type *to, Expr *expr);
bool sema_analyse_decl(Context *context, Decl *decl);
@@ -969,6 +994,12 @@ void fprint_decl(FILE *file, Decl *dec);
void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent);
void fprint_expr_recursive(FILE *file, Expr *expr, int indent);
bool func_return_value_as_out(FunctionSignature *func_sig);
static inline bool func_has_error_return(FunctionSignature *func_sig)
{
return func_sig->throws || func_sig->throw_any;
}
Token lexer_scan_token(Lexer *lexer);
Token lexer_scan_ident_test(Lexer *lexer, const char *scan);
@@ -1035,6 +1066,7 @@ void target_setup();
int target_alloca_addr_space();
void *target_data_layout();
void *target_machine();
void *target_target();
#define TOKEN_MAX_LENGTH 0xFFFF
#define TOK2VARSTR(_token) _token.span.length, _token.start
@@ -1047,9 +1079,10 @@ static inline Token wrap(const char *string)
}
Type *type_get_ptr(Type *ptr_type);
Type *type_get_meta(Type *meta_type);
Type *type_get_array(Type *arr_type, uint64_t len);
Type *type_signed_int_by_size(int bytesize);
Type *type_unsigned_int_by_size(int bytesize);
Type *type_signed_int_by_bitsize(unsigned bytesize);
Type *type_unsigned_int_by_bitsize(unsigned bytesize);
bool type_is_subtype(Type *type, Type *possible_subtype);
Type *type_find_common_ancestor(Type *left, Type *right);
const char *type_to_error_string(Type *type);
@@ -1141,7 +1174,6 @@ static inline bool type_is_number(Type *type)
__type->name_loc = _name; __type->unresolved.module = _module; __type; })
#define TYPE_UNRESOLVED(_name) ({ TypeInfo *__type = type_new(TYPE_USER_DEFINED); __type->name_loc = _name; __type; })
AssignOp assignop_from_token(TokenType type);
UnaryOp unaryop_from_token(TokenType type);
TokenType unaryop_to_token(UnaryOp type);
PostUnaryOp post_unaryop_from_token(TokenType type);
@@ -1159,8 +1191,7 @@ static inline const char* struct_union_name_from_token(TokenType type)
return type == TOKEN_STRUCT ? "struct" : "union";
}
#define BACKEND_TYPE(type) gencontext_get_llvm_type(context, type)
#define BACKEND_TYPE_GLOBAL(type) gencontext_get_llvm_type(NULL, type)
#define llvm_type(type) gencontext_get_llvm_type(context, type)
#define DEBUG_TYPE(type) gencontext_get_debug_type(context, type)
void advance(Context *context);

View File

@@ -63,6 +63,7 @@ typedef enum
BINARYOP_BIT_XOR_ASSIGN,
BINARYOP_SHR_ASSIGN,
BINARYOP_SHL_ASSIGN,
BINARYOP_LAST = BINARYOP_SHL_ASSIGN
} BinaryOp;
typedef enum
@@ -218,6 +219,7 @@ typedef enum
EXIT_BREAK,
EXIT_GOTO,
EXIT_CONTINUE,
EXIT_THROW,
EXIT_RETURN,
} ExitType;
@@ -243,6 +245,7 @@ typedef enum
EXPR_EXPRESSION_LIST,
EXPR_CAST,
EXPR_SCOPED_EXPR,
EXPR_MACRO_EXPR,
} ExprKind;
@@ -259,6 +262,7 @@ typedef enum
{
PREC_NONE,
PREC_ASSIGNMENT, // =, *=, /=, %=, ...
PREC_TRY, // try
PREC_TERNARY, // ?:
PREC_LOGICAL, // && ||
PREC_RELATIONAL, // < > <= >= == !=
@@ -266,7 +270,7 @@ typedef enum
PREC_BIT, // ^ | &
PREC_SHIFT, // << >> >>>
PREC_MULTIPLICATIVE, // * / %
PREC_UNARY, // ! - + ~ * & prefix ++/--
PREC_UNARY, // @ ! - + ~ * & prefix ++/--
PREC_CALL, // . () [] postfix ++/--
} Precedence;
@@ -401,9 +405,8 @@ typedef enum
TOKEN_CONST_IDENT, // Any purely upper case ident,
TOKEN_TYPE_IDENT, // Any ident on the format FooBar or __FooBar
// We want to parse @foo / #foo / $foo separately.
// Otherwise we allow things like "@ foo" which would be pretty bad.
TOKEN_AT_IDENT, // @foobar
// We want to parse #foo / $foo separately.
// Otherwise we allow things like "# foo" which would be pretty bad.
TOKEN_HASH_IDENT, // #foobar
TOKEN_CT_IDENT, // $foobar
@@ -486,6 +489,7 @@ typedef enum
TOKEN_EOF, // \n - SHOULD ALWAYS BE THE LAST TOKEN.
TOKEN_LAST = TOKEN_EOF,
} TokenType;
@@ -523,9 +527,11 @@ typedef enum
TYPE_ARRAY,
TYPE_VARARRAY,
TYPE_SUBARRAY,
TYPE_META_TYPE,
TYPE_LAST = TYPE_META_TYPE
} TypeKind;
#define TYPE_KINDS (TYPE_SUBARRAY + 1)
#define TYPE_KINDS (TYPE_LAST + 1)
typedef enum
{
@@ -537,6 +543,7 @@ typedef enum
UNARYOP_NOT,
UNARYOP_INC,
UNARYOP_DEC,
UNARYOP_LAST = UNARYOP_DEC
} UnaryOp;
typedef enum

View File

@@ -120,7 +120,11 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
SEMA_ERROR(expr, "Functions from other modules, must be prefixed with the module name");
return false;
}
if (decl->decl_kind == DECL_MACRO)
{
SEMA_ERROR(expr, "Macro expansions must be prefixed with '@', try using '@%s(...)' instead.", decl->name);
return false;
}
assert(decl->type);
expr->identifier_expr.decl = decl;
expr->type = decl->type;
@@ -133,29 +137,17 @@ static inline bool sema_expr_analyse_binary_sub_expr(Context *context, Expr *lef
}
static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr *expr) { TODO }
static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *expr, Decl *macro)
{
Ast *macro_parent;
// TODO handle loops
Decl *stored_macro = context->evaluating_macro;
Type *stored_rtype = context->rtype;
context->evaluating_macro = macro;
context->rtype = macro->macro_decl.rtype->type;
// Handle escaping macro
bool success = sema_analyse_statement(context, macro->macro_decl.body);
context->evaluating_macro = stored_macro;
context->rtype = stored_rtype;
if (!success) return false;
TODO
return success;
};
static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *expr) { TODO };
static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl)
{
Expr **args =expr->call_expr.arguments;
Decl **func_params = decl->func.function_signature.params;
unsigned error_params = decl->func.function_signature.throw_any || decl->func.function_signature.throws;
if (error_params)
{
TODO
}
unsigned num_args = vec_size(args);
// unsigned num_params = vec_size(func_params);
// TODO handle named parameters, handle default parameters, varargs etc
@@ -192,7 +184,8 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
case DECL_FUNC:
return sema_expr_analyse_func_call(context, to, expr, decl);
case DECL_MACRO:
return sema_expr_analyse_macro_call(context, to, expr, decl);
SEMA_ERROR(expr, "Macro calls must be preceeded by '@'.");
return false;
case DECL_GENERIC:
return sema_expr_analyse_generic_call(context, to, expr);
case DECL_POISONED:
@@ -402,57 +395,143 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp
return false;
}
static inline Decl *decl_find_by_name(Decl** decls, const char *name)
static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr);
static Decl *sema_analyse_init_identifier_string(Context *context, Decl *strukt, const char *string)
{
VECEACH(decls, i)
assert(decl_is_struct_type(strukt));
Decl **members = strukt->strukt.members;
VECEACH(members, i)
{
if (decls[i]->name == name) return decls[i];
Decl *member = members[i];
if (member->name == string) return member;
if (!member->name)
{
Decl *anonymous_member = sema_analyse_init_identifier_string(context, member->type->decl, string);
if (anonymous_member) return anonymous_member;
}
}
return NULL;
}
static inline bool expr_may_be_struct_field_decl(Expr *maybe_binary)
static Decl *sema_analyse_init_identifier(Context *context, Decl *strukt, Expr *expr)
{
if (maybe_binary->expr_kind != EXPR_BINARY) return false;
if (maybe_binary->binary_expr.operator != BINARYOP_EQ) return false;
Expr *expr = maybe_binary->binary_expr.left;
while (1)
assert(expr->resolve_status == RESOLVE_NOT_DONE);
expr->resolve_status = RESOLVE_RUNNING;
expr->identifier_expr.decl = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier);
expr->resolve_status = RESOLVE_DONE;
return expr->identifier_expr.decl;
}
static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *access_expr)
{
assert(access_expr->resolve_status == RESOLVE_NOT_DONE);
access_expr->resolve_status = RESOLVE_RUNNING;
Decl *decl = sema_analyse_init_path(context, strukt, access_expr->access_expr.parent);
if (!decl || !decl_is_struct_type(decl->type->decl))
{
if (expr->expr_kind == EXPR_IDENTIFIER) return true;
if (expr->expr_kind != EXPR_ACCESS) return false;
expr = expr->access_expr.parent;
access_expr->resolve_status = RESOLVE_DONE;
return NULL;
}
decl = access_expr->access_expr.ref = sema_analyse_init_identifier_string(context, decl->type->decl, access_expr->access_expr.sub_element.string);
access_expr->resolve_status = RESOLVE_DONE;
return decl;
}
static Decl *sema_analyse_init_subscript(Context *context, Decl *array, Expr *subscript)
{
TODO
if (array->type->type_kind != TYPE_ARRAY)
{
}
}
static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr)
{
switch (expr->expr_kind)
{
case EXPR_ACCESS:
return sema_analyse_init_access(context, strukt, expr);
case EXPR_IDENTIFIER:
return sema_analyse_init_identifier(context, strukt, expr);
case EXPR_SUBSCRIPT:
return sema_analyse_init_subscript(context, strukt, expr);
default:
return NULL;
}
}
typedef enum
{
INIT_SEMA_ERROR,
INIT_SEMA_NOT_FOUND,
INIT_SEMA_OK
} InitSemaResult;
static InitSemaResult sema_expr_analyse_struct_named_initializer_list(Context *context, Decl *assigned, Expr *expr_list)
{
VECEACH(expr_list->initializer_expr, i)
{
Expr *expr = expr_list->initializer_expr[i];
if (expr->expr_kind != EXPR_BINARY && expr->binary_expr.operator != BINARYOP_ASSIGN)
{
if (i != 0)
{
SEMA_ERROR(expr, "Named and non-named initializers are not allowed together, please choose one or the other.");
return INIT_SEMA_ERROR;
}
// If there is an unexpected expression and no previous element then this is a normal initializer list.
return INIT_SEMA_NOT_FOUND;
}
Expr *path = expr->binary_expr.left;
Expr *value = expr->binary_expr.right;
Decl *result = sema_analyse_init_path(context, assigned, path);
if (!result)
{
if (i != 0)
{
SEMA_ERROR(path, "Unexpected element when initializing '%s', did you get the name right?", assigned->name);
return INIT_SEMA_ERROR;
}
return INIT_SEMA_NOT_FOUND;
}
if (!sema_analyse_expr(context, result->type, value)) return INIT_SEMA_ERROR;
}
return INIT_SEMA_OK;
}
static inline bool sema_expr_analyse_struct_initializer_list(Context *context, Type *assigned, Expr *expr)
{
Decl **members = assigned->decl->strukt.members;
unsigned size = vec_size(members);
// Zero size init will initialize to empty.
if (size == 0) return true;
InitSemaResult result = sema_expr_analyse_struct_named_initializer_list(context, assigned->decl, expr);
if (result == INIT_SEMA_ERROR) return false;
if (result == INIT_SEMA_OK)
{
TODO
}
if (assigned->type_kind == TYPE_UNION)
{
SEMA_ERROR(expr->initializer_expr[0], "Initializer list for unions must use named initializers, e.g. { a = 4 }");
return false;
}
if (size < vec_size(expr->initializer_expr))
{
SEMA_ERROR(expr->initializer_expr[size], "Too many elements in initializer, expected only %d.", size);
return false;
}
VECEACH(expr->initializer_expr, i)
{
Expr *field = expr->initializer_expr[i];
Decl *decl;
if (expr_may_be_struct_field_decl(field))
{
if (field->expr_kind == EXPR_IDENTIFIER)
{
decl = decl_find_by_name(members, field->identifier_expr.identifier);
}
TODO
}
else
{
if (i >= size)
{
SEMA_ERROR(field, "Too many elements in initializer");
return false;
}
decl = members[i];
}
if (!cast(field, decl->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false;
if (!sema_analyse_expr(context, members[i]->type, expr->initializer_expr[i])) return false;
}
expr->type = assigned;
return true;
}
static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to, Expr *expr)
{
assert(to);
@@ -1303,6 +1382,7 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *
case TYPE_STRING:
case TYPE_ENUM:
case TYPE_ERROR:
case TYPE_META_TYPE:
SEMA_ERROR(expr, "Cannot use 'not' on %s", type_to_error_string(inner->type));
return false;
}
@@ -1428,8 +1508,8 @@ static inline bool sema_expr_analyse_unary(Context *context, Type *to, Expr *exp
case UNARYOP_DEC:
case UNARYOP_INC:
return sema_expr_analyse_incdec(context, to, expr, inner);
default:
UNREACHABLE
case UNARYOP_ERROR:
return false;
}
}
@@ -1457,9 +1537,398 @@ static inline bool sema_expr_analyse_try(Context *context, Type *to, Expr *expr)
return true;
}
static Ast *ast_shallow_copy(Ast *source)
{
Ast *copy = malloc_arena(sizeof(Ast));
memcpy(copy, source, sizeof(Ast));
return copy;
}
static Expr *expr_shallow_copy(Expr *source)
{
Expr *copy = malloc_arena(sizeof(Expr));
memcpy(copy, source, sizeof(Expr));
return copy;
}
static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr **expr_list);
static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr);
static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source);
static void ast_copy_list_from_macro(Context *context, Expr *macro, Ast ***to_convert);
static TypeInfo *type_info_copy_from_macro(Context *context, Expr *macro, TypeInfo *source)
{
if (!source) return NULL;
TypeInfo *copy = malloc_arena(sizeof(TypeInfo));
memcpy(copy, source, sizeof(TypeInfo));
switch (source->kind)
{
case TYPE_INFO_POISON:
return copy;
case TYPE_INFO_IDENTIFIER:
assert(source->resolve_status == RESOLVE_NOT_DONE);
TODO
break;
case TYPE_INFO_EXPRESSION:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->unresolved_type_expr = expr_copy_from_macro(context, macro, source->unresolved_type_expr);
return copy;
case TYPE_INFO_ARRAY:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->array.len = expr_copy_from_macro(context, macro, source->array.len);
copy->array.base = type_info_copy_from_macro(context, macro, source->array.base);
return copy;
case TYPE_INFO_INC_ARRAY:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->array.base = type_info_copy_from_macro(context, macro, source->array.base);
return copy;
case TYPE_INFO_POINTER:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->pointer = type_info_copy_from_macro(context, macro, source->pointer);
return copy;
}
}
static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr)
{
#define EXPR_COPY(x) x = expr_copy_from_macro(context, macro, x)
if (!source_expr) return NULL;
Expr *expr = expr_shallow_copy(source_expr);
switch (source_expr->expr_kind)
{
case EXPR_POISONED:
return source_expr;
case EXPR_TRY:
EXPR_COPY(expr->try_expr.expr);
EXPR_COPY(expr->try_expr.else_expr);
return expr;
case EXPR_CONST:
return expr;
case EXPR_BINARY:
EXPR_COPY(expr->binary_expr.left);
EXPR_COPY(expr->binary_expr.right);
return expr;
case EXPR_TERNARY:
EXPR_COPY(expr->ternary_expr.cond);
EXPR_COPY(expr->ternary_expr.then_expr);
EXPR_COPY(expr->ternary_expr.else_expr);
return expr;
case EXPR_UNARY:
EXPR_COPY(expr->unary_expr.expr);
return expr;
case EXPR_POST_UNARY:
EXPR_COPY(expr->post_expr.expr);
return expr;
case EXPR_TYPE:
expr->type_expr.type = type_info_copy_from_macro(context, macro, expr->type_expr.type);
return expr;
case EXPR_IDENTIFIER:
TODO
break;
case EXPR_TYPE_ACCESS:
expr->type_access.type = type_info_copy_from_macro(context, macro, expr->type_expr.type);
return expr;
case EXPR_CALL:
EXPR_COPY(expr->call_expr.function);
expr->call_expr.arguments = expr_copy_expr_list_from_macro(context, macro, expr->call_expr.arguments);
return expr;
case EXPR_SIZEOF:
TODO
break;
case EXPR_SUBSCRIPT:
EXPR_COPY(expr->subscript_expr.expr);
EXPR_COPY(expr->subscript_expr.index);
return expr;
case EXPR_ACCESS:
EXPR_COPY(expr->access_expr.parent);
return expr;
case EXPR_STRUCT_VALUE:
expr->struct_value_expr.type = type_info_copy_from_macro(context, macro, expr->struct_value_expr.type);
EXPR_COPY(expr->struct_value_expr.init_expr);
return expr;
case EXPR_STRUCT_INIT_VALUES:
TODO
return expr;
case EXPR_INITIALIZER_LIST:
expr->initializer_expr = expr_copy_expr_list_from_macro(context, macro, expr->initializer_expr);
return expr;
case EXPR_EXPRESSION_LIST:
expr->expression_list = expr_copy_expr_list_from_macro(context, macro, expr->expression_list);
return expr;
case EXPR_CAST:
EXPR_COPY(expr->cast_expr.expr);
expr->cast_expr.type_info = expr->cast_expr.type_info = type_info_copy_from_macro(context, macro, expr->cast_expr.type_info);
return expr;
case EXPR_SCOPED_EXPR:
EXPR_COPY(expr->expr_scope.expr);
return expr;
case EXPR_MACRO_EXPR:
EXPR_COPY(expr->macro_expr);
return expr;
}
#undef EXPR_COPY
}
static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr **expr_list)
{
Expr **result = NULL;
VECEACH(expr_list, i)
{
vec_add(result, expr_copy_from_macro(context, macro, expr_list[i]));
}
return result;
}
static void ast_copy_list_from_macro(Context *context, Expr *macro, Ast ***to_convert)
{
Ast **result = NULL;
Ast **list = *to_convert;
VECEACH(list, i)
{
vec_add(result, ast_copy_from_macro(context, macro, list[i]));
}
*to_convert = result;
}
static void type_info_copy_list_from_macro(Context *context, Expr *macro, TypeInfo ***to_convert)
{
TypeInfo **result = NULL;
TypeInfo **list = *to_convert;
VECEACH(list, i)
{
vec_add(result, type_info_copy_from_macro(context, macro, list[i]));
}
*to_convert = result;
}
static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source)
{
#define EXPR_COPY(x) x = expr_copy_from_macro(context, macro, x)
#define AST_COPY(x) x = ast_copy_from_macro(context, macro, x)
Ast *ast = ast_shallow_copy(source);
switch (source->ast_kind)
{
case AST_POISONED:
return ast;
case AST_ASM_STMT:
TODO
case AST_ATTRIBUTE:
UNREACHABLE
case AST_BREAK_STMT:
return ast;
case AST_CASE_STMT:
AST_COPY(ast->case_stmt.body);
EXPR_COPY(ast->case_stmt.expr);
return ast;
break;
case AST_CATCH_STMT:
AST_COPY(ast->catch_stmt.body);
return ast;
case AST_COMPOUND_STMT:
ast_copy_list_from_macro(context, macro, &ast->compound_stmt.stmts);
return ast;
case AST_CONTINUE_STMT:
return ast;
case AST_CT_IF_STMT:
EXPR_COPY(ast->ct_if_stmt.expr);
AST_COPY(ast->ct_if_stmt.elif);
AST_COPY(ast->ct_if_stmt.then);
return ast;
case AST_CT_ELIF_STMT:
EXPR_COPY(ast->ct_elif_stmt.expr);
AST_COPY(ast->ct_elif_stmt.then);
AST_COPY(ast->ct_elif_stmt.elif);
return ast;
case AST_CT_ELSE_STMT:
AST_COPY(ast->ct_else_stmt);
return ast;
case AST_CT_FOR_STMT:
AST_COPY(ast->ct_for_stmt.body);
EXPR_COPY(ast->ct_for_stmt.expr);
return ast;
case AST_CT_SWITCH_STMT:
EXPR_COPY(ast->ct_switch_stmt.cond);
ast_copy_list_from_macro(context, macro, &ast->ct_switch_stmt.body);
return ast;
case AST_CT_DEFAULT_STMT:
AST_COPY(ast->ct_default_stmt);
return ast;
case AST_CT_CASE_STMT:
AST_COPY(ast->ct_case_stmt.body);
type_info_copy_list_from_macro(context, macro, &ast->ct_case_stmt.types);
return ast;
case AST_DECLARE_STMT:
TODO
return ast;
case AST_DEFAULT_STMT:
AST_COPY(ast->case_stmt.body);
return ast;
case AST_DEFER_STMT:
assert(!ast->defer_stmt.prev_defer);
AST_COPY(ast->defer_stmt.body);
return ast;
case AST_DO_STMT:
AST_COPY(ast->do_stmt.body);
EXPR_COPY(ast->do_stmt.expr);
return ast;
case AST_EXPR_STMT:
EXPR_COPY(ast->expr_stmt);
return ast;
case AST_FOR_STMT:
EXPR_COPY(ast->for_stmt.cond);
EXPR_COPY(ast->for_stmt.incr);
AST_COPY(ast->for_stmt.body);
AST_COPY(ast->for_stmt.init);
return ast;
case AST_FUNCTION_BLOCK_STMT:
ast_copy_list_from_macro(context, macro, &ast->function_block_stmt.stmts);
return ast;
case AST_GENERIC_CASE_STMT:
AST_COPY(ast->generic_case_stmt.body);
// ast->generic_case_stmt.types = ...
TODO
return ast;
case AST_GENERIC_DEFAULT_STMT:
AST_COPY(ast->generic_default_stmt);
return ast;
case AST_GOTO_STMT:
AST_COPY(ast->goto_stmt.label);
// TODO fixup name, which needs to be macro local.
TODO
return ast;
case AST_IF_STMT:
AST_COPY(ast->if_stmt.cond);
AST_COPY(ast->if_stmt.decl);
AST_COPY(ast->if_stmt.else_body);
AST_COPY(ast->if_stmt.then_body);
return ast;
case AST_LABEL:
assert(!ast->label_stmt.defer);
assert(!ast->label_stmt.in_defer);
// TODO fixup name which needs to be macro local.
TODO
return ast;
case AST_NOP_STMT:
return ast;
case AST_RETURN_STMT:
EXPR_COPY(ast->return_stmt.expr);
// TODO handle conversions?
TODO
return ast;
case AST_DECL_EXPR_LIST:
ast_copy_list_from_macro(context, macro, &ast->decl_expr_stmt);
return ast;
case AST_SWITCH_STMT:
AST_COPY(ast->switch_stmt.decl);
AST_COPY(ast->switch_stmt.cond);
ast_copy_list_from_macro(context, macro, &ast->switch_stmt.cases);
return ast;
case AST_THROW_STMT:
EXPR_COPY(ast->throw_stmt.throw_value);
return ast;
case AST_TRY_STMT:
AST_COPY(ast->try_stmt);
return ast;
case AST_NEXT_STMT:
TODO
return ast;
case AST_VOLATILE_STMT:
TODO
return ast;
case AST_WHILE_STMT:
AST_COPY(ast->while_stmt.cond);
AST_COPY(ast->while_stmt.decl);
AST_COPY(ast->while_stmt.body);
return ast;
case AST_SCOPED_STMT:
AST_COPY(ast->scoped_stmt.stmt);
return ast;
}
#undef EXPR_COPY
#undef AST_COPY
}
static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *macro, Expr *inner)
{
Expr *func_expr = inner->call_expr.function;
if (!sema_analyse_expr(context, NULL, func_expr)) return false;
Decl *decl;
switch (func_expr->expr_kind)
{
case EXPR_TYPE_ACCESS:
TODO
case EXPR_IDENTIFIER:
decl = func_expr->identifier_expr.decl;
break;
default:
TODO
}
if (decl->decl_kind != DECL_MACRO)
{
SEMA_ERROR(macro, "A macro was expected here.");
return false;
}
Expr **args =func_expr->call_expr.arguments;
Decl **func_params = decl->macro_decl.parameters;
// TODO handle bare macros.
// TODO handle $ args and # args
unsigned num_args = vec_size(args);
// unsigned num_params = vec_size(func_params);
for (unsigned i = 0; i < num_args; i++)
{
Expr *arg = args[i];
Decl *param = func_params[i];
if (!sema_analyse_expr(context, param->type, arg)) return false;
}
Ast *body = ast_copy_from_macro(context, inner, decl->macro_decl.body);
TODO
}
static inline bool sema_expr_analyse_macro_call2(Context *context, Type *to, Expr *expr, Decl *macro)
{
Ast *macro_parent;
// TODO handle loops
Decl *stored_macro = context->evaluating_macro;
Type *stored_rtype = context->rtype;
context->evaluating_macro = macro;
context->rtype = macro->macro_decl.rtype->type;
// Handle escaping macro
bool success = sema_analyse_statement(context, macro->macro_decl.body);
context->evaluating_macro = stored_macro;
context->rtype = stored_rtype;
if (!success) return false;
TODO
return success;
};
static inline bool sema_expr_analyse_macro_expr(Context *context, Type *to, Expr *expr)
{
Expr *inner = expr->macro_expr;
switch (inner->expr_kind)
{
case EXPR_CALL:
return sema_expr_analyse_macro_call(context, to, expr, inner);
case EXPR_ACCESS:
case EXPR_IDENTIFIER:
// Allow @f unrolling?
default:
SEMA_ERROR(expr, "Expected a macro name after '@'");
return false;
}
}
static inline bool sema_expr_analyse_type(Context *context, Type *to, Expr *expr)
{
TODO
if (!sema_resolve_type_info(context, expr->type_expr.type))
{
return expr_poison(expr);
}
expr->type = type_get_meta(expr->type_expr.type->type);
return true;
}
@@ -1476,6 +1945,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
return false;
case EXPR_SCOPED_EXPR:
UNREACHABLE
case EXPR_MACRO_EXPR:
return sema_expr_analyse_macro_expr(context, to, expr);
case EXPR_TRY:
return sema_expr_analyse_try(context, to, expr);
case EXPR_CONST:

View File

@@ -504,7 +504,7 @@ Token lexer_scan_token(Lexer *lexer)
switch (c)
{
case '@':
return scan_prefixed_ident(lexer, TOKEN_AT_IDENT, TOKEN_AT, true, "@");
return make_token(lexer, TOKEN_AT, "@");
case '\'':
return scan_char(lexer);
case '"':

View File

@@ -170,12 +170,6 @@ void llvm_codegen(Context *context)
gencontext_emit_function_decl(&gen_context, context->functions[i]);
}
VECEACH(gen_context.generated_types, i)
{
Type *type = gen_context.generated_types[i];
type->backend_debug_type = NULL;
type->backend_type = NULL;
}
gencontext_print_llvm_ir(&gen_context);

View File

@@ -109,6 +109,7 @@ LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type)
case TYPE_IXX:
case TYPE_UXX:
case TYPE_FXX:
case TYPE_META_TYPE:
UNREACHABLE
case TYPE_BOOL:
return gencontext_simple_debug_type(context, type, DW_ATE_boolean);

View File

@@ -41,7 +41,7 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
TODO
case TYPE_POINTER:
return LLVMBuildGEP2(context->builder,
BACKEND_TYPE(type->pointer),
llvm_type(type->pointer),
gencontext_emit_expr(context, expr->subscript_expr.expr),
&index, 1, "[]");
case TYPE_VARARRAY:
@@ -56,7 +56,7 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
static inline LLVMValueRef gencontext_emit_access_addr(GenContext *context, Expr *expr)
{
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
return LLVMBuildStructGEP2(context->builder, BACKEND_TYPE(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
return LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
}
LLVMValueRef gencontext_emit_scoped_expr(GenContext *context, Expr *expr)
@@ -103,6 +103,7 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
case EXPR_INITIALIZER_LIST:
case EXPR_EXPRESSION_LIST:
case EXPR_CAST:
case EXPR_MACRO_EXPR:
UNREACHABLE
}
UNREACHABLE
@@ -115,9 +116,9 @@ LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMV
case CAST_ERROR:
UNREACHABLE
case CAST_PTRPTR:
return LLVMBuildPointerCast(context->builder, value, BACKEND_TYPE(type), "ptrptr");
return LLVMBuildPointerCast(context->builder, value, llvm_type(type), "ptrptr");
case CAST_PTRXI:
return LLVMBuildPtrToInt(context->builder, value, BACKEND_TYPE(type), "ptrxi");
return LLVMBuildPtrToInt(context->builder, value, llvm_type(type), "ptrxi");
case CAST_VARRPTR:
TODO
case CAST_ARRPTR:
@@ -125,45 +126,45 @@ LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMV
case CAST_STRPTR:
TODO
case CAST_PTRBOOL:
return LLVMBuildICmp(context->builder, LLVMIntNE, value, LLVMConstPointerNull(BACKEND_TYPE(type->canonical->pointer)), "ptrbool");
return LLVMBuildICmp(context->builder, LLVMIntNE, value, LLVMConstPointerNull(llvm_type(type->canonical->pointer)), "ptrbool");
case CAST_BOOLINT:
return LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "boolsi");
return LLVMBuildTrunc(context->builder, value, llvm_type(type), "boolsi");
case CAST_FPBOOL:
return LLVMBuildFCmp(context->builder, LLVMRealUNE, value, LLVMConstNull(LLVMTypeOf(value)), "fpbool");
case CAST_BOOLFP:
return LLVMBuildSIToFP(context->builder, value, BACKEND_TYPE(type), "boolfp");
return LLVMBuildSIToFP(context->builder, value, llvm_type(type), "boolfp");
case CAST_INTBOOL:
return LLVMBuildICmp(context->builder, LLVMIntNE, value, LLVMConstNull(LLVMTypeOf(value)), "intbool");
case CAST_FPFP:
return type_convert_will_trunc(type, target_type)
? LLVMBuildFPTrunc(context->builder, value, BACKEND_TYPE(type), "fpfptrunc")
: LLVMBuildFPExt(context->builder, value, BACKEND_TYPE(type), "fpfpext");
? LLVMBuildFPTrunc(context->builder, value, llvm_type(type), "fpfptrunc")
: LLVMBuildFPExt(context->builder, value, llvm_type(type), "fpfpext");
case CAST_FPSI:
return LLVMBuildFPToSI(context->builder, value, BACKEND_TYPE(type), "fpsi");
return LLVMBuildFPToSI(context->builder, value, llvm_type(type), "fpsi");
case CAST_FPUI:
return LLVMBuildFPToUI(context->builder, value, BACKEND_TYPE(type), "fpui");
return LLVMBuildFPToUI(context->builder, value, llvm_type(type), "fpui");
case CAST_SISI:
return type_convert_will_trunc(type, target_type)
? LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "sisitrunc")
: LLVMBuildSExt(context->builder, value, BACKEND_TYPE(type), "sisiext");
? LLVMBuildTrunc(context->builder, value, llvm_type(type), "sisitrunc")
: LLVMBuildSExt(context->builder, value, llvm_type(type), "sisiext");
case CAST_SIUI:
return type_convert_will_trunc(type, target_type)
? LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "siuitrunc")
: LLVMBuildZExt(context->builder, value, BACKEND_TYPE(type), "siuiext");
? LLVMBuildTrunc(context->builder, value, llvm_type(type), "siuitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(type), "siuiext");
case CAST_SIFP:
return LLVMBuildSIToFP(context->builder, value, BACKEND_TYPE(type), "sifp");
return LLVMBuildSIToFP(context->builder, value, llvm_type(type), "sifp");
case CAST_XIPTR:
return LLVMBuildIntToPtr(context->builder, value, BACKEND_TYPE(type), "xiptr");
return LLVMBuildIntToPtr(context->builder, value, llvm_type(type), "xiptr");
case CAST_UISI:
return type_convert_will_trunc(type, target_type)
? LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "uisitrunc")
: LLVMBuildZExt(context->builder, value, BACKEND_TYPE(type), "uisiext");
? LLVMBuildTrunc(context->builder, value, llvm_type(type), "uisitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(type), "uisiext");
case CAST_UIUI:
return type_convert_will_trunc(type, target_type)
? LLVMBuildTrunc(context->builder, value, BACKEND_TYPE(type), "uiuitrunc")
: LLVMBuildZExt(context->builder, value, BACKEND_TYPE(type), "uiuiext");
? LLVMBuildTrunc(context->builder, value, llvm_type(type), "uiuitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(type), "uiuiext");
case CAST_UIFP:
return LLVMBuildUIToFP(context->builder, value, BACKEND_TYPE(type), "uifp");
return LLVMBuildUIToFP(context->builder, value, llvm_type(type), "uifp");
case CAST_ENUMSI:
TODO
}
@@ -177,11 +178,11 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
static inline LLVMValueRef gencontext_emit_inc_dec_change(GenContext *context, bool use_mod, LLVMValueRef current_value, Expr *expr, int diff)
{
Type *type = expr->type->canonical;
LLVMTypeRef llvm_type = BACKEND_TYPE(type);
LLVMTypeRef llvm_type = llvm_type(type);
if (type->type_kind == TYPE_POINTER)
{
LLVMValueRef add = LLVMConstInt(diff < 0 ? BACKEND_TYPE(type_isize) : BACKEND_TYPE(type_usize), diff, diff < 0);
LLVMValueRef add = LLVMConstInt(diff < 0 ? llvm_type(type_isize) : llvm_type(type_usize), diff, diff < 0);
return LLVMBuildGEP2(context->builder, llvm_type, current_value, &add, 1, "ptrincdec");
}
@@ -200,7 +201,7 @@ static inline LLVMValueRef gencontext_emit_inc_dec_change(GenContext *context, b
static inline LLVMValueRef gencontext_emit_pre_inc_dec(GenContext *context, Expr *expr, int diff, bool use_mod)
{
LLVMValueRef addr = gencontext_emit_address(context, expr);
LLVMValueRef value = LLVMBuildLoad2(context->builder, BACKEND_TYPE(expr->type), addr, "");
LLVMValueRef value = LLVMBuildLoad2(context->builder, llvm_type(expr->type), addr, "");
LLVMValueRef result = gencontext_emit_inc_dec_change(context, use_mod, value, expr, diff);
LLVMBuildStore(context->builder, result, addr);
return result;
@@ -209,7 +210,7 @@ static inline LLVMValueRef gencontext_emit_pre_inc_dec(GenContext *context, Expr
static inline LLVMValueRef gencontext_emit_post_inc_dec(GenContext *context, Expr *expr, int diff, bool use_mod)
{
LLVMValueRef addr = gencontext_emit_address(context, expr);
LLVMValueRef value = LLVMBuildLoad2(context->builder, BACKEND_TYPE(expr->type), addr, "");
LLVMValueRef value = LLVMBuildLoad2(context->builder, llvm_type(expr->type), addr, "");
LLVMValueRef result = gencontext_emit_inc_dec_change(context, use_mod, value, expr, diff);
LLVMBuildStore(context->builder, result, addr);
return value;
@@ -234,7 +235,7 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
case UNARYOP_ADDR:
return gencontext_emit_address(context, expr->unary_expr.expr);
case UNARYOP_DEREF:
return LLVMBuildLoad2(context->builder, BACKEND_TYPE(expr->unary_expr.expr->type), gencontext_emit_expr(context, expr->unary_expr.expr), "deref");
return LLVMBuildLoad2(context->builder, llvm_type(expr->unary_expr.expr->type), gencontext_emit_expr(context, expr->unary_expr.expr), "deref");
case UNARYOP_INC:
return gencontext_emit_pre_inc_dec(context, expr->unary_expr.expr, 1, false);
case UNARYOP_DEC:
@@ -277,9 +278,9 @@ static LLVMValueRef gencontext_emit_logical_and_or(GenContext *context, Expr *ex
// Simplify for LLVM by entering the constants we already know of.
LLVMValueRef result_on_skip = LLVMConstInt(LLVMInt1TypeInContext(context->context), op == BINARYOP_AND ? 0 : 1, false);
LLVMValueRef logicValues[2] = { result_on_skip, rhs };
LLVMValueRef logic_values[2] = { result_on_skip, rhs };
LLVMBasicBlockRef blocks[2] = { start_block, rhs_block };
LLVMAddIncoming(phi, logicValues, blocks, 2);
LLVMAddIncoming(phi, logic_values, blocks, 2);
return phi;
}
@@ -293,7 +294,7 @@ static inline LLVMValueRef gencontext_emit_initialization_from_expr(GenContext *
static inline LLVMValueRef gencontext_emit_struct_value_expr(GenContext *context, Expr *expr)
{
LLVMValueRef temp_alloc = gencontext_emit_alloca(context, BACKEND_TYPE(expr->type), "temp");
LLVMValueRef temp_alloc = gencontext_emit_alloca(context, llvm_type(expr->type), "temp");
return gencontext_emit_initialization_from_expr(context, temp_alloc, expr->struct_value_expr.init_expr);
}
@@ -314,7 +315,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
LLVMValueRef rhs_value;
if (lhs_addr)
{
lhs_value = LLVMBuildLoad2(context->builder, BACKEND_TYPE(lhs->type), lhs_addr, "");
lhs_value = LLVMBuildLoad2(context->builder, llvm_type(lhs->type), lhs_addr, "");
}
else
{
@@ -348,7 +349,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
{
if (lhs->type->canonical == rhs->type->canonical) return LLVMBuildPtrDiff(context->builder, lhs_value, rhs_value, "ptrdiff");
rhs_value = LLVMBuildNeg(context->builder, rhs_value, "");
return LLVMBuildGEP2(context->builder, BACKEND_TYPE(lhs->type), lhs_value, &rhs_value, 1, "ptrsub");
return LLVMBuildGEP2(context->builder, llvm_type(lhs->type), lhs_value, &rhs_value, 1, "ptrsub");
}
if (is_float) return LLVMBuildFSub(context->builder, lhs_value, rhs_value, "fsub");
return gencontext_emit_sub_int(context, lhs->type->canonical, binary_op == BINARYOP_SUB_MOD, lhs_value, rhs_value);
@@ -357,7 +358,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
if (lhs->type->canonical->type_kind == TYPE_POINTER)
{
assert(type_is_integer(rhs->type->canonical));
return LLVMBuildGEP2(context->builder, BACKEND_TYPE(lhs->type), lhs_value, &rhs_value, 1, "ptradd");
return LLVMBuildGEP2(context->builder, llvm_type(lhs->type), lhs_value, &rhs_value, 1, "ptradd");
}
if (is_float) return LLVMBuildFAdd(context->builder, lhs_value, rhs_value, "fadd");
return gencontext_emit_add_int(context, lhs->type->canonical, binary_op == BINARYOP_ADD_MOD, lhs_value, rhs_value);
@@ -491,9 +492,9 @@ LLVMValueRef gencontext_emit_elvis_expr(GenContext *context, Expr *expr)
gencontext_emit_block(context, phi_block);
LLVMValueRef phi = LLVMBuildPhi(context->builder, expr->type->backend_type, "val");
LLVMValueRef logicValues[2] = { lhs, rhs };
LLVMValueRef logic_values[2] = { lhs, rhs };
LLVMBasicBlockRef blocks[2] = { current_block, rhs_block };
LLVMAddIncoming(phi, logicValues, blocks, 2);
LLVMAddIncoming(phi, logic_values, blocks, 2);
return phi;
}
@@ -539,7 +540,7 @@ static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *e
LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
{
LLVMTypeRef type = BACKEND_TYPE(expr->type);
LLVMTypeRef type = llvm_type(expr->type);
switch (expr->const_expr.type)
{
case CONST_INT:
@@ -578,7 +579,8 @@ LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr)
Decl *function = expr->call_expr.function->identifier_expr.decl;
LLVMValueRef func = function->func.backend_value;
LLVMTypeRef func_type = BACKEND_TYPE(function->type);
LLVMTypeRef func_type = llvm_type(function->type);
// TODO fix throws and return optimization
LLVMValueRef call = LLVMBuildCall2(context->builder, func_type, func, values, args, "call");
/*
if (function->func.function_signature.convention)
@@ -595,7 +597,7 @@ static inline LLVMValueRef gencontext_emit_access_expr(GenContext *context, Expr
{
// Improve, add string description to the access?
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
LLVMValueRef val = LLVMBuildStructGEP2(context->builder, BACKEND_TYPE(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
LLVMValueRef val = LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
return LLVMBuildLoad2(context->builder, gencontext_get_llvm_type(context, expr->type), val, "");
}
@@ -611,19 +613,22 @@ static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *cont
static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr)
{
LLVMValueRef value = LLVMGetUndef(LLVMTYPE(expr->type));
LLVMTypeRef type = llvm_type(expr->type);
LLVMValueRef value = LLVMGetUndef(type);
/*
for (expr->initializer_expr)
expr->type.
else if (littype->tag == StructTag) {
LLVMValueRef strval = LLVMGetUndef(genlType(gen, littype));
unsigned int pos = 0;
for (nodesFor(lit->args, cnt, nodesp))
strval = LLVMBuildInsertValue(gen->builder, strval, genlExpr(gen, *nodesp), pos++, "literal");
return strval;
if (!vec_size(expr->initializer_expr))
{
LLVMValueRef ref = gencontext_emit_alloca(context, type, "temp");
value = LLVMBuildMemSet(context->builder, ref, LLVMConstInt(llvm_type(type_byte), 0, false),
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false), expr->type->decl->strukt.alignment);
return ref;
}
VECEACH(expr->initializer_expr, i)
{
LLVMValueRef init_value = gencontext_emit_expr(context, expr->initializer_expr[i]);
value = LLVMBuildInsertValue(context->builder, value, init_value, i, "literal");
}
TODO*/
return value;
}
@@ -654,6 +659,7 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
case EXPR_SIZEOF:
case EXPR_TYPE_ACCESS:
case EXPR_TRY:
case EXPR_MACRO_EXPR:
// These are folded in the semantic analysis step.
UNREACHABLE
case EXPR_IDENTIFIER:

View File

@@ -78,10 +78,22 @@ static inline void gencontext_emit_parameter(GenContext *context, Decl *decl, un
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_PARAM);
// Allocate room on stack and copy.
decl->var.backend_ref = gencontext_emit_alloca(context, BACKEND_TYPE(decl->type), decl->name);
decl->var.backend_ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name);
LLVMBuildStore(context->builder, LLVMGetParam(context->function, index), decl->var.backend_ref);
}
void gencontext_emit_implicit_return(GenContext *context)
{
if (func_has_error_return(&context->cur_func_decl->func.function_signature))
{
LLVMBuildRet(context->builder, LLVMConstInt(llvm_type(type_ulong), 0, false));
}
else
{
LLVMBuildRetVoid(context->builder);
}
}
void gencontext_emit_function_body(GenContext *context, Decl *decl)
{
assert(decl->func.backend_value);
@@ -90,6 +102,7 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
LLVMBuilderRef prev_builder = context->builder;
context->function = decl->func.backend_value;
context->cur_func_decl = decl;
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(context->context, context->function, "entry");
context->current_block = entry;
@@ -100,10 +113,22 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
LLVMValueRef alloca_point = LLVMBuildAlloca(context->builder, LLVMInt32TypeInContext(context->context), "alloca_point");
context->alloca_point = alloca_point;
unsigned return_parameter = func_return_value_as_out(&decl->func.function_signature) ? 1 : 0;
if (return_parameter)
{
context->return_out = gencontext_emit_alloca(context, llvm_type(decl->func.function_signature.rtype->type), "retval");
LLVMBuildStore(context->builder, LLVMGetParam(context->function, 0), context->return_out);
}
else
{
context->return_out = NULL;
}
// Generate LLVMValueRef's for all parameters, so we can use them as local vars in code
VECEACH(decl->func.function_signature.params, i)
{
gencontext_emit_parameter(context, decl->func.function_signature.params[i], i);
gencontext_emit_parameter(context, decl->func.function_signature.params[i], i + return_parameter);
}
VECEACH(decl->func.labels, i)
@@ -130,7 +155,7 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
assert(decl->func.function_signature.rtype->type->type_kind == TYPE_VOID);
assert(decl->func.body->compound_stmt.defer_list.end == NULL);
gencontext_emit_defer(context, decl->func.body->compound_stmt.defer_list.start, NULL);
LLVMBuildRetVoid(context->builder);
gencontext_emit_implicit_return(context);
}
// erase alloca point
@@ -151,7 +176,7 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl)
assert(decl->decl_kind == DECL_FUNC);
// Resolve function backend type for function.
decl->func.backend_value = LLVMAddFunction(context->module, decl->external_name,
BACKEND_TYPE(decl->type));
llvm_type(decl->type));
// Specify appropriate storage class, visibility and call convention
// extern functions (linkedited in separately):
@@ -208,11 +233,11 @@ void gencontext_emit_extern_decl(GenContext *context, Decl *decl)
UNREACHABLE;
case DECL_FUNC:
decl->func.backend_value = LLVMAddFunction(context->module, decl->external_name,
BACKEND_TYPE(decl->type));
llvm_type(decl->type));
LLVMSetVisibility(decl->func.backend_value, LLVMDefaultVisibility);
break;
case DECL_VAR:
decl->var.backend_ref = LLVMAddGlobal(context->module, BACKEND_TYPE(decl->type), decl->external_name);
decl->var.backend_ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->external_name);
LLVMSetVisibility(decl->var.backend_ref, LLVMDefaultVisibility);
break;
case DECL_TYPEDEF:
@@ -221,7 +246,7 @@ void gencontext_emit_extern_decl(GenContext *context, Decl *decl)
TODO
case DECL_STRUCT:
case DECL_UNION:
BACKEND_TYPE(decl->type);
llvm_type(decl->type);
break;
case DECL_ENUM:
TODO

View File

@@ -64,8 +64,7 @@ typedef struct
Context *ast_context;
BreakContinue break_continue_stack[BREAK_STACK_MAX];
size_t break_continue_stack_index;
LLVMTypeRef error_type;
Type **generated_types;
LLVMValueRef return_out;
} GenContext;
@@ -89,6 +88,7 @@ static inline LLVMBasicBlockRef gencontext_create_free_block(GenContext *context
return LLVMCreateBasicBlockInContext(context->context, name);
}
void gencontext_emit_implicit_return(GenContext *context);
void gencontext_emit_function_decl(GenContext *context, Decl *decl);
void gencontext_emit_extern_decl(GenContext *context, Decl *decl);
LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr);

View File

@@ -35,11 +35,6 @@ static inline LLVMTypeRef gencontext_create_basic_llvm_type(GenContext *context,
}
}
static inline void gencontext_init_basic_llvm_type(GenContext *context, Type *type)
{
vec_add(context->generated_types, type);
type->backend_type = gencontext_create_basic_llvm_type(context, type);
}
void gencontext_begin_module(GenContext *context)
{
assert(!context->module && "Expected no module");
@@ -72,18 +67,6 @@ void gencontext_begin_module(GenContext *context)
// Setup all types. Not thread-safe, but at this point in time we can assume a single context.
// We need to remove the context from the cache after this.
// This would seem to indicate that we should change Type / actual type.
gencontext_init_basic_llvm_type(context, type_char);
gencontext_init_basic_llvm_type(context, type_byte);
gencontext_init_basic_llvm_type(context, type_short);
gencontext_init_basic_llvm_type(context, type_ushort);
gencontext_init_basic_llvm_type(context, type_int);
gencontext_init_basic_llvm_type(context, type_uint);
gencontext_init_basic_llvm_type(context, type_long);
gencontext_init_basic_llvm_type(context, type_ulong);
gencontext_init_basic_llvm_type(context, type_float);
gencontext_init_basic_llvm_type(context, type_double);
gencontext_init_basic_llvm_type(context, type_void);
gencontext_init_basic_llvm_type(context, type_bool);
context->pointer_alignment = LLVMPointerSizeForAS(target_data_layout(), 0);

View File

@@ -23,7 +23,7 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
{
Decl *decl = ast->declare_stmt;
decl->var.backend_ref = gencontext_emit_alloca(context, BACKEND_TYPE(decl->type), decl->name);
decl->var.backend_ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name);
// TODO NRVO
// TODO debug info
/*
@@ -42,6 +42,16 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
*/
if (decl->var.init_expr)
{
Expr *expr = decl->var.init_expr;
// Quick path for empty initializer list
if (expr->expr_kind == EXPR_INITIALIZER_LIST && vec_size(expr->initializer_expr) == 0)
{
LLVMBuildMemSet(context->builder, decl->var.backend_ref, LLVMConstInt(llvm_type(type_byte), 0, false),
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false),
expr->type->decl->strukt.alignment);
return decl->var.backend_ref;
}
LLVMValueRef value = gencontext_emit_expr(context, decl->var.init_expr);
LLVMBuildStore(context->builder, value, decl->var.backend_ref);
return decl->var.backend_ref;
@@ -100,14 +110,37 @@ static inline void gencontext_emit_return(GenContext *context, Ast *ast)
{
// Ensure we are on a branch that is non empty.
if (!gencontext_check_block_branch_emit(context)) return;
LLVMValueRef ret_value = ast->return_stmt.expr ? gencontext_emit_expr(context, ast->return_stmt.expr) : NULL;
gencontext_emit_defer(context, ast->return_stmt.defer, NULL);
if (!ret_value)
{
LLVMBuildRetVoid(context->builder);
gencontext_emit_implicit_return(context);
return;
}
LLVMBuildRet(context->builder, ret_value);
if (context->return_out)
{
LLVMBuildStore(context->builder, ret_value, context->return_out);
gencontext_emit_implicit_return(context);
}
else
{
LLVMBuildRet(context->builder, ret_value);
}
context->current_block = NULL;
LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret");
gencontext_emit_block(context, post_ret_block);
}
static inline void gencontext_emit_throw(GenContext *context, Ast *ast)
{
// Ensure we are on a branch that is non empty.
if (!gencontext_check_block_branch_emit(context)) return;
gencontext_emit_defer(context, ast->throw_stmt.defers.start, ast->throw_stmt.defers.end);
// TODO handle throw if simply a jump
LLVMBuildRet(context->builder, LLVMConstInt(llvm_type(type_ulong), 10 + ast->throw_stmt.throw_value->identifier_expr.decl->error_constant.value, false));
context->current_block = NULL;
LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret");
gencontext_emit_block(context, post_ret_block);
@@ -154,10 +187,7 @@ void gencontext_emit_if(GenContext *context, Ast *ast)
}
static void gencontext_push_next(GenContext *context, LLVMBasicBlockRef nextBlock)
{
// TODO
}
static void
gencontext_push_break_continue(GenContext *context, LLVMBasicBlockRef break_block, LLVMBasicBlockRef continue_block,
LLVMBasicBlockRef next_block)
@@ -474,7 +504,7 @@ LLVMValueRef gencontext_get_defer_bool(GenContext *context, Ast *defer)
assert(defer->ast_kind == AST_DEFER_STMT && defer->defer_stmt.emit_boolean);
if (!defer->defer_stmt.bool_var)
{
defer->defer_stmt.bool_var = gencontext_emit_alloca(context, BACKEND_TYPE(type_bool), "defer");
defer->defer_stmt.bool_var = gencontext_emit_alloca(context, llvm_type(type_bool), "defer");
}
return defer->defer_stmt.bool_var;
}
@@ -492,7 +522,7 @@ void gencontext_emit_defer(GenContext *context, Ast *defer_start, Ast *defer_end
LLVMBasicBlockRef exit_block = LLVMCreateBasicBlockInContext(context->context, "skip.defer");
LLVMBasicBlockRef defer_block = LLVMCreateBasicBlockInContext(context->context, "do.defer");
LLVMValueRef value = LLVMBuildLoad2(context->builder, BACKEND_TYPE(type_bool), gencontext_get_defer_bool(context, defer), "will.defer");
LLVMValueRef value = LLVMBuildLoad2(context->builder, llvm_type(type_bool), gencontext_get_defer_bool(context, defer), "will.defer");
gencontext_emit_cond_br(context, value, defer_block, exit_block);
@@ -520,7 +550,7 @@ void gencontext_emit_goto(GenContext *context, Ast *ast)
Ast *defer = ast->goto_stmt.label->label_stmt.defer;
while (defer != ast->goto_stmt.defer.end)
{
LLVMBuildStore(context->builder, LLVMConstInt(BACKEND_TYPE(type_bool), 0, false),
LLVMBuildStore(context->builder, LLVMConstInt(llvm_type(type_bool), 0, false),
gencontext_get_defer_bool(context, defer));
defer = defer->defer_stmt.prev_defer;
}
@@ -604,7 +634,7 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
case AST_DEFER_STMT:
if (ast->defer_stmt.emit_boolean)
{
LLVMBuildStore(context->builder, LLVMConstInt(BACKEND_TYPE(type_bool), 1, false),
LLVMBuildStore(context->builder, LLVMConstInt(llvm_type(type_bool), 1, false),
gencontext_get_defer_bool(context, ast));
}
break;
@@ -612,9 +642,11 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
break;
case AST_CATCH_STMT:
case AST_TRY_STMT:
case AST_THROW_STMT:
// Should have been lowered.
UNREACHABLE
case AST_THROW_STMT:
gencontext_emit_throw(context, ast);
break;
case AST_ASM_STMT:
TODO
case AST_ATTRIBUTE:

View File

@@ -4,11 +4,11 @@
#include "llvm_codegen_internal.h"
#define LLVMCONTEXT(gen_context) (gen_context ? gen_context->context : LLVMGetGlobalContext())
LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type);
static inline LLVMTypeRef gencontext_create_llvm_type_from_decl(GenContext *context, Decl *decl)
static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl)
{
static LLVMTypeRef params[512];
static LLVMTypeRef params[MAX_PARAMS];
switch (decl->decl_kind)
{
case DECL_ATTRIBUTE:
@@ -28,26 +28,25 @@ static inline LLVMTypeRef gencontext_create_llvm_type_from_decl(GenContext *cont
{
VECEACH(decl->func.function_signature.params, i)
{
params[i] = BACKEND_TYPE(decl->func.function_signature.params[i]->type);
params[i] = llvm_get_type(context, decl->func.function_signature.params[i]->type);
}
unsigned param_size = vec_size(decl->func.function_signature.params);
return LLVMFunctionType(BACKEND_TYPE(decl->func.function_signature.rtype->type),
return LLVMFunctionType(llvm_get_type(context, decl->func.function_signature.rtype->type),
params,
param_size,
decl->func.function_signature.variadic);
}
case DECL_TYPEDEF:
return BACKEND_TYPE(decl->typedef_decl.type);
return llvm_get_type(context, decl->typedef_decl.type);
case DECL_STRUCT:
{
LLVMTypeRef *types = NULL;
VECEACH(decl->strukt.members, i)
{
VECADD(types, BACKEND_TYPE(decl->strukt.members[i]->type));
vec_add(types, llvm_get_type(context, decl->strukt.members[i]->type));
}
// TODO fix name.
LLVMTypeRef type = LLVMStructCreateNamed(LLVMCONTEXT(context), decl->external_name);
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->external_name);
LLVMStructSetBody(type, types, vec_size(types), decl->is_packed);
return type;
}
@@ -57,7 +56,7 @@ static inline LLVMTypeRef gencontext_create_llvm_type_from_decl(GenContext *cont
unsigned long long max_size = 0;
VECEACH(decl->strukt.members, i)
{
LLVMTypeRef type = BACKEND_TYPE(decl->strukt.members[i]->type);
LLVMTypeRef type = llvm_get_type(context, decl->strukt.members[i]->type);
unsigned long long size = LLVMStoreSizeOfType(target_data_layout(), type);
if (size > max_size || !max_type)
{
@@ -65,13 +64,15 @@ static inline LLVMTypeRef gencontext_create_llvm_type_from_decl(GenContext *cont
max_type = type;
}
}
LLVMTypeRef type = LLVMStructCreateNamed(LLVMCONTEXT(context), decl->external_name);
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->external_name);
LLVMStructSetBody(type, &max_type, 1, false);
return type;
}
case DECL_ENUM:
return BACKEND_TYPE(decl->type);
return llvm_get_type(context, decl->type);
case DECL_ERROR:
TODO
/*
if (!context->error_type)
{
LLVMTypeRef domain_type = LLVMInt64TypeInContext(LLVMCONTEXT(context));
@@ -81,117 +82,144 @@ static inline LLVMTypeRef gencontext_create_llvm_type_from_decl(GenContext *cont
LLVMStructSetBody(error_type, types, 2, false);
context->error_type = error_type;
}
return context->error_type;
return context->error_type;*/
case DECL_THROWS:
UNREACHABLE
}
UNREACHABLE
}
static inline LLVMTypeRef gencontext_create_llvm_type_from_ptr(GenContext *context, Type *type)
static inline LLVMTypeRef llvm_type_from_ptr(LLVMContextRef context, Type *type)
{
LLVMTypeRef base_llvm_type = BACKEND_TYPE(type->pointer);
vec_add(context->generated_types, type);
LLVMTypeRef base_llvm_type = llvm_get_type(context, type->pointer);
if (type->canonical != type)
{
return type->backend_type = BACKEND_TYPE(type->canonical);
return type->backend_type = llvm_get_type(context, type->canonical);
}
return type->backend_type = LLVMPointerType(base_llvm_type, /** TODO **/0);
}
static inline LLVMTypeRef gencontext_create_llvm_type_from_array(GenContext *context, Type *type)
static inline LLVMTypeRef llvm_type_from_array(LLVMContextRef context, Type *type)
{
LLVMTypeRef base_llvm_type = BACKEND_TYPE(type->array.base);
vec_add(context->generated_types, type);
LLVMTypeRef base_llvm_type = llvm_get_type(context, type->array.base);
if (type->canonical != type)
{
return type->backend_type = BACKEND_TYPE(type->canonical);
return type->backend_type = llvm_get_type(context, type->canonical);
}
return type->backend_type = LLVMPointerType(base_llvm_type, /** TODO **/0);
}
LLVMTypeRef gencontext_create_llvm_func_type(GenContext *context, Type *type)
LLVMTypeRef llvm_func_type(LLVMContextRef context, Type *type)
{
LLVMTypeRef *params = NULL;
FunctionSignature *signature = type->func.signature;
// TODO throws
if (vec_size(signature->params))
bool return_parameter = func_return_value_as_out(signature);
bool return_error = func_has_error_return(signature);
unsigned parameters = vec_size(signature->params) + return_parameter;
if (parameters)
{
params = malloc_arena(sizeof(LLVMTypeRef) * vec_size(signature->params));
params = malloc_arena(sizeof(LLVMTypeRef) * parameters);
if (return_parameter)
{
params[0] = llvm_get_type(context, signature->rtype->type);
}
VECEACH(signature->params, i)
{
params[i] = BACKEND_TYPE(signature->params[i]->type->canonical);
params[i + return_parameter] = llvm_get_type(context, signature->params[i]->type->canonical);
}
}
return LLVMFunctionType(
BACKEND_TYPE(type->func.signature->rtype->type),
params, vec_size(signature->params), signature->variadic);
LLVMTypeRef ret_type;
if (return_error)
{
ret_type = llvm_get_type(context, type_ulong);
}
else
{
ret_type = return_parameter ? llvm_get_type(context, type_void) : llvm_get_type(context, type->func.signature->rtype->type);
}
return LLVMFunctionType( ret_type, params, parameters, signature->variadic);
}
LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type)
LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type)
{
if (type->backend_type)
if (type->backend_type && LLVMGetTypeContext(type->backend_type) == context)
{
assert(LLVMGetTypeContext(type->backend_type) == context->context);
return type->backend_type;
}
vec_add(context->generated_types, type);
DEBUG_LOG("Generating type %s", type->name);
switch (type->type_kind)
{
case TYPE_POISONED:
case TYPE_IXX:
case TYPE_UXX:
case TYPE_FXX:
case TYPE_META_TYPE:
UNREACHABLE;
case TYPE_TYPEDEF:
return type->backend_type = BACKEND_TYPE(type->canonical);
return type->backend_type = llvm_get_type(context, type->canonical);
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ENUM:
case TYPE_ERROR:
case TYPE_ERROR_UNION:
return type->backend_type = gencontext_create_llvm_type_from_decl(context, type->decl);
return type->backend_type = llvm_type_from_decl(context, type->decl);
case TYPE_FUNC:
return type->backend_type = gencontext_create_llvm_func_type(context, type);
return type->backend_type = llvm_func_type(context, type);
case TYPE_VOID:
return type->backend_type = LLVMVoidTypeInContext(context);
case TYPE_F64:
return type->backend_type = LLVMDoubleTypeInContext(context);
case TYPE_F32:
return type->backend_type = LLVMFloatTypeInContext(context);
case TYPE_U64:
case TYPE_POISONED:
case TYPE_BOOL:
case TYPE_I8:
case TYPE_I16:
case TYPE_I32:
case TYPE_I64:
case TYPE_IXX:
case TYPE_U8:
case TYPE_U16:
return type->backend_type = LLVMIntTypeInContext(context, 64U);
case TYPE_U32:
case TYPE_UXX:
case TYPE_FXX:
UNREACHABLE;
case TYPE_I32:
return type->backend_type = LLVMIntTypeInContext(context, 32U);
case TYPE_U16:
case TYPE_I16:
return type->backend_type = LLVMIntTypeInContext(context, 16U);
case TYPE_U8:
case TYPE_I8:
return type->backend_type = LLVMIntTypeInContext(context, 8U);
case TYPE_BOOL:
return type->backend_type = LLVMIntTypeInContext(context, 1U);
case TYPE_POINTER:
return type->backend_type = gencontext_create_llvm_type_from_ptr(context, type);
return type->backend_type = llvm_type_from_ptr(context, type);
case TYPE_STRING:
// TODO
return type->backend_type = LLVMPointerType(LLVMTYPE(type_char), 0);
case TYPE_ARRAY:
return type->backend_type = gencontext_create_llvm_type_from_array(context, type);
return type->backend_type = llvm_type_from_array(context, type);
case TYPE_SUBARRAY:
{
LLVMTypeRef base_type = BACKEND_TYPE(type->array.base);
LLVMTypeRef size_type = BACKEND_TYPE(type_usize);
LLVMTypeRef base_type = llvm_get_type(context, type->array.base);
LLVMTypeRef size_type = llvm_get_type(context, type_usize);
assert(type->array.base->canonical->type_kind == TYPE_POINTER);
LLVMTypeRef array_type = LLVMStructCreateNamed(LLVMCONTEXT(context), type->name);
LLVMTypeRef array_type = LLVMStructCreateNamed(context, type->name);
LLVMTypeRef types[2] = { base_type, size_type };
LLVMStructSetBody(array_type, types, 2, false);
return type->backend_type = array_type;
}
case TYPE_VARARRAY:
return type->backend_type = LLVMPointerType(BACKEND_TYPE(type->array.base), 0);
return type->backend_type = LLVMPointerType(llvm_get_type(context, type->array.base), 0);
}
UNREACHABLE;
}
LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type)
{
return llvm_get_type(context->context, type);
}
void llvm_set_struct_size_alignment(Decl *decl)
{
LLVMTypeRef type = llvm_get_type(LLVMGetGlobalContext(), decl->type);
decl->strukt.size = LLVMStoreSizeOfType(target_data_layout(), type);
decl->strukt.alignment = LLVMPreferredAlignmentOfType(target_data_layout(), type);
}

View File

@@ -4,8 +4,6 @@
#include "compiler_internal.h"
const int MAX_DOCS_ROWS = 1024;
Token module = { .type = TOKEN_INVALID_TOKEN };
static Ast *parse_stmt(Context *context);
static Expr *parse_expr(Context *context);
@@ -29,8 +27,8 @@ extern ParseRule rules[TOKEN_EOF + 1];
void context_store_lexer_state(Context *context)
{
assert(!context->stored.has_stored && "Nested lexer store is forbidden");
context->stored.has_stored = true;
assert(!context->stored.in_lookahead && "Nested lexer store is forbidden");
context->stored.in_lookahead = true;
context->stored.current = context->lexer.current;
context->stored.start = context->lexer.lexing_start;
context->stored.tok = context->tok;
@@ -38,13 +36,12 @@ void context_store_lexer_state(Context *context)
context->stored.lead_comment = context->lead_comment;
context->stored.trailing_comment = context->trailing_comment;
context->stored.next_lead_comment = context->next_lead_comment;
context->stored.comments = vec_size(context->comments);
}
void context_restore_lexer_state(Context *context)
{
assert(context->stored.has_stored && "Tried to restore missing stored state.");
context->stored.has_stored = false;
assert(context->stored.in_lookahead && "Tried to restore missing stored state.");
context->stored.in_lookahead = false;
context->lexer.current = context->stored.current;
context->lexer.lexing_start = context->stored.start;
context->tok = context->stored.tok;
@@ -53,7 +50,6 @@ void context_restore_lexer_state(Context *context)
context->next_lead_comment = context->stored.next_lead_comment;
context->trailing_comment = context->stored.trailing_comment;
context->prev_tok_end = context->tok.span.end_loc;
vec_resize(context->comments, context->stored.comments);
}
inline void advance(Context *context)
@@ -70,6 +66,12 @@ inline void advance(Context *context)
if (context->next_tok.type == TOKEN_INVALID_TOKEN) continue;
if (context->stored.in_lookahead && (context->next_tok.type == TOKEN_COMMENT
|| context->next_tok.type == TOKEN_DOC_COMMENT))
{
continue;
}
// Walk through any regular comments
if (context->next_tok.type == TOKEN_COMMENT)
{
@@ -340,8 +342,6 @@ static Ast* parse_function_block(Context *context)
return ast;
}
static Path *parse_path_prefix(Context *context)
{
if (context->tok.type != TOKEN_IDENT || context->next_tok.type != TOKEN_SCOPE) return NULL;
@@ -402,7 +402,7 @@ static Path *parse_path_prefix(Context *context)
* ;
*
* Assume prev_token is the type.
* @return Type (poisoned if fails)
* @return TypeInfo (poisoned if fails)
*/
static inline TypeInfo *parse_base_type(Context *context)
{
@@ -657,15 +657,6 @@ static Ast *parse_declaration_stmt(Context *context)
}
typedef enum
{
NEXT_WAS_ERROR,
NEXT_WAS_EXPR,
NEXT_WAS_LABEL,
NEXT_WAS_DECL
} ExprCheck;
/**
* expr_stmt ::= expression EOS
* @return Ast* poisoned if expression fails to parse.
@@ -784,6 +775,14 @@ static inline Ast* parse_if_stmt(Context *context)
return if_ast;
}
/**
* while_stmt
* : WHILE '(' control_expression ')' statement
* ;
*
* @param context
* @return the while AST
*/
static inline Ast* parse_while_stmt(Context *context)
{
Ast *while_ast = AST_NEW_TOKEN(AST_WHILE_STMT, context->tok);
@@ -801,12 +800,13 @@ static inline Ast* parse_while_stmt(Context *context)
* : DEFER statement
* | DEFER catch statement
* ;
* @return
* @return the defer AST
*/
static inline Ast* parse_defer_stmt(Context *context)
{
Ast *defer_stmt = AST_NEW_TOKEN(AST_DEFER_STMT, context->tok);
advance_and_verify(context, TOKEN_DEFER);
// TODO catch
defer_stmt->defer_stmt.body = TRY_AST(parse_stmt(context));
return defer_stmt;
}
@@ -840,7 +840,8 @@ static inline Ast* parse_catch_stmt(Context *context)
return catch_stmt;
}
static inline Ast* parse_asm_stmt(Context *context)
static inline Ast* parse_asm_stmt(Context *context __unused)
{
TODO
}
@@ -994,7 +995,7 @@ static inline Ast* parse_ct_switch_stmt(Context *context)
stmt->ct_case_stmt.body = TRY_AST_OR(parse_stmt(context), &poisoned_ast);
vec_add(switch_statements, stmt);
break;
case TOKEN_DEFAULT:
case TOKEN_CT_DEFAULT:
stmt = AST_NEW_TOKEN(AST_CT_CASE_STMT, context->tok);
advance(context);
CONSUME_OR(TOKEN_COLON, &poisoned_ast);
@@ -1131,7 +1132,7 @@ static Ast *parse_throw_stmt(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_THROW_STMT, context->tok);
advance_and_verify(context, TOKEN_THROW);
ast->throw_stmt = TRY_EXPR_OR(parse_expr(context), &poisoned_ast);
ast->throw_stmt.throw_value = TRY_EXPR_OR(parse_expr(context), &poisoned_ast);
RETURN_AFTER_EOS(ast);
}
@@ -1174,7 +1175,7 @@ static inline bool is_expr_after_type_ident(Context *context)
return context->next_tok.type == TOKEN_DOT || context->next_tok.type == TOKEN_LPAREN;
}
static bool parse_type_or_expr(Context *context, Expr **exprPtr, TypeInfo **typePtr)
static bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr)
{
switch (context->tok.type)
{
@@ -1203,8 +1204,8 @@ static bool parse_type_or_expr(Context *context, Expr **exprPtr, TypeInfo **type
case TOKEN_C_ULONGLONG:
case TOKEN_TYPE_IDENT:
if (context->next_tok.type == TOKEN_DOT || context->next_tok.type == TOKEN_LPAREN) break;
*typePtr = parse_type_expression(context);
return type_info_ok(*typePtr);
*type_ptr = parse_type_expression(context);
return type_info_ok(*type_ptr);
case TOKEN_IDENT:
if (context->next_tok.type == TOKEN_SCOPE)
{
@@ -1217,8 +1218,8 @@ static bool parse_type_or_expr(Context *context, Expr **exprPtr, TypeInfo **type
if (context->tok.type == TOKEN_TYPE_IDENT && !is_expr_after_type_ident(context))
{
context_restore_lexer_state(context);
*typePtr = parse_type_expression(context);
return type_info_ok(*typePtr);
*type_ptr = parse_type_expression(context);
return type_info_ok(*type_ptr);
}
context_restore_lexer_state(context);
}
@@ -1234,20 +1235,20 @@ static bool parse_type_or_expr(Context *context, Expr **exprPtr, TypeInfo **type
CONSUME_OR(TOKEN_RPAREN, false);
if (inner_expr)
{
*typePtr = type_info_new(TYPE_INFO_EXPRESSION);
(**typePtr).unresolved_type_expr = inner_expr;
*type_ptr = type_info_new(TYPE_INFO_EXPRESSION);
(**type_ptr).unresolved_type_expr = inner_expr;
return true;
}
Expr *type_expr = expr_new(EXPR_TYPE, start);
type_expr->type_expr.type = inner_type;
*exprPtr = parse_precedence_with_left_side(context, type_expr, PREC_ASSIGNMENT);
return expr_ok(*exprPtr);
*expr_ptr = parse_precedence_with_left_side(context, type_expr, PREC_ASSIGNMENT);
return expr_ok(*expr_ptr);
}
default:
break;
}
*exprPtr = parse_expr(context);
return expr_ok(*exprPtr);
*expr_ptr = parse_expr(context);
return expr_ok(*expr_ptr);
}
@@ -1361,6 +1362,7 @@ static inline Ast* parse_switch_stmt(Context *context)
return switch_ast;
}
static Ast *parse_stmt(Context *context)
{
switch (context->tok.type)
@@ -1413,6 +1415,8 @@ static Ast *parse_stmt(Context *context)
return parse_label_stmt(context);
}
return parse_expr_stmt(context);
case TOKEN_AT:
return parse_expr_stmt(context);
case TOKEN_IDENT:
if (context->next_tok.type == TOKEN_SCOPE)
{
@@ -1487,7 +1491,6 @@ static Ast *parse_stmt(Context *context)
case TOKEN_PLUS:
case TOKEN_MINUSMINUS:
case TOKEN_PLUSPLUS:
case TOKEN_AT_IDENT:
case TOKEN_HASH_IDENT:
case TOKEN_CT_IDENT:
case TOKEN_STRING:
@@ -1500,7 +1503,6 @@ static Ast *parse_stmt(Context *context)
case TOKEN_INVALID_TOKEN:
advance(context);
return &poisoned_ast;
case TOKEN_AT:
case TOKEN_COLON:
case TOKEN_COMMA:
case TOKEN_EQ:
@@ -1638,7 +1640,6 @@ static inline bool parse_optional_module_params(Context *context, Token **tokens
case TOKEN_COMMA:
sema_error_range(context->next_tok.span, "Unexpected ','");
return false;
case TOKEN_AT_IDENT:
case TOKEN_CT_IDENT:
case TOKEN_HASH_IDENT:
case TOKEN_TYPE_IDENT:
@@ -1830,24 +1831,14 @@ static Expr *parse_precedence(Context *context, Precedence precedence)
return parse_precedence_with_left_side(context, left_side, precedence);
}
static inline Expr* parse_non_assign_expr(Context *context)
{
return parse_precedence(context, PREC_ASSIGNMENT + 1);
}
static inline Expr* parse_expr(Context *context)
{
SourceRange start = context->tok.span;
bool found_try = try_consume(context, TOKEN_TRY);
Expr *expr = TRY_EXPR_OR(parse_precedence(context, PREC_ASSIGNMENT), &poisoned_expr);
if (found_try)
{
Expr *try_expr = expr_new(EXPR_TRY, start);
try_expr->try_expr.expr = expr;
if (try_consume(context, TOKEN_ELSE))
{
try_expr->try_expr.else_expr = TRY_EXPR_OR(parse_precedence(context, PREC_ASSIGNMENT), &poisoned_expr);
}
return try_expr;
}
return expr;
return parse_precedence(context, PREC_ASSIGNMENT);
}
static inline Expr *parse_paren_expr(Context *context)
@@ -1942,10 +1933,10 @@ static inline Decl *parse_global_declaration(Context *context, Visibility visibi
* ;
*
* attribute
* : AT_IDENT
* | path AT_IDENT
* | AT_IDENT '(' constant_expression ')'
* | path AT_IDENT '(' constant_expression ')'
* : AT IDENT
* | AT path IDENT
* | AT IDENT '(' constant_expression ')'
* | AT path IDENT '(' constant_expression ')'
* ;
*
* @return true if parsing succeeded, false if recovery is needed
@@ -1954,7 +1945,7 @@ static inline bool parse_attributes(Context *context, Decl *parent_decl)
{
parent_decl->attributes = NULL;
while (context->tok.type == TOKEN_AT_IDENT || (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE))
while (try_consume(context, TOKEN_AT))
{
Path *path = parse_path_prefix(context);
@@ -1963,7 +1954,7 @@ static inline bool parse_attributes(Context *context, Decl *parent_decl)
attr->name = context->tok;
attr->path = path;
TRY_CONSUME_OR(TOKEN_AT_IDENT, "Expected an attribute", false);
TRY_CONSUME_OR(TOKEN_IDENT, "Expected an attribute", false);
if (context->tok.type == TOKEN_LPAREN)
{
@@ -2259,19 +2250,21 @@ static inline bool parse_opt_throw_declaration(Context *context, Visibility visi
}
if (!try_consume(context, TOKEN_THROWS)) return true;
if (context->tok.type != TOKEN_TYPE_IDENT)
if (context->tok.type != TOKEN_TYPE_IDENT && context->tok.type != TOKEN_IDENT)
{
VECADD(signature->throws, &all_error);
signature->throw_any = true;
return true;
}
Decl **throws = NULL;
while (context->tok.type == TOKEN_TYPE_IDENT)
{
Decl *error = decl_new(DECL_ERROR, context->tok, visibility);
advance(context);
VECADD(throws, error);
if (!try_consume(context, TOKEN_COMMA)) break;
}
while (1)
{
TypeInfo *type_info = parse_base_type(context);
if (!type_info_ok(type_info)) return false;
Decl *throw = decl_new(DECL_THROWS, context->tok, visibility);
throw->throws = type_info;
VECADD(throws, throw);
if (!try_consume(context, TOKEN_COMMA)) break;
}
switch (context->tok.type)
{
case TOKEN_TYPE_IDENT:
@@ -2346,8 +2339,8 @@ static AttributeDomains TOKEN_TO_ATTR[TOKEN_EOF + 1] = {
/**
* attribute_declaration
* : ATTRIBUTE attribute_domains AT_IDENT ';'
* | ATTRIBUTE attribute_domains AT_IDENT '(' parameter_type_list ')' ';'
* : ATTRIBUTE attribute_domains IDENT ';'
* | ATTRIBUTE attribute_domains IDENT '(' parameter_type_list ')' ';'
* ;
*
* attribute_domains
@@ -2387,8 +2380,8 @@ static inline Decl *parse_attribute_declaration(Context *context, Visibility vis
if (!try_consume(context, TOKEN_COMMA)) break;
last_domain = TOKEN_TO_ATTR[context->tok.type];
}
TRY_CONSUME_OR(TOKEN_AT_IDENT, "Expected an attribute name.", &poisoned_decl);
Decl *decl = decl_new(DECL_ATTRIBUTE, context->tok, visibility);
TRY_CONSUME_OR(TOKEN_IDENT, "Expected an attribute name.", &poisoned_decl);
if (last_domain == 0)
{
SEMA_TOKEN_ERROR(context->tok, "Expected at least one domain for attribute '%s'.", decl->name);
@@ -2449,14 +2442,14 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil
advance_and_verify(context, TOKEN_MACRO);
TypeInfo *rtype = NULL;
if (context->tok.type != TOKEN_AT_IDENT)
if (context->tok.type != TOKEN_IDENT)
{
rtype = TRY_TYPE_OR(parse_type_expression(context), &poisoned_decl);
}
Decl *decl = decl_new(DECL_MACRO, context->tok, visibility);
decl->macro_decl.rtype = rtype;
TRY_CONSUME_OR(TOKEN_AT_IDENT, "Expected a macro name starting with '@'", &poisoned_decl);
TRY_CONSUME_OR(TOKEN_IDENT, "Expected a macro name here", &poisoned_decl);
CONSUME_OR(TOKEN_LPAREN, &poisoned_decl);
Decl **params = NULL;
@@ -2467,7 +2460,6 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil
switch (context->tok.type)
{
case TOKEN_IDENT:
case TOKEN_AT_IDENT:
case TOKEN_CT_IDENT:
case TOKEN_HASH_IDENT:
break;
@@ -3456,7 +3448,6 @@ static Expr *parse_maybe_scope(Context *context, Expr *left)
{
case TOKEN_IDENT:
case TOKEN_CT_IDENT:
case TOKEN_AT_IDENT:
case TOKEN_CONST_IDENT:
return parse_identifier_with_path(context, path);
case TOKEN_TYPE_IDENT:
@@ -3480,6 +3471,28 @@ static Expr *parse_type_expr(Context *context, Expr *left)
return expr;
}
static Expr *parse_try_expr(Context *context, Expr *left)
{
assert(!left && "Unexpected left hand side");
Expr *try_expr = EXPR_NEW_TOKEN(EXPR_TRY, context->tok);
advance_and_verify(context, TOKEN_TRY);
try_expr->try_expr.expr = TRY_EXPR_OR(parse_precedence(context, PREC_TRY + 1), &poisoned_expr);
if (try_consume(context, TOKEN_ELSE))
{
try_expr->try_expr.else_expr = TRY_EXPR_OR(parse_precedence(context, PREC_ASSIGNMENT), &poisoned_expr);
}
return try_expr;
}
static Expr *parse_macro_expr(Context *context, Expr *left)
{
assert(!left && "Unexpected left hand side");
Expr *macro_expr = EXPR_NEW_TOKEN(EXPR_MACRO_EXPR, context->tok);
advance_and_verify(context, TOKEN_AT);
macro_expr->macro_expr = TRY_EXPR_OR(parse_precedence(context, PREC_UNARY + 1), &poisoned_expr);
return macro_expr;
}
static Expr *parse_cast_expr(Context *context, Expr *left)
{
assert(!left && "Unexpected left hand side");
@@ -3501,6 +3514,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
[TOKEN_LPAREN] = { parse_grouping_expr, parse_call_expr, PREC_CALL },
[TOKEN_TYPE] = { parse_type_expr, NULL, PREC_NONE },
[TOKEN_CAST] = { parse_cast_expr, NULL, PREC_NONE },
[TOKEN_TRY] = { parse_try_expr, NULL, PREC_TRY },
//[TOKEN_SIZEOF] = { parse_sizeof, NULL, PREC_NONE },
[TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL },
[TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
@@ -3532,7 +3546,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
[TOKEN_IDENT] = { parse_maybe_scope, NULL, PREC_NONE },
[TOKEN_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE },
[TOKEN_CT_IDENT] = { parse_identifier, NULL, PREC_NONE },
[TOKEN_AT_IDENT] = { parse_identifier, NULL, PREC_NONE },
[TOKEN_AT] = { parse_macro_expr, NULL, PREC_UNARY },
[TOKEN_CONST_IDENT] = { parse_identifier, NULL, PREC_NONE },
[TOKEN_STRING] = { parse_string_literal, NULL, PREC_NONE },
[TOKEN_FLOAT] = { parse_double, NULL, PREC_NONE },

View File

@@ -60,6 +60,14 @@ static inline void context_pop_defers_to(Context *context, DeferList *list)
context_pop_defers(context);
}
static inline void context_add_exit(Context *context, ExitType exit)
{
if (context->current_scope->exit < exit)
{
context->current_scope->exit = exit;
}
}
static inline void context_pop_scope(Context *context)
{
assert(context->current_scope != &context->scopes[0]);
@@ -201,7 +209,6 @@ static inline bool sema_analyse_struct_union(Context *context, Decl *decl)
}
}
DEBUG_LOG("Analysis complete.");
// Todo, resolve alignment, size etc.
return decl_ok(decl);
}
@@ -235,7 +242,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo
static inline Type *sema_analyse_function_signature(Context *context, FunctionSignature *signature, bool is_function)
{
char buffer[2048];
char buffer[MAX_FUNCTION_SIGNATURE_SIZE + 200];
size_t buffer_write_offset = 0;
bool all_ok = true;
all_ok = sema_resolve_type_info(context, signature->rtype) && all_ok;
@@ -244,8 +251,14 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi
type_append_signature_name(signature->rtype->type, buffer, &buffer_write_offset);
buffer[buffer_write_offset++] = '(';
}
if (vec_size(signature->params) > MAX_PARAMS)
{
SEMA_ERROR(signature->params[MAX_PARAMS], "Number of params exceeds %d which is unsupported.", MAX_PARAMS);
return false;
}
STable *names = &context->scratch_table;
stable_clear(names);
VECEACH(signature->params, i)
{
Decl *param = signature->params[i];
@@ -284,20 +297,28 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi
buffer[buffer_write_offset++] = '.';
}
buffer[buffer_write_offset++] = ')';
if (signature->throw_any)
{
assert(!signature->throws);
buffer[buffer_write_offset++] = '!';
}
if (vec_size(signature->throws))
{
buffer[buffer_write_offset++] = '!';
VECEACH(signature->throws, i)
{
TODO
Decl *err_decl = signature->throws[i];
if (!sema_analyse_decl(context, err_decl))
{
continue;
}
if (i > 0 && all_ok)
{
buffer[buffer_write_offset++] = ',';
buffer[buffer_write_offset++] = '|';
}
// type_append_signature_name(signature->tparam->var.type, buffer, &buffer_write_offset);
type_append_signature_name(err_decl->type, buffer, &buffer_write_offset);
}
}
if (!all_ok) return NULL;
TokenType type = TOKEN_INVALID_TOKEN;
signature->mangled_signature = symtab_add(buffer, buffer_write_offset, fnv1a(buffer, buffer_write_offset), &type);
@@ -587,6 +608,7 @@ static inline bool sema_analyse_goto_stmt(Context *context, Ast *statement)
}
}
vec_add(context->gotos, statement);
context_add_exit(context, EXIT_GOTO);
return true;
}
@@ -864,14 +886,47 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
return success;
}
static bool sema_analyse_try_stmt(Context *context __unused, Ast *statement __unused)
static bool sema_analyse_try_stmt(Context *context, Ast *statement)
{
TODO
context->try_nesting++;
unsigned errors = vec_size(context->errors);
if (!sema_analyse_statement(context, statement->try_stmt))
{
context->try_nesting--;
return false;
}
unsigned new_errors = vec_size(context->errors);
if (new_errors == errors)
{
SEMA_ERROR(statement, "No error to 'try' in the statement that follows, please remove the 'try'.");
return false;
}
for (unsigned i = errors; i < new_errors; i++)
{
// At least one uncaught error found!
if (context->errors[i]) return true;
}
SEMA_ERROR(statement, "All errors in the following statement was caught, please remove the 'try'.");
return false;
}
static bool sema_analyse_throw_stmt(Context *context __unused, Ast *statement __unused)
static bool sema_analyse_throw_stmt(Context *context, Ast *statement)
{
TODO
Expr *throw_value = statement->throw_stmt.throw_value;
if (!sema_analyse_expr(context, NULL, throw_value)) return false;
Type *type = throw_value->type->canonical;
if (type->type_kind != TYPE_ERROR)
{
SEMA_ERROR(throw_value, "Only 'error' types can be thrown, this is a '%s'.", type->name);
return false;
}
if (!context->try_nesting && !func_has_error_return(&context->active_function_for_analysis->func.function_signature))
{
SEMA_ERROR(statement, "This 'throw' is not handled, please add a 'throws %s' clause to the function signature or use try-catch.", type->name);
return false;
}
VECADD(context->errors, type->decl);
return true;
}
@@ -998,6 +1053,12 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
context->current_scope = &context->scopes[0];
// Clean out the current scope.
memset(context->current_scope, 0, sizeof(*context->current_scope));
// Clear try handling
vec_resize(context->errors, 0);
context->try_nesting = 0;
context->labels = NULL;
context->gotos = NULL;
context->last_local = &context->locals[0];
@@ -1222,10 +1283,42 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
return success;
}
static inline bool sema_analyse_throws(Context *context, Decl *decl)
{
if (!sema_resolve_type_info(context, decl->throws)) return false;
decl->type = decl->throws->type;
return true;
}
static inline bool sema_analyse_error(Context *context, Decl *decl)
{
// TODO assign numbers to constants
return true;
Decl **constants = decl->error.error_constants;
unsigned size = vec_size(constants);
if (size > MAX_ERRORS)
{
SEMA_ERROR(decl, "More than %d errors declared in a single error type.", MAX_ERRORS);
return false;
}
bool success = true;
for (unsigned i = 0; i < size; i++)
{
Decl *constant = constants[i];
for (unsigned j = 0; j < i; j++)
{
if (constant->name == constants[j]->name)
{
SEMA_ERROR(constant, "Duplicate error names, please remove one of them.");
SEMA_PREV(constants[j], "The previous declaration was here.");
decl_poison(constant);
decl_poison(constants[j]);
success = false;
break;
}
}
constant->error_constant.value = i;
constant->resolve_status = RESOLVE_DONE;
}
return success;
}
bool sema_analyse_decl(Context *context, Decl *decl)
@@ -1245,10 +1338,12 @@ bool sema_analyse_decl(Context *context, Decl *decl)
switch (decl->decl_kind)
{
case DECL_THROWS:
TODO
if (!sema_analyse_throws(context, decl)) return decl_poison(decl);
break;
case DECL_STRUCT:
case DECL_UNION:
if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl);
llvm_set_struct_size_alignment(decl);
decl_set_external_name(decl);
break;
case DECL_FUNC:
@@ -1408,17 +1503,18 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
type_info->unresolved.path,
&ambiguous_decl);
if (!decl)
{
SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "Unknown type '%s'.", type_info->unresolved.name_loc.string);
return type_info_poison(type_info);
}
// Already handled
if (!decl_ok(decl))
{
return type_info_poison(type_info);
}
if (!decl)
{
SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "Unknown type '%s'.", type_info->unresolved.name_loc.string);
return type_info_poison(type_info);
}
if (ambiguous_decl)
{

View File

@@ -1,25 +1,26 @@
#include <llvm-c/Target.h>
#include <llvm-c/TargetMachine.h>
#include <llvm-c/Core.h>
#include <target_info/target_info.h>
#include "compiler_internal.h"
typedef struct
{
LLVMTargetRef target;
LLVMTargetMachineRef machine;
LLVMTargetDataRef data_layout;
int alloca_address_space;
} Target;
static unsigned arch_pointer_bit_width(ArchType arch);
static ArchType arch_from_llvm_string(const char *string);
static unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type);
static OsType os_from_llvm_string(const char *string);
static VendorType vendor_from_llvm_string(const char *string);
static Target target = {};
Target build_target = {};
int target_alloca_addr_space()
{
return target.alloca_address_space;
return build_target.alloca_address_space;
}
void target_setup()
{
assert(!target.target);
assert(!build_target.target);
LLVMInitializeAllTargetInfos();
LLVMInitializeAllTargetMCs();
@@ -27,20 +28,20 @@ void target_setup()
LLVMInitializeAllAsmPrinters();
LLVMInitializeAllAsmParsers();
target.target = NULL;
build_target.target = NULL;
if (!build_options.target)
{
build_options.target = LLVMGetDefaultTargetTriple();
}
char *err = NULL;
if (LLVMGetTargetFromTriple(build_options.target, &target.target, &err) != 0)
if (LLVMGetTargetFromTriple(build_options.target, ((LLVMTargetRef *)&build_target.target), &err) != 0)
{
error_exit("Could not create target: %s", err);
// Usually we would dispose of err, but no need to do it due to exit.
}
target.alloca_address_space = 0;
build_target.alloca_address_space = 0;
DEBUG_LOG("Target set to %s.", build_options.target);
// Create a specific target machine
@@ -76,29 +77,395 @@ void target_setup()
{
opt->features = "";
}*/
if (!(target.machine = LLVMCreateTargetMachine(target.target, build_options.target, build_options.cpu, "", level, reloc_mode,
LLVMCodeModelDefault))) {
if (!(build_target.machine = LLVMCreateTargetMachine(build_target.target, build_options.target, "", "", level, reloc_mode,
LLVMCodeModelDefault))) {
error_exit("Failed to create target machine.");
}
// The below is broken for the AMDGPU target.
target.alloca_address_space = 0;
target.data_layout = LLVMCreateTargetDataLayout(target.machine);
build_options.pointer_size = (int)LLVMPointerSize(target.data_layout);
DEBUG_LOG("Deduced pointer size to be %d bits", build_options.pointer_size * 8);
build_target.llvm_data_layout = LLVMCreateTargetDataLayout(build_target.machine);
char *target_triple = LLVMGetTargetMachineTriple(build_target.machine);
build_target.arch_name = strdup(strtok(target_triple, "-"));
build_target.vendor_name = strdup(strtok(NULL, "-"));
build_target.os_name = strdup(strtok(NULL, "0123456789"));
LLVMDisposeMessage(target_triple);
build_target.arch = arch_from_llvm_string(build_target.arch_name);
build_target.os = os_from_llvm_string(build_target.os_name);
build_target.vendor = vendor_from_llvm_string(build_target.vendor_name);
build_target.width_pointer = arch_pointer_bit_width(build_target.arch);
assert(build_target.width_pointer == LLVMPointerSize(build_target.llvm_data_layout) * 8);
build_target.alloca_address_space = 0;
LLVMTypeRef byte_type = LLVMIntType(8);
LLVMTypeRef short_type = LLVMIntType(16);
LLVMTypeRef int_type = LLVMIntType(32);
LLVMTypeRef long_type = LLVMIntType(64);
LLVMTypeRef float_type = LLVMFloatType();
LLVMTypeRef double_type = LLVMDoubleType();
LLVMTypeRef quad_type = LLVMFP128Type();
build_target.align_byte = LLVMABIAlignmentOfType(build_target.llvm_data_layout, byte_type);
build_target.align_short = LLVMABIAlignmentOfType(build_target.llvm_data_layout, short_type);
build_target.align_int = LLVMABIAlignmentOfType(build_target.llvm_data_layout, int_type);
build_target.align_long = LLVMABIAlignmentOfType(build_target.llvm_data_layout, long_type);
build_target.align_f128 = LLVMABIAlignmentOfType(build_target.llvm_data_layout, quad_type);
build_target.align_double = LLVMABIAlignmentOfType(build_target.llvm_data_layout, double_type);
build_target.align_float = LLVMABIAlignmentOfType(build_target.llvm_data_layout, float_type);
build_target.little_endian = LLVMByteOrder(build_target.llvm_data_layout) == LLVMLittleEndian;
build_target.width_c_short = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_SHORT);
build_target.width_c_int = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_INT);
build_target.width_c_long = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_LONG);
build_target.width_c_long_long = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_LONG_LONG);
builtin_setup(&build_target);
}
void target_destroy()
{
assert(target.machine);
LLVMDisposeTargetMachine(target.machine);
assert(build_target.machine);
LLVMDisposeTargetMachine(build_target.machine);
}
void *target_target()
{
return build_target.target;
}
void *target_machine()
{
return target.machine;
return build_target.machine;
}
void *target_data_layout()
{
return target.data_layout;
}
return build_target.llvm_data_layout;
}
static ArchType arch_from_llvm_string(const char *string)
{
#define STRCASE(_str, _arch) if (strcmp(string, _str) == 0) return _arch;
STRCASE("i386", ARCH_TYPE_X86)
STRCASE("i486", ARCH_TYPE_X86)
STRCASE("i586", ARCH_TYPE_X86)
STRCASE("i686", ARCH_TYPE_X86)
STRCASE("i786", ARCH_TYPE_X86)
STRCASE("i886", ARCH_TYPE_X86)
STRCASE("i986", ARCH_TYPE_X86)
STRCASE("aarch64", ARCH_TYPE_AARCH64)
STRCASE("arm64", ARCH_TYPE_AARCH64)
STRCASE("aarch64_be", ARCH_TYPE_AARCH64_BE)
STRCASE("aarch64_32", ARCH_TYPE_AARCH64_32)
STRCASE("arm64_32", ARCH_TYPE_AARCH64_32)
STRCASE("arm", ARCH_TYPE_ARM)
STRCASE("xscale", ARCH_TYPE_ARM)
STRCASE("armeb", ARCH_TYPE_ARMB)
STRCASE("xscaleeb", ARCH_TYPE_ARMB)
STRCASE("arc", ARCH_TYPE_ARC)
STRCASE("avr", ARCH_TYPE_AVR)
STRCASE("bpfeb", ARCH_TYPE_BPFEB)
STRCASE("bpfel", ARCH_TYPE_BPFEL)
STRCASE("hexagon", ARCH_TYPE_HEXAGON)
STRCASE("mips", ARCH_TYPE_MIPS)
STRCASE("mipseb", ARCH_TYPE_MIPS)
STRCASE("mipsallegrex", ARCH_TYPE_MIPS)
STRCASE("mipsisa32r6", ARCH_TYPE_MIPS)
STRCASE("mipsr6", ARCH_TYPE_MIPS)
STRCASE("mipsel", ARCH_TYPE_MIPSEL)
STRCASE("mipsallegrexel", ARCH_TYPE_MIPSEL)
STRCASE("mipsisa32r6el", ARCH_TYPE_MIPSEL)
STRCASE("mipsr6el", ARCH_TYPE_MIPSEL)
STRCASE("mips64", ARCH_TYPE_MIPS64)
STRCASE("mips64eb", ARCH_TYPE_MIPS64)
STRCASE("mipsn32", ARCH_TYPE_MIPS64)
STRCASE("mipsisa64r6", ARCH_TYPE_MIPS64)
STRCASE("mips64r6", ARCH_TYPE_MIPS64)
STRCASE("mipsn32r6", ARCH_TYPE_MIPS64)
STRCASE("mips64el", ARCH_TYPE_MIPS64EL)
STRCASE("mipsn32el", ARCH_TYPE_MIPS64EL)
STRCASE("mipsisa64r6el", ARCH_TYPE_MIPS64EL)
STRCASE("mips64r6el", ARCH_TYPE_MIPS64EL)
STRCASE("mipsn32r6el", ARCH_TYPE_MIPS64EL)
STRCASE("msp430", ARCH_TYPE_MSP430)
STRCASE("powerpc64", ARCH_TYPE_PPC64)
STRCASE("ppu", ARCH_TYPE_PPC64)
STRCASE("ppc64", ARCH_TYPE_PPC64)
STRCASE("powerpc64le", ARCH_TYPE_PPC64LE)
STRCASE("ppc64le", ARCH_TYPE_PPC64LE)
STRCASE("powerpc", ARCH_TYPE_PPC)
STRCASE("ppc", ARCH_TYPE_PPC)
STRCASE("ppc32", ARCH_TYPE_PPC)
STRCASE("r600", ARCH_TYPE_R600)
STRCASE("amdgcn", ARCH_TYPE_AMDGCN)
STRCASE("riscv32", ARCH_TYPE_RISCV32)
STRCASE("riscv64", ARCH_TYPE_RISCV64)
STRCASE("sparc", ARCH_TYPE_SPARC)
STRCASE("sparcel", ARCH_TYPE_SPARCEL)
STRCASE("sparcv9", ARCH_TYPE_SPARCV9)
STRCASE("sparc64", ARCH_TYPE_SPARCV9)
STRCASE("systemz", ARCH_TYPE_SYSTEMZ)
STRCASE("s390x", ARCH_TYPE_SYSTEMZ)
STRCASE("tce", ARCH_TYPE_TCE)
STRCASE("tcele", ARCH_TYPE_TCELE)
STRCASE("thumb", ARCH_TYPE_THUMB)
STRCASE("thumbeb", ARCH_TYPE_THUMBEB)
STRCASE("x86_64", ARCH_TYPE_X86_64)
STRCASE("amd64", ARCH_TYPE_X86_64)
STRCASE("x86_64h", ARCH_TYPE_X86_64)
STRCASE("xcore", ARCH_TYPE_XCORE)
STRCASE("nvptx", ARCH_TYPE_NVPTX)
STRCASE("nvptx64", ARCH_TYPE_NVPTX64)
STRCASE("le32", ARCH_TYPE_LE32)
STRCASE("le64", ARCH_TYPE_LE64)
STRCASE("amdil", ARCH_TYPE_AMDIL)
STRCASE("amdil64", ARCH_TYPE_AMDIL64)
STRCASE("hsail", ARCH_TYPE_HSAIL)
STRCASE("hsail64", ARCH_TYPE_HSAIL64)
STRCASE("spir", ARCH_TYPE_SPIR)
STRCASE("spir64", ARCH_TYPE_SPIR64)
STRCASE("kalimba", ARCH_TYPE_KALIMBA)
STRCASE("lanai", ARCH_TYPE_LANAI)
STRCASE("shave", ARCH_TYPE_SHAVE)
STRCASE("wasm32", ARCH_TYPE_WASM32)
STRCASE("wasm64", ARCH_TYPE_WASM64)
STRCASE("renderscript32", ARCH_TYPE_RSCRIPT32)
STRCASE("renderscript64", ARCH_TYPE_RSCRIPT64)
return ARCH_TYPE_UNKNOWN;
#undef STRCASE
// TODO parse arm & bpf names
}
static OsType os_from_llvm_string(const char *string)
{
#define STRCASE(_str, _os) if (strcmp(string, _str) == 0) return _os;
STRCASE("ananas", OS_TYPE_ANANAS)
STRCASE("cloudabi", OS_TYPE_CLOUD_ABI)
STRCASE("darwin", OS_TYPE_DARWIN)
STRCASE("dragonfly", OS_TYPE_DRAGON_FLY)
STRCASE("freebsd", OS_TYPE_FREE_BSD)
STRCASE("fuchsia", OS_TYPE_FUCHSIA)
STRCASE("ios", OS_TYPE_IOS)
STRCASE("kfreebsd", OS_TYPE_KFREEBSD)
STRCASE("linux", OS_TYPE_LINUX)
STRCASE("lv2", OS_TYPE_PS3)
STRCASE("macosx", OS_TYPE_MACOSX)
STRCASE("netbsd", OS_TYPE_NETBSD)
STRCASE("openbsd", OS_TYPE_OPENBSD)
STRCASE("solaris", OS_TYPE_SOLARIS)
STRCASE("windows", OS_TYPE_WIN32)
STRCASE("haiku", OS_TYPE_HAIKU)
STRCASE("minix", OS_TYPE_MINIX)
STRCASE("rtems", OS_TYPE_RTEMS)
STRCASE("nacl", OS_TYPE_NACL)
STRCASE("cnk", OS_TYPE_CNK)
STRCASE("aix", OS_TYPE_AIX)
STRCASE("cuda", OS_TYPE_CUDA)
STRCASE("nvcl", OS_TYPE_NVOPENCL)
STRCASE("amdhsa", OS_TYPE_AMDHSA)
STRCASE("ps4", OS_TYPE_PS4)
STRCASE("elfiamcu", OS_TYPE_ELFIAMCU)
STRCASE("tvos", OS_TYPE_TVOS)
STRCASE("watchos", OS_TYPE_WATCHOS)
STRCASE("mesa3d", OS_TYPE_MESA3D)
STRCASE("contiki", OS_TYPE_CONTIKI)
STRCASE("amdpal", OS_TYPE_AMDPAL)
STRCASE("hermit", OS_TYPE_HERMITCORE)
STRCASE("hurd", OS_TYPE_HURD)
STRCASE("wasi", OS_TYPE_WASI)
STRCASE("emscripten", OS_TYPE_EMSCRIPTEN)
return OS_TYPE_UNKNOWN;
#undef STRCASE
}
static VendorType vendor_from_llvm_string(const char *string)
{
#define STRCASE(_str, _vendor) if (strcmp(string, _str) == 0) return _vendor;
STRCASE("apple", VENDOR_APPLE)
STRCASE("pc", VENDOR_PC)
STRCASE("scei", VENDOR_SCEI)
STRCASE("bgp", VENDOR_BGP)
STRCASE("bgq", VENDOR_BGQ)
STRCASE("fsl", VENDOR_FREESCALE)
STRCASE("ibm", VENDOR_IBM)
STRCASE("img", VENDOR_IMAGINATION_TECHNOLOGIES)
STRCASE("mti", VENDOR_MIPS_TECHNOLOGIES)
STRCASE("nvidia", VENDOR_NVIDIA)
STRCASE("csr", VENDOR_CSR)
STRCASE("myriad", VENDOR_MYRIAD)
STRCASE("amd", VENDOR_AMD)
STRCASE("mesa", VENDOR_MESA)
STRCASE("suse", VENDOR_SUSE)
STRCASE("oe", VENDOR_OPEN_EMBEDDED)
return VENDOR_UNKNOWN;
#undef STRCASE
}
static unsigned arch_pointer_bit_width(ArchType arch)
{
switch (arch)
{
case ARCH_TYPE_UNKNOWN:
return 0;
case ARCH_TYPE_MSP430:
case ARCH_TYPE_AVR:
return 16;
case ARCH_TYPE_ARM:
case ARCH_TYPE_ARMB:
case ARCH_TYPE_AARCH64_32:
case ARCH_TYPE_ARC:
case ARCH_TYPE_HEXAGON:
case ARCH_TYPE_MIPS:
case ARCH_TYPE_MIPSEL:
case ARCH_TYPE_PPC:
case ARCH_TYPE_R600:
case ARCH_TYPE_RISCV32:
case ARCH_TYPE_SPARC:
case ARCH_TYPE_SPARCEL:
case ARCH_TYPE_TCE:
case ARCH_TYPE_TCELE:
case ARCH_TYPE_THUMB:
case ARCH_TYPE_THUMBEB:
case ARCH_TYPE_X86:
case ARCH_TYPE_XCORE:
case ARCH_TYPE_NVPTX:
case ARCH_TYPE_LE32:
case ARCH_TYPE_AMDIL:
case ARCH_TYPE_HSAIL:
case ARCH_TYPE_SPIR:
case ARCH_TYPE_KALIMBA:
case ARCH_TYPE_SHAVE:
case ARCH_TYPE_LANAI:
case ARCH_TYPE_WASM32:
case ARCH_TYPE_RSCRIPT32:
return 32;
case ARCH_TYPE_SPIR64:
case ARCH_TYPE_RSCRIPT64:
case ARCH_TYPE_WASM64:
case ARCH_TYPE_LE64:
case ARCH_TYPE_BPFEL:
case ARCH_TYPE_BPFEB:
case ARCH_TYPE_AARCH64:
case ARCH_TYPE_AARCH64_BE:
case ARCH_TYPE_X86_64:
case ARCH_TYPE_SYSTEMZ:
case ARCH_TYPE_PPC64:
case ARCH_TYPE_SPARCV9:
case ARCH_TYPE_MIPS64:
case ARCH_TYPE_NVPTX64:
case ARCH_TYPE_AMDIL64:
case ARCH_TYPE_HSAIL64:
case ARCH_TYPE_RISCV64:
case ARCH_TYPE_AMDGCN:
case ARCH_TYPE_MIPS64EL:
case ARCH_TYPE_PPC64LE:
return 64;
default:
UNREACHABLE
}
}
unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type)
{
switch (os)
{
case OS_TYPE_UNKNOWN:
if (arch == ARCH_TYPE_MSP430)
{
switch (type)
{
case CTYPE_SHORT:
case CTYPE_INT:
return 16;
case CTYPE_LONG:
return 32;
case CTYPE_LONG_LONG:
return 64;
default:
UNREACHABLE
}
}
// Use default
break;
case OS_TYPE_LINUX:
case OS_TYPE_DARWIN:
case OS_TYPE_MACOSX:
case OS_TYPE_FREE_BSD:
case OS_TYPE_NETBSD:
case OS_TYPE_DRAGON_FLY:
case OS_TYPE_OPENBSD:
case OS_TYPE_WASI:
case OS_TYPE_EMSCRIPTEN:
// Use default
break;
case OS_TYPE_WIN32:
switch (type)
{
case CTYPE_SHORT:
return 16;
case CTYPE_INT:
case CTYPE_LONG:
return 32;
case CTYPE_LONG_LONG:
return 64;
default:
UNREACHABLE
}
case OS_TYPE_IOS:
switch (type)
{
case CTYPE_SHORT:
return 16;
case CTYPE_INT:
return 32;
case CTYPE_LONG:
case CTYPE_LONG_LONG:
return 64;
default:
UNREACHABLE
}
case OS_TYPE_ANANAS:
case OS_TYPE_CLOUD_ABI:
case OS_TYPE_FUCHSIA:
case OS_TYPE_KFREEBSD:
case OS_TYPE_PS3:
case OS_TYPE_SOLARIS:
case OS_TYPE_HAIKU:
case OS_TYPE_MINIX:
case OS_TYPE_RTEMS:
case OS_TYPE_NACL:
case OS_TYPE_CNK:
case OS_TYPE_AIX:
case OS_TYPE_CUDA:
case OS_TYPE_NVOPENCL:
case OS_TYPE_AMDHSA:
case OS_TYPE_PS4:
case OS_TYPE_ELFIAMCU:
case OS_TYPE_TVOS:
case OS_TYPE_WATCHOS:
case OS_TYPE_MESA3D:
case OS_TYPE_CONTIKI:
case OS_TYPE_AMDPAL:
case OS_TYPE_HERMITCORE:
case OS_TYPE_HURD:
TODO
}
switch (type)
{
case CTYPE_SHORT:
return 16;
case CTYPE_INT:
return 32;
case CTYPE_LONG:
return arch_pointer_bit_width(arch);
case CTYPE_LONG_LONG:
return 64;
default:
UNREACHABLE
}
}

197
src/compiler/target.h Normal file
View File

@@ -0,0 +1,197 @@
#pragma once
// Copyright (c) 2020 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
// Note: This list is based on Clang's
typedef enum
{
ARCH_TYPE_UNKNOWN,
ARCH_TYPE_ARM, // ARM (little endian): arm, armv.*, xscale
ARCH_TYPE_ARMB, // ARM (big endian): armeb
ARCH_TYPE_AARCH64, // AArch64 (little endian): aarch64
ARCH_TYPE_AARCH64_BE, // AArch64 (big endian): aarch64_be
ARCH_TYPE_AARCH64_32, // AArch64 (little endian) ILP32: aarch64_32
ARCH_TYPE_ARC, // ARC: Synopsys ARC
ARCH_TYPE_AVR, // AVR: Atmel AVR microcontroller
ARCH_TYPE_BPFEL, // eBPF or extended BPF or 64-bit BPF (little endian)
ARCH_TYPE_BPFEB, // eBPF or extended BPF or 64-bit BPF (big endian)
ARCH_TYPE_HEXAGON, // Hexagon: hexagon
ARCH_TYPE_MIPS, // MIPS: mips, mipsallegrex, mipsr6
ARCH_TYPE_MIPSEL, // MIPSEL: mipsel, mipsallegrexe, mipsr6el
ARCH_TYPE_MIPS64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6
ARCH_TYPE_MIPS64EL, // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el
ARCH_TYPE_MSP430, // MSP430: msp430
ARCH_TYPE_PPC, // PPC: powerpc
ARCH_TYPE_PPC64, // PPC64: powerpc64, ppu
ARCH_TYPE_PPC64LE, // PPC64LE: powerpc64le
ARCH_TYPE_R600, // R600: AMD GPUs HD2XXX - HD6XXX
ARCH_TYPE_AMDGCN, // AMDGCN: AMD GCN GPUs
ARCH_TYPE_RISCV32, // RISC-V (32-bit): riscv32
ARCH_TYPE_RISCV64, // RISC-V (64-bit): riscv64
ARCH_TYPE_SPARC, // Sparc: sparc
ARCH_TYPE_SPARCV9, // Sparcv9: Sparcv9
ARCH_TYPE_SPARCEL, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
ARCH_TYPE_SYSTEMZ, // SystemZ: s390x
ARCH_TYPE_TCE, // TCE (http://tce.cs.tut.fi/): tce
ARCH_TYPE_TCELE, // TCE little endian (http://tce.cs.tut.fi/): tcele
ARCH_TYPE_THUMB, // Thumb (little endian): thumb, thumbv.*
ARCH_TYPE_THUMBEB, // Thumb (big endian): thumbeb
ARCH_TYPE_X86, // X86: i[3-9]86
ARCH_TYPE_X86_64, // X86-64: amd64, x86_64
ARCH_TYPE_XCORE, // XCore: xcore
ARCH_TYPE_NVPTX, // NVPTX: 32-bit
ARCH_TYPE_NVPTX64, // NVPTX: 64-bit
ARCH_TYPE_LE32, // le32: generic little-endian 32-bit CPU (PNaCl)
ARCH_TYPE_LE64, // le64: generic little-endian 64-bit CPU (PNaCl)
ARCH_TYPE_AMDIL, // AMDIL
ARCH_TYPE_AMDIL64, // AMDIL with 64-bit pointers
ARCH_TYPE_HSAIL, // AMD HSAIL
ARCH_TYPE_HSAIL64, // AMD HSAIL with 64-bit pointers
ARCH_TYPE_SPIR, // SPIR: standard portable IR for OpenCL 32-bit version
ARCH_TYPE_SPIR64, // SPIR: standard portable IR for OpenCL 64-bit version
ARCH_TYPE_KALIMBA, // Kalimba: generic kalimba
ARCH_TYPE_SHAVE, // SHAVE: Movidius vector VLIW processors
ARCH_TYPE_LANAI, // Lanai: Lanai 32-bit
ARCH_TYPE_WASM32, // WebAssembly with 32-bit pointers
ARCH_TYPE_WASM64, // WebAssembly with 64-bit pointers
ARCH_TYPE_RSCRIPT32, // 32-bit RenderScript
ARCH_TYPE_RSCRIPT64, // 64-bit RenderScript
ARCH_TYPE_LAST = ARCH_TYPE_RSCRIPT64
} ArchType;
typedef enum
{
CTYPE_SHORT,
CTYPE_INT,
CTYPE_LONG,
CTYPE_LONG_LONG
} CType;
typedef enum
{
OS_TYPE_UNKNOWN,
OS_TYPE_ANANAS,
OS_TYPE_CLOUD_ABI,
OS_TYPE_DARWIN,
OS_TYPE_DRAGON_FLY,
OS_TYPE_FREE_BSD,
OS_TYPE_FUCHSIA,
OS_TYPE_IOS,
OS_TYPE_KFREEBSD,
OS_TYPE_LINUX,
OS_TYPE_PS3,
OS_TYPE_MACOSX,
OS_TYPE_NETBSD,
OS_TYPE_OPENBSD,
OS_TYPE_SOLARIS,
OS_TYPE_WIN32,
OS_TYPE_HAIKU,
OS_TYPE_MINIX,
OS_TYPE_RTEMS,
OS_TYPE_NACL, // Native Client
OS_TYPE_CNK, // BG/P Compute-Node Kernel
OS_TYPE_AIX,
OS_TYPE_CUDA,
OS_TYPE_NVOPENCL,
OS_TYPE_AMDHSA,
OS_TYPE_PS4,
OS_TYPE_ELFIAMCU,
OS_TYPE_TVOS,
OS_TYPE_WATCHOS,
OS_TYPE_MESA3D,
OS_TYPE_CONTIKI,
OS_TYPE_AMDPAL,
OS_TYPE_HERMITCORE,
OS_TYPE_HURD,
OS_TYPE_WASI,
OS_TYPE_EMSCRIPTEN,
OS_TYPE_LAST = OS_TYPE_EMSCRIPTEN
} OsType;
typedef enum
{
VENDOR_UNKNOWN,
VENDOR_APPLE,
VENDOR_PC,
VENDOR_SCEI,
VENDOR_BGP,
VENDOR_BGQ,
VENDOR_FREESCALE,
VENDOR_IBM,
VENDOR_IMAGINATION_TECHNOLOGIES,
VENDOR_MIPS_TECHNOLOGIES,
VENDOR_NVIDIA,
VENDOR_CSR,
VENDOR_MYRIAD,
VENDOR_AMD,
VENDOR_MESA,
VENDOR_SUSE,
VENDOR_OPEN_EMBEDDED,
VENDOR_LAST = VENDOR_OPEN_EMBEDDED
} VendorType;
typedef struct
{
void *target;
void *machine;
void *llvm_data_layout;
ArchType arch;
const char *arch_name;
OsType os;
const char *os_name;
VendorType vendor;
const char *vendor_name;
int alloca_address_space;
bool little_endian;
bool tls_supported;
bool asm_supported;
bool float_128;
bool float_16;
unsigned align_min_pointer;
unsigned align_min_byte;
unsigned align_min_short;
unsigned align_min_int;
unsigned align_min_long;
unsigned align_min_half;
unsigned align_min_float;
unsigned align_min_double;
unsigned align_min_f128;
unsigned align_pointer;
unsigned align_byte;
unsigned align_short;
unsigned align_int;
unsigned align_long;
unsigned align_half;
unsigned align_float;
unsigned align_double;
unsigned align_f128;
unsigned align_c_long_double;
unsigned align_c_int;
unsigned align_c_long;
unsigned align_c_long_long;
unsigned align_simd_default;
unsigned align_max_vector;
unsigned align_global_min;
unsigned align_new;
unsigned align_large_array;
unsigned width_pointer;
unsigned width_c_short;
unsigned width_c_int;
unsigned width_c_long;
unsigned width_c_long_long;
unsigned width_c_long_double;
unsigned width_c_wchar;
unsigned width_c_wint;
unsigned width_large_array_min;
unsigned reg_param_max;
unsigned sse_reg_param_max;
unsigned builtin_ms_valist;
unsigned aarch64sve_types;
char *platform_name;
} Target;
extern Target build_target;

View File

@@ -140,8 +140,6 @@ const char *token_type_to_string(TokenType type)
// Identifiers
case TOKEN_IDENT:
return "IDENT";
case TOKEN_AT_IDENT:
return "AT_IDENT";
case TOKEN_HASH_IDENT:
return "HASH_IDENT";
case TOKEN_CT_IDENT:

View File

@@ -21,26 +21,31 @@ Type t_cus, t_cui, t_cul, t_cull;
Type t_cs, t_ci, t_cl, t_cll;
Type t_voidstar;
Type *type_signed_int_by_size(int bytesize)
#define META_OFFSET 0
#define PTR_OFFSET 1
#define VAR_ARRAY_OFFSET 2
#define ARRAY_OFFSET 3
Type *type_signed_int_by_bitsize(unsigned bytesize)
{
switch (bytesize)
{
case 1: return type_char;
case 2: return type_short;
case 4: return type_int;
case 8: return type_long;
default: FATAL_ERROR("Illegal bytesize %d", bytesize);
case 8: return type_char;
case 16: return type_short;
case 32: return type_int;
case 64: return type_long;
default: FATAL_ERROR("Illegal bitsize %d", bytesize);
}
}
Type *type_unsigned_int_by_size(int bytesize)
Type *type_unsigned_int_by_bitsize(unsigned bytesize)
{
switch (bytesize)
{
case 1: return type_byte;
case 2: return type_ushort;
case 4: return type_uint;
case 8: return type_ulong;
default: FATAL_ERROR("Illegal bytesize %d", bytesize);
case 8: return type_byte;
case 16: return type_ushort;
case 32: return type_uint;
case 64: return type_ulong;
default: FATAL_ERROR("Illegal bitsize %d", bytesize);
}
}
@@ -73,6 +78,9 @@ const char *type_to_error_string(Type *type)
case TYPE_UNION:
case TYPE_ERROR:
return type->name;
case TYPE_META_TYPE:
asprintf(&buffer, "type %s", type_to_error_string(type->child));
return buffer;
case TYPE_POINTER:
asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
return buffer;
@@ -135,9 +143,25 @@ static void type_append_signature_name_user_defined(Decl *decl, char *dst, size_
}
void type_append_signature_name(Type *type, char *dst, size_t *offset)
{
assert(*offset < 2000);
memcpy(dst + *offset, type->name, strlen(type->name));
*offset += strlen(type->name);
assert(*offset < MAX_FUNCTION_SIGNATURE_SIZE);
const char *name;
switch (type->type_kind)
{
case TYPE_POISONED:
case TYPE_TYPEDEF:
UNREACHABLE;
case TYPE_ERROR:
case TYPE_ENUM:
case TYPE_STRUCT:
case TYPE_UNION:
name = type->decl->external_name;
break;
default:
name = type->name;
break;
}
memcpy(dst + *offset, name, strlen(name));
*offset += strlen(name);
}
@@ -149,6 +173,8 @@ size_t type_size(Type *canonical)
{
case TYPE_POISONED:
UNREACHABLE;
case TYPE_META_TYPE:
return 0;
case TYPE_ENUM:
case TYPE_TYPEDEF:
case TYPE_STRUCT:
@@ -188,27 +214,29 @@ size_t type_size(Type *canonical)
TODO
}
static inline void create_ptr_cache(Type *canonical_type)
static inline void create_type_cache(Type *canonical_type)
{
assert(canonical_type->canonical == canonical_type);
canonical_type->ptr_cache = VECADD(canonical_type->ptr_cache, NULL);
canonical_type->ptr_cache = VECADD(canonical_type->ptr_cache, NULL);
for (int i = 0; i < ARRAY_OFFSET; i++)
{
vec_add(canonical_type->type_cache, NULL);
}
}
static Type *type_generate_ptr(Type *ptr_type, bool canonical)
{
if (canonical) ptr_type = ptr_type->canonical;
if (!ptr_type->ptr_cache)
if (!ptr_type->type_cache)
{
create_ptr_cache(ptr_type);
create_type_cache(ptr_type);
}
Type *ptr = ptr_type->ptr_cache[0];
Type *ptr = ptr_type->type_cache[PTR_OFFSET];
if (ptr == NULL)
{
ptr = type_new(TYPE_POINTER, strformat("%s*", ptr_type->name));
ptr->pointer = ptr_type;
ptr_type->ptr_cache[0] = ptr;
ptr_type->type_cache[PTR_OFFSET] = ptr;
if (ptr_type == ptr_type->canonical)
{
ptr->canonical = ptr;
@@ -221,24 +249,56 @@ static Type *type_generate_ptr(Type *ptr_type, bool canonical)
return ptr;
}
static Type *type_generate_meta(Type *type, bool canonical)
{
if (canonical) type = type->canonical;
if (!type->type_cache)
{
create_type_cache(type);
}
Type *meta = type->type_cache[META_OFFSET];
if (meta == NULL)
{
meta = type_new(TYPE_META_TYPE, strformat("type %s", type->name));
meta->child = type;
type->type_cache[META_OFFSET] = meta;
if (type == type->canonical)
{
meta->canonical = meta;
}
else
{
meta->canonical = type_generate_meta(type->canonical, true);
}
}
return meta;
}
Type *type_get_ptr(Type *ptr_type)
{
return type_generate_ptr(ptr_type, false);
}
Type *type_get_meta(Type *meta_type)
{
return type_generate_meta(meta_type, false);
}
Type *type_create_array(Type *arr_type, uint64_t len, bool canonical)
{
if (canonical) arr_type = arr_type->canonical;
if (!arr_type->ptr_cache)
if (!arr_type->type_cache)
{
create_ptr_cache(arr_type);
create_type_cache(arr_type);
}
// Dynamic array
if (len == 0)
{
Type *array = arr_type->ptr_cache[1];
Type *array = arr_type->type_cache[VAR_ARRAY_OFFSET];
if (array == NULL)
{
array = type_new(TYPE_VARARRAY, strformat("%s[]", arr_type->name));
@@ -252,15 +312,15 @@ Type *type_create_array(Type *arr_type, uint64_t len, bool canonical)
{
array->canonical = type_create_array(arr_type, len, true);
}
arr_type->ptr_cache[1] = array;
arr_type->type_cache[VAR_ARRAY_OFFSET] = array;
}
return array;
}
int entries = (int)vec_size(arr_type->ptr_cache);
for (int i = 1; i < entries; i++)
int entries = (int)vec_size(arr_type->type_cache);
for (int i = ARRAY_OFFSET; i < entries; i++)
{
Type *ptr = arr_type->ptr_cache[i];
Type *ptr = arr_type->type_cache[i];
if (ptr->array.len == arr_type->array.len)
{
return ptr;
@@ -277,7 +337,7 @@ Type *type_create_array(Type *arr_type, uint64_t len, bool canonical)
{
array->canonical = type_create_array(arr_type, len, true);
}
VECADD(arr_type->ptr_cache, array);
VECADD(arr_type->type_cache, array);
return array;
}
@@ -286,14 +346,17 @@ Type *type_get_array(Type *arr_type, uint64_t len)
return type_create_array(arr_type, len, false);
}
static void type_create(const char *name, Type *location, Type **ptr, TypeKind kind, unsigned bytesize, unsigned bitsize)
static void type_create(const char *name, Type *location, Type **ptr, TypeKind kind, unsigned bitsize,
unsigned align, unsigned pref_align)
{
*location = (Type) {
.type_kind = kind,
.builtin.bytesize = bytesize,
.builtin.bytesize = (bitsize + 7) / 8,
.builtin.bitsize = bitsize,
.builtin.min_alignment = align,
.builtin.pref_alignment = pref_align,
.name = name,
.canonical = location
.canonical = location,
};
location->name = name;
location->canonical = location;
@@ -311,56 +374,58 @@ static void type_create_alias(const char *name, Type *location, Type **ptr, Type
}
void builtin_setup()
void builtin_setup(Target *target)
{
type_create("void", &t_u0, &type_void, TYPE_VOID, 1, 8);
type_create("string", &t_str, &type_string, TYPE_STRING, build_options.pointer_size, build_options.pointer_size * 8);
create_ptr_cache(type_void);
type_void->ptr_cache[0] = &t_voidstar;
type_create("void*", &t_voidstar, &type_voidptr, TYPE_POINTER, 0, 0);
t_voidstar.pointer = type_void;
/*TODO
* decl_string = (Decl) { .decl_kind = DECL_BUILTIN, .name.string = "string" };
create_type(&decl_string, &type_string);
type_string.type_kind = TYPE_STRING;
*/
#define DEF_TYPE(_name, _shortname, _type, _bits) \
type_create(#_name, &_shortname, &type_ ## _name, _type, (_bits + 7) / 8, _bits);
#define DEF_TYPE(_name, _shortname, _type, _bits, _align) \
type_create(#_name, &_shortname, &type_ ## _name, _type, _bits, target->align_min_ ## _align, target->align_ ## _align)
DEF_TYPE(compint, t_ixx, TYPE_IXX, 64);
DEF_TYPE(compuint, t_uxx, TYPE_UXX, 64);
DEF_TYPE(compfloat, t_fxx, TYPE_FXX, 64);
DEF_TYPE(bool, t_u1, TYPE_BOOL, 1);
DEF_TYPE(bool, t_u1, TYPE_BOOL, 1, byte);
DEF_TYPE(float, t_f32, TYPE_F32, 32, float);
DEF_TYPE(double, t_f64, TYPE_F64, 64, double);
DEF_TYPE(float, t_f32, TYPE_F32, 32);
DEF_TYPE(double, t_f64, TYPE_F64, 64);
DEF_TYPE(char, t_i8, TYPE_I8, 8, byte);
DEF_TYPE(short, t_i16, TYPE_I16, 16, short);
DEF_TYPE(int, t_i32, TYPE_I32, 32, int);
DEF_TYPE(long, t_i64, TYPE_I64, 64, long);
DEF_TYPE(char, t_i8, TYPE_I8, 8);
DEF_TYPE(short, t_i16, TYPE_I16, 16);
DEF_TYPE(int, t_i32, TYPE_I32, 32);
DEF_TYPE(long, t_i64, TYPE_I64, 64);
DEF_TYPE(byte, t_u8, TYPE_U8, 8, byte);
DEF_TYPE(ushort, t_u16, TYPE_U16, 16, short);
DEF_TYPE(uint, t_u32, TYPE_U32, 32, int);
DEF_TYPE(ulong, t_u64, TYPE_U64, 64, long);
DEF_TYPE(byte, t_u8, TYPE_U8, 8);
DEF_TYPE(ushort, t_u16, TYPE_U16, 16);
DEF_TYPE(uint, t_u32, TYPE_U32, 32);
DEF_TYPE(ulong, t_u64, TYPE_U64, 64);
type_create_alias("usize", &t_usz, &type_usize, type_unsigned_int_by_size(build_options.pointer_size));
type_create_alias("isize", &t_isz, &type_isize, type_signed_int_by_size(build_options.pointer_size));
type_create_alias("c_ushort", &t_cus, &type_c_ushort, type_unsigned_int_by_size(build_options.cshort_size));
type_create_alias("c_uint", &t_cui, &type_c_uint, type_unsigned_int_by_size(build_options.cint_size));
type_create_alias("c_ulong", &t_cul, &type_c_ulong, type_unsigned_int_by_size(build_options.clong_size));
type_create_alias("c_ulonglong", &t_cull, &type_c_ulonglong, type_unsigned_int_by_size(build_options.clonglong_size));
type_create_alias("c_short", &t_cs, &type_c_short, type_signed_int_by_size(build_options.cshort_size));
type_create_alias("c_int", &t_ci, &type_c_int, type_signed_int_by_size(build_options.cint_size));
type_create_alias("c_long", &t_cl, &type_c_long, type_signed_int_by_size(build_options.clong_size));
type_create_alias("c_longlong", &t_cll, &type_c_longlong, type_signed_int_by_size(build_options.clonglong_size));
DEF_TYPE(void, t_u0, TYPE_VOID, 8, byte);
DEF_TYPE(string, t_str, TYPE_STRING, target->width_pointer, pointer);
#undef DEF_TYPE
type_create("void*", &t_voidstar, &type_voidptr, TYPE_POINTER, target->width_pointer, target->align_min_pointer, target->align_pointer);
create_type_cache(type_void);
type_void->type_cache[0] = &t_voidstar;
t_voidstar.pointer = type_void;
type_create("compint", &t_ixx, &type_compint, TYPE_IXX, 64, 0, 0);
type_create("compuint", &t_uxx, &type_compuint, TYPE_UXX, 64, 0, 0);
type_create("compfloat", &t_fxx, &type_compfloat, TYPE_FXX, 64, 0, 0);
type_create_alias("usize", &t_usz, &type_usize, type_unsigned_int_by_bitsize(target->width_pointer));
type_create_alias("isize", &t_isz, &type_isize, type_signed_int_by_bitsize(target->width_pointer));
type_create_alias("c_ushort", &t_cus, &type_c_ushort, type_unsigned_int_by_bitsize(target->width_c_short));
type_create_alias("c_uint", &t_cui, &type_c_uint, type_unsigned_int_by_bitsize(target->width_c_int));
type_create_alias("c_ulong", &t_cul, &type_c_ulong, type_unsigned_int_by_bitsize(target->width_c_long));
type_create_alias("c_ulonglong", &t_cull, &type_c_ulonglong, type_unsigned_int_by_bitsize(target->width_c_long_long));
type_create_alias("c_short", &t_cs, &type_c_short, type_signed_int_by_bitsize(target->width_c_short));
type_create_alias("c_int", &t_ci, &type_c_int, type_signed_int_by_bitsize(target->width_c_int));
type_create_alias("c_long", &t_cl, &type_c_long, type_signed_int_by_bitsize(target->width_c_long));
type_create_alias("c_longlong", &t_cll, &type_c_longlong, type_signed_int_by_bitsize(target->width_c_long_long));
}
/**
@@ -395,6 +460,7 @@ bool type_may_have_method_functions(Type *type)
case TYPE_UNION:
case TYPE_STRUCT:
case TYPE_ENUM:
case TYPE_ERROR:
return true;
default:
return false;
@@ -441,9 +507,9 @@ Type *type_find_max_num_type(Type *num_type, Type *other_num)
assert (other_num->type_kind != TYPE_FXX);
return other_num;
case LS:
return type_signed_int_by_size(num_type->builtin.bytesize);
return type_signed_int_by_bitsize(num_type->builtin.bytesize * 8);
case RS:
return type_signed_int_by_size(other_num->builtin.bytesize);
return type_signed_int_by_bitsize(other_num->builtin.bytesize * 8);
case FL:
return type_double;
default:
@@ -579,6 +645,7 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_FUNC:
case TYPE_UNION:
case TYPE_ERROR_UNION:
case TYPE_META_TYPE:
return NULL;
case TYPE_STRUCT:
TODO

View File

@@ -0,0 +1,72 @@
// Copyright (c) 2020 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
#include "target_info_internal.h"
typedef enum
{
AVXABI_LEVEL_NONE,
AVXABI_AVX,
AVXABI_512
} X86AVXABILevel;
static unsigned x86avxabi_vector_size(X86AVXABILevel level)
{
switch (level)
{
case AVXABI_512:
return 512;
case AVXABI_AVX:
return 256;
case AVXABI_LEVEL_NONE:
return 128;
}
UNREACHABLE
}
TargetInfo target_info_new()
{
// From the glibc documentation, on GNU systems, malloc guarantees 16-byte
// alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See
// https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html.
// This alignment guarantee also applies to Windows and Android.
/*
if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment() || T.isAndroid())
NewAlign = Triple.isArch64Bit() ? 128 : Triple.isArch32Bit() ? 64 : 0;
else
NewAlign = 0; // Infer from basic type alignment.
*/
TargetInfo target_info = {
.little_endian = true,
.asm_supported = false,
.float_128 = false,
.float_16 = false,
.align_byte = 8,
.align_c_int = 32,
.align_c_long = 32,
.align_c_long_long = 64,
.align_c_long_double = 64,
.align_f128 = 128,
.align_large_array = 0,
.align_global_min = 0,
.align_new = 0,
.align_max_vector = 0,
.align_simd_default = 0,
.width_pointer = 32,
.width_c_int = 32,
.width_c_long = 32,
.width_c_long_long = 64,
.width_c_long_double = 64,
.width_large_array_min = 0,
.width_c_wchar = 32,
.width_c_wint = 32,
.reg_param_max = 0,
.sse_reg_param_max = 0,
.builtin_ms_valist = false,
.aarch64sve_types = false,
.platform_name = "unknown"
};
return target_info;
}

View File

@@ -0,0 +1,121 @@
#pragma once
// Copyright (c) 2020 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
#include "utils/common.h"
typedef enum
{
SUB_ARCH_NONE,
SUB_ARCH_ARM_V8_5A,
SUB_ARCH_ARM_V8_4A,
SUB_ARCH_ARM_V8_3A,
SUB_ARCH_ARM_V8_2A,
SUB_ARCH_ARM_V8_1A,
SUB_ARCH_ARM_V8,
SUB_ARCH_ARM_V8R,
SUB_ARCH_ARM_V8M_BASELINE,
SUB_ARCH_ARM_V8M_MAINLINE,
SUB_ARCH_ARM_V8_1M_MAINLINE,
SUB_ARCH_ARM_V7,
SUB_ARCH_ARM_V7EM,
SUB_ARCH_ARM_V7M,
SUB_ARCH_ARM_V7S,
SUB_ARCH_ARM_V7K,
SUB_ARCH_ARM_V7VE,
SUB_ARCH_ARM_V6,
SUB_ARCH_ARM_V6M,
SUB_ARCH_ARM_V6K,
SUB_ARCH_ARM_V6T2,
SUB_ARCH_ARM_V5,
SUB_ARCH_ARM_V5TE,
SUB_ARCH_ARM_V4,
SUB_ARCH_KALIMBA_V3,
SUB_ARCH_KALIMBA_V4,
SUB_ARCH_KALIMBA_V5,
SUB_ARCH_MIPS_V6,
} SubArchType;
typedef enum
{
ENV_TYPE_UNKNOWN,
ENV_TYPE_GNU,
ENV_TYPE_GNUABIN32,
ENV_TYPE_SNUABI64,
ENV_TYPE_GNUEABI,
ENV_TYPE_GNUEABIHF,
ENV_TYPE_GNUX32,
ENV_TYPE_CODE16,
ENV_TYPE_EABI,
ENV_TYPE_EABIHF,
ENV_TYPE_ELFV1,
ENV_TYPE_ELFV2,
ENV_TYPE_ANDROID,
ENV_TYPE_MUSL,
ENV_TYPE_MUSLEABI,
ENV_TYPE_MUSLEABIHF,
ENV_TYPE_MSVC,
ENV_TYPE_ITANIUM,
ENV_TYPE_CYGNUS,
ENV_TYPE_CORECLR,
ENV_TYPE_SIMULATOR,
ENV_TYPE_MACABI,
ENV_TYPE_LAST = ENV_TYPE_MACABI
} EnvironmentType;
typedef enum
{
OBJ_FORMAT_COFF,
OBJ_FORMAT_ELF,
OBJ_FORMAT_MACHO,
OBJ_FORMAT_WASM,
OBJ_FORMAT_XCOFF
} ObjectFormatType;
typedef struct
{
bool little_endian;
bool tls_supported;
bool asm_supported;
bool float_128;
bool float_16;
unsigned align_pointer;
unsigned align_byte;
unsigned align_short;
unsigned align_int;
unsigned align_long;
unsigned align_half;
unsigned align_float;
unsigned align_double;
unsigned align_f128;
unsigned align_c_long_double;
unsigned align_c_int;
unsigned align_c_long;
unsigned align_c_long_long;
unsigned align_simd_default;
unsigned align_max_vector;
unsigned align_global_min;
unsigned align_new;
unsigned align_large_array;
unsigned width_size;
unsigned width_pointer;
unsigned width_c_int;
unsigned width_c_long;
unsigned width_c_long_long;
unsigned width_c_long_double;
unsigned width_c_wchar;
unsigned width_c_wint;
unsigned width_large_array_min;
unsigned reg_param_max;
unsigned sse_reg_param_max;
unsigned builtin_ms_valist;
unsigned aarch64sve_types;
char *platform_name;
} TargetInfo;

View File

@@ -0,0 +1,7 @@
#pragma once
// Copyright (c) 2020 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
#include "target_info.h"