Commit dcfd15a7f0

Andrew Kelley <superjoe30@gmail.com>
2018-09-26 20:24:55
the last number in a packed ptr is host int bytes
See #1121
1 parent 631851f
src/all_types.hpp
@@ -664,7 +664,7 @@ struct AstNodePointerType {
     Token *star_token;
     AstNode *align_expr;
     BigInt *bit_offset_start;
-    BigInt *bit_offset_end;
+    BigInt *host_int_bytes;
     bool is_const;
     bool is_volatile;
     AstNode *op_expr;
@@ -1020,8 +1020,8 @@ struct ZigTypePointer {
     ZigType *slice_parent;
     PtrLen ptr_len;
     uint32_t explicit_alignment; // 0 means use ABI alignment
-    uint32_t bit_offset;
-    uint32_t unaligned_bit_count;
+    uint32_t bit_offset_in_host;
+    uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned
     bool is_const;
     bool is_volatile;
 };
@@ -1045,10 +1045,7 @@ struct TypeStructField {
     ZigType *type_entry;
     size_t src_index;
     size_t gen_index;
-    // offset from the memory at gen_index
-    size_t packed_bits_offset;
-    size_t packed_bits_size;
-    size_t unaligned_bit_count;
+    uint32_t bit_offset_in_host; // offset from the memory at gen_index
     AstNode *decl_node;
 };
 
@@ -1470,8 +1467,8 @@ struct TypeId {
             bool is_const;
             bool is_volatile;
             uint32_t alignment;
-            uint32_t bit_offset;
-            uint32_t unaligned_bit_count;
+            uint32_t bit_offset_in_host;
+            uint32_t host_int_bytes;
         } pointer;
         struct {
             ZigType *child_type;
@@ -2510,7 +2507,7 @@ struct IrInstructionPtrType {
     IrInstruction *align_value;
     IrInstruction *child_type;
     uint32_t bit_offset_start;
-    uint32_t bit_offset_end;
+    uint32_t host_int_bytes;
     PtrLen ptr_len;
     bool is_const;
     bool is_volatile;
src/analyze.cpp
@@ -419,7 +419,7 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
 }
 
 ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
-        bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
+        bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes)
 {
     assert(!type_is_invalid(child_type));
     assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
@@ -430,23 +430,31 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
             byte_alignment = 0;
     }
 
+    if (host_int_bytes != 0) {
+        uint32_t child_type_bits = type_size_bits(g, child_type);
+        if (host_int_bytes * 8 == child_type_bits) {
+            assert(bit_offset_in_host == 0);
+            host_int_bytes = 0;
+        }
+    }
+
     TypeId type_id = {};
     ZigType **parent_pointer = nullptr;
-    if (unaligned_bit_count != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) {
+    if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) {
         type_id.id = ZigTypeIdPointer;
         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;
+        type_id.data.pointer.bit_offset_in_host = bit_offset_in_host;
+        type_id.data.pointer.host_int_bytes = host_int_bytes;
         type_id.data.pointer.ptr_len = ptr_len;
 
         auto existing_entry = g->type_table.maybe_get(type_id);
         if (existing_entry)
             return existing_entry->value;
     } else {
-        assert(bit_offset == 0);
+        assert(bit_offset_in_host == 0);
         parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)];
         if (*parent_pointer) {
             assert((*parent_pointer)->data.pointer.explicit_alignment == 0);
@@ -463,17 +471,17 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
     const char *const_str = is_const ? "const " : "";
     const char *volatile_str = is_volatile ? "volatile " : "";
     buf_resize(&entry->name, 0);
-    if (unaligned_bit_count == 0 && byte_alignment == 0) {
+    if (host_int_bytes == 0 && byte_alignment == 0) {
         buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name));
-    } else if (unaligned_bit_count == 0) {
+    } else if (host_int_bytes == 0) {
         buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment,
                 const_str, volatile_str, buf_ptr(&child_type->name));
     } else if (byte_alignment == 0) {
         buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str,
-                bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
+                bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name));
     } else {
         buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment,
-                bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
+                bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name));
     }
 
     assert(child_type->id != ZigTypeIdInvalid);
@@ -481,7 +489,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
     entry->zero_bits = !type_has_bits(child_type);
 
     if (!entry->zero_bits) {
-        if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != 0 ||
+        if (is_const || is_volatile || host_int_bytes != 0 || byte_alignment != 0 ||
             ptr_len != PtrLenSingle)
         {
             ZigType *peer_type = get_pointer_to_type(g, child_type, false);
@@ -506,8 +514,8 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
     entry->data.pointer.is_const = is_const;
     entry->data.pointer.is_volatile = is_volatile;
     entry->data.pointer.explicit_alignment = byte_alignment;
-    entry->data.pointer.bit_offset = bit_offset;
-    entry->data.pointer.unaligned_bit_count = unaligned_bit_count;
+    entry->data.pointer.bit_offset_in_host = bit_offset_in_host;
+    entry->data.pointer.host_int_bytes = host_int_bytes;
 
     if (parent_pointer) {
         *parent_pointer = entry;
@@ -2007,12 +2015,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
             size_t field_size_in_bits = type_size_bits(g, field_type);
             size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;
 
-            type_struct_field->packed_bits_size = field_size_in_bits;
-
             if (first_packed_bits_offset_misalign != SIZE_MAX) {
                 // this field is not byte-aligned; it is part of the previous field with a bit offset
-                type_struct_field->packed_bits_offset = packed_bits_offset - first_packed_bits_offset_misalign;
-                type_struct_field->unaligned_bit_count = field_size_in_bits;
+                type_struct_field->bit_offset_in_host = packed_bits_offset - first_packed_bits_offset_misalign;
 
                 size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign;
                 LLVMTypeRef int_type_ref = LLVMIntType((unsigned)(full_bit_count));
@@ -2025,13 +2030,11 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
                 }
             } else if (8 * LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref) != field_size_in_bits) {
                 first_packed_bits_offset_misalign = packed_bits_offset;
-                type_struct_field->packed_bits_offset = 0;
-                type_struct_field->unaligned_bit_count = field_size_in_bits;
+                type_struct_field->bit_offset_in_host = 0;
             } else {
                 // This is a byte-aligned field (both start and end) in a packed struct.
                 element_types[gen_field_index] = field_type->type_ref;
-                type_struct_field->packed_bits_offset = 0;
-                type_struct_field->unaligned_bit_count = 0;
+                type_struct_field->bit_offset_in_host = 0;
                 gen_field_index += 1;
             }
             packed_bits_offset = next_packed_bits_offset;
@@ -2124,10 +2127,10 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
         uint64_t debug_align_in_bits;
         uint64_t debug_offset_in_bits;
         if (packed) {
-            debug_size_in_bits = type_struct_field->packed_bits_size;
+            debug_size_in_bits = type_size_bits(g, type_struct_field->type_entry);
             debug_align_in_bits = 1;
             debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref,
-                    (unsigned)gen_field_index) + type_struct_field->packed_bits_offset;
+                    (unsigned)gen_field_index) + type_struct_field->bit_offset_in_host;
         } else {
             debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
             debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_type->type_ref);
@@ -6007,8 +6010,8 @@ uint32_t type_id_hash(TypeId x) {
                 (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.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);
+                (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) +
+                (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
         case ZigTypeIdArray:
             return hash_ptr(x.data.array.child_type) +
                 ((uint32_t)x.data.array.size ^ (uint32_t)2122979968);
@@ -6055,8 +6058,8 @@ bool type_id_eql(TypeId a, TypeId b) {
                 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;
+                a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host &&
+                a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes;
         case ZigTypeIdArray:
             return a.data.array.child_type == b.data.array.child_type &&
                 a.data.array.size == b.data.array.size;
@@ -6534,3 +6537,13 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
         ty->id == ZigTypeIdUnreachable ||
         get_codegen_ptr_type(ty) != nullptr);
 }
+
+uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field) {
+    assert(struct_type->id == ZigTypeIdStruct);
+    if (struct_type->data.structure.layout != ContainerLayoutPacked) {
+        return 0;
+    }
+    LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(struct_type->type_ref, field->gen_index);
+    return LLVMStoreSizeOfType(g->target_data_ref, field_type);
+}
+
src/analyze.hpp
@@ -216,4 +216,6 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
 bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
 bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
 
+uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field);
+
 #endif
src/ast_render.cpp
@@ -635,7 +635,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
                     fprintf(ar->f, "align(");
                     render_node_grouped(ar, node->data.pointer_type.align_expr);
                     if (node->data.pointer_type.bit_offset_start != nullptr) {
-                        assert(node->data.pointer_type.bit_offset_end != nullptr);
+                        assert(node->data.pointer_type.host_int_bytes != nullptr);
 
                         Buf offset_start_buf = BUF_INIT;
                         buf_resize(&offset_start_buf, 0);
@@ -643,7 +643,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
 
                         Buf offset_end_buf = BUF_INIT;
                         buf_resize(&offset_end_buf, 0);
-                        bigint_append_buf(&offset_end_buf, node->data.pointer_type.bit_offset_end, 10);
+                        bigint_append_buf(&offset_end_buf, node->data.pointer_type.host_int_bytes, 10);
 
                         fprintf(ar->f, ":%s:%s ", buf_ptr(&offset_start_buf), buf_ptr(&offset_end_buf));
                     }
src/codegen.cpp
@@ -1795,8 +1795,8 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
         return nullptr;
     }
 
-    uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
-    if (unaligned_bit_count == 0) {
+    uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;
+    if (host_int_bytes == 0) {
         gen_store(g, value, ptr, ptr_type);
         return nullptr;
     }
@@ -1804,10 +1804,12 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
     bool big_endian = g->is_big_endian;
 
     LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
-
-    uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
     uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
-    uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - unaligned_bit_count : bit_offset;
+    assert(host_bit_count == host_int_bytes * 8);
+    uint32_t size_in_bits = type_size_bits(g, child_type);
+
+    uint32_t bit_offset = ptr_type->data.pointer.bit_offset_in_host;
+    uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset;
     LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
 
     LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
@@ -3209,18 +3211,20 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
     ZigType *ptr_type = instruction->ptr->value.type;
     assert(ptr_type->id == ZigTypeIdPointer);
 
-    uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
-    if (unaligned_bit_count == 0)
+    uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;
+    if (host_int_bytes == 0)
         return get_handle_value(g, ptr, child_type, ptr_type);
 
     bool big_endian = g->is_big_endian;
 
     assert(!handle_is_ptr(child_type));
     LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
-
-    uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
     uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
-    uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - unaligned_bit_count : bit_offset;
+    assert(host_bit_count == host_int_bytes * 8);
+    uint32_t size_in_bits = type_size_bits(g, child_type);
+
+    uint32_t bit_offset = ptr_type->data.pointer.bit_offset_in_host;
+    uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset;
 
     LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
     LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
@@ -3276,20 +3280,22 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
                     array_type->data.array.len, false);
             add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
         }
-        if (array_ptr_type->data.pointer.unaligned_bit_count != 0) {
+        if (array_ptr_type->data.pointer.host_int_bytes != 0) {
             return array_ptr_ptr;
         }
         ZigType *child_type = array_type->data.array.child_type;
         if (child_type->id == ZigTypeIdStruct &&
             child_type->data.structure.layout == ContainerLayoutPacked)
         {
-            size_t unaligned_bit_count = instruction->base.value.type->data.pointer.unaligned_bit_count;
-            if (unaligned_bit_count != 0) {
+            ZigType *ptr_type = instruction->base.value.type;
+            size_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;
+            if (host_int_bytes != 0) {
+                uint32_t size_in_bits = type_size_bits(g, ptr_type->data.pointer.child_type);
                 LLVMTypeRef ptr_u8_type_ref = LLVMPointerType(LLVMInt8Type(), 0);
                 LLVMValueRef u8_array_ptr = LLVMBuildBitCast(g->builder, array_ptr, ptr_u8_type_ref, "");
-                assert(unaligned_bit_count % 8 == 0);
+                assert(size_in_bits % 8 == 0);
                 LLVMValueRef elem_size_bytes = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
-                        unaligned_bit_count / 8, false);
+                        size_in_bits / 8, false);
                 LLVMValueRef byte_offset = LLVMBuildNUWMul(g->builder, subscript_value, elem_size_bytes, "");
                 LLVMValueRef indices[] = {
                     byte_offset
@@ -3505,7 +3511,7 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
         return nullptr;
 
     if (struct_ptr_type->id == ZigTypeIdPointer &&
-        struct_ptr_type->data.pointer.unaligned_bit_count != 0)
+        struct_ptr_type->data.pointer.host_int_bytes != 0)
     {
         return struct_ptr;
     }
@@ -4671,10 +4677,11 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
         LLVMValueRef value = ir_llvm_value(g, field->value);
 
         uint32_t field_align_bytes = get_abi_alignment(g, type_struct_field->type_entry);
+        uint32_t host_int_bytes = get_host_int_bytes(g, instruction->struct_type, type_struct_field);
 
         ZigType *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
                 false, false, PtrLenSingle, field_align_bytes,
-                (uint32_t)type_struct_field->packed_bits_offset, (uint32_t)type_struct_field->unaligned_bit_count);
+                (uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes);
 
         gen_assign_raw(g, field_ptr, ptr_type, value);
     }
@@ -5459,15 +5466,16 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
                         continue;
                     }
                     LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, &const_val->data.x_struct.fields[i]);
+                    uint32_t packed_bits_size = type_size_bits(g, field->type_entry);
                     if (is_big_endian) {
-                        LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false);
+                        LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false);
                         val = LLVMConstShl(val, shift_amt);
                         val = LLVMConstOr(val, child_val);
                     } else {
                         LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false);
                         LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt);
                         val = LLVMConstOr(val, child_val_shifted);
-                        used_bits += field->packed_bits_size;
+                        used_bits += packed_bits_size;
                     }
                 }
                 return val;
@@ -5677,16 +5685,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                                 }
                                 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref,
                                         &const_val->data.x_struct.fields[i]);
+                                uint32_t packed_bits_size = type_size_bits(g, it_field->type_entry);
                                 if (is_big_endian) {
                                     LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref,
-                                            it_field->packed_bits_size, false);
+                                            packed_bits_size, false);
                                     val = LLVMConstShl(val, shift_amt);
                                     val = LLVMConstOr(val, child_val);
                                 } else {
                                     LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false);
                                     LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt);
                                     val = LLVMConstOr(val, child_val_shifted);
-                                    used_bits += it_field->packed_bits_size;
+                                    used_bits += packed_bits_size;
                                 }
                             }
                             fields[type_struct_field->gen_index] = val;
src/ir.cpp
@@ -1296,7 +1296,7 @@ static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instru
 
 static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
         IrInstruction *child_type, bool is_const, bool is_volatile, PtrLen ptr_len,
-        IrInstruction *align_value, uint32_t bit_offset_start, uint32_t bit_offset_end)
+        IrInstruction *align_value, uint32_t bit_offset_start, uint32_t host_int_bytes)
 {
     IrInstructionPtrType *ptr_type_of_instruction = ir_build_instruction<IrInstructionPtrType>(irb, scope, source_node);
     ptr_type_of_instruction->align_value = align_value;
@@ -1305,7 +1305,7 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s
     ptr_type_of_instruction->is_volatile = is_volatile;
     ptr_type_of_instruction->ptr_len = ptr_len;
     ptr_type_of_instruction->bit_offset_start = bit_offset_start;
-    ptr_type_of_instruction->bit_offset_end = bit_offset_end;
+    ptr_type_of_instruction->host_int_bytes = host_int_bytes;
 
     if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
     ir_ref_instruction(child_type, irb->current_basic_block);
@@ -5154,26 +5154,26 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
         bit_offset_start = bigint_as_unsigned(node->data.pointer_type.bit_offset_start);
     }
 
-    uint32_t bit_offset_end = 0;
-    if (node->data.pointer_type.bit_offset_end != nullptr) {
-        if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_end, 32, false)) {
+    uint32_t host_int_bytes = 0;
+    if (node->data.pointer_type.host_int_bytes != nullptr) {
+        if (!bigint_fits_in_bits(node->data.pointer_type.host_int_bytes, 32, false)) {
             Buf *val_buf = buf_alloc();
-            bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_end, 10);
+            bigint_append_buf(val_buf, node->data.pointer_type.host_int_bytes, 10);
             exec_add_error_node(irb->codegen, irb->exec, node,
-                    buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
+                    buf_sprintf("value %s too large for u32 byte count", buf_ptr(val_buf)));
             return irb->codegen->invalid_instruction;
         }
-        bit_offset_end = bigint_as_unsigned(node->data.pointer_type.bit_offset_end);
+        host_int_bytes = bigint_as_unsigned(node->data.pointer_type.host_int_bytes);
     }
 
-    if ((bit_offset_start != 0 || bit_offset_end != 0) && bit_offset_start >= bit_offset_end) {
+    if (host_int_bytes != 0 && bit_offset_start >= host_int_bytes * 8) {
         exec_add_error_node(irb->codegen, irb->exec, node,
-                buf_sprintf("bit offset start must be less than bit offset end"));
+                buf_sprintf("bit offset starts after end of host integer"));
         return irb->codegen->invalid_instruction;
     }
 
     return ir_build_ptr_type(irb, scope, node, child_type, is_const, is_volatile,
-            ptr_len, align_value, bit_offset_start, bit_offset_end);
+            ptr_len, align_value, bit_offset_start, host_int_bytes);
 }
 
 static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
@@ -8600,8 +8600,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
         if ((actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) &&
             (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
             (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) &&
-            actual_type->data.pointer.bit_offset == wanted_type->data.pointer.bit_offset &&
-            actual_type->data.pointer.unaligned_bit_count == wanted_type->data.pointer.unaligned_bit_count &&
+            actual_type->data.pointer.bit_offset_in_host == wanted_type->data.pointer.bit_offset_in_host &&
+            actual_type->data.pointer.host_int_bytes == wanted_type->data.pointer.host_int_bytes &&
             get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type))
         {
             return result;
@@ -8622,8 +8622,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
         }
         if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) &&
             (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) &&
-            actual_ptr_type->data.pointer.bit_offset == wanted_ptr_type->data.pointer.bit_offset &&
-            actual_ptr_type->data.pointer.unaligned_bit_count == wanted_ptr_type->data.pointer.unaligned_bit_count &&
+            actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host &&
+            actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes &&
             get_ptr_align(g, actual_ptr_type) >= get_ptr_align(g, wanted_ptr_type))
         {
             ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type,
@@ -11166,8 +11166,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         if (dest_ptr_type != nullptr &&
             (!actual_type->data.pointer.is_const || dest_ptr_type->data.pointer.is_const) &&
             (!actual_type->data.pointer.is_volatile || dest_ptr_type->data.pointer.is_volatile) &&
-            actual_type->data.pointer.bit_offset == dest_ptr_type->data.pointer.bit_offset &&
-            actual_type->data.pointer.unaligned_bit_count == dest_ptr_type->data.pointer.unaligned_bit_count &&
+            actual_type->data.pointer.bit_offset_in_host == dest_ptr_type->data.pointer.bit_offset_in_host &&
+            actual_type->data.pointer.host_int_bytes == dest_ptr_type->data.pointer.host_int_bytes &&
             get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type))
         {
             return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr);
@@ -14359,7 +14359,7 @@ static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_ali
             ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
             ptr_type->data.pointer.ptr_len,
             new_align,
-            ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
+            ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
 }
 
 static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) {
@@ -14376,7 +14376,7 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
             ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
             ptr_len,
             ptr_type->data.pointer.explicit_alignment,
-            ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
+            ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
 }
 
 static ZigType *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
@@ -14423,7 +14423,7 @@ static ZigType *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionEle
             return ira->codegen->builtin_types.entry_invalid;
         }
         ZigType *child_type = array_type->data.array.child_type;
-        if (ptr_type->data.pointer.unaligned_bit_count == 0) {
+        if (ptr_type->data.pointer.host_int_bytes == 0) {
             return_type = get_pointer_to_type_extra(ira->codegen, child_type,
                     ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
                     elem_ptr_instruction->ptr_len,
@@ -14439,7 +14439,7 @@ static ZigType *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionEle
             return_type = get_pointer_to_type_extra(ira->codegen, child_type,
                     ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
                     elem_ptr_instruction->ptr_len,
-                    1, (uint32_t)bit_offset, (uint32_t)bit_width);
+                    1, (uint32_t)bit_offset, ptr_type->data.pointer.host_int_bytes);
         }
     } else if (array_type->id == ZigTypeIdPointer) {
         if (array_type->data.pointer.ptr_len == PtrLenSingle) {
@@ -14740,10 +14740,10 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
         if (field) {
             bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked);
             uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry);
-            size_t ptr_bit_offset = container_ptr->value.type->data.pointer.bit_offset;
-            size_t ptr_unaligned_bit_count = container_ptr->value.type->data.pointer.unaligned_bit_count;
-            size_t unaligned_bit_count_for_result_type = (ptr_unaligned_bit_count == 0) ?
-                field->unaligned_bit_count : type_size_bits(ira->codegen, field->type_entry);
+            uint32_t ptr_bit_offset = container_ptr->value.type->data.pointer.bit_offset_in_host;
+            uint32_t ptr_host_int_bytes = container_ptr->value.type->data.pointer.host_int_bytes;
+            uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ?
+                get_host_int_bytes(ira->codegen, bare_type, field) : ptr_host_int_bytes;
             if (instr_is_comptime(container_ptr)) {
                 ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
                 if (!ptr_val)
@@ -14758,8 +14758,8 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
                     ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
                     ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type,
                             is_const, is_volatile, PtrLenSingle, align_bytes,
-                            (uint32_t)(ptr_bit_offset + field->packed_bits_offset),
-                            (uint32_t)unaligned_bit_count_for_result_type);
+                            (uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
+                            (uint32_t)host_int_bytes_for_result_type);
                     IrInstruction *result = ir_get_const(ira, source_instr);
                     ConstExprValue *const_val = &result->value;
                     const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
@@ -14775,8 +14775,8 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
             result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
                     PtrLenSingle,
                     align_bytes,
-                    (uint32_t)(ptr_bit_offset + field->packed_bits_offset),
-                    (uint32_t)unaligned_bit_count_for_result_type);
+                    (uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
+                    host_int_bytes_for_result_type);
             return result;
         } else {
             return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
@@ -17135,7 +17135,7 @@ static ZigType *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,
     if (!(field = validate_byte_offset(ira, type_value, field_name_value, &byte_offset)))
         return ira->codegen->builtin_types.entry_invalid;
 
-    size_t bit_offset = byte_offset * 8 + field->packed_bits_offset;
+    size_t bit_offset = byte_offset * 8 + field->bit_offset_in_host;
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
     bigint_init_unsigned(&out_val->data.x_bigint, bit_offset);
     return ira->codegen->builtin_types.entry_num_lit_int;
@@ -20758,7 +20758,7 @@ static ZigType *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtr
     out_val->data.x_type = get_pointer_to_type_extra(ira->codegen, child_type,
             instruction->is_const, instruction->is_volatile,
             instruction->ptr_len, align_bytes,
-            instruction->bit_offset_start, instruction->bit_offset_end - instruction->bit_offset_start);
+            instruction->bit_offset_start, instruction->host_int_bytes);
 
     return ira->codegen->builtin_types.entry_type;
 }
src/ir_print.cpp
@@ -1015,7 +1015,7 @@ static void ir_print_ptr_type(IrPrint *irp, IrInstructionPtrType *instruction) {
     }
     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,
+    fprintf(irp->f, ":%" PRIu32 ":%" PRIu32 " %s%s", instruction->bit_offset_start, instruction->host_int_bytes,
             const_str, volatile_str);
     ir_print_other_instruction(irp, instruction->child_type);
 }
src/parser.cpp
@@ -1161,10 +1161,10 @@ static AstNode *ast_parse_pointer_type(ParseContext *pc, size_t *token_index, To
             *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 *host_int_bytes_tok = ast_eat_token(pc, token_index, TokenIdIntLiteral);
 
             node->data.pointer_type.bit_offset_start = token_bigint(bit_offset_start_tok);
-            node->data.pointer_type.bit_offset_end = token_bigint(bit_offset_end_tok);
+            node->data.pointer_type.host_int_bytes = token_bigint(host_int_bytes_tok);
         }
         ast_eat_token(pc, token_index, TokenIdRParen);
         token = &pc->tokens->at(*token_index);
test/cases/align.zig
@@ -40,7 +40,7 @@ const blah: packed struct {
 } = undefined;
 
 test "bit field alignment" {
-    assert(@typeOf(&blah.b) == *align(1:3:6) const u3);
+    assert(@typeOf(&blah.b) == *align(1:3:1) const u3);
 }
 
 test "default alignment allows unspecified in type syntax" {
test/cases/eval.zig
@@ -754,3 +754,11 @@ test "comptime bitwise operators" {
         assert(~u128(0) == 0xffffffffffffffffffffffffffffffff);
     }
 }
+
+test "*align(1) u16 is the same as *align(1:0:2) u16" {
+    comptime {
+        assert(*align(1:0:2) u16 == *align(1) u16);
+        // TODO add parsing support for this syntax
+        //assert(*align(:0:2) u16 == *u16);
+    }
+}
test/compile_errors.zig
@@ -3536,7 +3536,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\
         \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
     ,
-        ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(:3:6) const u3'",
+        ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'",
     );
 
     cases.add(