mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Implement static finalize / initialize. Version bump.
This commit is contained in:
committed by
Christoffer Lerno
parent
58647043f4
commit
e1b5b0b60c
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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(¤t));
|
llvm_emit_stmt(c, ast_next(¤t));
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 ---
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define COMPILER_VERSION "0.3.59"
|
#define COMPILER_VERSION "0.3.60"
|
||||||
@@ -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!
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
static int ifej; // #error: Expected a top level declaration here
|
static int ifej; // #error: 'static' can only used with local variables
|
||||||
16
test/test_suite/initialize/initialize_bad_prio.c3
Normal file
16
test/test_suite/initialize/initialize_bad_prio.c3
Normal 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'
|
||||||
|
{
|
||||||
|
}
|
||||||
62
test/test_suite/initialize/initialize_finalize.c3t
Normal file
62
test/test_suite/initialize/initialize_finalize.c3t
Normal 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
|
||||||
|
}
|
||||||
9
test/test_suite/initialize/initialize_jump.c3
Normal file
9
test/test_suite/initialize/initialize_jump.c3
Normal 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.
|
||||||
|
}
|
||||||
1
test/test_suite/initialize/initialize_parse_error.c3
Normal file
1
test/test_suite/initialize/initialize_parse_error.c3
Normal file
@@ -0,0 +1 @@
|
|||||||
|
static foo {} ; // #error: Expected 'static initialize'
|
||||||
3
test/test_suite/initialize/initialize_prio.c3
Normal file
3
test/test_suite/initialize/initialize_prio.c3
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
static initialize @priority() // #error: An expression was expected.
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -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
|
||||||
16
test/test_suite2/initialize/initialize_bad_prio.c3
Normal file
16
test/test_suite2/initialize/initialize_bad_prio.c3
Normal 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'
|
||||||
|
{
|
||||||
|
}
|
||||||
62
test/test_suite2/initialize/initialize_finalize.c3t
Normal file
62
test/test_suite2/initialize/initialize_finalize.c3t
Normal 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
|
||||||
|
}
|
||||||
9
test/test_suite2/initialize/initialize_jump.c3
Normal file
9
test/test_suite2/initialize/initialize_jump.c3
Normal 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.
|
||||||
|
}
|
||||||
1
test/test_suite2/initialize/initialize_parse_error.c3
Normal file
1
test/test_suite2/initialize/initialize_parse_error.c3
Normal file
@@ -0,0 +1 @@
|
|||||||
|
static foo {} ; // #error: Expected 'static initialize'
|
||||||
3
test/test_suite2/initialize/initialize_prio.c3
Normal file
3
test/test_suite2/initialize/initialize_prio.c3
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
static initialize @priority() // #error: An expression was expected.
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user