authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-16 19:35:42-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-16 19:35:42-05:00
log0148f39df929cc00c1b2231acce41c22f74f9969
tree6b7904248232572d9edc5b69b74a67c166bb8008
parent244362fed7ed9280a0612c7c57ed67f6fa33b40d

pointers with bit offset contain length

adds compile error when passing pointer that is byte-aligned at the beginning but not the end to a function expecting a fully byte aligned pointer closes #261

6 files changed, 74 insertions(+), 57 deletions(-)

src/all_types.hpp+3
......@@ -853,6 +853,7 @@ struct TypeTableEntryPointer {
853853 bool is_const;
854854 bool is_volatile;
855855 uint32_t bit_offset;
856 uint32_t unaligned_bit_count;
856857};
857858
858859struct TypeTableEntryInt {
......@@ -877,6 +878,7 @@ struct TypeStructField {
877878 // offset from the memory at gen_index
878879 size_t packed_bits_offset;
879880 size_t packed_bits_size;
881 size_t unaligned_bit_count;
880882};
881883struct TypeTableEntryStruct {
882884 AstNode *decl_node;
......@@ -1204,6 +1206,7 @@ struct TypeId {
12041206 bool is_const;
12051207 bool is_volatile;
12061208 uint32_t bit_offset;
1209 uint32_t unaligned_bit_count;
12071210 } pointer;
12081211 struct {
12091212 TypeTableEntry *child_type;
src/analyze.cpp+23-11
......@@ -287,23 +287,25 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
287287}
288288
289289TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
290 uint32_t bit_offset, bool is_volatile)
290 bool is_volatile, uint32_t bit_offset, uint32_t unaligned_bit_count)
291291{
292292 assert(child_type->id != TypeTableEntryIdInvalid);
293293
294294 TypeId type_id = {};
295295 TypeTableEntry **parent_pointer = nullptr;
296 if (bit_offset != 0 || is_volatile) {
296 if (unaligned_bit_count != 0 || is_volatile) {
297297 type_id.id = TypeTableEntryIdPointer;
298298 type_id.data.pointer.child_type = child_type;
299299 type_id.data.pointer.is_const = is_const;
300300 type_id.data.pointer.is_volatile = is_volatile;
301301 type_id.data.pointer.bit_offset = bit_offset;
302 type_id.data.pointer.unaligned_bit_count = unaligned_bit_count;
302303
303304 auto existing_entry = g->type_table.maybe_get(type_id);
304305 if (existing_entry)
305306 return existing_entry->value;
306307 } else {
308 assert(bit_offset == 0);
307309 parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)];
308310 if (*parent_pointer)
309311 return *parent_pointer;
......@@ -316,11 +318,11 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
316318 const char *const_str = is_const ? "const " : "";
317319 const char *volatile_str = is_volatile ? "volatile " : "";
318320 buf_resize(&entry->name, 0);
319 if (bit_offset == 0) {
321 if (unaligned_bit_count == 0) {
320322 buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
321323 } else {
322 buf_appendf(&entry->name, "&:%" PRIu8 " %s%s%s", bit_offset, const_str,
323 volatile_str, buf_ptr(&child_type->name));
324 buf_appendf(&entry->name, "&:%" PRIu32 ":%" PRIu32 " %s%s%s", bit_offset,
325 bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
324326 }
325327
326328 TypeTableEntry *canon_child_type = get_underlying_type(child_type);
......@@ -344,6 +346,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
344346 entry->data.pointer.is_const = is_const;
345347 entry->data.pointer.is_volatile = is_volatile;
346348 entry->data.pointer.bit_offset = bit_offset;
349 entry->data.pointer.unaligned_bit_count = unaligned_bit_count;
347350
348351 if (parent_pointer) {
349352 *parent_pointer = entry;
......@@ -354,7 +357,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
354357}
355358
356359TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
357 return get_pointer_to_type_extra(g, child_type, is_const, 0, false);
360 return get_pointer_to_type_extra(g, child_type, is_const, false, 0, 0);
358361}
359362
360363TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
......@@ -1429,13 +1432,15 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
14291432 break;
14301433 }
14311434
1432 type_struct_field->packed_bits_size = type_size_bits(g, field_type);
1435 size_t field_size_in_bits = type_size_bits(g, field_type);
1436 size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;
14331437
1434 size_t next_packed_bits_offset = packed_bits_offset + type_struct_field->packed_bits_size;
1438 type_struct_field->packed_bits_size = field_size_in_bits;
14351439
14361440 if (first_packed_bits_offset_misalign != SIZE_MAX) {
14371441 // this field is not byte-aligned; it is part of the previous field with a bit offset
14381442 type_struct_field->packed_bits_offset = packed_bits_offset - first_packed_bits_offset_misalign;
1443 type_struct_field->unaligned_bit_count = field_size_in_bits;
14391444
14401445 if (next_packed_bits_offset % 8 == 0) {
14411446 // next field recovers byte alignment
......@@ -1448,9 +1453,12 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
14481453 } else if (next_packed_bits_offset % 8 != 0) {
14491454 first_packed_bits_offset_misalign = packed_bits_offset;
14501455 type_struct_field->packed_bits_offset = 0;
1456 type_struct_field->unaligned_bit_count = field_size_in_bits;
14511457 } else {
1458 // This is a byte-aligned field (both start and end) in a packed struct.
14521459 element_types[gen_field_index] = field_type->type_ref;
14531460 type_struct_field->packed_bits_offset = 0;
1461 type_struct_field->unaligned_bit_count = 0;
14541462 gen_field_index += 1;
14551463 }
14561464 packed_bits_offset = next_packed_bits_offset;
......@@ -2237,7 +2245,9 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
22372245 if (expected_type->id == TypeTableEntryIdPointer &&
22382246 actual_type->id == TypeTableEntryIdPointer &&
22392247 (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const) &&
2240 (!actual_type->data.pointer.is_volatile || expected_type->data.pointer.is_volatile))
2248 (!actual_type->data.pointer.is_volatile || expected_type->data.pointer.is_volatile) &&
2249 actual_type->data.pointer.bit_offset == expected_type->data.pointer.bit_offset &&
2250 actual_type->data.pointer.unaligned_bit_count == expected_type->data.pointer.unaligned_bit_count)
22412251 {
22422252 return types_match_const_cast_only(expected_type->data.pointer.child_type,
22432253 actual_type->data.pointer.child_type);
......@@ -3943,7 +3953,8 @@ uint32_t type_id_hash(TypeId x) {
39433953 return hash_ptr(x.data.pointer.child_type) +
39443954 (x.data.pointer.is_const ? 2749109194 : 4047371087) +
39453955 (x.data.pointer.is_volatile ? 536730450 : 1685612214) +
3946 (((uint32_t)x.data.pointer.bit_offset) * 2639019452);
3956 (((uint32_t)x.data.pointer.bit_offset) * 2639019452) +
3957 (((uint32_t)x.data.pointer.unaligned_bit_count) * 529908881);
39473958 case TypeTableEntryIdArray:
39483959 return hash_ptr(x.data.array.child_type) +
39493960 (x.data.array.size * 2122979968);
......@@ -3987,7 +3998,8 @@ bool type_id_eql(TypeId a, TypeId b) {
39873998 return a.data.pointer.child_type == b.data.pointer.child_type &&
39883999 a.data.pointer.is_const == b.data.pointer.is_const &&
39894000 a.data.pointer.is_volatile == b.data.pointer.is_volatile &&
3990 a.data.pointer.bit_offset == b.data.pointer.bit_offset;
4001 a.data.pointer.bit_offset == b.data.pointer.bit_offset &&
4002 a.data.pointer.unaligned_bit_count == b.data.pointer.unaligned_bit_count;
39914003 case TypeTableEntryIdArray:
39924004 return a.data.array.child_type == b.data.array.child_type &&
39934005 a.data.array.size == b.data.array.size;
src/analyze.hpp+1-1
......@@ -16,7 +16,7 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m
1616TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
1717TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
1818TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
19 uint32_t bit_offset, bool is_volatile);
19 bool is_volatile, uint32_t bit_offset, uint32_t unaligned_bit_count);
2020bool is_node_void_expr(AstNode *node);
2121uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
2222uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry);
src/codegen.cpp+16-33
......@@ -1374,27 +1374,17 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
13741374 assert(ptr_type->id == TypeTableEntryIdPointer);
13751375 bool is_volatile = ptr_type->data.pointer.is_volatile;
13761376
1377 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
1378 LLVMValueRef containing_int;
1379 if (bit_offset == 0) {
1380 LLVMValueRef result_val = get_handle_value(g, ptr, child_type, is_volatile);
1381 if (LLVMGetTypeKind(LLVMTypeOf(result_val)) == LLVMIntegerTypeKind &&
1382 LLVMGetTypeKind(child_type->type_ref) == LLVMIntegerTypeKind &&
1383 LLVMGetIntTypeWidth(child_type->type_ref) < LLVMGetIntTypeWidth(LLVMTypeOf(result_val)))
1384 {
1385 containing_int = result_val;
1386 } else {
1387 return result_val;
1388 }
1389 } else {
1390 assert(!handle_is_ptr(child_type));
1391 containing_int = LLVMBuildLoad(g->builder, ptr, "");
1392 LLVMSetVolatile(containing_int, is_volatile);
1393 }
1377 uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
1378 if (unaligned_bit_count == 0)
1379 return get_handle_value(g, ptr, child_type, is_volatile);
1380
1381 assert(!handle_is_ptr(child_type));
1382 LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
1383 LLVMSetVolatile(containing_int, is_volatile);
13941384
1395 uint32_t child_bit_count = type_size_bits(g, child_type);
1385 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
13961386 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
1397 uint32_t shift_amt = host_bit_count - bit_offset - child_bit_count;
1387 uint32_t shift_amt = host_bit_count - bit_offset - unaligned_bit_count;
13981388
13991389 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
14001390 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
......@@ -1416,25 +1406,18 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
14161406 if (handle_is_ptr(child_type))
14171407 return gen_struct_memcpy(g, value, ptr, child_type);
14181408
1419 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
1420 if (bit_offset == 0) {
1421 LLVMTypeRef ptr_child_ref = LLVMGetElementType(LLVMTypeOf(ptr));
1422 bool need_to_do_some_bit_stuff =
1423 LLVMGetTypeKind(ptr_child_ref) == LLVMIntegerTypeKind &&
1424 LLVMGetTypeKind(child_type->type_ref) == LLVMIntegerTypeKind &&
1425 LLVMGetIntTypeWidth(child_type->type_ref) < LLVMGetIntTypeWidth(ptr_child_ref);
1426 if (!need_to_do_some_bit_stuff) {
1427 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr);
1428 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
1429 return nullptr;
1430 }
1409 uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
1410 if (unaligned_bit_count == 0) {
1411 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr);
1412 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
1413 return nullptr;
14311414 }
14321415
14331416 LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
14341417
1435 uint32_t child_bit_count = type_size_bits(g, child_type);
1418 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
14361419 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
1437 uint32_t shift_amt = host_bit_count - bit_offset - child_bit_count;
1420 uint32_t shift_amt = host_bit_count - bit_offset - unaligned_bit_count;
14381421 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
14391422
14401423 LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
src/ir.cpp+12-12
......@@ -6227,11 +6227,11 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
62276227 const_val->type = pointee_type;
62286228 type_ensure_zero_bits_known(ira->codegen, type_entry);
62296229 const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry,
6230 ptr_is_const, 0, ptr_is_volatile);
6230 ptr_is_const, ptr_is_volatile, 0, 0);
62316231 return const_instr;
62326232 } else {
62336233 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, pointee_type,
6234 ptr_is_const, 0, ptr_is_volatile);
6234 ptr_is_const, ptr_is_volatile, 0, 0);
62356235 IrInstruction *const_instr = ir_get_const(ira, instruction);
62366236 ConstExprValue *const_val = &const_instr->value;
62376237 const_val->type = ptr_type;
......@@ -6547,7 +6547,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
65476547 ConstPtrMutComptimeConst, is_const, is_volatile);
65486548 }
65496549
6550 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, is_const, 0, is_volatile);
6550 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, is_const, is_volatile, 0, 0);
65516551 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
65526552 assert(fn_entry);
65536553 IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
......@@ -8839,7 +8839,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
88398839 }
88408840 TypeTableEntry *child_type = array_type->data.array.child_type;
88418841 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
8842 ptr_type->data.pointer.is_const, 0, ptr_type->data.pointer.is_volatile);
8842 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0);
88438843 } else if (array_type->id == TypeTableEntryIdPointer) {
88448844 return_type = array_type;
88458845 } else if (is_slice(array_type)) {
......@@ -9057,7 +9057,7 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
90579057 ConstExprValue *struct_val = const_ptr_pointee(ptr_val);
90589058 ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
90599059 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type,
9060 is_const, 0, is_volatile);
9060 is_const, is_volatile, 0, 0);
90619061 ConstExprValue *const_val = ir_build_const_from(ira, &field_ptr_instruction->base);
90629062 const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
90639063 const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
......@@ -9068,7 +9068,7 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
90689068 }
90699069 ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
90709070 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const,
9071 field->packed_bits_offset, is_volatile);
9071 is_volatile, field->packed_bits_offset, field->unaligned_bit_count);
90729072 } else {
90739073 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
90749074 field_ptr_instruction, container_ptr, container_type);
......@@ -9080,7 +9080,7 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
90809080 TypeEnumField *field = find_enum_type_field(bare_type, field_name);
90819081 if (field) {
90829082 ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
9083 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, 0, is_volatile);
9083 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, 0, 0);
90849084 } else {
90859085 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
90869086 field_ptr_instruction, container_ptr, container_type);
......@@ -10016,7 +10016,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
1001610016 }
1001710017 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
1001810018 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
10019 ptr_type->data.pointer.is_const, 0, ptr_type->data.pointer.is_volatile);
10019 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0);
1002010020
1002110021 if (instr_is_comptime(value)) {
1002210022 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
......@@ -11322,7 +11322,7 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi
1132211322
1132311323 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
1132411324 TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
11325 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, 0, dest_is_volatile);
11325 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, 0, 0);
1132611326
1132711327 IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr);
1132811328 if (casted_dest_ptr->value.type->id == TypeTableEntryIdInvalid)
......@@ -11410,8 +11410,8 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
1141011410
1141111411 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
1141211412 TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8;
11413 TypeTableEntry *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, 0, dest_is_volatile);
11414 TypeTableEntry *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, 0, src_is_volatile);
11413 TypeTableEntry *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, 0, 0);
11414 TypeTableEntry *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile, 0, 0);
1141511415
1141611416 IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut);
1141711417 if (casted_dest_ptr->value.type->id == TypeTableEntryIdInvalid)
......@@ -11929,7 +11929,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
1192911929 } else if (canon_type->id == TypeTableEntryIdErrorUnion) {
1193011930 TypeTableEntry *child_type = canon_type->data.error.child_type;
1193111931 TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
11932 ptr_type->data.pointer.is_const, 0, ptr_type->data.pointer.is_volatile);
11932 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0);
1193311933 if (instr_is_comptime(value)) {
1193411934 ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
1193511935 if (!ptr_val)
test/run_tests.cpp+19
......@@ -1627,6 +1627,25 @@ pub fn main(args: [][]u8) -> ??void {
16271627}
16281628 )SOURCE", 1, ".tmp_source.zig:2:30: error: expected return type of main to be '%void', instead is '??void'");
16291629
1630 add_compile_fail_case("casting bit offset pointer to regular pointer", R"SOURCE(
1631const u2 = @intType(false, 2);
1632const u3 = @intType(false, 3);
1633
1634const BitField = packed struct {
1635 a: u3,
1636 b: u3,
1637 c: u2,
1638};
1639
1640fn foo(bit_field: &const BitField) -> u3 {
1641 return bar(&bit_field.b);
1642}
1643
1644fn bar(x: &const u3) -> u3 {
1645 return *x;
1646}
1647 )SOURCE", 1, ".tmp_source.zig:12:26: error: expected type '&const u3', found '&:3:6 const u3'");
1648
16301649}
16311650
16321651//////////////////////////////////////////////////////////////////////////////