aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-08-29 23:33:25 -0400
committerAndrew Kelley <superjoe30@gmail.com>2017-08-29 23:33:25 -0400
commit898d65baa9198f2fb1c5df91fba51a58c3148626 (patch)
treefd4f7178f974b7be7236782aacde4981df03238b /src
parent910a96f0468c635a135d9fccd39f139ba0775ef9 (diff)
downloadzig-898d65baa9198f2fb1c5df91fba51a58c3148626.tar.gz
zig-898d65baa9198f2fb1c5df91fba51a58c3148626.zip
more alignment improvements
* add alignment capability for fn protos * add @alignCast * fix some ast rendering code * fix some ir rendering code * add error for pointer cast increasing alignment * update allocators in std to correctly align See #37
Diffstat (limited to 'src')
-rw-r--r--src/all_types.hpp11
-rw-r--r--src/analyze.cpp31
-rw-r--r--src/ast_render.cpp2
-rw-r--r--src/codegen.cpp71
-rw-r--r--src/ir.cpp202
-rw-r--r--src/ir_print.cpp31
6 files changed, 311 insertions, 37 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 461270357b..39e6033988 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1252,6 +1252,7 @@ enum BuiltinFnId {
BuiltinFnIdShlExact,
BuiltinFnIdShrExact,
BuiltinFnIdSetEvalBranchQuota,
+ BuiltinFnIdAlignCast,
};
struct BuiltinFnEntry {
@@ -1274,6 +1275,7 @@ enum PanicMsgId {
PanicMsgIdSliceWidenRemainder,
PanicMsgIdUnwrapMaybeFail,
PanicMsgIdInvalidErrorCode,
+ PanicMsgIdIncorrectAlignment,
PanicMsgIdCount,
};
@@ -1856,6 +1858,7 @@ enum IrInstructionId {
IrInstructionIdTypeId,
IrInstructionIdSetEvalBranchQuota,
IrInstructionIdPtrTypeOf,
+ IrInstructionIdAlignCast,
};
struct IrInstruction {
@@ -2462,6 +2465,7 @@ struct IrInstructionFnProto {
IrInstruction base;
IrInstruction **param_types;
+ IrInstruction *align_value;
IrInstruction *return_type;
bool is_var_args;
};
@@ -2638,6 +2642,13 @@ struct IrInstructionPtrTypeOf {
bool is_volatile;
};
+struct IrInstructionAlignCast {
+ IrInstruction base;
+
+ IrInstruction *align_bytes;
+ IrInstruction *target;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 35ccd3b4d3..6adf4b3d51 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -884,6 +884,9 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
buf_appendf(&fn_type->name, "%s...", comma);
}
buf_appendf(&fn_type->name, ")");
+ if (fn_type_id->alignment != 0) {
+ buf_appendf(&fn_type->name, " align %" PRIu32, fn_type_id->alignment);
+ }
if (fn_type_id->return_type->id != TypeTableEntryIdVoid) {
buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id->return_type->name));
}
@@ -1058,12 +1061,13 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou
fn_type_id->is_var_args = fn_proto->is_var_args;
}
-static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) {
+static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, uint32_t alignment) {
assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
FnTypeId fn_type_id = {0};
init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);
+ fn_type_id.alignment = alignment;
for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) {
AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index);
@@ -2056,23 +2060,23 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
}
Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope;
- fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope);
-
- if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) {
- tld_fn->base.resolution = TldResolutionInvalid;
- return;
- }
+ uint32_t alignment = 0;
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))
- {
+ if (!analyze_const_align(g, child_scope, fn_proto->align_expr, &alignment)) {
fn_table_entry->type_entry = g->builtin_types.entry_invalid;
tld_fn->base.resolution = TldResolutionInvalid;
return;
}
}
+ fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, alignment);
+
+ if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) {
+ tld_fn->base.resolution = TldResolutionInvalid;
+ return;
+ }
+
if (!fn_table_entry->type_entry->data.fn.is_generic) {
g->fn_protos.append(fn_table_entry);
@@ -2663,6 +2667,9 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
if (expected_type->id == TypeTableEntryIdFn &&
actual_type->id == TypeTableEntryIdFn)
{
+ if (expected_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
+ return false;
+ }
if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
return false;
}
@@ -3384,6 +3391,7 @@ uint32_t fn_type_id_hash(FnTypeId *id) {
result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;
result += id->is_var_args ? (uint32_t)1931444534 : 0;
result += hash_ptr(id->return_type);
+ result += id->alignment * 0xd3b3f3e2;
for (size_t i = 0; i < id->param_count; i += 1) {
FnTypeParamInfo *info = &id->param_info[i];
result += info->is_noalias ? (uint32_t)892356923 : 0;
@@ -3396,7 +3404,8 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
if (a->cc != b->cc ||
a->return_type != b->return_type ||
a->is_var_args != b->is_var_args ||
- a->param_count != b->param_count)
+ a->param_count != b->param_count ||
+ a->alignment != b->alignment)
{
return false;
}
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index b053a4e8af..d245863216 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -953,7 +953,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
render_node_ungrouped(ar, node->data.slice_expr.array_ref_expr);
fprintf(ar->f, "[");
render_node_grouped(ar, node->data.slice_expr.start);
- fprintf(ar->f, "...");
+ fprintf(ar->f, "..");
if (node->data.slice_expr.end)
render_node_grouped(ar, node->data.slice_expr.end);
fprintf(ar->f, "]");
diff --git a/src/codegen.cpp b/src/codegen.cpp
index cd0dc60f00..3954f310b6 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -688,6 +688,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
return buf_create_from_str("reached unreachable code");
case PanicMsgIdInvalidErrorCode:
return buf_create_from_str("invalid error code");
+ case PanicMsgIdIncorrectAlignment:
+ return buf_create_from_str("incorrect alignment");
}
zig_unreachable();
}
@@ -2605,6 +2607,72 @@ static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executa
}
}
+static LLVMValueRef get_default_aligned_load(CodeGen *g, LLVMValueRef ptr) {
+ LLVMValueRef result = LLVMBuildLoad(g->builder, ptr, "");
+ LLVMSetAlignment(result, LLVMABIAlignmentOfType(g->target_data_ref, LLVMGetElementType(LLVMTypeOf(ptr))));
+ return result;
+}
+
+static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, IrInstructionAlignCast *instruction) {
+ LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
+ assert(target_val);
+
+ bool want_debug_safety = ir_want_debug_safety(g, &instruction->base);
+ if (!want_debug_safety) {
+ return target_val;
+ }
+
+ TypeTableEntry *target_type = instruction->base.value.type;
+ uint32_t align_bytes;
+ LLVMValueRef ptr_val;
+
+ if (target_type->id == TypeTableEntryIdPointer) {
+ align_bytes = target_type->data.pointer.alignment;
+ ptr_val = target_val;
+ } else if (target_type->id == TypeTableEntryIdFn) {
+ align_bytes = target_type->data.fn.fn_type_id.alignment;
+ ptr_val = target_val;
+ } else if (target_type->id == TypeTableEntryIdMaybe &&
+ target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
+ {
+ align_bytes = target_type->data.maybe.child_type->data.pointer.alignment;
+ ptr_val = target_val;
+ } else if (target_type->id == TypeTableEntryIdMaybe &&
+ target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
+ {
+ align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
+ ptr_val = target_val;
+ } else if (target_type->id == TypeTableEntryIdStruct && target_type->data.structure.is_slice) {
+ TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
+ align_bytes = slice_ptr_type->data.pointer.alignment;
+
+ size_t ptr_index = target_type->data.structure.fields[slice_ptr_index].gen_index;
+ LLVMValueRef ptr_val_ptr = LLVMBuildStructGEP(g->builder, target_val, (unsigned)ptr_index, "");
+ ptr_val = get_default_aligned_load(g, ptr_val_ptr);
+ } else {
+ zig_unreachable();
+ }
+
+ assert(align_bytes != 1);
+
+ TypeTableEntry *usize = g->builtin_types.entry_usize;
+ LLVMValueRef ptr_as_int_val = LLVMBuildPtrToInt(g->builder, ptr_val, usize->type_ref, "");
+ LLVMValueRef alignment_minus_1 = LLVMConstInt(usize->type_ref, align_bytes - 1, false);
+ LLVMValueRef anded_val = LLVMBuildAnd(g->builder, ptr_as_int_val, alignment_minus_1, "");
+ LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, anded_val, LLVMConstNull(usize->type_ref), "");
+
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "AlignCastOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "AlignCastFail");
+
+ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_debug_safety_crash(g, PanicMsgIdIncorrectAlignment);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+
+ return target_val;
+}
static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
switch (atomic_order) {
@@ -3350,6 +3418,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction);
case IrInstructionIdFieldParentPtr:
return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
+ case IrInstructionIdAlignCast:
+ return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
}
zig_unreachable();
}
@@ -4633,6 +4703,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1);
+ create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
}
static const char *bool_to_str(bool b) {
diff --git a/src/ir.cpp b/src/ir.cpp
index 251c597224..243a8a2389 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -555,6 +555,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeOf *) {
return IrInstructionIdPtrTypeOf;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignCast *) {
+ return IrInstructionIdAlignCast;
+}
+
template<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -1899,10 +1903,11 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
}
static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction **param_types, IrInstruction *return_type, bool is_var_args)
+ IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type, bool is_var_args)
{
IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
instruction->param_types = param_types;
+ instruction->align_value = align_value;
instruction->return_type = return_type;
instruction->is_var_args = is_var_args;
@@ -1912,6 +1917,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
for (size_t i = 0; i < param_count; i += 1) {
ir_ref_instruction(param_types[i], irb->current_basic_block);
}
+ if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
ir_ref_instruction(return_type, irb->current_basic_block);
return &instruction->base;
@@ -2219,6 +2225,19 @@ static IrInstruction *ir_build_set_eval_branch_quota(IrBuilder *irb, Scope *scop
return &instruction->base;
}
+static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *align_bytes, IrInstruction *target)
+{
+ IrInstructionAlignCast *instruction = ir_build_instruction<IrInstructionAlignCast>(irb, scope, source_node);
+ instruction->align_bytes = align_bytes;
+ instruction->target = target;
+
+ ir_ref_instruction(align_bytes, irb->current_basic_block);
+ ir_ref_instruction(target, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
return nullptr;
}
@@ -2738,6 +2757,10 @@ static IrInstruction *ir_instruction_fnproto_get_dep(IrInstructionFnProto *instr
if (param_index < instruction->base.source_node->data.fn_proto.params.length) {
return instruction->param_types[param_index];
}
+ size_t next_index = param_index - instruction->base.source_node->data.fn_proto.params.length;
+ if (next_index == 0 && instruction->align_value != nullptr) {
+ return instruction->align_value;
+ }
return nullptr;
}
@@ -2925,6 +2948,14 @@ static IrInstruction *ir_instruction_ptrtypeof_get_dep(IrInstructionPtrTypeOf *i
}
}
+static IrInstruction *ir_instruction_aligncast_get_dep(IrInstructionAlignCast *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->align_bytes;
+ case 1: return instruction->target;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -3121,6 +3152,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_setevalbranchquota_get_dep((IrInstructionSetEvalBranchQuota *) instruction, index);
case IrInstructionIdPtrTypeOf:
return ir_instruction_ptrtypeof_get_dep((IrInstructionPtrTypeOf *) instruction, index);
+ case IrInstructionIdAlignCast:
+ return ir_instruction_aligncast_get_dep((IrInstructionAlignCast *) instruction, index);
}
zig_unreachable();
}
@@ -4531,6 +4564,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_set_eval_branch_quota(irb, scope, node, arg0_value);
}
+ case BuiltinFnIdAlignCast:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+ return ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
+ }
}
zig_unreachable();
}
@@ -6060,11 +6107,18 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
param_types[i] = type_value;
}
+ IrInstruction *align_value = nullptr;
+ if (node->data.fn_proto.align_expr != nullptr) {
+ align_value = ir_gen_node(irb, node->data.fn_proto.align_expr, parent_scope);
+ if (align_value == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+ }
+
IrInstruction *return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
if (return_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type, is_var_args);
+ return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
}
static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
@@ -8316,15 +8370,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
// explicit cast from []T to []u8 or []u8 to []T
- if (is_slice(wanted_type) && is_slice(actual_type) &&
- (is_u8(wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type) ||
- is_u8(actual_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type)) &&
- (wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
- !actual_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const))
- {
- if (!ir_emit_global_runtime_side_effect(ira, source_instr))
- return ira->codegen->invalid_instruction;
- return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true);
+ if (is_slice(wanted_type) && is_slice(actual_type)) {
+ TypeTableEntry *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
+ TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
+ if ((is_u8(wanted_ptr_type->data.pointer.child_type) || is_u8(actual_ptr_type->data.pointer.child_type)) &&
+ (wanted_ptr_type->data.pointer.is_const || !actual_ptr_type->data.pointer.is_const))
+ {
+ uint32_t src_align_bytes = get_ptr_align(actual_ptr_type);
+ uint32_t dest_align_bytes = get_ptr_align(wanted_ptr_type);
+
+ if (dest_align_bytes > src_align_bytes) {
+ ErrorMsg *msg = ir_add_error(ira, source_instr,
+ buf_sprintf("cast increases pointer alignment"));
+ add_error_note(ira->codegen, msg, source_instr->source_node,
+ buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), src_align_bytes));
+ add_error_note(ira->codegen, msg, source_instr->source_node,
+ buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), dest_align_bytes));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (!ir_emit_global_runtime_side_effect(ira, source_instr))
+ return ira->codegen->invalid_instruction;
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true);
+ }
}
// explicit cast from [N]u8 to []const T
@@ -10226,7 +10294,10 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec);
- ir_resolve_align(ira, align_result, &impl_fn->align_bytes);
+ uint32_t align_bytes = 0;
+ ir_resolve_align(ira, align_result, &align_bytes);
+ impl_fn->align_bytes = align_bytes;
+ inst_fn_type_id.alignment = align_bytes;
}
{
@@ -13728,11 +13799,9 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
TypeTableEntry *return_type;
if (array_type->id == TypeTableEntryIdArray) {
- uint32_t normal_array_alignment = get_abi_alignment(ira->codegen, array_type);
- uint32_t align_bytes = (ptr_type->data.pointer.alignment >= normal_array_alignment) ?
- normal_array_alignment : 1;
TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, align_bytes, 0, 0);
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ ptr_type->data.pointer.alignment, 0, 0);
return_type = get_slice_type(ira->codegen, slice_ptr_type);
} else if (array_type->id == TypeTableEntryIdPointer) {
TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,
@@ -14237,6 +14306,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
}
}
+ if (instruction->align_value != nullptr) {
+ if (!ir_resolve_align(ira, instruction->align_value->other, &fn_type_id.alignment))
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
IrInstruction *return_type_value = instruction->return_type->other;
fn_type_id.return_type = ir_resolve_type(ira, return_type_value);
if (type_is_invalid(fn_type_id.return_type))
@@ -14866,6 +14940,90 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_of(IrAnalyze *ira, IrInst
return ira->codegen->builtin_types.entry_type;
}
+static TypeTableEntry *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {
+ uint32_t align_bytes;
+ IrInstruction *align_bytes_inst = instruction->align_bytes->other;
+ if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *target = instruction->target->other;
+ TypeTableEntry *target_type = target->value.type;
+ if (type_is_invalid(target_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeTableEntry *result_type;
+ uint32_t old_align_bytes;
+
+ if (target_type->id == TypeTableEntryIdPointer) {
+ result_type = get_pointer_to_type_extra(ira->codegen,
+ target_type->data.pointer.child_type,
+ target_type->data.pointer.is_const, target_type->data.pointer.is_volatile,
+ align_bytes,
+ target_type->data.pointer.bit_offset, target_type->data.pointer.unaligned_bit_count);
+ } else if (target_type->id == TypeTableEntryIdFn) {
+ FnTypeId fn_type_id = target_type->data.fn.fn_type_id;
+ old_align_bytes = fn_type_id.alignment;
+ fn_type_id.alignment = align_bytes;
+ result_type = get_fn_type(ira->codegen, &fn_type_id);
+ } else if (target_type->id == TypeTableEntryIdMaybe &&
+ target_type->data.maybe.child_type->id == TypeTableEntryIdPointer)
+ {
+ TypeTableEntry *ptr_type = target_type->data.maybe.child_type;
+ old_align_bytes = ptr_type->data.pointer.alignment;
+ TypeTableEntry *better_ptr_type = get_pointer_to_type_extra(ira->codegen,
+ ptr_type->data.pointer.child_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ align_bytes,
+ ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
+
+ result_type = get_maybe_type(ira->codegen, better_ptr_type);
+ } else if (target_type->id == TypeTableEntryIdMaybe &&
+ target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
+ {
+ FnTypeId fn_type_id = target_type->data.maybe.child_type->data.fn.fn_type_id;
+ old_align_bytes = fn_type_id.alignment;
+ fn_type_id.alignment = align_bytes;
+ TypeTableEntry *fn_type = get_fn_type(ira->codegen, &fn_type_id);
+ result_type = get_maybe_type(ira->codegen, fn_type);
+ } else if (is_slice(target_type)) {
+ TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
+ old_align_bytes = slice_ptr_type->data.pointer.alignment;
+ TypeTableEntry *result_ptr_type = get_pointer_to_type_extra(ira->codegen,
+ slice_ptr_type->data.pointer.child_type,
+ slice_ptr_type->data.pointer.is_const, slice_ptr_type->data.pointer.is_volatile,
+ align_bytes,
+ slice_ptr_type->data.pointer.bit_offset, slice_ptr_type->data.pointer.unaligned_bit_count);
+ result_type = get_slice_type(ira->codegen, result_ptr_type);
+ } else {
+ ir_add_error(ira, target,
+ buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (instr_is_comptime(target)) {
+ ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
+ if (!val)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ copy_const_val(out_val, val, false);
+ out_val->type = result_type;
+ return result_type;
+ }
+
+ IrInstruction *result;
+ if (align_bytes > old_align_bytes && align_bytes != 1) {
+ result = ir_build_align_cast(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
+ align_bytes_inst, target);
+ } else {
+ result = ir_build_cast(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
+ result_type, target, CastOpNoop);
+ }
+ ir_link_new_instruction(result, &instruction->base);
+ result->value.type = result_type;
+ return result_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -14877,6 +15035,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
case IrInstructionIdStructFieldPtr:
case IrInstructionIdEnumFieldPtr:
case IrInstructionIdInitEnum:
+ case IrInstructionIdMaybeWrap:
+ case IrInstructionIdErrWrapCode:
+ case IrInstructionIdErrWrapPayload:
+ case IrInstructionIdCast:
zig_unreachable();
case IrInstructionIdReturn:
return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);
@@ -15046,11 +15208,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_set_eval_branch_quota(ira, (IrInstructionSetEvalBranchQuota *)instruction);
case IrInstructionIdPtrTypeOf:
return ir_analyze_instruction_ptr_type_of(ira, (IrInstructionPtrTypeOf *)instruction);
- case IrInstructionIdMaybeWrap:
- case IrInstructionIdErrWrapCode:
- case IrInstructionIdErrWrapPayload:
- case IrInstructionIdCast:
- zig_panic("TODO analyze more instructions");
+ case IrInstructionIdAlignCast:
+ return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction);
}
zig_unreachable();
}
@@ -15228,6 +15387,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdFieldParentPtr:
case IrInstructionIdOffsetOf:
case IrInstructionIdTypeId:
+ case IrInstructionIdAlignCast:
return false;
case IrInstructionIdAsm:
{
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index bfaf45835b..3c6154b21d 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -174,10 +174,16 @@ static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instr
if (decl_var_instruction->var_type) {
fprintf(irp->f, "%s %s: ", var_or_const, name);
ir_print_other_instruction(irp, decl_var_instruction->var_type);
- fprintf(irp->f, " = ");
+ fprintf(irp->f, " ");
} else {
- fprintf(irp->f, "%s %s = ", var_or_const, name);
+ fprintf(irp->f, "%s %s ", var_or_const, name);
+ }
+ if (decl_var_instruction->align_value) {
+ fprintf(irp->f, "align ");
+ ir_print_other_instruction(irp, decl_var_instruction->align_value);
+ fprintf(irp->f, " ");
}
+ fprintf(irp->f, "= ");
ir_print_other_instruction(irp, decl_var_instruction->init_value);
if (decl_var_instruction->var->is_comptime != nullptr) {
fprintf(irp->f, " // comptime = ");
@@ -640,7 +646,7 @@ static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) {
ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, "[");
ir_print_other_instruction(irp, instruction->start);
- fprintf(irp->f, "...");
+ fprintf(irp->f, "..");
if (instruction->end)
ir_print_other_instruction(irp, instruction->end);
fprintf(irp->f, "]");
@@ -745,7 +751,13 @@ static void ir_print_fn_proto(IrPrint *irp, IrInstructionFnProto *instruction) {
ir_print_other_instruction(irp, instruction->param_types[i]);
}
}
- fprintf(irp->f, ")->");
+ fprintf(irp->f, ")");
+ if (instruction->align_value != nullptr) {
+ fprintf(irp->f, " align ");
+ ir_print_other_instruction(irp, instruction->align_value);
+ fprintf(irp->f, " ");
+ }
+ fprintf(irp->f, "->");
ir_print_other_instruction(irp, instruction->return_type);
}
@@ -920,6 +932,14 @@ static void ir_print_set_eval_branch_quota(IrPrint *irp, IrInstructionSetEvalBra
fprintf(irp->f, ")");
}
+static void ir_print_align_cast(IrPrint *irp, IrInstructionAlignCast *instruction) {
+ fprintf(irp->f, "@alignCast(");
+ ir_print_other_instruction(irp, instruction->align_bytes);
+ fprintf(irp->f, ",");
+ ir_print_other_instruction(irp, instruction->target);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1213,6 +1233,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSetEvalBranchQuota:
ir_print_set_eval_branch_quota(irp, (IrInstructionSetEvalBranchQuota *)instruction);
break;
+ case IrInstructionIdAlignCast:
+ ir_print_align_cast(irp, (IrInstructionAlignCast *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}