Commit c5c9d98065
Changed files (20)
src/all_types.hpp
@@ -303,8 +303,6 @@ struct TldVar {
Tld base;
VariableTableEntry *var;
- AstNode *set_global_align_node;
- uint32_t alignment;
AstNode *set_global_section_node;
Buf *section_name;
AstNode *set_global_linkage_node;
@@ -358,6 +356,7 @@ enum NodeType {
NodeTypeCharLiteral,
NodeTypeSymbol,
NodeTypePrefixOpExpr,
+ NodeTypeAddrOfExpr,
NodeTypeFnCallExpr,
NodeTypeArrayAccessExpr,
NodeTypeSliceExpr,
@@ -415,6 +414,8 @@ struct AstNodeFnProto {
AstNode *fn_def_node;
// populated if this is an extern declaration
Buf *lib_name;
+ // populated if the "align A" is present
+ AstNode *align_expr;
};
struct AstNodeFnDef {
@@ -470,6 +471,8 @@ struct AstNodeVariableDeclaration {
AstNode *expr;
// populated if this is an extern declaration
Buf *lib_name;
+ // populated if the "align A" is present
+ AstNode *align_expr;
};
struct AstNodeErrorValueDecl {
@@ -579,10 +582,6 @@ enum PrefixOp {
PrefixOpBinNot,
PrefixOpNegation,
PrefixOpNegationWrap,
- PrefixOpAddressOf,
- PrefixOpConstAddressOf,
- PrefixOpVolatileAddressOf,
- PrefixOpConstVolatileAddressOf,
PrefixOpDereference,
PrefixOpMaybe,
PrefixOpError,
@@ -595,6 +594,23 @@ struct AstNodePrefixOpExpr {
AstNode *primary_expr;
};
+struct AstNodeAddrOfExpr {
+ AstNode *align_expr;
+ BigInt *bit_offset_start;
+ BigInt *bit_offset_end;
+ bool is_const;
+ bool is_volatile;
+ AstNode *op_expr;
+};
+
+struct AstNodeArrayType {
+ AstNode *size;
+ AstNode *child_type;
+ AstNode *align_expr;
+ bool is_const;
+ bool is_volatile;
+};
+
struct AstNodeUse {
VisibMod visib_mod;
AstNode *expr;
@@ -807,12 +823,6 @@ struct AstNodeUnreachableExpr {
};
-struct AstNodeArrayType {
- AstNode *size;
- AstNode *child_type;
- bool is_const;
-};
-
struct AstNodeErrorType {
};
@@ -841,6 +851,7 @@ struct AstNode {
AstNodeBinOpExpr bin_op_expr;
AstNodeUnwrapErrorExpr unwrap_err_expr;
AstNodePrefixOpExpr prefix_op_expr;
+ AstNodeAddrOfExpr addr_of_expr;
AstNodeFnCallExpr fn_call_expr;
AstNodeArrayAccessExpr array_access_expr;
AstNodeSliceExpr slice_expr;
@@ -911,8 +922,10 @@ struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
bool is_volatile;
+ uint32_t alignment;
uint32_t bit_offset;
uint32_t unaligned_bit_count;
+ TypeTableEntry *slice_parent;
};
struct TypeTableEntryInt {
@@ -958,6 +971,7 @@ struct TypeTableEntryStruct {
bool zero_bits_loop_flag;
bool zero_bits_known;
+ uint32_t abi_alignment; // also figured out with zero_bits pass
};
struct TypeTableEntryMaybe {
@@ -989,6 +1003,7 @@ struct TypeTableEntryEnum {
bool zero_bits_loop_flag;
bool zero_bits_known;
+ uint32_t abi_alignment; // also figured out with zero_bits pass
size_t gen_union_index;
size_t gen_tag_index;
@@ -1101,7 +1116,6 @@ struct TypeTableEntry {
// use these fields to make sure we don't duplicate type table entries for the same type
TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
- TypeTableEntry *slice_parent[2]; // [0 - mut, 1 - const]
TypeTableEntry *maybe_parent;
TypeTableEntry *error_parent;
// If we generate a constant name value for this type, we memoize it here.
@@ -1164,6 +1178,7 @@ struct FnTableEntry {
size_t prealloc_bbc;
AstNode **param_source_nodes;
Buf **param_names;
+ uint32_t align_bytes;
AstNode *fn_no_inline_set_node;
AstNode *fn_static_eval_set_node;
@@ -1171,8 +1186,6 @@ struct FnTableEntry {
ZigList<IrInstruction *> alloca_list;
ZigList<VariableTableEntry *> variable_list;
- AstNode *set_global_align_node;
- uint32_t alignment;
AstNode *set_global_section_node;
Buf *section_name;
AstNode *set_global_linkage_node;
@@ -1187,8 +1200,7 @@ enum BuiltinFnId {
BuiltinFnIdMemcpy,
BuiltinFnIdMemset,
BuiltinFnIdSizeof,
- BuiltinFnIdPreferredAlignOf,
- BuiltinFnIdAbiAlignOf,
+ BuiltinFnIdAlignOf,
BuiltinFnIdMaxValue,
BuiltinFnIdMinValue,
BuiltinFnIdMemberCount,
@@ -1224,7 +1236,6 @@ enum BuiltinFnId {
BuiltinFnIdSetFloatMode,
BuiltinFnIdTypeName,
BuiltinFnIdCanImplicitCast,
- BuiltinFnIdSetGlobalAlign,
BuiltinFnIdSetGlobalSection,
BuiltinFnIdSetGlobalLinkage,
BuiltinFnIdPanic,
@@ -1277,6 +1288,7 @@ struct TypeId {
TypeTableEntry *child_type;
bool is_const;
bool is_volatile;
+ uint32_t alignment;
uint32_t bit_offset;
uint32_t unaligned_bit_count;
} pointer;
@@ -1392,7 +1404,7 @@ struct CodeGen {
struct {
TypeTableEntry *entry_bool;
- TypeTableEntry *entry_int[2][10]; // [signed,unsigned][3,4,5,6,7,8,16,32,64,128]
+ TypeTableEntry *entry_int[2][11]; // [signed,unsigned][2,3,4,5,6,7,8,16,32,64,128]
TypeTableEntry *entry_c_int[CIntTypeCount];
TypeTableEntry *entry_c_longdouble;
TypeTableEntry *entry_c_void;
@@ -1547,6 +1559,8 @@ struct CodeGen {
ZigList<FnTableEntry *> inline_fns;
ZigList<AstNode *> tld_ref_source_node_stack;
+
+ TypeTableEntry *align_amt_type;
};
enum VarLinkage {
@@ -1575,6 +1589,7 @@ struct VariableTableEntry {
size_t ref_count;
VarLinkage linkage;
IrInstruction *decl_instruction;
+ uint32_t align_bytes;
};
struct ErrorTableEntry {
@@ -1808,8 +1823,7 @@ enum IrInstructionId {
IrInstructionIdBreakpoint,
IrInstructionIdReturnAddress,
IrInstructionIdFrameAddress,
- IrInstructionIdPreferredAlignOf,
- IrInstructionIdAbiAlignOf,
+ IrInstructionIdAlignOf,
IrInstructionIdOverflowOp,
IrInstructionIdTestErr,
IrInstructionIdUnwrapErrCode,
@@ -1831,7 +1845,6 @@ enum IrInstructionId {
IrInstructionIdCheckStatementIsVoid,
IrInstructionIdTypeName,
IrInstructionIdCanImplicitCast,
- IrInstructionIdSetGlobalAlign,
IrInstructionIdSetGlobalSection,
IrInstructionIdSetGlobalLinkage,
IrInstructionIdDeclRef,
@@ -1841,6 +1854,7 @@ enum IrInstructionId {
IrInstructionIdOffsetOf,
IrInstructionIdTypeId,
IrInstructionIdSetEvalBranchQuota,
+ IrInstructionIdPtrTypeOf,
};
struct IrInstruction {
@@ -1976,6 +1990,7 @@ struct IrInstructionDeclVar {
VariableTableEntry *var;
IrInstruction *var_type;
+ IrInstruction *align_value;
IrInstruction *init_value;
};
@@ -2152,7 +2167,9 @@ struct IrInstructionArrayType {
struct IrInstructionSliceType {
IrInstruction base;
+ IrInstruction *align_value;
bool is_const;
+ bool is_volatile;
IrInstruction *child_type;
};
@@ -2393,13 +2410,7 @@ struct IrInstructionOverflowOp {
TypeTableEntry *result_ptr_type;
};
-struct IrInstructionPreferredAlignOf {
- IrInstruction base;
-
- IrInstruction *type_value;
-};
-
-struct IrInstructionAbiAlignOf {
+struct IrInstructionAlignOf {
IrInstruction base;
IrInstruction *type_value;
@@ -2554,13 +2565,6 @@ struct IrInstructionCanImplicitCast {
IrInstruction *target_value;
};
-struct IrInstructionSetGlobalAlign {
- IrInstruction base;
-
- Tld *tld;
- IrInstruction *value;
-};
-
struct IrInstructionSetGlobalSection {
IrInstruction base;
@@ -2622,6 +2626,17 @@ struct IrInstructionSetEvalBranchQuota {
IrInstruction *new_quota;
};
+struct IrInstructionPtrTypeOf {
+ IrInstruction base;
+
+ IrInstruction *align_value;
+ IrInstruction *child_type;
+ uint32_t bit_offset_start;
+ uint32_t bit_offset_end;
+ bool is_const;
+ bool is_volatile;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
src/analyze.cpp
@@ -320,17 +320,21 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
}
TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
- bool is_volatile, uint32_t bit_offset, uint32_t unaligned_bit_count)
+ bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
{
assert(child_type->id != TypeTableEntryIdInvalid);
TypeId type_id = {};
TypeTableEntry **parent_pointer = nullptr;
- if (unaligned_bit_count != 0 || is_volatile) {
+ uint32_t abi_alignment;
+ if (unaligned_bit_count != 0 || is_volatile ||
+ byte_alignment != (abi_alignment = get_abi_alignment(g, child_type)))
+ {
type_id.id = TypeTableEntryIdPointer;
type_id.data.pointer.child_type = child_type;
type_id.data.pointer.is_const = is_const;
type_id.data.pointer.is_volatile = is_volatile;
+ type_id.data.pointer.alignment = byte_alignment;
type_id.data.pointer.bit_offset = bit_offset;
type_id.data.pointer.unaligned_bit_count = unaligned_bit_count;
@@ -352,11 +356,14 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
const char *const_str = is_const ? "const " : "";
const char *volatile_str = is_volatile ? "volatile " : "";
buf_resize(&entry->name, 0);
- if (unaligned_bit_count == 0) {
+ if (unaligned_bit_count == 0 && byte_alignment == abi_alignment) {
buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
+ } else if (unaligned_bit_count == 0) {
+ buf_appendf(&entry->name, "&align %" PRIu32 " %s%s%s", byte_alignment,
+ const_str, volatile_str, buf_ptr(&child_type->name));
} else {
- buf_appendf(&entry->name, "&:%" PRIu32 ":%" PRIu32 " %s%s%s", bit_offset,
- bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
+ buf_appendf(&entry->name, "&align %" PRIu32 ":%" PRIu32 ":%" PRIu32 " %s%s%s", byte_alignment,
+ bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
}
assert(child_type->id != TypeTableEntryIdInvalid);
@@ -364,20 +371,29 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
entry->zero_bits = !type_has_bits(child_type);
if (!entry->zero_bits) {
- entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
+ assert(byte_alignment > 0);
+ if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != abi_alignment) {
+ TypeTableEntry *peer_type = get_pointer_to_type(g, child_type, false);
+ entry->type_ref = peer_type->type_ref;
+ entry->di_type = peer_type->di_type;
+ } else {
+ entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
- uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
- assert(child_type->di_type);
- entry->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, child_type->di_type,
- debug_size_in_bits, debug_align_in_bits, buf_ptr(&entry->name));
+ uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
+ uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref);
+ assert(child_type->di_type);
+ entry->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, child_type->di_type,
+ debug_size_in_bits, debug_align_in_bits, buf_ptr(&entry->name));
+ }
} else {
+ assert(byte_alignment == 0);
entry->di_type = g->builtin_types.entry_void->di_type;
}
entry->data.pointer.child_type = child_type;
entry->data.pointer.is_const = is_const;
entry->data.pointer.is_volatile = is_volatile;
+ entry->data.pointer.alignment = byte_alignment;
entry->data.pointer.bit_offset = bit_offset;
entry->data.pointer.unaligned_bit_count = unaligned_bit_count;
@@ -390,7 +406,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
}
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
- return get_pointer_to_type_extra(g, child_type, is_const, false, 0, 0);
+ return get_pointer_to_type_extra(g, child_type, is_const, false, get_abi_alignment(g, child_type), 0, 0);
}
TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
@@ -592,11 +608,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
return entry;
}
-static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type,
- bool is_const, TypeTableEntry *entry)
-{
- TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
-
+static void slice_type_common_init(CodeGen *g, TypeTableEntry *pointer_type, TypeTableEntry *entry) {
unsigned element_count = 2;
entry->data.structure.layout = ContainerLayoutAuto;
entry->data.structure.is_slice = true;
@@ -612,156 +624,167 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type,
entry->data.structure.fields[slice_len_index].src_index = slice_len_index;
entry->data.structure.fields[slice_len_index].gen_index = 1;
- assert(type_has_zero_bits_known(child_type));
- if (child_type->zero_bits) {
+ assert(type_has_zero_bits_known(pointer_type->data.pointer.child_type));
+ if (pointer_type->data.pointer.child_type->zero_bits) {
entry->data.structure.gen_field_count = 1;
entry->data.structure.fields[slice_ptr_index].gen_index = SIZE_MAX;
entry->data.structure.fields[slice_len_index].gen_index = 0;
}
}
-TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
- assert(child_type->id != TypeTableEntryIdInvalid);
- TypeTableEntry **parent_pointer = &child_type->slice_parent[(is_const ? 1 : 0)];
+TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type) {
+ assert(ptr_type->id == TypeTableEntryIdPointer);
+ TypeTableEntry **parent_pointer = &ptr_type->data.pointer.slice_parent;
if (*parent_pointer) {
return *parent_pointer;
- } else if (is_const) {
- TypeTableEntry *var_peer = get_slice_type(g, child_type, false);
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
- entry->is_copyable = true;
+ }
- buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
+ entry->is_copyable = true;
- slice_type_common_init(g, child_type, is_const, entry);
+ // replace the & with [] to go from a ptr type name to a slice type name
+ buf_resize(&entry->name, 0);
+ buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + 1);
- entry->type_ref = var_peer->type_ref;
- entry->di_type = var_peer->di_type;
+ TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
+ uint32_t abi_alignment;
+ if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
+ ptr_type->data.pointer.alignment != (abi_alignment = get_abi_alignment(g, child_type)))
+ {
+ TypeTableEntry *peer_ptr_type = get_pointer_to_type(g, child_type, false);
+ TypeTableEntry *peer_slice_type = get_slice_type(g, peer_ptr_type);
+
+ slice_type_common_init(g, ptr_type, entry);
+
+ entry->type_ref = peer_slice_type->type_ref;
+ entry->di_type = peer_slice_type->di_type;
entry->data.structure.complete = true;
entry->data.structure.zero_bits_known = true;
+ entry->data.structure.abi_alignment = peer_slice_type->data.structure.abi_alignment;
*parent_pointer = entry;
return entry;
- } else {
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
- entry->is_copyable = true;
-
- // If the child type is []const T then we need to make sure the type ref
- // and debug info is the same as if the child type were []T.
- if (is_slice(child_type)) {
- TypeTableEntry *ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
- assert(ptr_type->id == TypeTableEntryIdPointer);
- if (ptr_type->data.pointer.is_const) {
- TypeTableEntry *non_const_child_type = get_slice_type(g,
- ptr_type->data.pointer.child_type, false);
- TypeTableEntry *var_peer = get_slice_type(g, non_const_child_type, false);
-
- entry->type_ref = var_peer->type_ref;
- entry->di_type = var_peer->di_type;
- }
+ }
+
+ // If the child type is []const T then we need to make sure the type ref
+ // and debug info is the same as if the child type were []T.
+ if (is_slice(child_type)) {
+ TypeTableEntry *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(child_ptr_type->id == TypeTableEntryIdPointer);
+ TypeTableEntry *grand_child_type = child_ptr_type->data.pointer.child_type;
+ if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
+ child_ptr_type->data.pointer.alignment != get_abi_alignment(g, grand_child_type))
+ {
+ TypeTableEntry *bland_child_ptr_type = get_pointer_to_type(g, grand_child_type, false);
+ TypeTableEntry *bland_child_slice = get_slice_type(g, bland_child_ptr_type);
+ TypeTableEntry *peer_ptr_type = get_pointer_to_type(g, bland_child_slice, false);
+ TypeTableEntry *peer_slice_type = get_slice_type(g, peer_ptr_type);
+
+ entry->type_ref = peer_slice_type->type_ref;
+ entry->di_type = peer_slice_type->di_type;
+ entry->data.structure.abi_alignment = peer_slice_type->data.structure.abi_alignment;
}
+ }
- buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name));
+ slice_type_common_init(g, ptr_type, entry);
- slice_type_common_init(g, child_type, is_const, entry);
+ if (!entry->type_ref) {
+ entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name));
- if (!entry->type_ref) {
- entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name));
+ ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
+ ZigLLVMDIFile *di_file = nullptr;
+ unsigned line = 0;
+ entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
+ ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
+ compile_unit_scope, di_file, line);
- ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
- ZigLLVMDIFile *di_file = nullptr;
- unsigned line = 0;
- entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
- ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
- compile_unit_scope, di_file, line);
+ if (child_type->zero_bits) {
+ LLVMTypeRef element_types[] = {
+ g->builtin_types.entry_usize->type_ref,
+ };
+ LLVMStructSetBody(entry->type_ref, element_types, 1, false);
- if (child_type->zero_bits) {
- LLVMTypeRef element_types[] = {
- g->builtin_types.entry_usize->type_ref,
- };
- LLVMStructSetBody(entry->type_ref, element_types, 1, false);
-
- TypeTableEntry *usize_type = g->builtin_types.entry_usize;
- uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, usize_type->type_ref);
- uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, usize_type->type_ref);
- uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
-
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
- uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
-
- ZigLLVMDIType *di_element_types[] = {
- ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
- "len", di_file, line,
- len_debug_size_in_bits,
- len_debug_align_in_bits,
- len_offset_in_bits,
- 0, usize_type->di_type),
- };
- ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
- compile_unit_scope,
- buf_ptr(&entry->name),
- di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
- nullptr, di_element_types, 1, 0, nullptr, "");
-
- ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
- entry->di_type = replacement_di_type;
- } else {
- TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
+ TypeTableEntry *usize_type = g->builtin_types.entry_usize;
+ uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, usize_type->type_ref);
+ uint64_t len_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, usize_type->type_ref);
+ uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
- unsigned element_count = 2;
- LLVMTypeRef element_types[] = {
- pointer_type->type_ref,
- g->builtin_types.entry_usize->type_ref,
- };
- LLVMStructSetBody(entry->type_ref, element_types, element_count, false);
-
-
- uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, pointer_type->type_ref);
- uint64_t ptr_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, pointer_type->type_ref);
- uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
-
- TypeTableEntry *usize_type = g->builtin_types.entry_usize;
- uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, usize_type->type_ref);
- uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, usize_type->type_ref);
- uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1);
-
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
- uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
-
- ZigLLVMDIType *di_element_types[] = {
- ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
- "ptr", di_file, line,
- ptr_debug_size_in_bits,
- ptr_debug_align_in_bits,
- ptr_offset_in_bits,
- 0, pointer_type->di_type),
- ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
- "len", di_file, line,
- len_debug_size_in_bits,
- len_debug_align_in_bits,
- len_offset_in_bits,
- 0, usize_type->di_type),
- };
- ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
- compile_unit_scope,
- buf_ptr(&entry->name),
- di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
- nullptr, di_element_types, 2, 0, nullptr, "");
-
- ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
- entry->di_type = replacement_di_type;
- }
- }
+ uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
+ uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref);
+ ZigLLVMDIType *di_element_types[] = {
+ ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
+ "len", di_file, line,
+ len_debug_size_in_bits,
+ len_debug_align_in_bits,
+ len_offset_in_bits,
+ 0, usize_type->di_type),
+ };
+ ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+ compile_unit_scope,
+ buf_ptr(&entry->name),
+ di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
+ nullptr, di_element_types, 1, 0, nullptr, "");
- entry->data.structure.complete = true;
- entry->data.structure.zero_bits_known = true;
+ ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
+ entry->di_type = replacement_di_type;
- *parent_pointer = entry;
- return entry;
+ entry->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, usize_type->type_ref);
+ } else {
+ unsigned element_count = 2;
+ LLVMTypeRef element_types[] = {
+ ptr_type->type_ref,
+ g->builtin_types.entry_usize->type_ref,
+ };
+ LLVMStructSetBody(entry->type_ref, element_types, element_count, false);
+
+
+ uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, ptr_type->type_ref);
+ uint64_t ptr_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, ptr_type->type_ref);
+ uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
+
+ TypeTableEntry *usize_type = g->builtin_types.entry_usize;
+ uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, usize_type->type_ref);
+ uint64_t len_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, usize_type->type_ref);
+ uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1);
+
+ uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
+ uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref);
+
+ ZigLLVMDIType *di_element_types[] = {
+ ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
+ "ptr", di_file, line,
+ ptr_debug_size_in_bits,
+ ptr_debug_align_in_bits,
+ ptr_offset_in_bits,
+ 0, ptr_type->di_type),
+ ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
+ "len", di_file, line,
+ len_debug_size_in_bits,
+ len_debug_align_in_bits,
+ len_offset_in_bits,
+ 0, usize_type->di_type),
+ };
+ ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+ compile_unit_scope,
+ buf_ptr(&entry->name),
+ di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
+ nullptr, di_element_types, 2, 0, nullptr, "");
+
+ ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
+ entry->di_type = replacement_di_type;
+
+ entry->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref);
+ }
}
+
+
+ entry->data.structure.complete = true;
+ entry->data.structure.zero_bits_known = true;
+
+ *parent_pointer = entry;
+ return entry;
}
TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name) {
@@ -1273,26 +1296,24 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
continue;
uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
- uint64_t preferred_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, field_type->type_ref);
+ uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
assert(store_size_in_bits > 0);
- assert(preferred_align_in_bits > 0);
+ assert(abi_align_in_bits > 0);
union_inner_di_types[type_enum_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(enum_type->di_type), buf_ptr(type_enum_field->name),
import->di_file, (unsigned)(field_node->line + 1),
store_size_in_bits,
- preferred_align_in_bits,
+ abi_align_in_bits,
0,
0, field_type->di_type);
biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits);
- if (!most_aligned_union_member ||
- preferred_align_in_bits > biggest_align_in_bits)
- {
+ if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) {
most_aligned_union_member = field_type;
- biggest_align_in_bits = preferred_align_in_bits;
+ biggest_align_in_bits = abi_align_in_bits;
size_of_most_aligned_member_in_bits = store_size_in_bits;
}
}
@@ -1306,7 +1327,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
enum_type->data.enumeration.tag_type = tag_type_entry;
- uint64_t align_of_tag_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
+ uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
if (most_aligned_union_member) {
// create llvm type for union
@@ -1328,7 +1349,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
}
enum_type->data.enumeration.union_type_ref = union_type_ref;
- assert(8*LLVMPreferredAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
+ assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
if (align_of_tag_in_bits >= biggest_align_in_bits) {
@@ -1347,7 +1368,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
// create debug type for tag
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
import->di_file, (unsigned)(decl_node->line + 1),
@@ -1405,7 +1426,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
// create debug type for tag
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
import->di_file, (unsigned)(decl_node->line + 1),
@@ -1497,7 +1518,7 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
TypeTableEntry *field_type = type_struct_field->type_entry;
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
- uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_type->type_ref);
+ uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
uint64_t debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref, i);
di_element_types[i] = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
@@ -1522,6 +1543,7 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type);
struct_type->di_type = replacement_di_type;
+ struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, struct_type->type_ref);
return struct_type;
}
@@ -1663,6 +1685,10 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
struct_type->data.structure.gen_field_count = (uint32_t)gen_field_count;
LLVMStructSetBody(struct_type->type_ref, element_types, (unsigned)gen_field_count, packed);
+
+ // if you hit this assert then probably this type or a related type didn't
+ // get ensure_complete_type called on it before using it with something that
+ // requires a complete type
assert(LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref) > 0);
ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
@@ -1760,6 +1786,8 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
+ uint32_t biggest_align_bytes = 0;
+
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
uint32_t gen_field_index = 0;
@@ -1782,12 +1810,22 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
type_enum_field->gen_index = gen_field_index;
gen_field_index += 1;
+
+ uint32_t field_align_bytes = get_abi_alignment(g, field_type);
+ if (field_align_bytes > biggest_align_bytes) {
+ biggest_align_bytes = field_align_bytes;
+ }
}
enum_type->data.enumeration.zero_bits_loop_flag = false;
enum_type->data.enumeration.gen_field_count = gen_field_index;
enum_type->zero_bits = (gen_field_index == 0 && field_count < 2);
enum_type->data.enumeration.zero_bits_known = true;
+
+ // also compute abi_alignment
+ TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
+ uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
+ enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
}
static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
@@ -1797,7 +1835,19 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
return;
if (struct_type->data.structure.zero_bits_loop_flag) {
+ // If we get here it's due to recursion. From this we conclude that the struct is
+ // not zero bits, and if abi_alignment == 0 we further conclude that the first field
+ // is a pointer to this very struct, or a function pointer with parameters that
+ // reference such a type.
struct_type->data.structure.zero_bits_known = true;
+ if (struct_type->data.structure.abi_alignment == 0) {
+ if (struct_type->data.structure.layout == ContainerLayoutPacked) {
+ struct_type->data.structure.abi_alignment = 1;
+ } else {
+ struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref,
+ LLVMPointerType(LLVMInt8Type(), 0));
+ }
+ }
return;
}
@@ -1833,6 +1883,17 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
if (!type_has_bits(field_type))
continue;
+ if (gen_field_index == 0) {
+ if (struct_type->data.structure.layout == ContainerLayoutPacked) {
+ struct_type->data.structure.abi_alignment = 1;
+ } else {
+ // Alignment of structs is the alignment of the first field, for now.
+ // TODO change this when we re-order struct fields (issue #168)
+ struct_type->data.structure.abi_alignment = get_abi_alignment(g, field_type);
+ assert(struct_type->data.structure.abi_alignment != 0);
+ }
+ }
+
type_struct_field->gen_index = gen_field_index;
gen_field_index += 1;
}
@@ -1925,7 +1986,8 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
if (fn_type_id->param_count != 1) {
return wrong_panic_prototype(g, proto_node, fn_type);
}
- TypeTableEntry *const_u8_slice = get_slice_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *const_u8_ptr = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *const_u8_slice = get_slice_type(g, const_u8_ptr);
if (fn_type_id->param_info[0].type != const_u8_slice) {
return wrong_panic_prototype(g, proto_node, fn_type);
}
@@ -1946,6 +2008,25 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) {
return g->test_fn_type;
}
+static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) {
+ IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
+ if (type_is_invalid(align_result->value.type))
+ return false;
+
+ uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint);
+ if (align_bytes == 0) {
+ add_node_error(g, node, buf_sprintf("alignment must be >= 1"));
+ return false;
+ }
+ if (!is_power_of_2(align_bytes)) {
+ add_node_error(g, node, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
+ return false;
+ }
+
+ *result = align_bytes;
+ return true;
+}
+
static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
ImportTableEntry *import = tld_fn->base.import;
AstNode *source_node = tld_fn->base.source_node;
@@ -1982,6 +2063,16 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
return;
}
+ if (fn_proto->align_expr != nullptr) {
+ if (!analyze_const_align(g, tld_fn->base.parent_scope, fn_proto->align_expr,
+ &fn_table_entry->align_bytes))
+ {
+ fn_table_entry->type_entry = g->builtin_types.entry_invalid;
+ tld_fn->base.resolution = TldResolutionInvalid;
+ return;
+ }
+ }
+
if (!fn_table_entry->type_entry->data.fn.is_generic) {
g->fn_protos.append(fn_table_entry);
@@ -2149,6 +2240,7 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
tld_var->var->value = value;
+ tld_var->var->align_bytes = get_abi_alignment(g, value->type);
}
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
@@ -2236,6 +2328,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeThisLiteral:
case NodeTypeSymbol:
case NodeTypePrefixOpExpr:
+ case NodeTypeAddrOfExpr:
case NodeTypeIfBoolExpr:
case NodeTypeWhileExpr:
case NodeTypeForExpr:
@@ -2331,6 +2424,7 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent
variable_entry->shadowable = false;
variable_entry->mem_slot_index = SIZE_MAX;
variable_entry->src_arg_index = SIZE_MAX;
+ variable_entry->align_bytes = get_abi_alignment(g, value->type);
assert(name);
@@ -2389,7 +2483,8 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent
}
static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
- AstNodeVariableDeclaration *var_decl = &tld_var->base.source_node->data.variable_declaration;
+ AstNode *source_node = tld_var->base.source_node;
+ AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration;
bool is_const = var_decl->is_const;
bool is_export = (tld_var->base.visib_mod == VisibModExport);
@@ -2401,8 +2496,6 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
explicit_type = validate_var_type(g, var_decl->type, proposed_type);
}
- AstNode *source_node = tld_var->base.source_node;
-
if (is_export && is_extern) {
add_node_error(g, source_node, buf_sprintf("variable is both export and extern"));
}
@@ -2458,6 +2551,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
is_const, init_val, &tld_var->base);
tld_var->var->linkage = linkage;
+ if (var_decl->align_expr != nullptr) {
+ if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) {
+ tld_var->var->value->type = g->builtin_types.entry_invalid;
+ }
+ }
+
g->global_vars.append(tld_var);
}
@@ -3129,26 +3228,28 @@ void semantic_analyze(CodeGen *g) {
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
size_t index;
- if (size_in_bits == 3) {
+ if (size_in_bits == 2) {
index = 0;
- } else if (size_in_bits == 4) {
+ } else if (size_in_bits == 3) {
index = 1;
- } else if (size_in_bits == 5) {
+ } else if (size_in_bits == 4) {
index = 2;
- } else if (size_in_bits == 6) {
+ } else if (size_in_bits == 5) {
index = 3;
- } else if (size_in_bits == 7) {
+ } else if (size_in_bits == 6) {
index = 4;
- } else if (size_in_bits == 8) {
+ } else if (size_in_bits == 7) {
index = 5;
- } else if (size_in_bits == 16) {
+ } else if (size_in_bits == 8) {
index = 6;
- } else if (size_in_bits == 32) {
+ } else if (size_in_bits == 16) {
index = 7;
- } else if (size_in_bits == 64) {
+ } else if (size_in_bits == 32) {
index = 8;
- } else if (size_in_bits == 128) {
+ } else if (size_in_bits == 64) {
index = 9;
+ } else if (size_in_bits == 128) {
+ index = 10;
} else {
return nullptr;
}
@@ -3723,8 +3824,10 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
{
assert(array_val->type->id == TypeTableEntryIdArray);
+ TypeTableEntry *ptr_type = get_pointer_to_type(g, array_val->type->data.array.child_type, is_const);
+
const_val->special = ConstValSpecialStatic;
- const_val->type = get_slice_type(g, array_val->type->data.array.child_type, is_const);
+ const_val->type = get_slice_type(g, ptr_type);
const_val->data.x_struct.fields = create_const_vals(2);
init_const_ptr_array(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const);
@@ -4342,14 +4445,15 @@ uint32_t type_id_hash(TypeId x) {
return hash_ptr(x.data.pointer.child_type) +
(x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
(x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) +
- (((uint32_t)x.data.pointer.bit_offset) * (uint32_t)2639019452) +
- (((uint32_t)x.data.pointer.unaligned_bit_count) * (uint32_t)529908881);
+ (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) +
+ (((uint32_t)x.data.pointer.bit_offset) ^ (uint32_t)2639019452) +
+ (((uint32_t)x.data.pointer.unaligned_bit_count) ^ (uint32_t)529908881);
case TypeTableEntryIdArray:
return hash_ptr(x.data.array.child_type) +
- ((uint32_t)x.data.array.size * (uint32_t)2122979968);
+ ((uint32_t)x.data.array.size ^ (uint32_t)2122979968);
case TypeTableEntryIdInt:
return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) +
- (((uint32_t)x.data.integer.bit_count) * (uint32_t)2998081557);
+ (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557);
}
zig_unreachable();
}
@@ -4387,6 +4491,7 @@ bool type_id_eql(TypeId a, TypeId b) {
return a.data.pointer.child_type == b.data.pointer.child_type &&
a.data.pointer.is_const == b.data.pointer.is_const &&
a.data.pointer.is_volatile == b.data.pointer.is_volatile &&
+ a.data.pointer.alignment == b.data.pointer.alignment &&
a.data.pointer.bit_offset == b.data.pointer.bit_offset &&
a.data.pointer.unaligned_bit_count == b.data.pointer.unaligned_bit_count;
case TypeTableEntryIdArray:
@@ -4692,3 +4797,30 @@ void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name) {
}
link_lib->symbols.append(symbol_name);
}
+
+uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
+ type_ensure_zero_bits_known(g, type_entry);
+ if (type_entry->zero_bits) return 0;
+
+ // We need to make this function work without requiring ensure_complete_type
+ // so that we can have structs with fields that are pointers to their own type.
+ if (type_entry->id == TypeTableEntryIdStruct) {
+ assert(type_entry->data.structure.abi_alignment != 0);
+ return type_entry->data.structure.abi_alignment;
+ } else if (type_entry->id == TypeTableEntryIdEnum) {
+ assert(type_entry->data.enumeration.abi_alignment != 0);
+ return type_entry->data.enumeration.abi_alignment;
+ } else if (type_entry->id == TypeTableEntryIdUnion) {
+ zig_panic("TODO");
+ } else {
+ return LLVMABIAlignmentOfType(g->target_data_ref, type_entry->type_ref);
+ }
+}
+
+TypeTableEntry *get_align_amt_type(CodeGen *g) {
+ if (g->align_amt_type == nullptr) {
+ // according to LLVM the maximum alignment is 1 << 29.
+ g->align_amt_type = get_int_type(g, false, 29);
+ }
+ return g->align_amt_type;
+}
src/analyze.hpp
@@ -16,7 +16,7 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
- bool is_volatile, uint32_t bit_offset, uint32_t unaligned_bit_count);
+ bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count);
uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry);
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_bits);
@@ -26,7 +26,7 @@ TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
-TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
+TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type);
TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
AstNode *decl_node, const char *name, ContainerLayout layout);
TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
@@ -171,4 +171,7 @@ bool calling_convention_does_first_arg_return(CallingConvention cc);
LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name);
+uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry);
+TypeTableEntry *get_align_amt_type(CodeGen *g);
+
#endif
src/ast_render.cpp
@@ -65,10 +65,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
case PrefixOpNegationWrap: return "-%";
case PrefixOpBoolNot: return "!";
case PrefixOpBinNot: return "~";
- case PrefixOpAddressOf: return "&";
- case PrefixOpConstAddressOf: return "&const ";
- case PrefixOpVolatileAddressOf: return "&volatile ";
- case PrefixOpConstVolatileAddressOf: return "&const volatile ";
case PrefixOpDereference: return "*";
case PrefixOpMaybe: return "?";
case PrefixOpError: return "%";
@@ -192,6 +188,8 @@ static const char *node_type_str(NodeType node_type) {
return "Symbol";
case NodeTypePrefixOpExpr:
return "PrefixOpExpr";
+ case NodeTypeAddrOfExpr:
+ return "AddrOfExpr";
case NodeTypeUse:
return "Use";
case NodeTypeBoolLiteral:
@@ -583,6 +581,38 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
render_node_ungrouped(ar, node->data.prefix_op_expr.primary_expr);
break;
}
+ case NodeTypeAddrOfExpr:
+ {
+ fprintf(ar->f, "&");
+ if (node->data.addr_of_expr.align_expr != nullptr) {
+ fprintf(ar->f, "align ");
+ render_node_grouped(ar, node->data.addr_of_expr.align_expr);
+ if (node->data.addr_of_expr.bit_offset_start != nullptr) {
+ assert(node->data.addr_of_expr.bit_offset_end != nullptr);
+
+ Buf offset_start_buf = BUF_INIT;
+ buf_resize(&offset_start_buf, 0);
+ bigint_append_buf(&offset_start_buf, node->data.addr_of_expr.bit_offset_start, 10);
+
+ Buf offset_end_buf = BUF_INIT;
+ buf_resize(&offset_end_buf, 0);
+ bigint_append_buf(&offset_end_buf, node->data.addr_of_expr.bit_offset_end, 10);
+
+ fprintf(ar->f, ":%s:%s ", buf_ptr(&offset_start_buf), buf_ptr(&offset_end_buf));
+ } else {
+ fprintf(ar->f, " ");
+ }
+ }
+ if (node->data.addr_of_expr.is_const) {
+ fprintf(ar->f, "const ");
+ }
+ if (node->data.addr_of_expr.is_volatile) {
+ fprintf(ar->f, "volatile ");
+ }
+
+ render_node_ungrouped(ar, node->data.addr_of_expr.op_expr);
+ break;
+ }
case NodeTypeFnCallExpr:
{
if (node->data.fn_call_expr.is_builtin) {
src/codegen.cpp
@@ -350,6 +350,12 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
zig_unreachable();
}
+static uint32_t get_pref_fn_align(CodeGen *g, LLVMTypeRef fn_type_ref) {
+ uint32_t pref_align = LLVMPreferredAlignmentOfType(g->target_data_ref, fn_type_ref);
+ uint32_t abi_align = LLVMABIAlignmentOfType(g->target_data_ref, fn_type_ref);
+ return (pref_align > abi_align) ? pref_align : abi_align;
+}
+
static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (fn_table_entry->llvm_value)
return fn_table_entry->llvm_value;
@@ -442,14 +448,14 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (fn_table_entry->section_name) {
LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name));
}
- if (fn_table_entry->alignment) {
- LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->alignment);
- } else if (external_linkage) {
+ if (fn_table_entry->align_bytes > 0) {
+ LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes);
+ } else if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionUnspecified) {
LLVMSetAlignment(fn_table_entry->llvm_value,
- LLVMABIAlignmentOfType(g->target_data_ref, fn_table_entry->type_entry->data.fn.raw_type_ref));
+ get_pref_fn_align(g, fn_table_entry->type_entry->data.fn.raw_type_ref));
} else {
LLVMSetAlignment(fn_table_entry->llvm_value,
- LLVMPreferredAlignmentOfType(g->target_data_ref, fn_table_entry->type_entry->data.fn.raw_type_ref));
+ LLVMABIAlignmentOfType(g->target_data_ref, fn_table_entry->type_entry->data.fn.raw_type_ref));
}
return fn_table_entry->llvm_value;
@@ -604,13 +610,15 @@ static LLVMValueRef get_floor_ceil_fn(CodeGen *g, TypeTableEntry *type_entry, Zi
return fn_val;
}
-static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *type, bool is_volatile) {
+static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *type, TypeTableEntry *ptr_type) {
if (type_has_bits(type)) {
if (handle_is_ptr(type)) {
return ptr;
} else {
+ assert(ptr_type->id == TypeTableEntryIdPointer);
LLVMValueRef result = LLVMBuildLoad(g->builder, ptr, "");
- LLVMSetVolatile(result, is_volatile);
+ LLVMSetVolatile(result, ptr_type->data.pointer.is_volatile);
+ LLVMSetAlignment(result, ptr_type->data.pointer.alignment);
return result;
}
} else {
@@ -657,34 +665,6 @@ static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
return true;
}
-static bool is_array_of_at_least_n_bytes(CodeGen *g, TypeTableEntry *type_entry, uint32_t n) {
- if (type_entry->id != TypeTableEntryIdArray)
- return false;
-
- TypeTableEntry *child_type = type_entry->data.array.child_type;
- if (child_type->id != TypeTableEntryIdInt)
- return false;
-
- if (child_type != g->builtin_types.entry_u8)
- return false;
-
- if (type_entry->data.array.len < n)
- return false;
-
- return true;
-}
-
-static uint32_t get_type_alignment(CodeGen *g, TypeTableEntry *type_entry) {
- uint32_t alignment = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, type_entry->type_ref);
- uint32_t dbl_ptr_bytes = g->pointer_size_bytes * 2;
- if (is_array_of_at_least_n_bytes(g, type_entry, dbl_ptr_bytes)) {
- return (alignment < dbl_ptr_bytes) ? dbl_ptr_bytes : alignment;
- } else {
- return alignment;
- }
-}
-
-
static Buf *panic_msg_buf(PanicMsgId msg_id) {
switch (msg_id) {
case PanicMsgIdCount:
@@ -745,7 +725,8 @@ static void gen_panic_raw(CodeGen *g, LLVMValueRef msg_ptr, LLVMValueRef msg_len
}
static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
- TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *str_type = get_slice_type(g, ptr_type);
size_t ptr_index = str_type->data.structure.fields[slice_ptr_index].gen_index;
size_t len_index = str_type->data.structure.fields[slice_len_index].gen_index;
LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, msg_arg, (unsigned)ptr_index, "");
@@ -806,7 +787,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
LLVMSetLinkage(global_value, LLVMInternalLinkage);
LLVMSetGlobalConstant(global_value, false);
LLVMSetUnnamedAddr(global_value, true);
- LLVMSetAlignment(global_value, get_type_alignment(g, g->builtin_types.entry_u8));
+ LLVMSetAlignment(global_value, get_abi_alignment(g, g->builtin_types.entry_u8));
TypeTableEntry *usize = g->builtin_types.entry_usize;
LLVMValueRef full_buf_ptr_indices[] = {
@@ -833,7 +814,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
}
- LLVMSetAlignment(fn_val, LLVMPreferredAlignmentOfType(g->target_data_ref, fn_type_ref));
+ LLVMSetAlignment(fn_val, get_pref_fn_align(g, fn_type_ref));
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
@@ -1056,50 +1037,49 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {
}
}
-static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef dest,
- TypeTableEntry *type_entry)
-{
- assert(handle_is_ptr(type_entry));
-
- assert(LLVMGetTypeKind(LLVMTypeOf(src)) == LLVMPointerTypeKind);
- assert(LLVMGetTypeKind(LLVMTypeOf(dest)) == LLVMPointerTypeKind);
-
- LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
-
- LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, src, ptr_u8, "");
- LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, dest, ptr_u8, "");
-
- TypeTableEntry *usize = g->builtin_types.entry_usize;
- uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
- uint64_t align_bytes = get_type_alignment(g, type_entry);
- assert(size_bytes > 0);
- assert(align_bytes > 0);
-
- LLVMValueRef params[] = {
- dest_ptr, // dest pointer
- src_ptr, // source pointer
- LLVMConstInt(usize->type_ref, size_bytes, false),
- LLVMConstInt(LLVMInt32Type(), align_bytes, false),
- LLVMConstNull(LLVMInt1Type()), // is volatile
- };
-
- return LLVMBuildCall(g->builder, get_memcpy_fn_val(g), params, 5, "");
-}
-
static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *ptr_type,
LLVMValueRef value)
{
+ assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
if (!type_has_bits(child_type))
return nullptr;
- if (handle_is_ptr(child_type))
- return gen_struct_memcpy(g, value, ptr, child_type);
+ if (handle_is_ptr(child_type)) {
+ assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind);
+ assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind);
+
+ LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+
+ LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, value, ptr_u8, "");
+ LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
+
+ TypeTableEntry *usize = g->builtin_types.entry_usize;
+ uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref);
+ uint64_t align_bytes = ptr_type->data.pointer.alignment;
+ assert(size_bytes > 0);
+ assert(align_bytes > 0);
+
+ LLVMValueRef volatile_bit = ptr_type->data.pointer.is_volatile ?
+ LLVMConstAllOnes(LLVMInt1Type()) : LLVMConstNull(LLVMInt1Type());
+
+ LLVMValueRef params[] = {
+ dest_ptr, // dest pointer
+ src_ptr, // source pointer
+ LLVMConstInt(usize->type_ref, size_bytes, false),
+ LLVMConstInt(LLVMInt32Type(), align_bytes, false),
+ volatile_bit,
+ };
+
+ LLVMBuildCall(g->builder, get_memcpy_fn_val(g), params, 5, "");
+ return nullptr;
+ }
uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
if (unaligned_bit_count == 0) {
LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr);
+ LLVMSetAlignment(llvm_instruction, ptr_type->data.pointer.alignment);
LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
return nullptr;
}
@@ -1122,6 +1102,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry
LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, ored_value, ptr);
+ LLVMSetAlignment(llvm_instruction, ptr_type->data.pointer.alignment);
LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
return nullptr;
}
@@ -2010,23 +1991,24 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
if (have_init_expr) {
assert(var->value->type == init_value->value.type);
- gen_assign_raw(g, var->value_ref, get_pointer_to_type(g, var->value->type, false),
- ir_llvm_value(g, init_value));
+ TypeTableEntry *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
+ var->align_bytes, 0, 0);
+ gen_assign_raw(g, var->value_ref, var_ptr_type, ir_llvm_value(g, init_value));
} else {
- bool ignore_uninit = false;
- // handle runtime stack allocation
bool want_safe = ir_want_debug_safety(g, &decl_var_instruction->base);
- if (!ignore_uninit && want_safe) {
+ if (want_safe) {
TypeTableEntry *usize = g->builtin_types.entry_usize;
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref);
- uint64_t align_bytes = get_type_alignment(g, var->value->type);
+ assert(size_bytes > 0);
+
+ assert(var->align_bytes > 0);
// memset uninitialized memory to 0xa
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, "");
LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
- LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false);
+ LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), var->align_bytes, false);
LLVMValueRef params[] = {
dest_ptr,
fill_char,
@@ -2051,15 +2033,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
TypeTableEntry *ptr_type = instruction->ptr->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
- bool is_volatile = ptr_type->data.pointer.is_volatile;
uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
if (unaligned_bit_count == 0)
- return get_handle_value(g, ptr, child_type, is_volatile);
+ return get_handle_value(g, ptr, child_type, ptr_type);
assert(!handle_is_ptr(child_type));
LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
- LLVMSetVolatile(containing_int, is_volatile);
+ LLVMSetVolatile(containing_int, ptr_type->data.pointer.is_volatile);
uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
@@ -2097,9 +2078,8 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr);
TypeTableEntry *array_ptr_type = instruction->array_ptr->value.type;
assert(array_ptr_type->id == TypeTableEntryIdPointer);
- bool is_volatile = array_ptr_type->data.pointer.is_volatile;
TypeTableEntry *array_type = array_ptr_type->data.pointer.child_type;
- LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, is_volatile);
+ LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index);
assert(subscript_value);
@@ -2427,12 +2407,11 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
{
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
- bool is_volatile = ptr_type->data.pointer.is_volatile;
TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
assert(maybe_type->id == TypeTableEntryIdMaybe);
TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
- LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, is_volatile);
+ LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
@@ -2451,7 +2430,7 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
if (maybe_is_ptr) {
return maybe_ptr;
} else {
- LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, is_volatile);
+ LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, "");
}
}
@@ -2694,11 +2673,13 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrIns
LLVMValueRef is_volatile = ptr_type->data.pointer.is_volatile ?
LLVMConstAllOnes(LLVMInt1Type()) : LLVMConstNull(LLVMInt1Type());
+ LLVMValueRef align_val = LLVMConstInt(LLVMInt32Type(), ptr_type->data.pointer.alignment, false);
+
LLVMValueRef params[] = {
- dest_ptr_casted, // dest pointer
- char_val, // source pointer
- len_val, // byte count
- LLVMConstInt(LLVMInt32Type(), 1, false), // align in bytes
+ dest_ptr_casted,
+ char_val,
+ len_val,
+ align_val,
is_volatile,
};
@@ -2725,11 +2706,14 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
LLVMValueRef is_volatile = (dest_ptr_type->data.pointer.is_volatile || src_ptr_type->data.pointer.is_volatile) ?
LLVMConstAllOnes(LLVMInt1Type()) : LLVMConstNull(LLVMInt1Type());
+ uint32_t min_align_bytes = min(src_ptr_type->data.pointer.alignment, dest_ptr_type->data.pointer.alignment);
+ LLVMValueRef align_val = LLVMConstInt(LLVMInt32Type(), min_align_bytes, false);
+
LLVMValueRef params[] = {
- dest_ptr_casted, // dest pointer
- src_ptr_casted, // source pointer
- len_val, // byte count
- LLVMConstInt(LLVMInt32Type(), 1, false), // align in bytes
+ dest_ptr_casted,
+ src_ptr_casted,
+ len_val,
+ align_val,
is_volatile,
};
@@ -2743,9 +2727,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr);
TypeTableEntry *array_ptr_type = instruction->ptr->value.type;
assert(array_ptr_type->id == TypeTableEntryIdPointer);
- bool is_volatile = array_ptr_type->data.pointer.is_volatile;
TypeTableEntry *array_type = array_ptr_type->data.pointer.child_type;
- LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, is_volatile);
+ LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
@@ -2989,11 +2972,10 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) {
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
- bool is_volatile = ptr_type->data.pointer.is_volatile;
TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;
TypeTableEntry *child_type = err_union_type->data.error.child_type;
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
- LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, is_volatile);
+ LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
if (type_has_bits(child_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
@@ -3006,11 +2988,10 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
- bool is_volatile = ptr_type->data.pointer.is_volatile;
TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;
TypeTableEntry *child_type = err_union_type->data.error.child_type;
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
- LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, is_volatile);
+ LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on && g->error_decls.length > 1) {
LLVMValueRef err_val;
@@ -3123,7 +3104,8 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI
return enum_val;
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_type->data.enumeration.gen_tag_index, "");
- return get_handle_value(g, tag_field_ptr, tag_type, false);
+ TypeTableEntry *ptr_type = get_pointer_to_type(g, tag_type, false);
+ return get_handle_value(g, tag_field_ptr, tag_type, ptr_type);
}
static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {
@@ -3164,8 +3146,10 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
(unsigned)type_struct_field->gen_index, "");
LLVMValueRef value = ir_llvm_value(g, field->value);
+ uint32_t field_align_bytes = get_abi_alignment(g, type_struct_field->type_entry);
+
TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
- false, false,
+ false, false, field_align_bytes,
(uint32_t)type_struct_field->packed_bits_offset, (uint32_t)type_struct_field->unaligned_bit_count);
gen_assign_raw(g, field_ptr, ptr_type, value);
@@ -3243,15 +3227,13 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdEmbedFile:
case IrInstructionIdIntType:
case IrInstructionIdMemberCount:
- case IrInstructionIdPreferredAlignOf:
- case IrInstructionIdAbiAlignOf:
+ case IrInstructionIdAlignOf:
case IrInstructionIdFnProto:
case IrInstructionIdTestComptime:
case IrInstructionIdCheckSwitchProngs:
case IrInstructionIdCheckStatementIsVoid:
case IrInstructionIdTypeName:
case IrInstructionIdCanImplicitCast:
- case IrInstructionIdSetGlobalAlign:
case IrInstructionIdSetGlobalSection:
case IrInstructionIdSetGlobalLinkage:
case IrInstructionIdDeclRef:
@@ -3259,6 +3241,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdOffsetOf:
case IrInstructionIdTypeId:
case IrInstructionIdSetEvalBranchQuota:
+ case IrInstructionIdPtrTypeOf:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -3840,7 +3823,7 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const
LLVMSetLinkage(global_value, LLVMInternalLinkage);
LLVMSetGlobalConstant(global_value, true);
LLVMSetUnnamedAddr(global_value, true);
- LLVMSetAlignment(global_value, get_type_alignment(g, const_val->type));
+ LLVMSetAlignment(global_value, get_abi_alignment(g, const_val->type));
const_val->global_refs->llvm_global = global_value;
}
@@ -3856,8 +3839,8 @@ static void generate_error_name_table(CodeGen *g) {
assert(g->error_decls.length > 0);
- TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
- TypeTableEntry *u8_ptr_type = str_type->data.structure.fields[0].type_entry;
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
LLVMValueRef *values = allocate<LLVMValueRef>(g->error_decls.length);
values[0] = LLVMGetUndef(str_type->type_ref);
@@ -3893,8 +3876,8 @@ static void generate_error_name_table(CodeGen *g) {
}
static void generate_enum_name_tables(CodeGen *g) {
- TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
- TypeTableEntry *u8_ptr_type = str_type->data.structure.fields[0].type_entry;
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) {
TypeTableEntry *enum_tag_type = g->name_table_enums.at(enum_i);
@@ -3965,9 +3948,10 @@ static void gen_global_var(CodeGen *g, VariableTableEntry *var, LLVMValueRef ini
// TODO ^^ make an actual global variable
}
-static LLVMValueRef build_alloca(CodeGen *g, TypeTableEntry *type_entry, const char *name) {
+static LLVMValueRef build_alloca(CodeGen *g, TypeTableEntry *type_entry, const char *name, uint32_t alignment) {
+ assert(alignment > 0);
LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
- LLVMSetAlignment(result, get_type_alignment(g, type_entry));
+ LLVMSetAlignment(result, alignment);
return result;
}
@@ -4056,6 +4040,7 @@ static void do_code_gen(CodeGen *g) {
// TODO debug info for the extern variable
LLVMSetLinkage(global_value, LLVMExternalLinkage);
+ LLVMSetAlignment(global_value, var->align_bytes);
} else {
bool exported = (var->linkage == VarLinkageExport);
render_const_val(g, var->value);
@@ -4068,8 +4053,7 @@ static void do_code_gen(CodeGen *g) {
if (tld_var->section_name) {
LLVMSetSection(global_value, buf_ptr(tld_var->section_name));
}
- LLVMSetAlignment(global_value, tld_var->alignment ?
- tld_var->alignment : get_type_alignment(g, var->value->type));
+ LLVMSetAlignment(global_value, var->align_bytes);
// TODO debug info for function pointers
if (var->gen_is_const && var->value->type->id != TypeTableEntryIdFn) {
@@ -4189,7 +4173,7 @@ static void do_code_gen(CodeGen *g) {
} else {
zig_unreachable();
}
- *slot = build_alloca(g, slot_type, "");
+ *slot = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type));
}
ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
@@ -4207,7 +4191,7 @@ static void do_code_gen(CodeGen *g) {
continue;
if (var->src_arg_index == SIZE_MAX) {
- var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name));
+ var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
@@ -4227,7 +4211,7 @@ static void do_code_gen(CodeGen *g) {
var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index);
} else {
gen_type = var->value->type;
- var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name));
+ var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
}
if (var->decl_node) {
var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
@@ -4309,6 +4293,7 @@ static void do_code_gen(CodeGen *g) {
}
static const uint8_t int_sizes_in_bits[] = {
+ 2,
3,
4,
5,
@@ -4605,8 +4590,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);
create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);
- create_builtin_fn(g, BuiltinFnIdPreferredAlignOf, "preferredAlignOf", 1);
- create_builtin_fn(g, BuiltinFnIdAbiAlignOf, "cAbiAlignOf", 1);
+ create_builtin_fn(g, BuiltinFnIdAlignOf, "alignOf", 1);
create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1);
create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1);
create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
@@ -4634,7 +4618,6 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2);
create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2);
- create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1);
@@ -4989,7 +4972,8 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
exit(0);
}
- TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+ TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
TypeTableEntry *fn_type = get_test_fn_type(g);
const char *field_names[] = { "name", "func", };
src/ir.cpp
@@ -51,6 +51,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc
static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type);
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr);
+static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg);
ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
assert(const_val->type->id == TypeTableEntryIdPointer);
@@ -422,12 +423,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)
return IrInstructionIdFrameAddress;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionPreferredAlignOf *) {
- return IrInstructionIdPreferredAlignOf;
-}
-
-static constexpr IrInstructionId ir_instruction_id(IrInstructionAbiAlignOf *) {
- return IrInstructionIdAbiAlignOf;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {
+ return IrInstructionIdAlignOf;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionOverflowOp *) {
@@ -518,10 +515,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast
return IrInstructionIdCanImplicitCast;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalAlign *) {
- return IrInstructionIdSetGlobalAlign;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection *) {
return IrInstructionIdSetGlobalSection;
}
@@ -558,6 +551,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetEvalBranchQuo
return IrInstructionIdSetEvalBranchQuota;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeOf *) {
+ return IrInstructionIdPtrTypeOf;
+}
+
template<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -988,6 +985,24 @@ static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instru
return new_instruction;
}
+static IrInstruction *ir_build_ptr_type_of(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value,
+ uint32_t bit_offset_start, uint32_t bit_offset_end)
+{
+ IrInstructionPtrTypeOf *ptr_type_of_instruction = ir_build_instruction<IrInstructionPtrTypeOf>(irb, scope, source_node);
+ ptr_type_of_instruction->align_value = align_value;
+ ptr_type_of_instruction->child_type = child_type;
+ ptr_type_of_instruction->is_const = is_const;
+ ptr_type_of_instruction->is_volatile = is_volatile;
+ ptr_type_of_instruction->bit_offset_start = bit_offset_start;
+ ptr_type_of_instruction->bit_offset_end = bit_offset_end;
+
+ ir_ref_instruction(align_value, irb->current_basic_block);
+ ir_ref_instruction(child_type, irb->current_basic_block);
+
+ return &ptr_type_of_instruction->base;
+}
+
static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, IrInstruction *value) {
IrInstructionUnOp *br_instruction = ir_build_instruction<IrInstructionUnOp>(irb, scope, source_node);
br_instruction->op_id = op_id;
@@ -1112,26 +1127,28 @@ static IrInstruction *ir_build_store_ptr_from(IrBuilder *irb, IrInstruction *old
}
static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
- VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value)
+ VariableTableEntry *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value)
{
IrInstructionDeclVar *decl_var_instruction = ir_build_instruction<IrInstructionDeclVar>(irb, scope, source_node);
decl_var_instruction->base.value.special = ConstValSpecialStatic;
decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
decl_var_instruction->var = var;
decl_var_instruction->var_type = var_type;
+ decl_var_instruction->align_value = align_value;
decl_var_instruction->init_value = init_value;
if (var_type) ir_ref_instruction(var_type, irb->current_basic_block);
+ if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
ir_ref_instruction(init_value, irb->current_basic_block);
return &decl_var_instruction->base;
}
static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_instruction,
- VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value)
+ VariableTableEntry *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value)
{
IrInstruction *new_instruction = ir_build_var_decl(irb, old_instruction->scope,
- old_instruction->source_node, var, var_type, init_value);
+ old_instruction->source_node, var, var_type, align_value, init_value);
ir_link_new_instruction(new_instruction, old_instruction);
return new_instruction;
}
@@ -1221,14 +1238,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
-static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node, bool is_const,
- IrInstruction *child_type)
+static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value)
{
IrInstructionSliceType *instruction = ir_build_instruction<IrInstructionSliceType>(irb, scope, source_node);
instruction->is_const = is_const;
+ instruction->is_volatile = is_volatile;
instruction->child_type = child_type;
+ instruction->align_value = align_value;
ir_ref_instruction(child_type, irb->current_basic_block);
+ if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
return &instruction->base;
}
@@ -1810,17 +1830,8 @@ static IrInstruction *ir_build_overflow_op_from(IrBuilder *irb, IrInstruction *o
return new_instruction;
}
-static IrInstruction *ir_build_preferred_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
- IrInstructionPreferredAlignOf *instruction = ir_build_instruction<IrInstructionPreferredAlignOf>(irb, scope, source_node);
- instruction->type_value = type_value;
-
- ir_ref_instruction(type_value, irb->current_basic_block);
-
- return &instruction->base;
-}
-
-static IrInstruction *ir_build_abi_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
- IrInstructionAbiAlignOf *instruction = ir_build_instruction<IrInstructionAbiAlignOf>(irb, scope, source_node);
+static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
+ IrInstructionAlignOf *instruction = ir_build_instruction<IrInstructionAlignOf>(irb, scope, source_node);
instruction->type_value = type_value;
ir_ref_instruction(type_value, irb->current_basic_block);
@@ -2097,19 +2108,6 @@ static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, A
return &instruction->base;
}
-static IrInstruction *ir_build_set_global_align(IrBuilder *irb, Scope *scope, AstNode *source_node,
- Tld *tld, IrInstruction *value)
-{
- IrInstructionSetGlobalAlign *instruction = ir_build_instruction<IrInstructionSetGlobalAlign>(
- irb, scope, source_node);
- instruction->tld = tld;
- instruction->value = value;
-
- ir_ref_instruction(value, irb->current_basic_block);
-
- return &instruction->base;
-}
-
static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope, AstNode *source_node,
Tld *tld, IrInstruction *value)
{
@@ -2277,11 +2275,20 @@ static IrInstruction *ir_instruction_binop_get_dep(IrInstructionBinOp *instructi
}
static IrInstruction *ir_instruction_declvar_get_dep(IrInstructionDeclVar *instruction, size_t index) {
- switch (index) {
- case 0: return instruction->init_value;
- case 1: return instruction->var_type;
- default: return nullptr;
+ if (index == 0) return instruction->init_value;
+ index -= 1;
+
+ if (instruction->align_value != nullptr) {
+ if (index == 0) return instruction->align_value;
+ index -= 1;
+ }
+
+ if (instruction->var_type != nullptr) {
+ if (index == 0) return instruction->var_type;
+ index -= 1;
}
+
+ return nullptr;
}
static IrInstruction *ir_instruction_loadptr_get_dep(IrInstructionLoadPtr *instruction, size_t index) {
@@ -2671,14 +2678,7 @@ static IrInstruction *ir_instruction_frameaddress_get_dep(IrInstructionFrameAddr
return nullptr;
}
-static IrInstruction *ir_instruction_preferredalignof_get_dep(IrInstructionPreferredAlignOf *instruction, size_t index) {
- switch (index) {
- case 0: return instruction->type_value;
- default: return nullptr;
- }
-}
-
-static IrInstruction *ir_instruction_abialignof_get_dep(IrInstructionAbiAlignOf *instruction, size_t index) {
+static IrInstruction *ir_instruction_alignof_get_dep(IrInstructionAlignOf *instruction, size_t index) {
switch (index) {
case 0: return instruction->type_value;
default: return nullptr;
@@ -2854,13 +2854,6 @@ static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImp
}
}
-static IrInstruction *ir_instruction_setglobalalign_get_dep(IrInstructionSetGlobalAlign *instruction, size_t index) {
- switch (index) {
- case 0: return instruction->value;
- default: return nullptr;
- }
-}
-
static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGlobalSection *instruction, size_t index) {
switch (index) {
case 0: return instruction->value;
@@ -2924,6 +2917,14 @@ static IrInstruction *ir_instruction_setevalbranchquota_get_dep(IrInstructionSet
}
}
+static IrInstruction *ir_instruction_ptrtypeof_get_dep(IrInstructionPtrTypeOf *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->align_value;
+ case 1: return instruction->child_type;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -3056,10 +3057,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_returnaddress_get_dep((IrInstructionReturnAddress *) instruction, index);
case IrInstructionIdFrameAddress:
return ir_instruction_frameaddress_get_dep((IrInstructionFrameAddress *) instruction, index);
- case IrInstructionIdPreferredAlignOf:
- return ir_instruction_preferredalignof_get_dep((IrInstructionPreferredAlignOf *) instruction, index);
- case IrInstructionIdAbiAlignOf:
- return ir_instruction_abialignof_get_dep((IrInstructionAbiAlignOf *) instruction, index);
+ case IrInstructionIdAlignOf:
+ return ir_instruction_alignof_get_dep((IrInstructionAlignOf *) instruction, index);
case IrInstructionIdOverflowOp:
return ir_instruction_overflowop_get_dep((IrInstructionOverflowOp *) instruction, index);
case IrInstructionIdTestErr:
@@ -3102,8 +3101,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index);
case IrInstructionIdCanImplicitCast:
return ir_instruction_canimplicitcast_get_dep((IrInstructionCanImplicitCast *) instruction, index);
- case IrInstructionIdSetGlobalAlign:
- return ir_instruction_setglobalalign_get_dep((IrInstructionSetGlobalAlign *) instruction, index);
case IrInstructionIdSetGlobalSection:
return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index);
case IrInstructionIdSetGlobalLinkage:
@@ -3122,6 +3119,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_typeid_get_dep((IrInstructionTypeId *) instruction, index);
case IrInstructionIdSetEvalBranchQuota:
return ir_instruction_setevalbranchquota_get_dep((IrInstructionSetEvalBranchQuota *) instruction, index);
+ case IrInstructionIdPtrTypeOf:
+ return ir_instruction_ptrtypeof_get_dep((IrInstructionPtrTypeOf *) instruction, index);
}
zig_unreachable();
}
@@ -4286,23 +4285,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_return_address(irb, scope, node);
case BuiltinFnIdFrameAddress:
return ir_build_frame_address(irb, scope, node);
- case BuiltinFnIdPreferredAlignOf:
- {
- AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
- if (arg0_value == irb->codegen->invalid_instruction)
- return arg0_value;
-
- return ir_build_preferred_align_of(irb, scope, node, arg0_value);
- }
- case BuiltinFnIdAbiAlignOf:
+ case BuiltinFnIdAlignOf:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- return ir_build_abi_align_of(irb, scope, node, arg0_value);
+ return ir_build_align_of(irb, scope, node, arg0_value);
}
case BuiltinFnIdAddWithOverflow:
return ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd);
@@ -4335,7 +4325,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value);
}
- case BuiltinFnIdSetGlobalAlign:
case BuiltinFnIdSetGlobalSection:
case BuiltinFnIdSetGlobalLinkage:
{
@@ -4361,9 +4350,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- if (builtin_fn->id == BuiltinFnIdSetGlobalAlign) {
- return ir_build_set_global_align(irb, scope, node, tld, arg1_value);
- } else if (builtin_fn->id == BuiltinFnIdSetGlobalSection) {
+ if (builtin_fn->id == BuiltinFnIdSetGlobalSection) {
return ir_build_set_global_section(irb, scope, node, tld, arg1_value);
} else if (builtin_fn->id == BuiltinFnIdSetGlobalLinkage) {
return ir_build_set_global_linkage(irb, scope, node, tld, arg1_value);
@@ -4652,17 +4639,51 @@ static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *
return ir_build_ref(irb, scope, value->source_node, value, lval.is_const, lval.is_volatile);
}
-static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *node,
- bool is_const, bool is_volatile, LVal lval)
-{
- assert(node->type == NodeTypePrefixOpExpr);
- AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
+static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *node) {
+ assert(node->type == NodeTypeAddrOfExpr);
+ bool is_const = node->data.addr_of_expr.is_const;
+ bool is_volatile = node->data.addr_of_expr.is_volatile;
+ AstNode *expr_node = node->data.addr_of_expr.op_expr;
+ AstNode *align_expr = node->data.addr_of_expr.align_expr;
- IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, make_lval_addr(is_const, is_volatile));
- if (value == irb->codegen->invalid_instruction)
- return value;
+ if (align_expr == nullptr) {
+ return ir_gen_node_extra(irb, expr_node, scope, make_lval_addr(is_const, is_volatile));
+ }
+
+ IrInstruction *align_value = ir_gen_node(irb, align_expr, scope);
+ if (align_value == irb->codegen->invalid_instruction)
+ return align_value;
+
+ IrInstruction *child_type = ir_gen_node(irb, expr_node, scope);
+ if (child_type == irb->codegen->invalid_instruction)
+ return child_type;
+
+ uint32_t bit_offset_start = 0;
+ if (node->data.addr_of_expr.bit_offset_start != nullptr) {
+ if (!bigint_fits_in_bits(node->data.addr_of_expr.bit_offset_start, 32, false)) {
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, node->data.addr_of_expr.bit_offset_start, 10);
+ exec_add_error_node(irb->codegen, irb->exec, node,
+ buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
+ return irb->codegen->invalid_instruction;
+ }
+ bit_offset_start = bigint_as_unsigned(node->data.addr_of_expr.bit_offset_start);
+ }
+
+ uint32_t bit_offset_end = 0;
+ if (node->data.addr_of_expr.bit_offset_end != nullptr) {
+ if (!bigint_fits_in_bits(node->data.addr_of_expr.bit_offset_end, 32, false)) {
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, node->data.addr_of_expr.bit_offset_end, 10);
+ exec_add_error_node(irb->codegen, irb->exec, node,
+ buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
+ return irb->codegen->invalid_instruction;
+ }
+ bit_offset_end = bigint_as_unsigned(node->data.addr_of_expr.bit_offset_end);
+ }
- return ir_lval_wrap(irb, scope, value, lval);
+ return ir_build_ptr_type_of(irb, scope, node, child_type, is_const, is_volatile,
+ align_value, bit_offset_start, bit_offset_end);
}
static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
@@ -4725,14 +4746,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
case PrefixOpNegationWrap:
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
- case PrefixOpAddressOf:
- return ir_gen_address_of(irb, scope, node, false, false, lval);
- case PrefixOpConstAddressOf:
- return ir_gen_address_of(irb, scope, node, true, false, lval);
- case PrefixOpVolatileAddressOf:
- return ir_gen_address_of(irb, scope, node, false, true, lval);
- case PrefixOpConstVolatileAddressOf:
- return ir_gen_address_of(irb, scope, node, true, true, lval);
case PrefixOpDereference:
return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
case PrefixOpMaybe:
@@ -4822,11 +4835,18 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
return irb->codegen->invalid_instruction;
}
+ IrInstruction *align_value = nullptr;
+ if (variable_declaration->align_expr != nullptr) {
+ align_value = ir_gen_node(irb, variable_declaration->align_expr, scope);
+ if (align_value == irb->codegen->invalid_instruction)
+ return align_value;
+ }
+
IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope);
if (init_value == irb->codegen->invalid_instruction)
return init_value;
- IrInstruction *result = ir_build_var_decl(irb, scope, node, var, type_instruction, init_value);
+ IrInstruction *result = ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value);
var->decl_instruction = result;
return result;
}
@@ -4883,7 +4903,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
err_val_ptr, false);
IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);
- ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value);
+ ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
}
ZigList<IrInstruction *> incoming_values = {0};
@@ -4922,7 +4942,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
true, false, false, is_comptime);
Scope *err_scope = err_var->child_scope;
IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
- ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, err_var_value);
+ ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
else_result = ir_gen_node(irb, else_node, err_scope);
if (else_result == irb->codegen->invalid_instruction)
@@ -4964,7 +4984,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);
- ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value);
+ ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
ZigList<IrInstruction *> incoming_values = {0};
ZigList<IrBasicBlock *> incoming_blocks = {0};
@@ -5115,7 +5135,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
Scope *child_scope = elem_var->child_scope;
IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node);
- ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, undefined_value);
+ ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value);
IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var, false, false);
AstNode *index_var_source_node;
@@ -5133,7 +5153,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize);
IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
- ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, zero);
+ ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero);
IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var, false, false);
@@ -5254,12 +5274,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
AstNode *size_node = node->data.array_type.size;
AstNode *child_type_node = node->data.array_type.child_type;
bool is_const = node->data.array_type.is_const;
+ bool is_volatile = node->data.array_type.is_volatile;
+ AstNode *align_expr = node->data.array_type.align_expr;
if (size_node) {
if (is_const) {
add_node_error(irb->codegen, node, buf_create_from_str("const qualifier invalid on array type"));
return irb->codegen->invalid_instruction;
}
+ if (is_volatile) {
+ add_node_error(irb->codegen, node, buf_create_from_str("volatile qualifier invalid on array type"));
+ return irb->codegen->invalid_instruction;
+ }
+ if (align_expr != nullptr) {
+ add_node_error(irb->codegen, node, buf_create_from_str("align qualifier invalid on array type"));
+ return irb->codegen->invalid_instruction;
+ }
IrInstruction *size_value = ir_gen_node(irb, size_node, scope);
if (size_value == irb->codegen->invalid_instruction)
@@ -5271,11 +5301,20 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
return ir_build_array_type(irb, scope, node, size_value, child_type);
} else {
+ IrInstruction *align_value;
+ if (align_expr != nullptr) {
+ align_value = ir_gen_node(irb, align_expr, scope);
+ if (align_value == irb->codegen->invalid_instruction)
+ return align_value;
+ } else {
+ align_value = nullptr;
+ }
+
IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope);
if (child_type == irb->codegen->invalid_instruction)
return child_type;
- return ir_build_slice_type(irb, scope, node, is_const, child_type);
+ return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value);
}
}
@@ -5375,7 +5414,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false);
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);
- ir_build_var_decl(irb, scope, node, var, var_type, var_value);
+ ir_build_var_decl(irb, scope, node, var, var_type, nullptr, var_value);
var_scope = var->child_scope;
} else {
var_scope = scope;
@@ -5452,7 +5491,7 @@ static IrInstruction *ir_gen_try_expr(IrBuilder *irb, Scope *scope, AstNode *nod
IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false);
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);
- ir_build_var_decl(irb, scope, node, var, var_type, var_value);
+ ir_build_var_decl(irb, scope, node, var, var_type, nullptr, var_value);
var_scope = var->child_scope;
} else {
var_scope = scope;
@@ -5477,7 +5516,7 @@ static IrInstruction *ir_gen_try_expr(IrBuilder *irb, Scope *scope, AstNode *nod
err_symbol, is_const, is_const, is_shadowable, is_comptime);
IrInstruction *var_value = ir_build_unwrap_err_code(irb, scope, node, err_val_ptr);
- ir_build_var_decl(irb, scope, node, var, var_type, var_value);
+ ir_build_var_decl(irb, scope, node, var, var_type, nullptr, var_value);
err_var_scope = var->child_scope;
} else {
err_var_scope = scope;
@@ -5531,7 +5570,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
}
IrInstruction *var_type = nullptr; // infer the type
- ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, var_value);
+ ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value);
} else {
child_scope = scope;
}
@@ -5912,7 +5951,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
is_const, is_const, is_shadowable, is_comptime);
err_scope = var->child_scope;
IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
- ir_build_var_decl(irb, err_scope, var_node, var, var_type, err_val);
+ ir_build_var_decl(irb, err_scope, var_node, var, var_type, nullptr, err_val);
} else {
err_scope = parent_scope;
}
@@ -6056,6 +6095,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval);
case NodeTypePrefixOpExpr:
return ir_gen_prefix_op_expr(irb, scope, node, lval);
+ case NodeTypeAddrOfExpr:
+ return ir_lval_wrap(irb, scope, ir_gen_address_of(irb, scope, node), lval);
case NodeTypeContainerInitExpr:
return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval);
case NodeTypeVariableDeclaration:
@@ -7264,7 +7305,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
}
if (convert_to_const_slice) {
assert(prev_inst->value.type->id == TypeTableEntryIdArray);
- TypeTableEntry *slice_type = get_slice_type(ira->codegen, prev_inst->value.type->data.array.child_type, true);
+ TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true);
+ TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type);
if (any_are_pure_error) {
return get_error_type(ira->codegen, slice_type);
} else {
@@ -7569,7 +7611,7 @@ static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instructio
static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
ConstExprValue *pointee, TypeTableEntry *pointee_type,
- ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile)
+ ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile, uint32_t ptr_align)
{
if (pointee_type->id == TypeTableEntryIdMetaType) {
TypeTableEntry *type_entry = pointee->data.x_type;
@@ -7583,11 +7625,11 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
const_val->type = pointee_type;
type_ensure_zero_bits_known(ira->codegen, type_entry);
const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry,
- ptr_is_const, ptr_is_volatile, 0, 0);
+ ptr_is_const, ptr_is_volatile, get_abi_alignment(ira->codegen, type_entry), 0, 0);
return const_instr;
} else {
TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, pointee_type,
- ptr_is_const, ptr_is_volatile, 0, 0);
+ ptr_is_const, ptr_is_volatile, ptr_align, 0, 0);
IrInstruction *const_instr = ir_get_const(ira, instruction);
ConstExprValue *const_val = &const_instr->value;
const_val->type = ptr_type;
@@ -7603,7 +7645,8 @@ static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instr
ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile)
{
IrInstruction *const_instr = ir_get_const_ptr(ira, instruction, pointee,
- pointee_type, ptr_mut, ptr_is_const, ptr_is_volatile);
+ pointee_type, ptr_mut, ptr_is_const, ptr_is_volatile,
+ get_abi_alignment(ira->codegen, pointee_type));
ir_link_new_instruction(const_instr, instruction);
return const_instr->value.type;
}
@@ -7876,10 +7919,12 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
return ira->codegen->invalid_instruction;
bool final_is_const = (value->value.type->id == TypeTableEntryIdMetaType) ? is_const : true;
return ir_get_const_ptr(ira, source_instruction, val, value->value.type,
- ConstPtrMutComptimeConst, final_is_const, is_volatile);
+ ConstPtrMutComptimeConst, final_is_const, is_volatile,
+ get_abi_alignment(ira->codegen, value->value.type));
}
- TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, is_const, is_volatile, 0, 0);
+ TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
+ is_const, is_volatile, get_abi_alignment(ira->codegen, value->value.type), 0, 0);
FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
assert(fn_entry);
IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
@@ -8579,6 +8624,33 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
return result->value.type;
}
+static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {
+ if (type_is_invalid(value->value.type))
+ return false;
+
+ IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen));
+ if (type_is_invalid(casted_value->value.type))
+ return false;
+
+ ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
+ if (!const_val)
+ return false;
+
+ uint32_t align_bytes = bigint_as_unsigned(&const_val->data.x_bigint);
+ if (align_bytes == 0) {
+ ir_add_error(ira, value, buf_sprintf("alignment must be >= 1"));
+ return false;
+ }
+
+ if (!is_power_of_2(align_bytes)) {
+ ir_add_error(ira, value, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
+ return false;
+ }
+
+ *out = align_bytes;
+ return true;
+}
+
static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) {
if (type_is_invalid(value->value.type))
return false;
@@ -8656,7 +8728,8 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
if (type_is_invalid(value->value.type))
return nullptr;
- TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
+ TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
+ TypeTableEntry *str_type = get_slice_type(ira->codegen, ptr_type);
IrInstruction *casted_value = ir_implicit_cast(ira, value, str_type);
if (type_is_invalid(casted_value->value.type))
return nullptr;
@@ -9715,6 +9788,14 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
bool is_comptime = ir_get_var_is_comptime(var);
+ if (decl_var_instruction->align_value == nullptr) {
+ var->align_bytes = get_abi_alignment(ira->codegen, result_type);
+ } else {
+ if (!ir_resolve_align(ira, decl_var_instruction->align_value->other, &var->align_bytes)) {
+ var->value->type = ira->codegen->builtin_types.entry_invalid;
+ }
+ }
+
if (casted_init_value->value.special != ConstValSpecialRuntime) {
if (var->mem_slot_index != SIZE_MAX) {
assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
@@ -9733,7 +9814,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
return ira->codegen->builtin_types.entry_invalid;
}
- ir_build_var_decl_from(&ira->new_irb, &decl_var_instruction->base, var, var_type, casted_init_value);
+ ir_build_var_decl_from(&ira->new_irb, &decl_var_instruction->base, var, var_type, nullptr, casted_init_value);
FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
if (fn_entry)
@@ -9892,11 +9973,12 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
ptr_mut = ConstPtrMutRuntimeVar;
}
return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
- ptr_mut, is_const, is_volatile);
+ ptr_mut, is_const, is_volatile, var->align_bytes);
} else {
IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
instruction->scope, instruction->source_node, var, is_const, is_volatile);
- var_ptr_instruction->value.type = get_pointer_to_type(ira->codegen, var->value->type, var->src_is_const);
+ var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
+ var->src_is_const, is_volatile, var->align_bytes, 0, 0);
type_ensure_zero_bits_known(ira->codegen, var->value->type);
bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
@@ -10131,6 +10213,16 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
impl_fn->child_scope, param_name, true, var_args_val, nullptr);
impl_fn->child_scope = var->child_scope;
}
+
+ if (fn_proto_node->data.fn_proto.align_expr != nullptr) {
+ IrInstruction *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
+ fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen),
+ ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
+ nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec);
+
+ ir_resolve_align(ira, align_result, &impl_fn->align_bytes);
+ }
+
{
AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
TypeTableEntry *return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node);
@@ -10731,7 +10823,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
TypeTableEntry *child_type = array_type->data.array.child_type;
if (ptr_type->data.pointer.unaligned_bit_count == 0) {
return_type = get_pointer_to_type_extra(ira->codegen, child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0);
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ get_abi_alignment(ira->codegen, child_type), 0, 0);
} else {
uint64_t elem_val_scalar;
if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar))
@@ -10742,6 +10835,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
return_type = get_pointer_to_type_extra(ira->codegen, child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ get_abi_alignment(ira->codegen, child_type),
(uint32_t)bit_offset, (uint32_t)bit_width);
}
} else if (array_type->id == TypeTableEntryIdPointer) {
@@ -10964,6 +11058,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
TypeStructField *field = find_struct_type_field(bare_type, field_name);
if (field) {
+ bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked);
+ uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry);
if (instr_is_comptime(container_ptr)) {
ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
if (!ptr_val)
@@ -10973,7 +11069,7 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
ConstExprValue *struct_val = const_ptr_pointee(ira->codegen, ptr_val);
ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type,
- is_const, is_volatile, 0, 0);
+ is_const, is_volatile, align_bytes, 0, 0);
ConstExprValue *const_val = ir_build_const_from(ira, &field_ptr_instruction->base);
const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
@@ -10988,6 +11084,7 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
field->unaligned_bit_count : type_size_bits(ira->codegen, field->type_entry);
ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
+ align_bytes,
(uint32_t)(ptr_bit_offset + field->packed_bits_offset),
(uint32_t)unaligned_bit_count_for_result_type);
} else {
@@ -11001,7 +11098,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
TypeEnumField *field = find_enum_type_field(bare_type, field_name);
if (field) {
ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
- return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, 0, 0);
+ return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
+ get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
} else {
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
field_ptr_instruction, container_ptr, container_type);
@@ -11427,7 +11525,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira,
if (type_is_invalid(type_entry))
return type_entry;
- // TODO handle typedefs
if (type_entry->id != TypeTableEntryIdPointer) {
ir_add_error_node(ira, ptr_type_child_instruction->base.source_node,
buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name)));
@@ -11439,69 +11536,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_type;
}
-static TypeTableEntry *ir_analyze_instruction_set_global_align(IrAnalyze *ira,
- IrInstructionSetGlobalAlign *instruction)
-{
- Tld *tld = instruction->tld;
- IrInstruction *align_value = instruction->value->other;
-
- resolve_top_level_decl(ira->codegen, tld, true, instruction->base.source_node);
- if (tld->resolution == TldResolutionInvalid)
- return ira->codegen->builtin_types.entry_invalid;
-
- uint64_t scalar_align;
- if (!ir_resolve_usize(ira, align_value, &scalar_align))
- return ira->codegen->builtin_types.entry_invalid;
-
- if (!is_power_of_2(scalar_align)) {
- ir_add_error(ira, instruction->value, buf_sprintf("alignment value must be power of 2"));
- return ira->codegen->builtin_types.entry_invalid;
- }
-
- AstNode **set_global_align_node;
- uint32_t *alignment_ptr;
- if (tld->id == TldIdVar) {
- TldVar *tld_var = (TldVar *)tld;
- set_global_align_node = &tld_var->set_global_align_node;
- alignment_ptr = &tld_var->alignment;
-
- if (tld_var->var->linkage == VarLinkageExternal) {
- ErrorMsg *msg = ir_add_error(ira, &instruction->base,
- buf_sprintf("cannot set alignment of external variable '%s'", buf_ptr(&tld_var->var->name)));
- add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here"));
- return ira->codegen->builtin_types.entry_invalid;
- }
- } else if (tld->id == TldIdFn) {
- TldFn *tld_fn = (TldFn *)tld;
- FnTableEntry *fn_entry = tld_fn->fn_entry;
- set_global_align_node = &fn_entry->set_global_align_node;
- alignment_ptr = &fn_entry->alignment;
-
- if (fn_entry->def_scope == nullptr) {
- ErrorMsg *msg = ir_add_error(ira, &instruction->base,
- buf_sprintf("cannot set alignment of external function '%s'", buf_ptr(&fn_entry->symbol_name)));
- add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here"));
- return ira->codegen->builtin_types.entry_invalid;
- }
- } else {
- // error is caught in pass1 IR gen
- zig_unreachable();
- }
-
- AstNode *source_node = instruction->base.source_node;
- if (*set_global_align_node) {
- ErrorMsg *msg = ir_add_error_node(ira, source_node,
- buf_sprintf("alignment set twice"));
- add_error_note(ira->codegen, msg, *set_global_align_node, buf_sprintf("first set here"));
- return ira->codegen->builtin_types.entry_invalid;
- }
- *set_global_align_node = source_node;
- *alignment_ptr = (uint32_t)scalar_align;
-
- ir_build_const_from(ira, &instruction->base);
- return ira->codegen->builtin_types.entry_void;
-}
-
static TypeTableEntry *ir_analyze_instruction_set_global_section(IrAnalyze *ira,
IrInstructionSetGlobalSection *instruction)
{
@@ -11750,16 +11784,24 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
IrInstructionSliceType *slice_type_instruction)
{
- IrInstruction *child_type = slice_type_instruction->child_type->other;
- if (type_is_invalid(child_type->value.type))
- return ira->codegen->builtin_types.entry_invalid;
- bool is_const = slice_type_instruction->is_const;
+ uint32_t align_bytes;
+ if (slice_type_instruction->align_value != nullptr) {
+ if (!ir_resolve_align(ira, slice_type_instruction->align_value->other, &align_bytes))
+ return ira->codegen->builtin_types.entry_invalid;
+ }
- TypeTableEntry *resolved_child_type = ir_resolve_type(ira, child_type);
- if (type_is_invalid(resolved_child_type))
+ TypeTableEntry *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->other);
+ if (type_is_invalid(child_type))
return ira->codegen->builtin_types.entry_invalid;
- switch (resolved_child_type->id) {
+ if (slice_type_instruction->align_value == nullptr) {
+ align_bytes = get_abi_alignment(ira->codegen, child_type);
+ }
+
+ bool is_const = slice_type_instruction->is_const;
+ bool is_volatile = slice_type_instruction->is_volatile;
+
+ switch (child_type->id) {
case TypeTableEntryIdInvalid: // handled above
zig_unreachable();
case TypeTableEntryIdVar:
@@ -11770,7 +11812,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdOpaque:
ir_add_error_node(ira, slice_type_instruction->base.source_node,
- buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name)));
+ buf_sprintf("slice of type '%s' not allowed", buf_ptr(&child_type->name)));
return ira->codegen->builtin_types.entry_invalid;
case TypeTableEntryIdMetaType:
case TypeTableEntryIdVoid:
@@ -11792,8 +11834,10 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdEnumTag:
{
- type_ensure_zero_bits_known(ira->codegen, resolved_child_type);
- TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const);
+ type_ensure_zero_bits_known(ira->codegen, child_type);
+ TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
+ is_const, is_volatile, align_bytes, 0, 0);
+ TypeTableEntry *result_type = get_slice_type(ira->codegen, slice_ptr_type);
ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base);
out_val->data.x_type = result_type;
return ira->codegen->builtin_types.entry_type;
@@ -12018,7 +12062,6 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
- // TODO handle typedef
if (type_is_invalid(type_entry)) {
return ira->codegen->builtin_types.entry_invalid;
} else if (type_entry->id != TypeTableEntryIdMaybe) {
@@ -12028,7 +12071,8 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
}
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0);
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ get_abi_alignment(ira->codegen, child_type), 0, 0);
if (instr_is_comptime(value)) {
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
@@ -12887,7 +12931,8 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
if (type_is_invalid(casted_value->value.type))
return ira->codegen->builtin_types.entry_invalid;
- TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
+ TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
if (casted_value->value.special == ConstValSpecialStatic) {
ErrorTableEntry *err = casted_value->value.data.x_pure_err;
if (!err->cached_error_name_val) {
@@ -12929,7 +12974,8 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
IrInstruction *result = ir_build_enum_tag_name(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, target);
ir_link_new_instruction(result, &instruction->base);
- result->value.type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
+ result->value.type = get_slice_type(ira->codegen, u8_ptr_type);
return result->value.type;
}
@@ -12972,16 +13018,22 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_invalid;
}
+ bool is_packed = (container_type->data.structure.layout == ContainerLayoutPacked);
+ uint32_t field_ptr_align = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry);
+ uint32_t parent_ptr_align = is_packed ? 1 : get_abi_alignment(ira->codegen, container_type);
+
TypeTableEntry *field_ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry,
field_ptr->value.type->data.pointer.is_const,
- field_ptr->value.type->data.pointer.is_volatile, 0, 0);
+ field_ptr->value.type->data.pointer.is_volatile,
+ field_ptr_align, 0, 0);
IrInstruction *casted_field_ptr = ir_implicit_cast(ira, field_ptr, field_ptr_type);
if (type_is_invalid(casted_field_ptr->value.type))
return ira->codegen->builtin_types.entry_invalid;
TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, container_type,
casted_field_ptr->value.type->data.pointer.is_const,
- casted_field_ptr->value.type->data.pointer.is_volatile, 0, 0);
+ casted_field_ptr->value.type->data.pointer.is_volatile,
+ parent_ptr_align, 0, 0);
if (instr_is_comptime(casted_field_ptr)) {
ConstExprValue *field_ptr_val = ir_resolve_const(ira, casted_field_ptr, UndefBad);
@@ -13436,7 +13488,9 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi
TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
- TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, 0, 0);
+ uint32_t dest_align = (dest_uncasted_type->id == TypeTableEntryIdPointer) ?
+ dest_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8);
+ TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, dest_align, 0, 0);
IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr);
if (type_is_invalid(casted_dest_ptr->value.type))
@@ -13517,17 +13571,21 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
if (type_is_invalid(count_value->value.type))
return ira->codegen->builtin_types.entry_invalid;
+ TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
TypeTableEntry *dest_uncasted_type = dest_ptr->value.type;
TypeTableEntry *src_uncasted_type = src_ptr->value.type;
bool dest_is_volatile = (dest_uncasted_type->id == TypeTableEntryIdPointer) &&
dest_uncasted_type->data.pointer.is_volatile;
bool src_is_volatile = (src_uncasted_type->id == TypeTableEntryIdPointer) &&
src_uncasted_type->data.pointer.is_volatile;
+ uint32_t dest_align = (dest_uncasted_type->id == TypeTableEntryIdPointer) ?
+ dest_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8);
+ uint32_t src_align = (src_uncasted_type->id == TypeTableEntryIdPointer) ?
+ src_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8);
TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
- TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
- TypeTableEntry *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, 0, 0);
- TypeTableEntry *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile, 0, 0);
+ TypeTableEntry *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, dest_align, 0, 0);
+ TypeTableEntry *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile, src_align, 0, 0);
IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut);
if (type_is_invalid(casted_dest_ptr->value.type))
@@ -13662,17 +13720,24 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
TypeTableEntry *return_type;
if (array_type->id == TypeTableEntryIdArray) {
- return_type = get_slice_type(ira->codegen, array_type->data.array.child_type, ptr_type->data.pointer.is_const);
+ uint32_t normal_array_alignment = get_abi_alignment(ira->codegen, array_type);
+ uint32_t align_bytes = (ptr_type->data.pointer.alignment >= normal_array_alignment) ?
+ normal_array_alignment : 1;
+ TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, align_bytes, 0, 0);
+ return_type = get_slice_type(ira->codegen, slice_ptr_type);
} else if (array_type->id == TypeTableEntryIdPointer) {
- return_type = get_slice_type(ira->codegen, array_type->data.pointer.child_type,
- array_type->data.pointer.is_const);
+ TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,
+ array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
+ array_type->data.pointer.alignment, 0, 0);
+ return_type = get_slice_type(ira->codegen, slice_ptr_type);
if (!end) {
ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
return ira->codegen->builtin_types.entry_invalid;
}
} else if (is_slice(array_type)) {
TypeTableEntry *ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
- return_type = get_slice_type(ira->codegen, ptr_type->data.pointer.child_type, ptr_type->data.pointer.is_const);
+ return_type = get_slice_type(ira->codegen, ptr_type);
} else {
ir_add_error(ira, &instruction->base,
buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));
@@ -13860,7 +13925,7 @@ static TypeTableEntry *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIn
return u8_ptr_const;
}
-static TypeTableEntry *ir_analyze_instruction_preferred_align_of(IrAnalyze *ira, IrInstructionPreferredAlignOf *instruction) {
+static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) {
IrInstruction *type_value = instruction->type_value->other;
if (type_is_invalid(type_value->value.type))
return ira->codegen->builtin_types.entry_invalid;
@@ -13884,62 +13949,11 @@ static TypeTableEntry *ir_analyze_instruction_preferred_align_of(IrAnalyze *ira,
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdArgTuple:
- ir_add_error(ira, instruction->type_value,
- buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
- return ira->codegen->builtin_types.entry_invalid;
case TypeTableEntryIdVoid:
- case TypeTableEntryIdBool:
- case TypeTableEntryIdInt:
- case TypeTableEntryIdFloat:
- case TypeTableEntryIdPointer:
- case TypeTableEntryIdArray:
- case TypeTableEntryIdStruct:
- case TypeTableEntryIdMaybe:
- case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
- case TypeTableEntryIdEnum:
- case TypeTableEntryIdEnumTag:
- case TypeTableEntryIdUnion:
- case TypeTableEntryIdFn:
case TypeTableEntryIdOpaque:
- {
- uint64_t align_in_bytes = LLVMPreferredAlignmentOfType(ira->codegen->target_data_ref, type_entry->type_ref);
- ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- bigint_init_unsigned(&out_val->data.x_bigint, align_in_bytes);
- return ira->codegen->builtin_types.entry_num_lit_int;
- }
- }
- zig_unreachable();
-}
-
-static TypeTableEntry *ir_analyze_instruction_abi_align_of(IrAnalyze *ira, IrInstructionAbiAlignOf *instruction) {
- IrInstruction *type_value = instruction->type_value->other;
- if (type_is_invalid(type_value->value.type))
- return ira->codegen->builtin_types.entry_invalid;
- TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
-
- ensure_complete_type(ira->codegen, type_entry);
- if (type_is_invalid(type_entry))
- return ira->codegen->builtin_types.entry_invalid;
-
- switch (type_entry->id) {
- case TypeTableEntryIdInvalid:
- case TypeTableEntryIdVar:
- zig_unreachable();
- case TypeTableEntryIdMetaType:
- case TypeTableEntryIdUnreachable:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdNullLit:
- case TypeTableEntryIdNamespace:
- case TypeTableEntryIdBlock:
- case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdArgTuple:
ir_add_error(ira, instruction->type_value,
buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->builtin_types.entry_invalid;
- case TypeTableEntryIdVoid:
case TypeTableEntryIdBool:
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
@@ -13953,9 +13967,8 @@ static TypeTableEntry *ir_analyze_instruction_abi_align_of(IrAnalyze *ira, IrIns
case TypeTableEntryIdEnumTag:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
- case TypeTableEntryIdOpaque:
{
- uint64_t align_in_bytes = LLVMABIAlignmentOfType(ira->codegen->target_data_ref, type_entry->type_ref);
+ uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
bigint_init_unsigned(&out_val->data.x_bigint, align_in_bytes);
return ira->codegen->builtin_types.entry_num_lit_int;
@@ -14143,7 +14156,8 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
} else if (type_entry->id == TypeTableEntryIdErrorUnion) {
TypeTableEntry *child_type = type_entry->data.error.child_type;
TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0);
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ get_abi_alignment(ira->codegen, child_type), 0, 0);
if (instr_is_comptime(value)) {
ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
if (!ptr_val)
@@ -14390,7 +14404,8 @@ static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructio
if (type_is_invalid(msg->value.type))
return ira->codegen->builtin_types.entry_invalid;
- TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
+ TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
+ TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
if (type_is_invalid(casted_msg->value.type))
return ira->codegen->builtin_types.entry_invalid;
@@ -14814,6 +14829,23 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr
return usize;
}
+static TypeTableEntry *ir_analyze_instruction_ptr_type_of(IrAnalyze *ira, IrInstructionPtrTypeOf *instruction) {
+ TypeTableEntry *child_type = ir_resolve_type(ira, instruction->child_type->other);
+ if (type_is_invalid(child_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ uint32_t align_bytes;
+ if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = get_pointer_to_type_extra(ira->codegen, child_type,
+ instruction->is_const, instruction->is_volatile, align_bytes,
+ instruction->bit_offset_start, instruction->bit_offset_end);
+
+ return ira->codegen->builtin_types.entry_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -14862,8 +14894,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction);
case IrInstructionIdPtrTypeChild:
return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction);
- case IrInstructionIdSetGlobalAlign:
- return ir_analyze_instruction_set_global_align(ira, (IrInstructionSetGlobalAlign *)instruction);
case IrInstructionIdSetGlobalSection:
return ir_analyze_instruction_set_global_section(ira, (IrInstructionSetGlobalSection *)instruction);
case IrInstructionIdSetGlobalLinkage:
@@ -14952,10 +14982,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);
case IrInstructionIdFrameAddress:
return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);
- case IrInstructionIdPreferredAlignOf:
- return ir_analyze_instruction_preferred_align_of(ira, (IrInstructionPreferredAlignOf *)instruction);
- case IrInstructionIdAbiAlignOf:
- return ir_analyze_instruction_abi_align_of(ira, (IrInstructionAbiAlignOf *)instruction);
+ case IrInstructionIdAlignOf:
+ return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);
case IrInstructionIdOverflowOp:
return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction);
case IrInstructionIdTestErr:
@@ -14996,6 +15024,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction);
case IrInstructionIdSetEvalBranchQuota:
return ir_analyze_instruction_set_eval_branch_quota(ira, (IrInstructionSetEvalBranchQuota *)instruction);
+ case IrInstructionIdPtrTypeOf:
+ return ir_analyze_instruction_ptr_type_of(ira, (IrInstructionPtrTypeOf *)instruction);
case IrInstructionIdMaybeWrap:
case IrInstructionIdErrWrapCode:
case IrInstructionIdErrWrapPayload:
@@ -15108,11 +15138,11 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free
case IrInstructionIdCheckSwitchProngs:
case IrInstructionIdCheckStatementIsVoid:
- case IrInstructionIdSetGlobalAlign:
case IrInstructionIdSetGlobalSection:
case IrInstructionIdSetGlobalLinkage:
case IrInstructionIdPanic:
case IrInstructionIdSetEvalBranchQuota:
+ case IrInstructionIdPtrTypeOf:
return true;
case IrInstructionIdPhi:
case IrInstructionIdUnOp:
@@ -15151,8 +15181,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBoolNot:
case IrInstructionIdSlice:
case IrInstructionIdMemberCount:
- case IrInstructionIdPreferredAlignOf:
- case IrInstructionIdAbiAlignOf:
+ case IrInstructionIdAlignOf:
case IrInstructionIdReturnAddress:
case IrInstructionIdFrameAddress:
case IrInstructionIdTestErr:
src/ir_print.cpp
@@ -664,14 +664,8 @@ static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *in
fprintf(irp->f, "@returnAddress()");
}
-static void ir_print_preferred_align_of(IrPrint *irp, IrInstructionPreferredAlignOf *instruction) {
- fprintf(irp->f, "@preferredAlignOf(");
- ir_print_other_instruction(irp, instruction->type_value);
- fprintf(irp->f, ")");
-}
-
-static void ir_print_abi_align_of(IrPrint *irp, IrInstructionAbiAlignOf *instruction) {
- fprintf(irp->f, "@abiAlignOf(");
+static void ir_print_align_of(IrPrint *irp, IrInstructionAlignOf *instruction) {
+ fprintf(irp->f, "@alignOf(");
ir_print_other_instruction(irp, instruction->type_value);
fprintf(irp->f, ")");
}
@@ -860,10 +854,14 @@ static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCas
fprintf(irp->f, ")");
}
-static void ir_print_set_global_align(IrPrint *irp, IrInstructionSetGlobalAlign *instruction) {
- fprintf(irp->f, "@setGlobalAlign(%s,", buf_ptr(instruction->tld->name));
- ir_print_other_instruction(irp, instruction->value);
- fprintf(irp->f, ")");
+static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instruction) {
+ fprintf(irp->f, "&align ");
+ ir_print_other_instruction(irp, instruction->align_value);
+ const char *const_str = instruction->is_const ? "const " : "";
+ const char *volatile_str = instruction->is_volatile ? "volatile " : "";
+ fprintf(irp->f, ":%" PRIu32 ":%" PRIu32 " %s%s", instruction->bit_offset_start, instruction->bit_offset_end,
+ const_str, volatile_str);
+ ir_print_other_instruction(irp, instruction->child_type);
}
static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSection *instruction) {
@@ -1116,11 +1114,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdFrameAddress:
ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);
break;
- case IrInstructionIdPreferredAlignOf:
- ir_print_preferred_align_of(irp, (IrInstructionPreferredAlignOf *)instruction);
- break;
- case IrInstructionIdAbiAlignOf:
- ir_print_abi_align_of(irp, (IrInstructionAbiAlignOf *)instruction);
+ case IrInstructionIdAlignOf:
+ ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);
break;
case IrInstructionIdOverflowOp:
ir_print_overflow_op(irp, (IrInstructionOverflowOp *)instruction);
@@ -1191,8 +1186,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdCanImplicitCast:
ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
break;
- case IrInstructionIdSetGlobalAlign:
- ir_print_set_global_align(irp, (IrInstructionSetGlobalAlign *)instruction);
+ case IrInstructionIdPtrTypeOf:
+ ir_print_ptr_type_of(irp, (IrInstructionPtrTypeOf *)instruction);
break;
case IrInstructionIdSetGlobalSection:
ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction);
src/parseh.cpp
@@ -710,6 +710,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
TypeTableEntry *enum_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base,
ContainerKindEnum, c->source_node, buf_ptr(full_type_name), ContainerLayoutExtern);
enum_type->data.enumeration.zero_bits_known = true;
+ enum_type->data.enumeration.abi_alignment = 1;
c->enum_type_table.put(bare_name, enum_type);
c->decl_table.put(enum_decl, enum_type);
replace_with_fwd_decl(c, enum_type, full_type_name);
@@ -741,6 +742,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
enum_type->data.enumeration.gen_field_count = 0;
enum_type->data.enumeration.complete = true;
enum_type->data.enumeration.zero_bits_known = true;
+ enum_type->data.enumeration.abi_alignment = 1;
enum_type->data.enumeration.tag_type = tag_type_entry;
enum_type->data.enumeration.src_field_count = field_count;
@@ -778,6 +780,9 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
// create llvm type for root struct
enum_type->type_ref = tag_type_entry->type_ref;
+ enum_type->data.enumeration.abi_alignment = LLVMABIAlignmentOfType(c->codegen->target_data_ref,
+ enum_type->type_ref);
+
// create debug type for tag
unsigned line = c->source_node ? (c->source_node->line + 1) : 0;
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(c->codegen->target_data_ref, enum_type->type_ref);
@@ -864,6 +869,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
TypeTableEntry *struct_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base,
ContainerKindStruct, c->source_node, buf_ptr(full_type_name), ContainerLayoutExtern);
struct_type->data.structure.zero_bits_known = true;
+ struct_type->data.structure.abi_alignment = 1;
c->struct_type_table.put(bare_name, struct_type);
c->decl_table.put(record_decl, struct_type);
@@ -950,6 +956,8 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
struct_type->data.structure.gen_field_count = field_count;
struct_type->data.structure.complete = true;
+ struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(c->codegen->target_data_ref,
+ struct_type->type_ref);
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(c->codegen->target_data_ref, struct_type->type_ref);
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, struct_type->type_ref);
src/parser.cpp
@@ -228,6 +228,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index);
static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bool mandatory);
static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory);
+static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory);
static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
if (token->id == token_id) {
@@ -384,7 +385,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo
}
/*
-ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression
+ArrayType : "[" option(Expression) "]" option("align" PrimaryExpression)) option("const") option("volatile") PrefixOpExpression
*/
static AstNode *ast_parse_array_type_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *l_bracket = &pc->tokens->at(*token_index);
@@ -403,10 +404,22 @@ static AstNode *ast_parse_array_type_expr(ParseContext *pc, size_t *token_index,
ast_eat_token(pc, token_index, TokenIdRBracket);
- Token *const_tok = &pc->tokens->at(*token_index);
- if (const_tok->id == TokenIdKeywordConst) {
+ Token *token = &pc->tokens->at(*token_index);
+ if (token->id == TokenIdKeywordAlign) {
+ *token_index += 1;
+ node->data.array_type.align_expr = ast_parse_primary_expr(pc, token_index, true);
+
+ token = &pc->tokens->at(*token_index);
+ }
+ if (token->id == TokenIdKeywordConst) {
*token_index += 1;
node->data.array_type.is_const = true;
+
+ token = &pc->tokens->at(*token_index);
+ }
+ if (token->id == TokenIdKeywordVolatile) {
+ *token_index += 1;
+ node->data.array_type.is_volatile = true;
}
node->data.array_type.child_type = ast_parse_type_expr(pc, token_index, true);
@@ -953,7 +966,6 @@ static PrefixOp tok_to_prefix_op(Token *token) {
case TokenIdDash: return PrefixOpNegation;
case TokenIdMinusPercent: return PrefixOpNegationWrap;
case TokenIdTilde: return PrefixOpBinNot;
- case TokenIdAmpersand: return PrefixOpAddressOf;
case TokenIdStar: return PrefixOpDereference;
case TokenIdMaybe: return PrefixOpMaybe;
case TokenIdPercent: return PrefixOpError;
@@ -964,12 +976,52 @@ static PrefixOp tok_to_prefix_op(Token *token) {
}
}
+static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
+ Token *ampersand_tok = ast_eat_token(pc, token_index, TokenIdAmpersand);
+
+ AstNode *node = ast_create_node(pc, NodeTypeAddrOfExpr, ampersand_tok);
+
+ Token *token = &pc->tokens->at(*token_index);
+ if (token->id == TokenIdKeywordAlign) {
+ *token_index += 1;
+ node->data.addr_of_expr.align_expr = ast_parse_primary_expr(pc, token_index, true);
+
+ token = &pc->tokens->at(*token_index);
+ if (token->id == TokenIdColon) {
+ *token_index += 1;
+ Token *bit_offset_start_tok = ast_eat_token(pc, token_index, TokenIdIntLiteral);
+ ast_eat_token(pc, token_index, TokenIdColon);
+ Token *bit_offset_end_tok = ast_eat_token(pc, token_index, TokenIdIntLiteral);
+ token = &pc->tokens->at(*token_index);
+
+ node->data.addr_of_expr.bit_offset_start = token_bigint(bit_offset_start_tok);
+ node->data.addr_of_expr.bit_offset_end = token_bigint(bit_offset_end_tok);
+ }
+ }
+ if (token->id == TokenIdKeywordConst) {
+ *token_index += 1;
+ node->data.addr_of_expr.is_const = true;
+
+ token = &pc->tokens->at(*token_index);
+ }
+ if (token->id == TokenIdKeywordVolatile) {
+ *token_index += 1;
+ node->data.addr_of_expr.is_volatile = true;
+ }
+
+ node->data.addr_of_expr.op_expr = ast_parse_prefix_op_expr(pc, token_index, true);
+ return node;
+}
+
/*
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
-PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
+PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" PrimaryExpression option(":" Integer ":" Integer)) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
*/
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
+ if (token->id == TokenIdAmpersand) {
+ return ast_parse_addr_of(pc, token_index);
+ }
PrefixOp prefix_op = tok_to_prefix_op(token);
if (prefix_op == PrefixOpInvalid) {
return ast_parse_suffix_op_expr(pc, token_index, mandatory);
@@ -997,23 +1049,6 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
node->column += 1;
}
- if (prefix_op == PrefixOpAddressOf) {
- Token *const_or_volatile_tok = &pc->tokens->at(*token_index);
- if (const_or_volatile_tok->id == TokenIdKeywordConst) {
- *token_index += 1;
- Token *volatile_token = &pc->tokens->at(*token_index);
- if (volatile_token->id == TokenIdKeywordVolatile) {
- *token_index += 1;
- prefix_op = PrefixOpConstVolatileAddressOf;
- } else {
- prefix_op = PrefixOpConstAddressOf;
- }
- } else if (const_or_volatile_tok->id == TokenIdKeywordVolatile) {
- prefix_op = PrefixOpVolatileAddressOf;
- *token_index += 1;
- }
- }
-
AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, true);
node->data.prefix_op_expr.primary_expr = prefix_op_expr;
node->data.prefix_op_expr.prefix_op = prefix_op;
@@ -1499,7 +1534,7 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
}
/*
-VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) "=" Expression
+VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" PrimaryExpression) "=" Expression
*/
static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory,
VisibMod visib_mod)
@@ -1549,25 +1584,28 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
node->data.variable_declaration.symbol = token_buf(name_token);
- Token *eq_or_colon = &pc->tokens->at(*token_index);
- *token_index += 1;
- if (eq_or_colon->id == TokenIdEq) {
- node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
- } else if (eq_or_colon->id == TokenIdColon) {
+ Token *next_token = &pc->tokens->at(*token_index);
+
+ if (next_token->id == TokenIdColon) {
+ *token_index += 1;
node->data.variable_declaration.type = ast_parse_type_expr(pc, token_index, true);
- Token *eq_token = &pc->tokens->at(*token_index);
- if (eq_token->id == TokenIdEq) {
- *token_index += 1;
+ next_token = &pc->tokens->at(*token_index);
+ }
- node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
- }
- } else {
- ast_invalid_token_error(pc, eq_or_colon);
+ if (next_token->id == TokenIdKeywordAlign) {
+ *token_index += 1;
+ node->data.variable_declaration.align_expr = ast_parse_primary_expr(pc, token_index, true);
+ next_token = &pc->tokens->at(*token_index);
+ }
+
+ if (next_token->id == TokenIdEq) {
+ *token_index += 1;
+ node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
+ next_token = &pc->tokens->at(*token_index);
}
// peek ahead and ensure that all variable declarations are followed by a semicolon
- Token *semicolon_token = &pc->tokens->at(*token_index);
- ast_expect_token(pc, semicolon_token, TokenIdSemicolon);
+ ast_expect_token(pc, next_token, TokenIdSemicolon);
return node;
}
@@ -2165,7 +2203,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
}
/*
-FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
+FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" PrimaryExpression) option("->" TypeExpr)
*/
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -2200,6 +2238,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
node->data.fn_proto.cc = cc;
Token *fn_name = &pc->tokens->at(*token_index);
+
if (fn_name->id == TokenIdSymbol) {
*token_index += 1;
node->data.fn_proto.name = token_buf(fn_name);
@@ -2210,6 +2249,12 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
Token *next_token = &pc->tokens->at(*token_index);
+ if (next_token->id == TokenIdKeywordAlign) {
+ *token_index += 1;
+
+ node->data.fn_proto.align_expr = ast_parse_primary_expr(pc, token_index, true);
+ next_token = &pc->tokens->at(*token_index);
+ }
if (next_token->id == TokenIdArrow) {
*token_index += 1;
node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, false);
@@ -2595,6 +2640,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeFnProto:
visit_field(&node->data.fn_proto.return_type, visit, context);
visit_node_list(&node->data.fn_proto.params, visit, context);
+ visit_field(&node->data.fn_proto.align_expr, visit, context);
break;
case NodeTypeFnDef:
visit_field(&node->data.fn_def.fn_proto, visit, context);
@@ -2621,6 +2667,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeVariableDeclaration:
visit_field(&node->data.variable_declaration.type, visit, context);
visit_field(&node->data.variable_declaration.expr, visit, context);
+ visit_field(&node->data.variable_declaration.align_expr, visit, context);
break;
case NodeTypeErrorValueDecl:
// none
@@ -2769,6 +2816,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeArrayType:
visit_field(&node->data.array_type.size, visit, context);
visit_field(&node->data.array_type.child_type, visit, context);
+ visit_field(&node->data.array_type.align_expr, visit, context);
break;
case NodeTypeErrorType:
// none
@@ -2776,5 +2824,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeVarLiteral:
// none
break;
+ case NodeTypeAddrOfExpr:
+ visit_field(&node->data.addr_of_expr.align_expr, visit, context);
+ visit_field(&node->data.addr_of_expr.op_expr, visit, context);
+ break;
}
}
src/tokenizer.cpp
@@ -107,6 +107,7 @@ struct ZigKeyword {
};
static const struct ZigKeyword zig_keywords[] = {
+ {"align", TokenIdKeywordAlign},
{"and", TokenIdKeywordAnd},
{"asm", TokenIdKeywordAsm},
{"break", TokenIdKeywordBreak},
@@ -1454,6 +1455,7 @@ const char * token_name(TokenId id) {
case TokenIdFatArrow: return "=>";
case TokenIdFloatLiteral: return "FloatLiteral";
case TokenIdIntLiteral: return "IntLiteral";
+ case TokenIdKeywordAlign: return "align";
case TokenIdKeywordAnd: return "and";
case TokenIdKeywordAsm: return "asm";
case TokenIdKeywordBreak: return "break";
src/tokenizer.hpp
@@ -46,6 +46,7 @@ enum TokenId {
TokenIdFatArrow,
TokenIdFloatLiteral,
TokenIdIntLiteral,
+ TokenIdKeywordAlign,
TokenIdKeywordAnd,
TokenIdKeywordAsm,
TokenIdKeywordBreak,
src/zig_llvm.cpp
@@ -713,11 +713,6 @@ void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module) {
unwrap(module)->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION);
}
-unsigned ZigLLVMGetPrefTypeAlignment(LLVMTargetDataRef TD, LLVMTypeRef Ty) {
- return unwrap(TD)->getPrefTypeAlignment(unwrap(Ty));
-}
-
-
static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {
switch (Ordering) {
case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic;
src/zig_llvm.hpp
@@ -167,8 +167,6 @@ void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
-unsigned ZigLLVMGetPrefTypeAlignment(LLVMTargetDataRef TD, LLVMTypeRef Ty);
-
// copied from include/llvm/ADT/Triple.h
std/hash_map.zig
@@ -251,7 +251,7 @@ test "basicHashMapTest" {
}
fn hash_i32(x: i32) -> u32 {
- *@ptrCast(&u32, &x)
+ @bitCast(u32, x)
}
fn eql_i32(a: i32, b: i32) -> bool {
std/mem.zig
@@ -21,10 +21,7 @@ pub const Allocator = struct {
/// Aborts the program if an allocation fails.
fn checkedAlloc(self: &Allocator, comptime T: type, n: usize) -> []T {
- alloc(self, T, n) %% |err| {
- %%io.stderr.printf("allocation failure: {}\n", @errorName(err));
- os.abort()
- }
+ alloc(self, T, n) %% |err| debug.panic("allocation failure: {}", @errorName(err))
}
fn create(self: &Allocator, comptime T: type) -> %&T {
test/cases/alignof.zig
@@ -3,12 +3,9 @@ const builtin = @import("builtin");
const Foo = struct { x: u32, y: u32, z: u32, };
-test "@abiAlignOf(T) before referencing T" {
- comptime assert(@cAbiAlignOf(Foo) != @maxValue(usize));
+test "@alignOf(T) before referencing T" {
+ comptime assert(@alignOf(Foo) != @maxValue(usize));
if (builtin.arch == builtin.Arch.x86_64) {
- comptime {
- assert(@cAbiAlignOf(Foo) == 4);
- assert(@preferredAlignOf(Foo) == 8);
- }
+ comptime assert(@alignOf(Foo) == 4);
}
}
test/cases/enum.zig
@@ -124,8 +124,8 @@ const BareNumber = enum {
test "enum alignment" {
comptime {
- assert(@cAbiAlignOf(AlignTestEnum) >= @cAbiAlignOf([9]u8));
- assert(@cAbiAlignOf(AlignTestEnum) >= @cAbiAlignOf(u64));
+ assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
+ assert(@alignOf(AlignTestEnum) >= @alignOf(u64));
}
}
test/cases/struct.zig
@@ -201,8 +201,6 @@ test "packed struct" {
}
-const u2 = @IntType(false, 2);
-
const BitField1 = packed struct {
a: u3,
b: u3,
test/cases/switch.zig
@@ -172,7 +172,6 @@ test "switch handles all cases of number" {
comptime testSwitchHandleAllCases();
}
-const u2 = @IntType(false, 2);
fn testSwitchHandleAllCases() {
assert(testSwitchHandleAllCasesExhaustive(0) == 3);
assert(testSwitchHandleAllCasesExhaustive(1) == 2);
test/compile_errors.zig
@@ -1316,13 +1316,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\}
, ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'");
- cases.add("set global variable alignment to non power of 2",
- \\const some_data: [100]u8 = undefined;
- \\comptime {
- \\ @setGlobalAlign(some_data, 3);
- \\}
+ cases.add("global variable alignment non power of 2",
+ \\const some_data: [100]u8 align 3 = undefined;
\\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) }
- , ".tmp_source.zig:3:32: error: alignment value must be power of 2");
+ , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2");
+
+ cases.add("function alignment non power of 2",
+ \\extern fn foo() align 3;
+ \\export fn entry() { foo() }
+ , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2");
cases.add("compile log",
\\export fn foo() {
@@ -1342,9 +1344,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
".tmp_source.zig:2:17: note: called from here");
cases.add("casting bit offset pointer to regular pointer",
- \\const u2 = @IntType(false, 2);
- \\const u3 = @IntType(false, 3);
- \\
\\const BitField = packed struct {
\\ a: u3,
\\ b: u3,
@@ -1360,7 +1359,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\}
\\
\\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
- , ".tmp_source.zig:11:26: error: expected type '&const u3', found '&:3:6 const u3'");
+ , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align 1:3:6 const u3'");
cases.add("referring to a struct that is invalid",
\\const UsbDeviceRequest = struct {
@@ -1626,24 +1625,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
"error: 'main' is private",
".tmp_source.zig:1:1: note: declared here");
- cases.add("@setGlobalAlign extern variable",
- \\extern var foo: i32;
- \\comptime {
- \\ @setGlobalAlign(foo, 4);
- \\}
- ,
- ".tmp_source.zig:3:5: error: cannot set alignment of external variable 'foo'",
- ".tmp_source.zig:1:8: note: declared here");
-
- cases.add("@setGlobalAlign extern fn",
- \\extern fn foo();
- \\comptime {
- \\ @setGlobalAlign(foo, 4);
- \\}
- ,
- ".tmp_source.zig:3:5: error: cannot set alignment of external function 'foo'",
- ".tmp_source.zig:1:8: note: declared here");
-
cases.add("@setGlobalSection extern variable",
\\extern var foo: i32;
\\comptime {