mirror of
https://github.com/odin-lang/Odin.git
synced 2026-10-08 05:48:51 -04:00
Add @(align=N) for variables, raising the alignment of globals, locals, @(static) and @(thread_local) variables to at least N
This commit is contained in:
1 parent
30f80e1079
commit
5ff7268cab
8 files changed
+35
-5
No files matched your search
@@ -1753,6 +1753,7 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast
|
||||
|
||||
e->Variable.thread_local_model = ac.thread_local_model;
|
||||
e->Variable.is_export = ac.is_export;
|
||||
e->Variable.custom_align = ac.align;
|
||||
e->flags &= ~EntityFlag_Static;
|
||||
if (ac.is_static) {
|
||||
error(e->token, "@(static) is not supported for global variables, nor required");
|
||||
|
||||
@@ -2287,6 +2287,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
||||
if (ac.link_name.len > 0) {
|
||||
e->Variable.link_name = ac.link_name;
|
||||
}
|
||||
e->Variable.custom_align = ac.align;
|
||||
|
||||
e->flags &= ~EntityFlag_Static;
|
||||
if (ac.is_static) {
|
||||
|
||||
@@ -4653,6 +4653,24 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
|
||||
error(elem, "Expected either no value or a string for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
} else if (name == "align") {
|
||||
ExactValue ev = check_decl_attribute_value(c, value);
|
||||
if (ev.kind != ExactValue_Integer) {
|
||||
error(elem, "Expected a constant integer for '%.*s'", LIT(name));
|
||||
return true;
|
||||
}
|
||||
i64 align = exact_value_to_i64(ev);
|
||||
if (ev.value_integer.used > 1 ||
|
||||
align < 1 ||
|
||||
align > (1ll<<31) ||
|
||||
!gb_is_power_of_two(cast(isize)align)) {
|
||||
gbString str = exact_value_to_string(ev);
|
||||
error(elem, "'%.*s' must be a power of 2 no greater than 2^31, got %s", LIT(name), str);
|
||||
gb_string_free(str);
|
||||
} else {
|
||||
ac->align = align;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (c->curr_proc_decl != nullptr) {
|
||||
|
||||
@@ -123,6 +123,7 @@ struct AttributeContext {
|
||||
String link_section;
|
||||
String linkage;
|
||||
isize init_expr_list_count;
|
||||
i64 align;
|
||||
String thread_local_model;
|
||||
String deprecated_message;
|
||||
String warning_message;
|
||||
|
||||
@@ -273,6 +273,7 @@ struct Entity {
|
||||
String link_prefix;
|
||||
String link_suffix;
|
||||
String link_section;
|
||||
i64 custom_align;
|
||||
CommentGroup *docs;
|
||||
CommentGroup *comment;
|
||||
bool is_foreign;
|
||||
|
||||
@@ -2421,7 +2421,7 @@ gb_internal void lb_create_global_variable(lbModule *m, lbGlobalVariable *var) {
|
||||
LLVM_SET_INTERNAL_WEAK_LINKAGE(g.value);
|
||||
}
|
||||
lb_set_linkage_from_entity_flags(m, g.value, e->flags);
|
||||
LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type));
|
||||
LLVMSetAlignment(g.value, cast(u32)gb_max(type_align_of(e->type), e->Variable.custom_align));
|
||||
|
||||
if (e->Variable.link_section.len > 0) {
|
||||
LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section));
|
||||
|
||||
@@ -4676,6 +4676,9 @@ gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero
|
||||
if (is_type_matrix(type)) {
|
||||
alignment *= 2; // NOTE(bill): Just in case
|
||||
}
|
||||
if (e != nullptr && e->kind == Entity_Variable) {
|
||||
alignment = gb_max(alignment, cast(unsigned)e->Variable.custom_align);
|
||||
}
|
||||
|
||||
LLVMValueRef ptr = llvm_alloca(p, llvm_type, alignment, name);
|
||||
|
||||
|
||||
@@ -109,7 +109,10 @@ gb_internal void lb_scan_for_sret_rvo(lbProcedure *p) {
|
||||
Entity *e = entity_of_node(vd->names[0]);
|
||||
if (e == ret_entity) {
|
||||
Ast *rhs = unparen_expr(vd->values[0]);
|
||||
if (rhs->kind == Ast_CallExpr && lb_call_sret_eligible(p, rhs, e->type)) {
|
||||
// NOTE(bill): the caller's return slot only has the type's alignment and not @(align=N)'s
|
||||
if (rhs->kind == Ast_CallExpr &&
|
||||
e->Variable.custom_align == 0 &&
|
||||
lb_call_sret_eligible(p, rhs, e->type)) {
|
||||
decl_index = i;
|
||||
}
|
||||
goto done_scanning;
|
||||
@@ -2481,7 +2484,7 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
|
||||
char *c_name = alloc_cstring(permanent_allocator(), mangled_name);
|
||||
|
||||
LLVMValueRef global = LLVMAddGlobal(p->module->mod, lb_type(p->module, e->type), c_name);
|
||||
LLVMSetAlignment(global, cast(u32)type_align_of(e->type));
|
||||
LLVMSetAlignment(global, cast(u32)gb_max(type_align_of(e->type), e->Variable.custom_align));
|
||||
LLVMSetInitializer(global, LLVMConstNull(lb_type(p->module, e->type)));
|
||||
|
||||
if (e->Variable.is_rodata) {
|
||||
@@ -2528,7 +2531,7 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
|
||||
if (actual_type != expected_type) {
|
||||
LLVMDeleteGlobal(global);
|
||||
global = LLVMAddGlobal(p->module->mod, actual_type, c_name);
|
||||
LLVMSetAlignment(global, cast(u32)type_align_of(e->type));
|
||||
LLVMSetAlignment(global, cast(u32)gb_max(type_align_of(e->type), e->Variable.custom_align));
|
||||
if (e->Variable.is_rodata) {
|
||||
LLVMSetGlobalConstant(global, true);
|
||||
}
|
||||
@@ -3464,7 +3467,9 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||
// the literal is one of its variants, so reusing that storage would bind the
|
||||
// variable to a bare `[]int` and never build the union at all
|
||||
if (comp_lit_addr && are_types_identical(lb_addr_type(*comp_lit_addr), type_of_expr(vd->names[lval_index]))) {
|
||||
if (Entity *e = entity_of_node(vd->names[lval_index])) {
|
||||
Entity *e = entity_of_node(vd->names[lval_index]);
|
||||
// NOTE(bill): the literal's storage only has the type's alignment and not @(align=N)'s
|
||||
if (e != nullptr && e->Variable.custom_align == 0) {
|
||||
lbValue val = comp_lit_addr->addr;
|
||||
lb_add_entity(p->module, e, val);
|
||||
lb_add_debug_local_variable(p, val.value, e->type, e->token);
|
||||
|
||||
Reference in new issue
Block a user