Implement static finalize / initialize. Version bump.

This commit is contained in:
Christoffer Lerno
2022-09-28 17:03:30 +02:00
committed by Christoffer Lerno
parent 58647043f4
commit e1b5b0b60c
33 changed files with 478 additions and 44 deletions

View File

@@ -87,6 +87,8 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type, V
case DECL_CT_ASSERT: case DECL_CT_ASSERT:
case DECL_DECLARRAY: case DECL_DECLARRAY:
case DECL_BODYPARAM: case DECL_BODYPARAM:
case DECL_INITIALIZE:
case DECL_FINALIZE:
UNREACHABLE UNREACHABLE
} }
Type *type = type_new(kind, name ? name : "$anon"); Type *type = type_new(kind, name ? name : "$anon");
@@ -156,6 +158,10 @@ const char *decl_to_a_name(Decl *decl)
return "a struct"; return "a struct";
case DECL_UNION: case DECL_UNION:
return "a union"; return "a union";
case DECL_INITIALIZE:
return "a static initializer";
case DECL_FINALIZE:
return "a static finalizer";
case DECL_VAR: case DECL_VAR:
switch (decl->var.kind) switch (decl->var.kind)
{ {

View File

@@ -37,6 +37,7 @@ typedef uint64_t BitSize;
#define MAX_BITSTRUCT 0x1000 #define MAX_BITSTRUCT 0x1000
#define MAX_MEMBERS ((MemberIndex)(((uint64_t)2) << 28)) #define MAX_MEMBERS ((MemberIndex)(((uint64_t)2) << 28))
#define MAX_ALIGNMENT ((MemberIndex)(((uint64_t)2) << 28)) #define MAX_ALIGNMENT ((MemberIndex)(((uint64_t)2) << 28))
#define MAX_PRIORITY 0xFFFF
#define MAX_TYPE_SIZE UINT32_MAX #define MAX_TYPE_SIZE UINT32_MAX
#define MAX_GLOBAL_DECL_STACK (65536) #define MAX_GLOBAL_DECL_STACK (65536)
#define MAX_ASM_INSTRUCTION_PARAMS 6 #define MAX_ASM_INSTRUCTION_PARAMS 6
@@ -611,6 +612,11 @@ typedef struct
AstId parent; AstId parent;
} LabelDecl; } LabelDecl;
typedef struct
{
unsigned priority;
AstId init;
} InitializerDecl;
@@ -663,6 +669,7 @@ typedef struct Decl_
Type *type; Type *type;
union union
{ {
InitializerDecl xxlizer;
Decl** decl_list; Decl** decl_list;
struct struct
{ {
@@ -1521,6 +1528,7 @@ struct CompilationUnit_
}; };
Decl **ct_ifs; Decl **ct_ifs;
Decl **ct_asserts; Decl **ct_asserts;
Decl **xxlizers;
Decl **vars; Decl **vars;
Decl **macros; Decl **macros;
Decl **methods; Decl **methods;
@@ -1782,12 +1790,13 @@ extern const char *kw_std;
extern const char *kw_max; extern const char *kw_max;
extern const char *kw_min; extern const char *kw_min;
extern const char *kw_elements; extern const char *kw_elements;
extern const char *kw_finalize;
extern const char *kw_align; extern const char *kw_align;
extern const char *kw_nameof; extern const char *kw_nameof;
extern const char *kw_names; extern const char *kw_names;
extern const char *kw_sizeof; extern const char *kw_sizeof;
extern const char *kw_in; extern const char *kw_in;
extern const char *kw_initialize;
extern const char *kw_out; extern const char *kw_out;
extern const char *kw_inout; extern const char *kw_inout;
extern const char *kw_deprecated; extern const char *kw_deprecated;

View File

@@ -132,6 +132,8 @@ void decl_register(Decl *decl)
if (decl->visibility != VISIBLE_PUBLIC && decl->visibility != VISIBLE_EXTERN) return; if (decl->visibility != VISIBLE_PUBLIC && decl->visibility != VISIBLE_EXTERN) return;
switch (decl->decl_kind) switch (decl->decl_kind)
{ {
case DECL_INITIALIZE:
case DECL_FINALIZE:
case DECL_POISONED: case DECL_POISONED:
case DECL_CT_CASE: case DECL_CT_CASE:
case DECL_CT_ELIF: case DECL_CT_ELIF:
@@ -264,6 +266,10 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
case DECL_CT_ASSERT: case DECL_CT_ASSERT:
vec_add(unit->ct_asserts, decl); vec_add(unit->ct_asserts, decl);
return; return;
case DECL_INITIALIZE:
case DECL_FINALIZE:
vec_add(unit->xxlizers, decl);
return;
} }
DEBUG_LOG("Registering symbol '%s' in %s.", decl->name, unit->module->name->module); DEBUG_LOG("Registering symbol '%s' in %s.", decl->name, unit->module->name->module);

View File

@@ -751,6 +751,10 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
{ {
case DECL_POISONED: case DECL_POISONED:
break; break;
case DECL_INITIALIZE:
case DECL_FINALIZE:
MACRO_COPY_ASTID(copy->xxlizer.init);
break;
case DECL_BODYPARAM: case DECL_BODYPARAM:
MACRO_COPY_DECL_LIST(copy->body_params); MACRO_COPY_DECL_LIST(copy->body_params);
break; break;

View File

@@ -137,6 +137,8 @@ typedef enum
DECL_FAULT, DECL_FAULT,
DECL_FAULTVALUE, DECL_FAULTVALUE,
DECL_FUNC, DECL_FUNC,
DECL_INITIALIZE,
DECL_FINALIZE,
DECL_GENERIC, DECL_GENERIC,
DECL_IMPORT, DECL_IMPORT,
DECL_LABEL, DECL_LABEL,
@@ -152,7 +154,7 @@ typedef enum
#define NON_TYPE_DECLS DECL_IMPORT: case DECL_MACRO: \ #define NON_TYPE_DECLS DECL_IMPORT: case DECL_MACRO: \
case DECL_DECLARRAY: case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \ 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_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_LABEL: \
case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENERIC case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENERIC: case DECL_INITIALIZE: case DECL_FINALIZE
#define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \ #define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \
case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \ case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \
@@ -723,6 +725,9 @@ typedef enum
ATTR_CALL = 1 << 11, ATTR_CALL = 1 << 11,
ATTR_BITSTRUCT = 1 << 12, ATTR_BITSTRUCT = 1 << 12,
ATTR_MACRO = 1 << 13, ATTR_MACRO = 1 << 13,
ATTR_INITIALIZER = 1 << 14,
ATTR_FINALIZER = 1 << 15,
ATTR_XXLIZER = ATTR_INITIALIZER | ATTR_FINALIZER
} AttributeDomain; } AttributeDomain;
typedef enum typedef enum
@@ -752,6 +757,7 @@ typedef enum
ATTRIBUTE_OPERATOR, ATTRIBUTE_OPERATOR,
ATTRIBUTE_OVERLAP, ATTRIBUTE_OVERLAP,
ATTRIBUTE_PACKED, ATTRIBUTE_PACKED,
ATTRIBUTE_PRIORITY,
ATTRIBUTE_PURE, ATTRIBUTE_PURE,
ATTRIBUTE_REFLECT, ATTRIBUTE_REFLECT,
ATTRIBUTE_REGCALL, ATTRIBUTE_REGCALL,

View File

@@ -15,6 +15,7 @@ LLVMPassBuilderOptionsRef LLVMCreatePassBuilderOptions(void);
void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options, LLVMBool VerifyEach); void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options, LLVMBool VerifyEach);
void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options, LLVMBool DebugLogging); void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options, LLVMBool DebugLogging);
void LLVMDisposePassBuilderOptions(LLVMPassBuilderOptionsRef Options); void LLVMDisposePassBuilderOptions(LLVMPassBuilderOptionsRef Options);
static void llvm_emit_constructors_and_destructors(GenContext *c);
const char* llvm_version = LLVM_VERSION_STRING; const char* llvm_version = LLVM_VERSION_STRING;
const char* llvm_target = LLVM_DEFAULT_TARGET_TRIPLE; const char* llvm_target = LLVM_DEFAULT_TARGET_TRIPLE;
@@ -80,6 +81,22 @@ LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ptr, uint
return LLVMBuildMemSet(c->builder, ptr, llvm_get_zero(c, type_char), llvm_const_int(c, type_usize, size), align); return LLVMBuildMemSet(c->builder, ptr, llvm_get_zero(c, type_char), llvm_const_int(c, type_usize, size), align);
} }
INLINE void llvm_emit_xtor(GenContext *c, LLVMValueRef *list, const char *name)
{
if (!list) return;
unsigned len = vec_size(list);
LLVMTypeRef type = LLVMTypeOf(list[0]);
LLVMValueRef array = LLVMConstArray(type, list, len);
LLVMValueRef global = LLVMAddGlobal(c->module, LLVMTypeOf(array), name);
LLVMSetLinkage(global, LLVMAppendingLinkage);
LLVMSetInitializer(global, array);
}
void llvm_emit_constructors_and_destructors(GenContext *c)
{
llvm_emit_xtor(c, c->constructors, "llvm.global_ctors");
llvm_emit_xtor(c, c->destructors, "llvm.global_dtors");
}
/** /**
* Consider the case when we have int[5] x = { [0] = 1, [1] = 3 } * Consider the case when we have int[5] x = { [0] = 1, [1] = 3 }
* In this case we want this: { i32 0, i32 2, [8 x i32] zeroinitializer } * In this case we want this: { i32 0, i32 2, [8 x i32] zeroinitializer }
@@ -968,6 +985,8 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
case DECL_TYPEDEF: case DECL_TYPEDEF:
case DECL_UNION: case DECL_UNION:
case DECL_DECLARRAY: case DECL_DECLARRAY:
case DECL_INITIALIZE:
case DECL_FINALIZE:
case DECL_BODYPARAM: case DECL_BODYPARAM:
UNREACHABLE; UNREACHABLE;
} }
@@ -988,6 +1007,9 @@ void *llvm_gen(Module *module)
gen_context->debug.compile_unit = unit->llvm.debug_compile_unit; gen_context->debug.compile_unit = unit->llvm.debug_compile_unit;
gen_context->debug.file = unit->llvm.debug_file; gen_context->debug.file = unit->llvm.debug_file;
FOREACH_BEGIN(Decl *initializer, unit->xxlizers)
llvm_emit_xxlizer(gen_context, initializer);
FOREACH_END();
VECEACH(unit->methods, i) VECEACH(unit->methods, i)
{ {
llvm_emit_function_decl(gen_context, unit->methods[i]); llvm_emit_function_decl(gen_context, unit->methods[i]);
@@ -1043,6 +1065,9 @@ void *llvm_gen(Module *module)
gencontext_end_file_emit(gen_context, unit); gencontext_end_file_emit(gen_context, unit);
} }
llvm_emit_constructors_and_destructors(gen_context);
// EmitDeferred() // EmitDeferred()
if (llvm_use_debug(gen_context)) if (llvm_use_debug(gen_context))

View File

@@ -3575,7 +3575,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value,
// TODO, we should add info about the error. // TODO, we should add info about the error.
SourceSpan loc = expr->span; SourceSpan loc = expr->span;
File *file = source_file_by_id(loc.file_id); File *file = source_file_by_id(loc.file_id);
llvm_emit_panic(c, "Runtime error force unwrap!", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1); llvm_emit_panic(c, "Runtime error force unwrap!", file->name, c->cur_func.name, loc.row ? loc.row : 1);
LLVMBuildUnreachable(c->builder); LLVMBuildUnreachable(c->builder);
c->current_block = NULL; c->current_block = NULL;
c->current_block_is_target = false; c->current_block_is_target = false;
@@ -5254,7 +5254,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next); llvm_emit_block(c, next);
} }
File *file = source_file_by_id(expr->span.file_id); File *file = source_file_by_id(expr->span.file_id);
llvm_emit_panic(c, "Attempted to access 'inner' on non composite type", file->name, c->cur_func_decl->name, expr->span.row); llvm_emit_panic(c, "Attempted to access 'inner' on non composite type", file->name, c->cur_func.name, expr->span.row);
c->current_block = NULL; c->current_block = NULL;
c->current_block_is_target = false; c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder); LLVMBuildUnreachable(c->builder);
@@ -5287,7 +5287,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next); llvm_emit_block(c, next);
} }
File *file = source_file_by_id(expr->span.file_id); File *file = source_file_by_id(expr->span.file_id);
llvm_emit_panic(c, "Attempted to access 'names' on non enum/fault type.", file->name, c->cur_func_decl->name, expr->span.row); llvm_emit_panic(c, "Attempted to access 'names' on non enum/fault type.", file->name, c->cur_func.name, expr->span.row);
c->current_block = NULL; c->current_block = NULL;
c->current_block_is_target = false; c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder); LLVMBuildUnreachable(c->builder);
@@ -5324,7 +5324,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next); llvm_emit_block(c, next);
} }
File *file = source_file_by_id(expr->span.file_id); File *file = source_file_by_id(expr->span.file_id);
llvm_emit_panic(c, "Attempted to access 'len' on non array type", file->name, c->cur_func_decl->name, expr->span.row); llvm_emit_panic(c, "Attempted to access 'len' on non array type", file->name, c->cur_func.name, expr->span.row);
c->current_block = NULL; c->current_block = NULL;
c->current_block_is_target = false; c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder); LLVMBuildUnreachable(c->builder);

View File

@@ -10,6 +10,9 @@ static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef valu
static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index, AlignSize alignment); static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index, AlignSize alignment);
static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, ABIArgInfo *info, unsigned *index); static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, ABIArgInfo *info, unsigned *index);
static inline void llvm_emit_parameter(GenContext *context, Decl *decl, ABIArgInfo *abi_info, unsigned *index, unsigned real_index); static inline void llvm_emit_parameter(GenContext *context, Decl *decl, ABIArgInfo *abi_info, unsigned *index, unsigned real_index);
static inline void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_name,
const char *function_name,
FileId file_id, FunctionPrototype *prototype, Signature *signature, Ast *body);
bool llvm_emit_check_block_branch(GenContext *context) bool llvm_emit_check_block_branch(GenContext *context)
{ {
@@ -275,7 +278,15 @@ static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef valu
void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failable) void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failable)
{ {
FunctionPrototype *prototype = c->cur_func_decl->type->function.prototype; FunctionPrototype *prototype = c->cur_func.prototype;
// If there is no prototype, this is a static initializer, so bail.
if (!prototype)
{
llvm_emit_return_value(c, NULL);
return;
}
ABIArgInfo *info = prototype->ret_abi_info; ABIArgInfo *info = prototype->ret_abi_info;
// If we have a failable it's always the return argument, so we need to copy // If we have a failable it's always the return argument, so we need to copy
@@ -388,7 +399,7 @@ DIRECT_RETURN:
void llvm_emit_return_implicit(GenContext *c) void llvm_emit_return_implicit(GenContext *c)
{ {
Type *rtype_real = c->cur_func_decl->type->function.prototype->rtype; Type *rtype_real = c->cur_func.prototype ? c->cur_func.prototype->rtype : type_void;
if (type_lowering(type_no_optional(rtype_real)) != type_void) if (type_lowering(type_no_optional(rtype_real)) != type_void)
{ {
LLVMBuildUnreachable(c->builder); LLVMBuildUnreachable(c->builder);
@@ -408,34 +419,47 @@ void llvm_emit_function_body(GenContext *c, Decl *decl)
{ {
DEBUG_LOG("Generating function %s.", decl->extname); DEBUG_LOG("Generating function %s.", decl->extname);
assert(decl->backend_ref); assert(decl->backend_ref);
llvm_emit_body(c,
decl->backend_ref,
decl->unit->module->name->module,
decl->name,
decl->span.file_id,
decl->type->function.prototype,
decl->func_decl.attr_naked ? NULL : &decl->func_decl.signature,
astptr(decl->func_decl.body));
}
void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_name, const char *function_name,
FileId file_id, FunctionPrototype *prototype, Signature *signature, Ast *body)
{
bool emit_debug = llvm_use_debug(c); bool emit_debug = llvm_use_debug(c);
LLVMValueRef prev_function = c->function; LLVMValueRef prev_function = c->function;
LLVMBuilderRef prev_builder = c->builder; LLVMBuilderRef prev_builder = c->builder;
c->opt_var = NULL; c->opt_var = NULL;
c->catch_block = NULL; c->catch_block = NULL;
c->function = decl->backend_ref; c->function = function;
if (!function_name) function_name = "anonymous function";
if (emit_debug) if (emit_debug)
{ {
c->debug.function = LLVMGetSubprogram(c->function); c->debug.function = LLVMGetSubprogram(function);
if (c->debug.enable_stacktrace) if (c->debug.enable_stacktrace)
{ {
scratch_buffer_clear(); scratch_buffer_clear();
scratch_buffer_append(decl->unit->module->name->module); scratch_buffer_append(module_name);
scratch_buffer_append("::"); scratch_buffer_append("::");
scratch_buffer_append(decl->name ? decl->name : "$anon"); scratch_buffer_append(function_name);
c->debug.func_name = llvm_emit_zstring(c, scratch_buffer_to_string()); c->debug.func_name = llvm_emit_zstring(c, scratch_buffer_to_string());
File *file = source_file_by_id(decl->span.file_id); File *file = source_file_by_id(file_id);
c->debug.file_name = llvm_emit_zstring(c, file->name); c->debug.file_name = llvm_emit_zstring(c, file->name);
} }
} }
c->cur_func_decl = decl; c->cur_func.name = function_name;
c->cur_func.prototype = prototype;
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, c->function, "entry"); LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, c->function, "entry");
c->current_block = entry; c->current_block = entry;
c->current_block_is_target = true; c->current_block_is_target = true;
@@ -446,7 +470,6 @@ void llvm_emit_function_body(GenContext *c, Decl *decl)
LLVMValueRef alloca_point = LLVMBuildAlloca(c->builder, LLVMInt32TypeInContext(c->context), "alloca_point"); LLVMValueRef alloca_point = LLVMBuildAlloca(c->builder, LLVMInt32TypeInContext(c->context), "alloca_point");
c->alloca_point = alloca_point; c->alloca_point = alloca_point;
FunctionPrototype *prototype = decl->type->function.prototype;
unsigned arg = 0; unsigned arg = 0;
if (emit_debug) if (emit_debug)
@@ -486,7 +509,7 @@ void llvm_emit_function_body(GenContext *c, Decl *decl)
c->failable_out = NULL; c->failable_out = NULL;
c->return_out = NULL; c->return_out = NULL;
if (prototype->ret_abi_info->kind == ABI_ARG_INDIRECT) if (prototype && prototype->ret_abi_info->kind == ABI_ARG_INDIRECT)
{ {
if (prototype->is_failable) if (prototype->is_failable)
{ {
@@ -497,26 +520,24 @@ void llvm_emit_function_body(GenContext *c, Decl *decl)
c->return_out = LLVMGetParam(c->function, arg++); c->return_out = LLVMGetParam(c->function, arg++);
} }
} }
if (prototype->ret_by_ref_abi_info) if (prototype && prototype->ret_by_ref_abi_info)
{ {
assert(!c->return_out); assert(!c->return_out);
c->return_out = LLVMGetParam(c->function, arg++); c->return_out = LLVMGetParam(c->function, arg++);
} }
if (!decl->func_decl.attr_naked) if (signature)
{ {
// Generate LLVMValueRef's for all parameters, so we can use them as local vars in code // Generate LLVMValueRef's for all parameters, so we can use them as local vars in code
VECEACH(decl->func_decl.signature.params, i) FOREACH_BEGIN_IDX(i, Decl *param, signature->params)
{ llvm_emit_parameter(c, param, prototype->abi_args[i], &arg, i);
llvm_emit_parameter(c, decl->func_decl.signature.params[i], prototype->abi_args[i], &arg, i); FOREACH_END();
}
} }
LLVMSetCurrentDebugLocation2(c->builder, NULL); LLVMSetCurrentDebugLocation2(c->builder, NULL);
assert(decl->func_decl.body); AstId current = body->compound_stmt.first_stmt;
AstId current = astptr(decl->func_decl.body)->compound_stmt.first_stmt;
while (current) while (current)
{ {
llvm_emit_stmt(c, ast_next(&current)); llvm_emit_stmt(c, ast_next(&current));
@@ -606,6 +627,34 @@ static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABI
} }
} }
void llvm_emit_xxlizer(GenContext *c, Decl *decl)
{
Ast *body = astptrzero(decl->xxlizer.init);
if (!body)
{
// Skip if it doesn't have a body.
return;
}
LLVMTypeRef initializer_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), NULL, 0, false);
bool is_finalizer = decl->decl_kind == DECL_FINALIZE;
LLVMValueRef **array_ref = is_finalizer ? &c->destructors : &c->constructors;
scratch_buffer_clear();
scratch_buffer_printf(is_finalizer ? ".static_finalize.%u" : ".static_initialize.%u", vec_size(*array_ref));
LLVMValueRef function = LLVMAddFunction(c->module, scratch_buffer_to_string(), initializer_type);
llvm_emit_body(c,
function,
decl->unit->module->name->module,
is_finalizer ? "[static finalizer]" : "[static initializer]",
decl->span.file_id,
NULL,
NULL,
body);
unsigned priority = decl->xxlizer.priority;
LLVMValueRef vals[3] = { llvm_const_int(c, type_int, priority), function, llvm_get_zero(c, type_voidptr) };
vec_add(*array_ref, LLVMConstStructInContext(c->context, vals, 3, false));
}
void llvm_emit_function_decl(GenContext *c, Decl *decl) void llvm_emit_function_decl(GenContext *c, Decl *decl)
{ {
assert(decl->decl_kind == DECL_FUNC); assert(decl->decl_kind == DECL_FUNC);

View File

@@ -72,6 +72,8 @@ typedef struct
LLVMBuilderRef builder; LLVMBuilderRef builder;
LLVMBasicBlockRef current_block; LLVMBasicBlockRef current_block;
LLVMBasicBlockRef catch_block; LLVMBasicBlockRef catch_block;
LLVMValueRef *constructors;
LLVMValueRef *destructors;
const char *ir_filename; const char *ir_filename;
const char *object_filename; const char *object_filename;
const char *asm_filename; const char *asm_filename;
@@ -83,8 +85,12 @@ typedef struct
LLVMTypeRef fault_type; LLVMTypeRef fault_type;
LLVMTypeRef size_type; LLVMTypeRef size_type;
Decl *panicfn; Decl *panicfn;
Decl *cur_code_decl; struct
Decl *cur_func_decl; {
const char *name;
FunctionPrototype *prototype;
Type *rtype;
} cur_func;
TypeInfo *current_return_type; TypeInfo *current_return_type;
int block_global_unique_count; int block_global_unique_count;
int ast_alloca_addr_space; int ast_alloca_addr_space;
@@ -267,6 +273,7 @@ LLVMMetadataRef llvm_get_debug_type(GenContext *c, Type *type);
LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type); LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type);
LLVMTypeRef llvm_get_pointee_type(GenContext *c, Type *any_type); LLVMTypeRef llvm_get_pointee_type(GenContext *c, Type *any_type);
void llvm_emit_function_decl(GenContext *c, Decl *decl); void llvm_emit_function_decl(GenContext *c, Decl *decl);
void llvm_emit_xxlizer(GenContext *c, Decl *decl);
INLINE LLVMTypeRef llvm_get_ptr_type(GenContext *c, Type *type); INLINE LLVMTypeRef llvm_get_ptr_type(GenContext *c, Type *type);
// -- Attributes --- // -- Attributes ---

View File

@@ -181,7 +181,7 @@ static inline void llvm_emit_return(GenContext *c, Ast *ast)
LLVMBasicBlockRef error_return_block = NULL; LLVMBasicBlockRef error_return_block = NULL;
LLVMValueRef error_out = NULL; LLVMValueRef error_out = NULL;
if (type_is_optional(c->cur_func_decl->type->function.prototype->rtype)) if (c->cur_func.prototype && type_is_optional(c->cur_func.prototype->rtype))
{ {
error_return_block = llvm_basic_block_new(c, "err_retblock"); error_return_block = llvm_basic_block_new(c, "err_retblock");
error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr"); error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr");
@@ -467,7 +467,7 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast)
SourceSpan loc = ast->span; SourceSpan loc = ast->span;
File *file = source_file_by_id(loc.file_id); File *file = source_file_by_id(loc.file_id);
llvm_emit_panic(c, "Infinite loop found", file->name, c->cur_func_decl->extname, loc.row ? loc.row : 1); llvm_emit_panic(c, "Infinite loop found", file->name, c->cur_func.name, loc.row ? loc.row : 1);
LLVMBuildUnreachable(c->builder); LLVMBuildUnreachable(c->builder);
LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block"); LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block");
c->current_block = NULL; c->current_block = NULL;
@@ -1001,7 +1001,7 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast)
error = "Assert violation"; error = "Assert violation";
} }
File *file = source_file_by_id(loc.file_id); File *file = source_file_by_id(loc.file_id);
llvm_emit_panic(c, error, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1); llvm_emit_panic(c, error, file->name, c->cur_func.name, loc.row ? loc.row : 1);
llvm_emit_br(c, on_ok); llvm_emit_br(c, on_ok);
llvm_emit_block(c, on_ok); llvm_emit_block(c, on_ok);
} }
@@ -1298,7 +1298,7 @@ void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_na
llvm_emit_cond_br(c, value, panic_block, ok_block); llvm_emit_cond_br(c, value, panic_block, ok_block);
llvm_emit_block(c, panic_block); llvm_emit_block(c, panic_block);
File *file = source_file_by_id(loc.file_id); File *file = source_file_by_id(loc.file_id);
llvm_emit_panic(c, panic_name, file->name, c->cur_func_decl->name, loc.row); llvm_emit_panic(c, panic_name, file->name, c->cur_func.name, loc.row);
llvm_emit_br(c, ok_block); llvm_emit_br(c, ok_block);
llvm_emit_block(c, ok_block); llvm_emit_block(c, ok_block);
} }
@@ -1312,7 +1312,7 @@ void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *pani
llvm_value_set_bool(&be_value, value); llvm_value_set_bool(&be_value, value);
llvm_emit_cond_br(c, &be_value, panic_block, ok_block); llvm_emit_cond_br(c, &be_value, panic_block, ok_block);
llvm_emit_block(c, panic_block); llvm_emit_block(c, panic_block);
llvm_emit_panic(c, panic_name, file->name, c->cur_func_decl->name, loc.row ? loc.row : 1); llvm_emit_panic(c, panic_name, file->name, c->cur_func.name, loc.row ? loc.row : 1);
llvm_emit_br(c, ok_block); llvm_emit_br(c, ok_block);
llvm_emit_block(c, ok_block); llvm_emit_block(c, ok_block);
} }

View File

@@ -5,6 +5,7 @@
static Decl *parse_const_declaration(ParseContext *c, Visibility visibility); static Decl *parse_const_declaration(ParseContext *c, Visibility visibility);
static inline Decl *parse_func_definition(ParseContext *c, Visibility visibility, AstId docs, bool is_interface); static inline Decl *parse_func_definition(ParseContext *c, Visibility visibility, AstId docs, bool is_interface);
static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl); static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl);
static inline Decl *parse_static_top_level(ParseContext *c);
#define DECL_VAR_NEW(type__, var__, visible__) decl_new_var(symstr(c), c->span, type__, var__, visible__); #define DECL_VAR_NEW(type__, var__, visible__) decl_new_var(symstr(c), c->span, type__, var__, visible__);
@@ -53,6 +54,7 @@ void recover_top_level(ParseContext *c)
case TOKEN_STRUCT: case TOKEN_STRUCT:
case TOKEN_UNION: case TOKEN_UNION:
case TOKEN_BITSTRUCT: case TOKEN_BITSTRUCT:
case TOKEN_STATIC:
case TYPELIKE_TOKENS: case TYPELIKE_TOKENS:
// Only recover if this is in the first col. // Only recover if this is in the first col.
if (c->span.col == 1) return; if (c->span.col == 1) return;
@@ -2173,6 +2175,37 @@ static inline Decl *parse_func_definition(ParseContext *c, Visibility visibility
return func; return func;
} }
static inline Decl *parse_static_top_level(ParseContext *c)
{
advance_and_verify(c, TOKEN_STATIC);
Decl *init = decl_calloc();
if (!tok_is(c, TOKEN_IDENT))
{
if (token_is_any_type(c->tok))
{
SEMA_ERROR_HERE("'static' can only used with local variables, to hide global variables and functions, use 'private'.");
return poisoned_decl;
}
SEMA_ERROR_HERE("Expected 'static initialize' or 'static finalize'.");
return poisoned_decl;
}
init->decl_kind = DECL_INITIALIZE;
if (c->data.string == kw_finalize)
{
init->decl_kind = DECL_FINALIZE;
}
else if (c->data.string != kw_initialize)
{
SEMA_ERROR_HERE("Expected 'static initialize' or 'static finalize'.");
return poisoned_decl;
}
advance(c);
Attr *attr = NULL;
if (!parse_attributes(c, &init->attributes)) return poisoned_decl;
ASSIGN_ASTID_OR_RET(init->xxlizer.init, parse_compound_stmt(c), poisoned_decl);
RANGE_EXTEND_PREV(init);
return init;
}
static inline bool check_no_visibility_before(ParseContext *c, Visibility visibility) static inline bool check_no_visibility_before(ParseContext *c, Visibility visibility)
{ {
@@ -2522,6 +2555,17 @@ Decl *parse_top_level_statement(ParseContext *c)
ASSIGN_DECL_OR_RET(decl, parse_func_definition(c, visibility, docs, false), poisoned_decl); ASSIGN_DECL_OR_RET(decl, parse_func_definition(c, visibility, docs, false), poisoned_decl);
break; break;
} }
case TOKEN_STATIC:
{
if (!check_no_visibility_before(c, visibility)) return poisoned_decl;
ASSIGN_DECL_OR_RET(decl, parse_static_top_level(c), poisoned_decl);
if (docs)
{
SEMA_ERROR(astptr(docs), "Unexpected doc comment before 'static', did you mean to use a regular comment?");
return poisoned_decl;
}
break;
}
case TOKEN_CT_ASSERT: case TOKEN_CT_ASSERT:
if (!check_no_visibility_before(c, visibility)) return poisoned_decl; if (!check_no_visibility_before(c, visibility)) return poisoned_decl;
{ {

View File

@@ -1419,6 +1419,12 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
return "typedef"; return "typedef";
case ATTR_CALL: case ATTR_CALL:
return "call"; return "call";
case ATTR_INITIALIZER:
return "static initializer";
case ATTR_FINALIZER:
return "static finalizer";
case ATTR_XXLIZER:
UNREACHABLE
} }
UNREACHABLE UNREACHABLE
} }
@@ -1429,7 +1435,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
assert(type >= 0 && type < NUMBER_OF_ATTRIBUTES); assert(type >= 0 && type < NUMBER_OF_ATTRIBUTES);
static AttributeDomain attribute_domain[NUMBER_OF_ATTRIBUTES] = { static AttributeDomain attribute_domain[NUMBER_OF_ATTRIBUTES] = {
[ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL, [ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL,
[ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_MACRO), [ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_MACRO | ATTR_XXLIZER),
[ATTRIBUTE_SECTION] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL, [ATTRIBUTE_SECTION] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL,
[ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION, [ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION,
[ATTRIBUTE_NORETURN] = ATTR_FUNC | ATTR_MACRO, [ATTRIBUTE_NORETURN] = ATTR_FUNC | ATTR_MACRO,
@@ -1441,8 +1447,8 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_MAYDISCARD] = ATTR_FUNC | ATTR_MACRO, [ATTRIBUTE_MAYDISCARD] = ATTR_FUNC | ATTR_MACRO,
[ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT, [ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT,
[ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT, [ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT,
[ATTRIBUTE_USED] = (AttributeDomain)~ATTR_CALL, [ATTRIBUTE_USED] = (AttributeDomain)~(ATTR_CALL | ATTR_XXLIZER ),
[ATTRIBUTE_UNUSED] = (AttributeDomain)~ATTR_CALL, [ATTRIBUTE_UNUSED] = (AttributeDomain)~(ATTR_CALL | ATTR_XXLIZER),
[ATTRIBUTE_NAKED] = ATTR_FUNC, [ATTRIBUTE_NAKED] = ATTR_FUNC,
[ATTRIBUTE_CDECL] = ATTR_FUNC, [ATTRIBUTE_CDECL] = ATTR_FUNC,
[ATTRIBUTE_STDCALL] = ATTR_FUNC, [ATTRIBUTE_STDCALL] = ATTR_FUNC,
@@ -1455,6 +1461,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_REFLECT] = ATTR_ENUM, [ATTRIBUTE_REFLECT] = ATTR_ENUM,
[ATTRIBUTE_OBFUSCATE] = ATTR_ENUM, [ATTRIBUTE_OBFUSCATE] = ATTR_ENUM,
[ATTRIBUTE_PURE] = ATTR_CALL, [ATTRIBUTE_PURE] = ATTR_CALL,
[ATTRIBUTE_PRIORITY] = ATTR_XXLIZER,
}; };
if ((attribute_domain[type] & domain) != domain) if ((attribute_domain[type] & domain) != domain)
@@ -1551,7 +1558,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
return false; return false;
} }
if (!sema_analyse_expr(context, expr)) return false; if (!sema_analyse_expr(context, expr)) return false;
if (expr->expr_kind != EXPR_CONST || !type_is_integer(expr->type->canonical)) if (!expr_is_const_int(expr))
{ {
SEMA_ERROR(expr, "Expected a constant integer value as argument."); SEMA_ERROR(expr, "Expected a constant integer value as argument.");
return false; return false;
@@ -1589,7 +1596,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
return false; return false;
} }
if (!sema_analyse_expr(context, expr)) return false; if (!sema_analyse_expr(context, expr)) return false;
if (expr->expr_kind != EXPR_CONST || expr->const_expr.const_kind != CONST_STRING) if (!expr_is_const_string(expr))
{ {
SEMA_ERROR(expr, "Expected a constant string value as argument."); SEMA_ERROR(expr, "Expected a constant string value as argument.");
return false; return false;
@@ -1660,6 +1667,19 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
case ATTRIBUTE_USED: case ATTRIBUTE_USED:
decl->is_must_use = true; decl->is_must_use = true;
break; break;
case ATTRIBUTE_PRIORITY:
if (!expr || !expr_is_const_int(expr)) goto ERROR_PRIORITY;
{
Int i = expr->const_expr.ixx;
if (!int_fits(i, TYPE_I64)) goto ERROR_PRIORITY;
int64_t priority = int_to_i64(i);
if (priority < 1 || priority > MAX_PRIORITY) goto ERROR_PRIORITY;
decl->xxlizer.priority = priority;
return true;
}
ERROR_PRIORITY:
SEMA_ERROR(attr, "Expected an argument to '@priority' between 1 and %d.", MAX_PRIORITY);
return decl_poison(decl);
case ATTRIBUTE_PURE: case ATTRIBUTE_PURE:
// Only used for calls. // Only used for calls.
UNREACHABLE UNREACHABLE
@@ -2001,6 +2021,51 @@ static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, boo
return true; return true;
} }
static inline bool sema_analyse_xxlizer(SemaContext *context, Decl *decl)
{
if (!sema_analyse_attributes(context, decl, decl->attributes, decl->decl_kind == DECL_INITIALIZE ? ATTR_INITIALIZER : ATTR_FINALIZER)) return decl_poison(decl);
if (decl->xxlizer.priority == 0) decl->xxlizer.priority = MAX_PRIORITY;
context->current_function = NULL;
context->current_function_pure = false;
context->rtype = type_void;
context->active_scope = (DynamicScope) {
.scope_id = 0,
.depth = 0,
.label_start = 0,
.current_local = 0
};
// Clear returns
vec_resize(context->returns, 0);
context->scope_id = 0;
context->continue_target = NULL;
context->next_target = 0;
context->next_switch = 0;
context->break_target = 0;
context->ensures = false;
Ast *body = astptr(decl->xxlizer.init);
// Insert an implicit return
AstId *next_id = &body->compound_stmt.first_stmt;
if (!*next_id)
{
decl->xxlizer.init = 0;
}
SourceSpan span = body->span;
if (*next_id)
{
Ast *last = ast_last(astptr(*next_id));
// Cleanup later
if (last->ast_kind == AST_RETURN_STMT) goto SKIP_NEW_RETURN;
span = last->span;
next_id = &last->next;
}
Ast *ret = new_ast(AST_RETURN_STMT, span);
ast_append(&next_id, ret);
SKIP_NEW_RETURN:
return sema_analyse_statement(context, body);
}
static inline bool sema_analyse_func(SemaContext *context, Decl *decl) static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
{ {
DEBUG_LOG("----Analysing function %s", decl->name); DEBUG_LOG("----Analysing function %s", decl->name);
@@ -2652,6 +2717,10 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
case DECL_DEFINE: case DECL_DEFINE:
if (!sema_analyse_define(context, decl)) goto FAILED; if (!sema_analyse_define(context, decl)) goto FAILED;
break; break;
case DECL_INITIALIZE:
case DECL_FINALIZE:
if (!sema_analyse_xxlizer(context, decl)) goto FAILED;
break;
case DECL_POISONED: case DECL_POISONED:
case DECL_IMPORT: case DECL_IMPORT:
case DECL_ENUM_CONSTANT: case DECL_ENUM_CONSTANT:

View File

@@ -477,6 +477,8 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
case DECL_TYPEDEF: case DECL_TYPEDEF:
case DECL_DECLARRAY: case DECL_DECLARRAY:
case DECL_BODYPARAM: case DECL_BODYPARAM:
case DECL_INITIALIZE:
case DECL_FINALIZE:
UNREACHABLE UNREACHABLE
case DECL_POISONED: case DECL_POISONED:
return expr_poison(expr); return expr_poison(expr);

View File

@@ -404,6 +404,10 @@ void sema_analysis_pass_decls(Module *module)
{ {
sema_analyse_decl(&context, unit->generic_defines[i]); sema_analyse_decl(&context, unit->generic_defines[i]);
} }
VECEACH(unit->xxlizers, i)
{
sema_analyse_decl(&context, unit->xxlizers[i]);
}
sema_context_destroy(&context); sema_context_destroy(&context);
} }
DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found);

View File

@@ -194,6 +194,8 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
case DECL_ATTRIBUTE: case DECL_ATTRIBUTE:
SEMA_ERROR(type_info, "This is not a type."); SEMA_ERROR(type_info, "This is not a type.");
return type_info_poison(type_info); return type_info_poison(type_info);
case DECL_INITIALIZE:
case DECL_FINALIZE:
case DECL_CT_ELSE: case DECL_CT_ELSE:
case DECL_CT_IF: case DECL_CT_IF:
case DECL_CT_ELIF: case DECL_CT_ELIF:

View File

@@ -167,6 +167,8 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls)
case DECL_LABEL: case DECL_LABEL:
case DECL_CT_ASSERT: case DECL_CT_ASSERT:
case DECL_DECLARRAY: case DECL_DECLARRAY:
case DECL_INITIALIZE:
case DECL_FINALIZE:
continue; continue;
case DECL_ATTRIBUTE: case DECL_ATTRIBUTE:
break; break;

View File

@@ -57,16 +57,18 @@ const char *kw_check_assign;
const char *kw_deprecated; const char *kw_deprecated;
const char *kw_distinct; const char *kw_distinct;
const char *kw_elements; const char *kw_elements;
const char *kw_finalize;
const char *kw_in; const char *kw_in;
const char *kw_incr; const char *kw_incr;
const char *kw_inf; const char *kw_inf;
const char *kw_initialize;
const char *kw_inline; const char *kw_inline;
const char *kw_inner; const char *kw_inner;
const char *kw_inout; const char *kw_inout;
const char *kw_kind; const char *kw_kind;
const char *kw_len; const char *kw_len;
const char *kw_mainstub;
const char *kw_main; const char *kw_main;
const char *kw_mainstub;
const char *kw_max; const char *kw_max;
const char *kw_min; const char *kw_min;
const char *kw_nameof; const char *kw_nameof;
@@ -82,8 +84,8 @@ const char *kw_sizeof;
const char *kw_std; const char *kw_std;
const char *kw_std__core; const char *kw_std__core;
const char *kw_std__core__types; const char *kw_std__core__types;
const char *kw_typekind;
const char *kw_type; const char *kw_type;
const char *kw_typekind;
const char *kw_values; const char *kw_values;
void symtab_destroy() void symtab_destroy()
@@ -142,7 +144,9 @@ void symtab_init(uint32_t capacity)
kw_deprecated = KW_DEF("deprecated"); kw_deprecated = KW_DEF("deprecated");
kw_distinct = KW_DEF("distinct"); kw_distinct = KW_DEF("distinct");
kw_elements = KW_DEF("elements"); kw_elements = KW_DEF("elements");
kw_finalize = KW_DEF("finalize");
kw_in = KW_DEF("in"); kw_in = KW_DEF("in");
kw_initialize = KW_DEF("initialize");
kw_incr = KW_DEF("incr"); kw_incr = KW_DEF("incr");
kw_inf = KW_DEF("inf"); kw_inf = KW_DEF("inf");
kw_inline = KW_DEF("inline"); kw_inline = KW_DEF("inline");
@@ -262,6 +266,7 @@ void symtab_init(uint32_t capacity)
attribute_list[ATTRIBUTE_OPERATOR] = KW_DEF("@operator"); attribute_list[ATTRIBUTE_OPERATOR] = KW_DEF("@operator");
attribute_list[ATTRIBUTE_OVERLAP] = KW_DEF("@overlap"); attribute_list[ATTRIBUTE_OVERLAP] = KW_DEF("@overlap");
attribute_list[ATTRIBUTE_PACKED] = KW_DEF("@packed"); attribute_list[ATTRIBUTE_PACKED] = KW_DEF("@packed");
attribute_list[ATTRIBUTE_PRIORITY] = KW_DEF("@priority");
attribute_list[ATTRIBUTE_PURE] = kw_at_pure; attribute_list[ATTRIBUTE_PURE] = kw_at_pure;
attribute_list[ATTRIBUTE_REFLECT] = KW_DEF("@reflect"); attribute_list[ATTRIBUTE_REFLECT] = KW_DEF("@reflect");
attribute_list[ATTRIBUTE_REGCALL] = KW_DEF("@regcall"); attribute_list[ATTRIBUTE_REGCALL] = KW_DEF("@regcall");

View File

@@ -3,6 +3,8 @@
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#include "compiler_internal.h" #include "compiler_internal.h"
extern void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array);
static unsigned arch_pointer_bit_width(OsType os, ArchType arch); static unsigned arch_pointer_bit_width(OsType os, ArchType arch);
static ArchType arch_from_llvm_string(StringSlice string); static ArchType arch_from_llvm_string(StringSlice string);
static EnvironmentType environment_type_from_llvm_string(StringSlice string); static EnvironmentType environment_type_from_llvm_string(StringSlice string);
@@ -1216,6 +1218,7 @@ static AlignSize os_target_pref_alignment_of_float(OsType os, ArchType arch, uin
} }
void *llvm_target_machine_create(void) void *llvm_target_machine_create(void)
{ {
char *err = NULL; char *err = NULL;
@@ -1271,6 +1274,7 @@ void *llvm_target_machine_create(void)
platform_target.cpu ? platform_target.cpu : "", features, platform_target.cpu ? platform_target.cpu : "", features,
(LLVMCodeGenOptLevel)platform_target.llvm_opt_level, (LLVMCodeGenOptLevel)platform_target.llvm_opt_level,
reloc_mode, LLVMCodeModelDefault); reloc_mode, LLVMCodeModelDefault);
LLVMSetTargetMachineUseInitArray(result, true);
if (!result) error_exit("Failed to create target machine."); if (!result) error_exit("Failed to create target machine.");
LLVMSetTargetMachineAsmVerbosity(result, 1); LLVMSetTargetMachineAsmVerbosity(result, 1);
return result; return result;

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.3.59" #define COMPILER_VERSION "0.3.60"

View File

@@ -109,7 +109,7 @@ loop.body: ; preds = %loop.cond
br label %loop.cond br label %loop.cond
loop.exit: ; preds = %loop.cond loop.exit: ; preds = %loop.cond
call void @std_core_builtin_panic(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.zstr, i64 0, i64 0), i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.zstr.1, i64 0, i64 0), i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.zstr.2, i64 0, i64 0), i32 14) call void @std_core_builtin_panic(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.zstr, i64 0, i64 0), i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.zstr.1, i64 0, i64 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.zstr.2, i64 0, i64 0), i32 14)
unreachable unreachable
unreachable_block: ; No predecessors! unreachable_block: ; No predecessors!

View File

@@ -1 +1 @@
static int ifej; // #error: Expected a top level declaration here static int ifej; // #error: 'static' can only used with local variables

View File

@@ -0,0 +1,16 @@
static initialize @priority("hello") // #error: Expected an argument to '@priority'
{
}
static initialize @priority(1, 2) // #error: Too many arguments for
{
}
static initialize @priority(0) // #error: Expected an argument to '@priority'
{
}
static initialize @priority(65536) // #error: Expected an argument to '@priority'
{
}

View File

@@ -0,0 +1,62 @@
// #target: linux-x64
module test;
import std::io;
fn void main()
{
io::println("Hello, world!");
}
extern fn void puts(char*);
static initialize @priority(300)
{
puts("Hello startup2");
}
static initialize
{
puts("Let's start main...");
}
static initialize @priority(200)
{
puts("Hello startup");
}
static initialize
{}
static finalize
{
puts("Bye bye");
}
/* #expect: test.ll
@llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 300, void ()* @.static_initialize.0, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @.static_initialize.1, i8* null }, { i32, void ()*, i8* } { i32 200, void ()* @.static_initialize.2, i8* null }]
@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @.static_finalize.0, i8* null }]
define void @.static_initialize.0() {
entry:
call void @puts(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i32 0, i32 0))
ret void
}
; Function Attrs: nounwind
declare void @puts(i8*) #0
define void @.static_initialize.1() {
entry:
call void @puts(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.1, i32 0, i32 0))
ret void
}
define void @.static_initialize.2() {
entry:
call void @puts(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.2, i32 0, i32 0))
ret void
}
define void @.static_finalize.0() {
entry:
call void @puts(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i32 0, i32 0))
ret void
}

View File

@@ -0,0 +1,9 @@
static initialize
{
return; // This is fine
}
static initialize
{
return 123; // #error: You cannot cast 'int' into 'void' even with an explicit cast, so this looks like an error.
}

View File

@@ -0,0 +1 @@
static foo {} ; // #error: Expected 'static initialize'

View File

@@ -0,0 +1,3 @@
static initialize @priority() // #error: An expression was expected.
{
}

View File

@@ -1 +1 @@
static int ifej; // #error: Expected a top level declaration here static int ifej; // #error: 'static' can only used with local variables, to hide global variables

View File

@@ -0,0 +1,16 @@
static initialize @priority("hello") // #error: Expected an argument to '@priority'
{
}
static initialize @priority(1, 2) // #error: Too many arguments for
{
}
static initialize @priority(0) // #error: Expected an argument to '@priority'
{
}
static initialize @priority(65536) // #error: Expected an argument to '@priority'
{
}

View File

@@ -0,0 +1,62 @@
// #target: linux-x64
module test;
import std::io;
fn void main()
{
io::println("Hello, world!");
}
extern fn void puts(char*);
static initialize @priority(300)
{
puts("Hello startup2");
}
static initialize
{
puts("Let's start main...");
}
static initialize @priority(200)
{
puts("Hello startup");
}
static initialize
{}
static finalize
{
puts("Bye bye");
}
/* #expect: test.ll
@llvm.global_ctors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 300, ptr @.static_initialize.0, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @.static_initialize.1, ptr null }, { i32, ptr, ptr } { i32 200, ptr @.static_initialize.2, ptr null }]
@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @.static_finalize.0, ptr null }]
define void @.static_initialize.0() {
entry:
call void @puts(ptr @.str)
ret void
}
; Function Attrs: nounwind
declare void @puts(ptr) #0
define void @.static_initialize.1() {
entry:
call void @puts(ptr @.str.1)
ret void
}
define void @.static_initialize.2() {
entry:
call void @puts(ptr @.str.2)
ret void
}
define void @.static_finalize.0() {
entry:
call void @puts(ptr @.str.3)
ret void
}

View File

@@ -0,0 +1,9 @@
static initialize
{
return; // This is fine
}
static initialize
{
return 123; // #error: You cannot cast 'int' into 'void' even with an explicit cast, so this looks like an error.
}

View File

@@ -0,0 +1 @@
static foo {} ; // #error: Expected 'static initialize'

View File

@@ -0,0 +1,3 @@
static initialize @priority() // #error: An expression was expected.
{
}

View File

@@ -5,6 +5,8 @@
#include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/IRObjectFile.h"
#include "llvm/Object/SymbolicFile.h" #include "llvm/Object/SymbolicFile.h"
#include "llvm-c/TargetMachine.h"
#include "llvm/Target/TargetMachine.h"
#if LLVM_VERSION_MAJOR > 13 #if LLVM_VERSION_MAJOR > 13
#define LINK_SIG \ #define LINK_SIG \
@@ -167,6 +169,12 @@ extern "C" {
int llvm_version_major = LLVM_VERSION_MAJOR; int llvm_version_major = LLVM_VERSION_MAJOR;
void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array)
{
auto machine = reinterpret_cast<llvm::TargetMachine *>(ref);
machine->Options.UseInitArray = use_init_array;
}
LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal) LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal)
{ {
llvm::Constant *Val = llvm::unwrap<llvm::Constant>(ConstantVal); llvm::Constant *Val = llvm::unwrap<llvm::Constant>(ConstantVal);