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
parent
b8ed0cb374
commit
c5c9d98065
|
@ -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;
|
||||
|
||||
|
|
492
src/analyze.cpp
492
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));
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
224
src/codegen.cpp
224
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", };
|
||||
|
|
583
src/ir.cpp
583
src/ir.cpp
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
130
src/parser.cpp
130
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -46,6 +46,7 @@ enum TokenId {
|
|||
TokenIdFatArrow,
|
||||
TokenIdFloatLiteral,
|
||||
TokenIdIntLiteral,
|
||||
TokenIdKeywordAlign,
|
||||
TokenIdKeywordAnd,
|
||||
TokenIdKeywordAsm,
|
||||
TokenIdKeywordBreak,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -201,8 +201,6 @@ test "packed struct" {
|
|||
}
|
||||
|
||||
|
||||
const u2 = @IntType(false, 2);
|
||||
|
||||
const BitField1 = packed struct {
|
||||
a: u3,
|
||||
b: u3,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue