mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 '"':
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
197
src/compiler/target.h
Normal 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;
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
72
src/target_info/target_info.c
Normal file
72
src/target_info/target_info.c
Normal 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;
|
||||
}
|
||||
|
||||
121
src/target_info/target_info.h
Normal file
121
src/target_info/target_info.h
Normal 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;
|
||||
7
src/target_info/target_info_internal.h
Normal file
7
src/target_info/target_info_internal.h
Normal 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"
|
||||
Reference in New Issue
Block a user