| ... | @@ -2424,6 +2424,24 @@ pub const DeclGen = struct { | ... | @@ -2424,6 +2424,24 @@ pub const DeclGen = struct { |
| 2424 | } | 2424 | } |
| 2425 | | 2425 | |
| 2426 | fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type { | 2426 | fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type { |
| | 2427 | const llvm_ty = try lowerTypeInner(dg, t); |
| | 2428 | if (std.debug.runtime_safety and false) check: { |
| | 2429 | if (t.zigTypeTag() == .Opaque) break :check; |
| | 2430 | if (!t.hasRuntimeBits()) break :check; |
| | 2431 | if (!llvm_ty.isSized().toBool()) break :check; |
| | 2432 | |
| | 2433 | const zig_size = t.abiSize(dg.module.getTarget()); |
| | 2434 | const llvm_size = dg.object.target_data.abiSizeOfType(llvm_ty); |
| | 2435 | if (llvm_size != zig_size) { |
| | 2436 | log.err("when lowering {}, Zig ABI size = {d} but LLVM ABI size = {d}", .{ |
| | 2437 | t.fmt(dg.module), zig_size, llvm_size, |
| | 2438 | }); |
| | 2439 | } |
| | 2440 | } |
| | 2441 | return llvm_ty; |
| | 2442 | } |
| | 2443 | |
| | 2444 | fn lowerTypeInner(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type { |
| 2427 | const gpa = dg.gpa; | 2445 | const gpa = dg.gpa; |
| 2428 | const target = dg.module.getTarget(); | 2446 | const target = dg.module.getTarget(); |
| 2429 | switch (t.zigTypeTag()) { | 2447 | switch (t.zigTypeTag()) { |
| ... | @@ -2519,10 +2537,18 @@ pub const DeclGen = struct { | ... | @@ -2519,10 +2537,18 @@ pub const DeclGen = struct { |
| 2519 | return payload_llvm_ty; | 2537 | return payload_llvm_ty; |
| 2520 | } | 2538 | } |
| 2521 | | 2539 | |
| 2522 | const fields: [2]*const llvm.Type = .{ | 2540 | comptime assert(optional_layout_version == 2); |
| 2523 | payload_llvm_ty, dg.context.intType(1), | 2541 | var fields_buf: [3]*const llvm.Type = .{ |
| | 2542 | payload_llvm_ty, dg.context.intType(1), undefined, |
| 2524 | }; | 2543 | }; |
| 2525 | return dg.context.structType(&fields, fields.len, .False); | 2544 | const offset = child_ty.abiSize(target) + 1; |
| | 2545 | const abi_size = t.abiSize(target); |
| | 2546 | const padding = @intCast(c_uint, abi_size - offset); |
| | 2547 | if (padding == 0) { |
| | 2548 | return dg.context.structType(&fields_buf, 2, .False); |
| | 2549 | } |
| | 2550 | fields_buf[2] = dg.context.intType(8).arrayType(padding); |
| | 2551 | return dg.context.structType(&fields_buf, 3, .False); |
| 2526 | }, | 2552 | }, |
| 2527 | .ErrorUnion => { | 2553 | .ErrorUnion => { |
| 2528 | const payload_ty = t.errorUnionPayload(); | 2554 | const payload_ty = t.errorUnionPayload(); |
| ... | @@ -2534,12 +2560,37 @@ pub const DeclGen = struct { | ... | @@ -2534,12 +2560,37 @@ pub const DeclGen = struct { |
| 2534 | | 2560 | |
| 2535 | const payload_align = payload_ty.abiAlignment(target); | 2561 | const payload_align = payload_ty.abiAlignment(target); |
| 2536 | const error_align = Type.anyerror.abiAlignment(target); | 2562 | const error_align = Type.anyerror.abiAlignment(target); |
| | 2563 | |
| | 2564 | const payload_size = payload_ty.abiSize(target); |
| | 2565 | const error_size = Type.anyerror.abiSize(target); |
| | 2566 | |
| | 2567 | var fields_buf: [3]*const llvm.Type = undefined; |
| 2537 | if (error_align > payload_align) { | 2568 | if (error_align > payload_align) { |
| 2538 | const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type }; | 2569 | fields_buf[0] = llvm_error_type; |
| 2539 | return dg.context.structType(&fields, fields.len, .False); | 2570 | fields_buf[1] = llvm_payload_type; |
| | 2571 | const payload_end = |
| | 2572 | std.mem.alignForwardGeneric(u64, error_size, payload_align) + |
| | 2573 | payload_size; |
| | 2574 | const abi_size = std.mem.alignForwardGeneric(u64, payload_end, error_align); |
| | 2575 | const padding = @intCast(c_uint, abi_size - payload_end); |
| | 2576 | if (padding == 0) { |
| | 2577 | return dg.context.structType(&fields_buf, 2, .False); |
| | 2578 | } |
| | 2579 | fields_buf[2] = dg.context.intType(8).arrayType(padding); |
| | 2580 | return dg.context.structType(&fields_buf, 3, .False); |
| 2540 | } else { | 2581 | } else { |
| 2541 | const fields: [2]*const llvm.Type = .{ llvm_payload_type, llvm_error_type }; | 2582 | fields_buf[0] = llvm_payload_type; |
| 2542 | return dg.context.structType(&fields, fields.len, .False); | 2583 | fields_buf[1] = llvm_error_type; |
| | 2584 | const error_end = |
| | 2585 | std.mem.alignForwardGeneric(u64, payload_size, error_align) + |
| | 2586 | error_size; |
| | 2587 | const abi_size = std.mem.alignForwardGeneric(u64, error_end, payload_align); |
| | 2588 | const padding = @intCast(c_uint, abi_size - error_end); |
| | 2589 | if (padding == 0) { |
| | 2590 | return dg.context.structType(&fields_buf, 2, .False); |
| | 2591 | } |
| | 2592 | fields_buf[2] = dg.context.intType(8).arrayType(padding); |
| | 2593 | return dg.context.structType(&fields_buf, 3, .False); |
| 2543 | } | 2594 | } |
| 2544 | }, | 2595 | }, |
| 2545 | .ErrorSet => return dg.context.intType(16), | 2596 | .ErrorSet => return dg.context.intType(16), |
| ... | @@ -2704,7 +2755,7 @@ pub const DeclGen = struct { | ... | @@ -2704,7 +2755,7 @@ pub const DeclGen = struct { |
| 2704 | llvm_aligned_field_ty, | 2755 | llvm_aligned_field_ty, |
| 2705 | dg.context.intType(8).arrayType(padding_len), | 2756 | dg.context.intType(8).arrayType(padding_len), |
| 2706 | }; | 2757 | }; |
| 2707 | break :t dg.context.structType(&fields, fields.len, .False); | 2758 | break :t dg.context.structType(&fields, fields.len, .True); |
| 2708 | }; | 2759 | }; |
| 2709 | | 2760 | |
| 2710 | if (layout.tag_size == 0) { | 2761 | if (layout.tag_size == 0) { |
| ... | @@ -3020,7 +3071,7 @@ pub const DeclGen = struct { | ... | @@ -3020,7 +3071,7 @@ pub const DeclGen = struct { |
| 3020 | return dg.context.constStruct( | 3071 | return dg.context.constStruct( |
| 3021 | llvm_elems.ptr, | 3072 | llvm_elems.ptr, |
| 3022 | @intCast(c_uint, llvm_elems.len), | 3073 | @intCast(c_uint, llvm_elems.len), |
| 3023 | .False, | 3074 | .True, |
| 3024 | ); | 3075 | ); |
| 3025 | } else { | 3076 | } else { |
| 3026 | const llvm_elem_ty = try dg.lowerType(elem_ty); | 3077 | const llvm_elem_ty = try dg.lowerType(elem_ty); |
| ... | @@ -3057,7 +3108,7 @@ pub const DeclGen = struct { | ... | @@ -3057,7 +3108,7 @@ pub const DeclGen = struct { |
| 3057 | return dg.context.constStruct( | 3108 | return dg.context.constStruct( |
| 3058 | llvm_elems.ptr, | 3109 | llvm_elems.ptr, |
| 3059 | @intCast(c_uint, llvm_elems.len), | 3110 | @intCast(c_uint, llvm_elems.len), |
| 3060 | .False, | 3111 | .True, |
| 3061 | ); | 3112 | ); |
| 3062 | } else { | 3113 | } else { |
| 3063 | const llvm_elem_ty = try dg.lowerType(elem_ty); | 3114 | const llvm_elem_ty = try dg.lowerType(elem_ty); |
| ... | @@ -3074,7 +3125,7 @@ pub const DeclGen = struct { | ... | @@ -3074,7 +3125,7 @@ pub const DeclGen = struct { |
| 3074 | const llvm_elems: [1]*const llvm.Value = .{sentinel}; | 3125 | const llvm_elems: [1]*const llvm.Value = .{sentinel}; |
| 3075 | const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]); | 3126 | const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]); |
| 3076 | if (need_unnamed) { | 3127 | if (need_unnamed) { |
| 3077 | return dg.context.constStruct(&llvm_elems, llvm_elems.len, .False); | 3128 | return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True); |
| 3078 | } else { | 3129 | } else { |
| 3079 | const llvm_elem_ty = try dg.lowerType(elem_ty); | 3130 | const llvm_elem_ty = try dg.lowerType(elem_ty); |
| 3080 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); | 3131 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); |
| ... | @@ -3083,6 +3134,7 @@ pub const DeclGen = struct { | ... | @@ -3083,6 +3134,7 @@ pub const DeclGen = struct { |
| 3083 | else => unreachable, | 3134 | else => unreachable, |
| 3084 | }, | 3135 | }, |
| 3085 | .Optional => { | 3136 | .Optional => { |
| | 3137 | comptime assert(optional_layout_version == 2); |
| 3086 | var buf: Type.Payload.ElemType = undefined; | 3138 | var buf: Type.Payload.ElemType = undefined; |
| 3087 | const payload_ty = tv.ty.optionalChild(&buf); | 3139 | const payload_ty = tv.ty.optionalChild(&buf); |
| 3088 | const llvm_i1 = dg.context.intType(1); | 3140 | const llvm_i1 = dg.context.intType(1); |
| ... | @@ -3091,25 +3143,30 @@ pub const DeclGen = struct { | ... | @@ -3091,25 +3143,30 @@ pub const DeclGen = struct { |
| 3091 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3143 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3092 | return non_null_bit; | 3144 | return non_null_bit; |
| 3093 | } | 3145 | } |
| | 3146 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3094 | if (tv.ty.optionalReprIsPayload()) { | 3147 | if (tv.ty.optionalReprIsPayload()) { |
| 3095 | if (tv.val.castTag(.opt_payload)) |payload| { | 3148 | if (tv.val.castTag(.opt_payload)) |payload| { |
| 3096 | return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data }); | 3149 | return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data }); |
| 3097 | } else if (is_pl) { | 3150 | } else if (is_pl) { |
| 3098 | return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val }); | 3151 | return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val }); |
| 3099 | } else { | 3152 | } else { |
| 3100 | const llvm_ty = try dg.lowerType(tv.ty); | | |
| 3101 | return llvm_ty.constNull(); | 3153 | return llvm_ty.constNull(); |
| 3102 | } | 3154 | } |
| 3103 | } | 3155 | } |
| 3104 | assert(payload_ty.zigTypeTag() != .Fn); | 3156 | assert(payload_ty.zigTypeTag() != .Fn); |
| 3105 | const fields: [2]*const llvm.Value = .{ | 3157 | |
| 3106 | try dg.lowerValue(.{ | 3158 | const llvm_field_count = llvm_ty.countStructElementTypes(); |
| 3107 | .ty = payload_ty, | 3159 | var fields_buf: [3]*const llvm.Value = undefined; |
| 3108 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | 3160 | fields_buf[0] = try dg.lowerValue(.{ |
| 3109 | }), | 3161 | .ty = payload_ty, |
| 3110 | non_null_bit, | 3162 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), |
| 3111 | }; | 3163 | }); |
| 3112 | return dg.context.constStruct(&fields, fields.len, .False); | 3164 | fields_buf[1] = non_null_bit; |
| | 3165 | if (llvm_field_count > 2) { |
| | 3166 | assert(llvm_field_count == 3); |
| | 3167 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); |
| | 3168 | } |
| | 3169 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); |
| 3113 | }, | 3170 | }, |
| 3114 | .Fn => { | 3171 | .Fn => { |
| 3115 | const fn_decl_index = switch (tv.val.tag()) { | 3172 | const fn_decl_index = switch (tv.val.tag()) { |
| ... | @@ -3155,12 +3212,23 @@ pub const DeclGen = struct { | ... | @@ -3155,12 +3212,23 @@ pub const DeclGen = struct { |
| 3155 | .ty = payload_type, | 3212 | .ty = payload_type, |
| 3156 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), | 3213 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), |
| 3157 | }); | 3214 | }); |
| | 3215 | var fields_buf: [3]*const llvm.Value = undefined; |
| | 3216 | |
| | 3217 | const llvm_ty = try dg.lowerType(tv.ty); |
| | 3218 | const llvm_field_count = llvm_ty.countStructElementTypes(); |
| | 3219 | if (llvm_field_count > 2) { |
| | 3220 | assert(llvm_field_count == 3); |
| | 3221 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); |
| | 3222 | } |
| | 3223 | |
| 3158 | if (error_align > payload_align) { | 3224 | if (error_align > payload_align) { |
| 3159 | const fields: [2]*const llvm.Value = .{ llvm_error_value, llvm_payload_value }; | 3225 | fields_buf[0] = llvm_error_value; |
| 3160 | return dg.context.constStruct(&fields, fields.len, .False); | 3226 | fields_buf[1] = llvm_payload_value; |
| | 3227 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); |
| 3161 | } else { | 3228 | } else { |
| 3162 | const fields: [2]*const llvm.Value = .{ llvm_payload_value, llvm_error_value }; | 3229 | fields_buf[0] = llvm_payload_value; |
| 3163 | return dg.context.constStruct(&fields, fields.len, .False); | 3230 | fields_buf[1] = llvm_error_value; |
| | 3231 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); |
| 3164 | } | 3232 | } |
| 3165 | }, | 3233 | }, |
| 3166 | .Struct => { | 3234 | .Struct => { |
| ... | @@ -3361,7 +3429,7 @@ pub const DeclGen = struct { | ... | @@ -3361,7 +3429,7 @@ pub const DeclGen = struct { |
| 3361 | const fields: [2]*const llvm.Value = .{ | 3429 | const fields: [2]*const llvm.Value = .{ |
| 3362 | field, dg.context.intType(8).arrayType(padding_len).getUndef(), | 3430 | field, dg.context.intType(8).arrayType(padding_len).getUndef(), |
| 3363 | }; | 3431 | }; |
| 3364 | break :p dg.context.constStruct(&fields, fields.len, .False); | 3432 | break :p dg.context.constStruct(&fields, fields.len, .True); |
| 3365 | }; | 3433 | }; |
| 3366 | | 3434 | |
| 3367 | if (layout.tag_size == 0) { | 3435 | if (layout.tag_size == 0) { |
| ... | @@ -5847,6 +5915,7 @@ pub const FuncGen = struct { | ... | @@ -5847,6 +5915,7 @@ pub const FuncGen = struct { |
| 5847 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5915 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5848 | const payload_ty = self.air.typeOf(ty_op.operand); | 5916 | const payload_ty = self.air.typeOf(ty_op.operand); |
| 5849 | const non_null_bit = self.context.intType(1).constAllOnes(); | 5917 | const non_null_bit = self.context.intType(1).constAllOnes(); |
| | 5918 | comptime assert(optional_layout_version == 2); |
| 5850 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit; | 5919 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit; |
| 5851 | const operand = try self.resolveInst(ty_op.operand); | 5920 | const operand = try self.resolveInst(ty_op.operand); |
| 5852 | const optional_ty = self.air.typeOfIndex(inst); | 5921 | const optional_ty = self.air.typeOfIndex(inst); |
| ... | @@ -9300,6 +9369,7 @@ fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { | ... | @@ -9300,6 +9369,7 @@ fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { |
| 9300 | /// We can do this because for all types, Zig ABI alignment >= LLVM ABI | 9369 | /// We can do this because for all types, Zig ABI alignment >= LLVM ABI |
| 9301 | /// alignment. | 9370 | /// alignment. |
| 9302 | const struct_layout_version = 2; | 9371 | const struct_layout_version = 2; |
| | 9372 | const optional_layout_version = 2; |
| 9303 | | 9373 | |
| 9304 | /// We use the least significant bit of the pointer address to tell us | 9374 | /// We use the least significant bit of the pointer address to tell us |
| 9305 | /// whether the type is fully resolved. Types that are only fwd declared | 9375 | /// whether the type is fully resolved. Types that are only fwd declared |