introduce align keyword

* remove `@setGlobalAlign`
 * add align keyword for setting alignment on functions and
   variables.
 * loads and stores use alignment from pointer
 * memcpy, memset use alignment from pointer
 * add syntax for pointer alignment
 * slices can have volatile
 * add u2, i2 primitives
 * ignore preferred align and use abi align everywhere
 * back to only having alignOf builtin.
   preferredAlignOf is too tricky to be useful.
   See #432. Partial revert of
   e726925e80.

See #37
master
Andrew Kelley 2017-08-29 07:30:22 -04:00
parent b8ed0cb374
commit c5c9d98065
20 changed files with 944 additions and 728 deletions

View File

@ -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;

View File

@ -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));
slice_type_common_init(g, child_type, is_const, entry);
entry->type_ref = var_peer->type_ref;
entry->di_type = var_peer->di_type;
entry->data.structure.complete = true;
entry->data.structure.zero_bits_known = true;
*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;
}
}
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name));
slice_type_common_init(g, child_type, is_const, entry);
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);
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);
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;
}
}
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
entry->is_copyable = true;
// 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);
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;
}
// 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;
}
}
slice_type_common_init(g, ptr_type, entry);
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);
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*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);
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, "");
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, 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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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", };

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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);

View File

@ -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) {
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;
Token *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 == TokenIdColon) {
*token_index += 1;
node->data.variable_declaration.type = ast_parse_type_expr(pc, token_index, true);
next_token = &pc->tokens->at(*token_index);
}
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;
}
}

View File

@ -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";

View File

@ -46,6 +46,7 @@ enum TokenId {
TokenIdFatArrow,
TokenIdFloatLiteral,
TokenIdIntLiteral,
TokenIdKeywordAlign,
TokenIdKeywordAnd,
TokenIdKeywordAsm,
TokenIdKeywordBreak,

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -201,8 +201,6 @@ test "packed struct" {
}
const u2 = @IntType(false, 2);
const BitField1 = packed struct {
a: u3,
b: u3,

View File

@ -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);

View File

@ -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 {