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:
gingerBill committed 2026-10-07 15:54:21 +01:00
1 parent 30f80e1079
commit 5ff7268cab
8 files changed
+35 -5

No files matched your search

+1
View File
@@ -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");
+1
View File
@@ -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) {
+18
View File
@@ -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) {
+1
View File
@@ -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;
+1
View File
@@ -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;
+1 -1
View File
@@ -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));
+3
View File
@@ -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);
+9 -4
View File
@@ -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);