aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
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/codegen.cpp
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/codegen.cpp')
-rw-r--r--src/codegen.cpp71
1 files changed, 71 insertions, 0 deletions
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) {