Fix for nolibc (eg wasm). Add multi global declarations. Simplicity wasm export / import. Prevent "extern" functions to have a function body.

This commit is contained in:
Christoffer Lerno
2023-02-11 11:16:31 +01:00
parent 2fa3ae7bc9
commit 3b49b87784
22 changed files with 146 additions and 58 deletions

View File

@@ -41,12 +41,13 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
int emax = - $emin - $bits + 3;
const int[*] P10S = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
usz index = 0;
usz index;
bool got_digit = chars[0] == '0';
bool got_rad;
long lrp, dc;
int k, j, lnz;
usz len = chars.len;
usz last_char = len - 1;
long lrp = 0;
assert(len);
@@ -77,10 +78,6 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
}
}
long dc = 0;
int k;
int j;
int lnz;
while (c - '0' < 10u || c == '.')
{
switch

View File

@@ -250,11 +250,16 @@ fn int fseek(CFile stream, SeekIndex offset, int whence) @weak @extern("fseek")
{
unreachable("'fseek' not available.");
}
fn CFile fopen(char* filename, char* mode) @weak @extern("fopen")
fn CFile fopen(ZString filename, ZString mode) @weak @extern("fopen")
{
unreachable("'fopen' not available.");
}
fn CFile freopen(ZString filename, ZString mode, CFile stream) @weak @extern("fopen")
{
unreachable("'freopen' not available.");
}
fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream) @weak @extern("fwrite")
{
unreachable("'fwrite' not available.");
@@ -280,7 +285,7 @@ fn int fputc(int c, CFile stream) @weak @extern("fputc")
unreachable("'fputc' not available.");
}
fn char* fgets(char* str, int n, CFile stream) @weak @extern("fgets")
fn char* fgets(ZString str, int n, CFile stream) @weak @extern("fgets")
{
unreachable("'fgets' not available.");
}
@@ -303,7 +308,7 @@ fn int putchar(int c) @weak @extern("putchar")
{
unreachable("'putchar' not available.");
}
fn int puts(char* str) @weak @extern("puts")
fn int puts(ZString str) @weak @extern("puts")
{
unreachable("'puts' not available.");
}

View File

@@ -98,6 +98,7 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type, V
case DECL_FINALIZE:
case DECL_CT_ECHO:
case DECL_CT_INCLUDE:
case DECL_GLOBALS:
UNREACHABLE
}
Type *type = type_new(kind, name ? name : "$anon");
@@ -175,6 +176,8 @@ const char *decl_to_a_name(Decl *decl)
return "a static finalizer";
case DECL_CT_INCLUDE:
return "an include";
case DECL_GLOBALS:
return "globals";
case DECL_VAR:
switch (decl->var.kind)
{

View File

@@ -674,7 +674,6 @@ typedef struct Decl_
bool obfuscate : 1;
bool is_dynamic : 1;
bool is_synthetic : 1;
bool is_wasm_interface : 1;
bool is_export : 1;
OperatorOverload operator : 4;
union
@@ -727,6 +726,7 @@ typedef struct Decl_
EnumConstantDecl enum_constant;
FuncDecl func_decl;
AttrDecl attr_decl;
Decl** decls;
TypedefDecl typedef_decl;
DefineDecl define_decl;
CtIfDecl ct_if_decl;

View File

@@ -149,6 +149,7 @@ void decl_register(Decl *decl)
case DECL_DECLARRAY:
case DECL_BODYPARAM:
case DECL_CT_INCLUDE:
case DECL_GLOBALS:
UNREACHABLE
case DECL_ATTRIBUTE:
case DECL_BITSTRUCT:
@@ -260,6 +261,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
case DECL_CT_CASE:
case DECL_DECLARRAY:
case DECL_BODYPARAM:
case DECL_GLOBALS:
UNREACHABLE
case DECL_CT_IF:
case DECL_CT_SWITCH:

View File

@@ -850,6 +850,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
MACRO_COPY_DECL_LIST(copy->methods);
break;
case DECL_DECLARRAY:
case DECL_GLOBALS:
UNREACHABLE
case DECL_BITSTRUCT:
copy_decl_type(copy);

View File

@@ -143,6 +143,7 @@ typedef enum
DECL_FAULT,
DECL_FAULTVALUE,
DECL_FUNC,
DECL_GLOBALS,
DECL_INITIALIZE,
DECL_FINALIZE,
DECL_GENERIC,
@@ -162,7 +163,7 @@ typedef enum
case DECL_DECLARRAY: case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \
case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_LABEL: \
case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENERIC: case DECL_INITIALIZE: \
case DECL_FINALIZE: case DECL_CT_ECHO: case DECL_CT_INCLUDE
case DECL_FINALIZE: case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GLOBALS
#define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \
case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \

View File

@@ -1021,17 +1021,17 @@ void llvm_append_function_attributes(GenContext *c, Decl *decl)
{
llvm_attribute_add(c, function, attribute_id.noreturn, -1);
}
if (decl->is_wasm_interface && arch_is_wasm(platform_target.arch))
if (decl->is_export && arch_is_wasm(platform_target.arch))
{
if (decl->visibility == VISIBLE_EXTERN)
{
llvm_attribute_add_string(c, function, "wasm-import-name", decl_get_extname(decl), -1);
}
else if (c->code_module == decl->unit->module)
if (c->code_module == decl->unit->module)
{
llvm_attribute_add_string(c, function, "wasm-export-name", decl_get_extname(decl), -1);
}
}
if (decl->visibility == VISIBLE_EXTERN && arch_is_wasm(platform_target.arch))
{
llvm_attribute_add_string(c, function, "wasm-import-name", decl_get_extname(decl), -1);
}
if (decl->alignment != type_abi_alignment(decl->type))
{
llvm_set_alignment(function, decl->alignment);
@@ -1104,6 +1104,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
case DECL_BODYPARAM:
case DECL_CT_ECHO:
case DECL_CT_INCLUDE:
case DECL_GLOBALS:
UNREACHABLE;
}
UNREACHABLE

View File

@@ -96,7 +96,7 @@ static inline bool parse_top_level_block(ParseContext *c, Decl ***decls, TokenTy
assert(decl);
if (decl_ok(decl))
{
vec_add(*decls, decl);
add_decl_to_list(decls, decl);
}
else
{
@@ -175,7 +175,7 @@ static inline Decl *parse_ct_case(ParseContext *c)
TokenType type = c->tok;
if (type == TOKEN_CT_DEFAULT || type == TOKEN_CT_CASE || type == TOKEN_CT_ENDSWITCH) break;
ASSIGN_DECL_OR_RET(Decl *stmt, parse_top_level_statement(c, NULL), poisoned_decl);
vec_add(decl->ct_case_decl.body, stmt);
add_decl_to_list(&decl->ct_case_decl.body, stmt);
}
return decl;
}
@@ -1062,9 +1062,6 @@ static inline Decl *parse_global_declaration(ParseContext *c, Visibility visibil
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_decl);
Decl *decl = DECL_VAR_NEW(type, VARDECL_GLOBAL, visibility);
decl->var.is_threadlocal = threadlocal;
if (tok_is(c, TOKEN_CONST_IDENT))
{
@@ -1072,23 +1069,54 @@ static inline Decl *parse_global_declaration(ParseContext *c, Visibility visibil
return poisoned_decl;
}
if (!try_consume(c, TOKEN_IDENT))
Decl *decl;
Decl **decls = NULL;
while (true)
{
if (token_is_some_ident(c->tok))
decl = DECL_VAR_NEW(type, VARDECL_GLOBAL, visibility);
decl->var.is_threadlocal = threadlocal;
if (!try_consume(c, TOKEN_IDENT))
{
SEMA_ERROR_HERE("I expected a variable name here, but global variables need to start with lower case.");
if (token_is_some_ident(c->tok))
{
SEMA_ERROR_HERE("I expected a variable name here, but global variables need to start with lower case.");
return poisoned_decl;
}
SEMA_ERROR_HERE("The name of a global variable was expected here");
return poisoned_decl;
}
SEMA_ERROR_HERE("The name of a global variable was expected here");
return poisoned_decl;
if (!try_consume(c, TOKEN_COMMA)) break;
vec_add(decls, decl);
}
// Add the last, or we miss it.
if (decls) vec_add(decls, decl);
if (!parse_attributes(c, &decl->attributes)) return poisoned_decl;
if (try_consume(c, TOKEN_EQ))
{
if (decls)
{
SEMA_ERROR_HERE("Initialization is not allowed with multiple declarations.");
return poisoned_decl;
}
if (!parse_decl_initializer(c, decl, true)) return poisoned_decl;
}
CONSUME_EOS_OR_RET(poisoned_decl);
Attr **attributes = decl->attributes;
if (attributes)
{
FOREACH_BEGIN(Decl *d, decls)
if (d == decl) continue;
d->attributes = copy_attributes_single(attributes);
FOREACH_END();
}
if (decls)
{
decl = decl_calloc();
decl->decl_kind = DECL_GLOBALS;
decl->decls = decls;
return decl;
}
return decl;
}
@@ -2606,7 +2634,7 @@ static Decl *parse_include(ParseContext *c)
decl_poison(decl);
goto END;
}
vec_add(list, inner);
add_decl_to_list(&list, inner);
}
decl->include.decls = list;
END:

View File

@@ -73,7 +73,7 @@ static inline void parse_translation_unit(ParseContext *c)
if (!decl) continue;
if (decl_ok(decl))
{
vec_add(c->unit->global_decls, decl);
add_decl_to_list(&c->unit->global_decls, decl);
}
else
{

View File

@@ -62,6 +62,18 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat);
Expr *parse_type_compound_literal_expr_after_type(ParseContext *c, TypeInfo *type_info);
INLINE void add_decl_to_list(Decl ***list, Decl *decl)
{
if (decl->decl_kind == DECL_GLOBALS)
{
FOREACH_BEGIN(Decl *d, decl->decls)
vec_add(*list, d);
FOREACH_END();
return;
}
vec_add(*list, decl);
}
bool parse_module(ParseContext *c, AstId docs);
Expr *parse_generic_parameter(ParseContext *c);
bool try_consume(ParseContext *c, TokenType type);

View File

@@ -1656,7 +1656,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
decl->is_weak = true;
break;
case ATTRIBUTE_WASM:
decl->is_wasm_interface = true;
decl->is_export = true;
break;
case ATTRIBUTE_NAKED:
assert(domain == ATTR_FUNC);
@@ -1969,7 +1969,10 @@ static inline MainType sema_find_main_type(SemaContext *context, Signature *sig,
static inline Decl *sema_create_synthetic_main(SemaContext *context, Decl *decl, MainType main, bool int_return, bool err_return, bool is_winmain, bool is_wmain)
{
Decl *function = decl_new(DECL_FUNC, NULL, decl->span, VISIBLE_EXTERN);
Decl *function = decl_new(DECL_FUNC, NULL, decl->span, VISIBLE_PUBLIC);
function->is_export = true;
function->has_extname = true;
function->extname = kw_mainstub;
function->name = kw_mainstub;
function->unit = decl->unit;
@@ -2158,7 +2161,9 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
if ((type == MAIN_TYPE_RAW || type == MAIN_TYPE_NO_ARGS) && is_int_return && !is_winmain)
{
// Int return is pass-through at the moment.
decl->visibility = VISIBLE_EXTERN;
decl->is_export = true;
decl->has_extname = true;
decl->extname = kw_main;
function = decl;
goto REGISTER_MAIN;
}
@@ -3052,6 +3057,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
case DECL_DECLARRAY:
case DECL_BODYPARAM:
case DECL_CT_INCLUDE:
case DECL_GLOBALS:
UNREACHABLE
}
decl->resolve_status = RESOLVE_DONE;

View File

@@ -549,6 +549,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
case DECL_INITIALIZE:
case DECL_FINALIZE:
case DECL_CT_INCLUDE:
case DECL_GLOBALS:
UNREACHABLE
case DECL_POISONED:
return expr_poison(expr);

View File

@@ -368,6 +368,11 @@ void sema_analysis_pass_ct_echo(Module *module)
static inline bool analyse_func_body(SemaContext *context, Decl *decl)
{
if (!decl->func_decl.body) return true;
if (decl->visibility == VISIBLE_EXTERN)
{
SEMA_ERROR(decl, "'extern' functions should never have a body.");
return decl_poison(decl);
}
// Don't analyse functions that are tests.
if (decl->func_decl.attr_test && !active_target.testing) return true;
if (!sema_analyse_function_body(context, decl)) return decl_poison(decl);

View File

@@ -245,6 +245,7 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
case DECL_DECLARRAY:
case DECL_BODYPARAM:
case DECL_CT_INCLUDE:
case DECL_GLOBALS:
UNREACHABLE
}
UNREACHABLE

View File

@@ -181,6 +181,7 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls)
case DECL_CT_ELSE:
case DECL_BODYPARAM:
case DECL_CT_INCLUDE:
case DECL_GLOBALS:
UNREACHABLE
case DECL_MACRO:
case DECL_DEFINE:

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.58"
#define COMPILER_VERSION "0.4.59"

View File

@@ -5,12 +5,13 @@ struct Vector2 {
float x;
float y;
}
extern fn Vector2 vector2_zero() { return Vector2 {}; }
extern fn Vector2 vector2_one() { return Vector2 {}; }
extern fn Vector2 vector2_add(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_add_value(Vector2 v, float add) { return Vector2 {}; }
extern fn Vector2 vector2_subtract(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_subtract_value(Vector2 v, float sub) { return Vector2 {}; }
fn Vector2 vector2_zero() @extern("vector2_zero") { return Vector2 {}; }
fn Vector2 vector2_one() @extern("vector2_one") { return Vector2 {}; }
fn Vector2 vector2_add(Vector2 v1, Vector2 v2) @extern("vector2_add") { return Vector2 {}; }
fn Vector2 vector2_add_value(Vector2 v, float add) @extern("vector2_add_value") { return Vector2 {}; }
fn Vector2 vector2_subtract(Vector2 v1, Vector2 v2) @extern("vector2_subtract") { return Vector2 {}; }
fn Vector2 vector2_subtract_value(Vector2 v, float sub) @extern("vector2_subtract_value") { return Vector2 {}; }
/* #expect: abi.ll

View File

@@ -5,12 +5,12 @@ struct Vector2 {
float x;
float y;
}
extern fn Vector2 vector2_zero() { return Vector2 {}; }
extern fn Vector2 vector2_one() { return Vector2 {}; }
extern fn Vector2 vector2_add(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_add_value(Vector2 v, float add) { return Vector2 {}; }
extern fn Vector2 vector2_subtract(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_subtract_value(Vector2 v, float sub) { return Vector2 {}; }
fn Vector2 vector2_zero() @extern("vector2_zero") { return Vector2 {}; }
fn Vector2 vector2_one() @extern("vector2_one") { return Vector2 {}; }
fn Vector2 vector2_add(Vector2 v1, Vector2 v2) @extern("vector2_add") { return Vector2 {}; }
fn Vector2 vector2_add_value(Vector2 v, float add) @extern("vector2_add_value") { return Vector2 {}; }
fn Vector2 vector2_subtract(Vector2 v1, Vector2 v2) @extern("vector2_subtract") { return Vector2 {}; }
fn Vector2 vector2_subtract_value(Vector2 v, float sub) @extern("vector2_subtract_value") { return Vector2 {}; }
/* #expect: abi.ll
@@ -73,7 +73,6 @@ entry:
ret void
}
; Function Attrs: nounwind
define void @vector2_subtract_value(ptr noalias sret(%Vector2) align 4 %0, ptr byval(%Vector2) align 4 %1, float %2) #0 {
entry:
%literal = alloca %Vector2, align 4

View File

@@ -5,12 +5,12 @@ struct Vector2 {
float x;
float y;
}
extern fn Vector2 vector2_zero() { return Vector2 {}; }
extern fn Vector2 vector2_one() { return Vector2 {}; }
extern fn Vector2 vector2_add(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_add_value(Vector2 v, float add) { return Vector2 {}; }
extern fn Vector2 vector2_subtract(Vector2 v1, Vector2 v2) { return Vector2 {}; }
extern fn Vector2 vector2_subtract_value(Vector2 v, float sub) { return Vector2 {}; }
fn Vector2 vector2_zero() @extern("vector2_zero") { return Vector2 {}; }
fn Vector2 vector2_one() @extern("vector2_one") { return Vector2 {}; }
fn Vector2 vector2_add(Vector2 v1, Vector2 v2) @extern("vector2_add") { return Vector2 {}; }
fn Vector2 vector2_add_value(Vector2 v, float add) @extern("vector2_add_value") { return Vector2 {}; }
fn Vector2 vector2_subtract(Vector2 v1, Vector2 v2) @extern("vector2_subtract") { return Vector2 {}; }
fn Vector2 vector2_subtract_value(Vector2 v, float sub) @extern("vector2_subtract_value") { return Vector2 {}; }
/* #expect: abi.ll

View File

@@ -0,0 +1,17 @@
// #target: wasm32
module test;
extern fn int get_abc();
fn int hello() @export("fgh")
{
return 1;
}
/* #expect: test.ll
target triple = "wasm32-unknown-unknown"
declare i32 @get_abc() #0
define i32 @fgh() #1
attributes #0 = { nounwind "wasm-import-name"="get_abc" }
attributes #1 = { nounwind "wasm-export-name"="fgh" }

View File

@@ -7,6 +7,10 @@ struct Abc
int z @noinit;
Abc y @noinit;
int a, b, c;
int x1, y1 @noinit;
tlocal int w, v;
fn void main()
{
z = y.x[0];
@@ -16,10 +20,13 @@ fn void main()
@test_z = local_unnamed_addr global i32 undef, align 4
@test_y = local_unnamed_addr global %Abc undef, align 4
@test_a = local_unnamed_addr global i32 0, align 4
@test_b = local_unnamed_addr global i32 0, align 4
@test_c = local_unnamed_addr global i32 0, align 4
@test_x1 = local_unnamed_addr global i32 undef, align 4
@test_y1 = local_unnamed_addr global i32 undef, align 4
@test_w = thread_local local_unnamed_addr global i32 0, align 4
@test_v = thread_local local_unnamed_addr global i32 0, align 4
define void @test_main() #0 {
entry:
%0 = load i32, ptr @test_y, align 4
store i32 %0, ptr @test_z, align 4
ret void
}
%0 = load i32, ptr @test_y, align 4
store i32 %0, ptr @test_z, align 4