| ... | ... | @@ -895,7 +895,7 @@ pub const Value = struct { |
| 895 | 895 | }; |
| 896 | 896 | const unused_bits = @max(new_unused_bits, old_unused_bits); |
| 897 | 897 | if (dst_ext == src_ext and bit_size <= old_bits) return; |
| 898 | | tracking_log.debug("{f}: {t} ({t}) -> {t} ({t}), {d}b -> {d}b", .{ vi, src_ext, new_ext, dst_ext, old_ext, old_bits, bit_size }); |
| 898 | tracking_log.debug("{f}: in {t} ({t}) -> out {t} ({t}), {d}b -> {d}b", .{ vi, src_ext, new_ext, dst_ext, old_ext, old_bits, bit_size }); |
| 899 | 899 | |
| 900 | 900 | // avoid setting extension to .garbage to reduce MIR for sequences like |
| 901 | 901 | // zero_ext -> garbage -> zero_ext |
| ... | ... | @@ -913,33 +913,8 @@ pub const Value = struct { |
| 913 | 913 | ); |
| 914 | 914 | try vi_mat.finish(isel); |
| 915 | 915 | } else { |
| 916 | | const unused_bytes = std.math.divCeil(u64, unused_bits, 8) catch unreachable; |
| 917 | | assert(unused_bytes <= isel.gprSize()); // TODO larger extending |
| 918 | | const used_bytes = vi.size(isel) - unused_bytes; |
| 919 | | |
| 920 | | var hit = false; |
| 921 | | var walker = vi.walk(isel, .{}); |
| 922 | | while (walker.next()) |part_vi| { |
| 923 | | const part_offset = part_vi.offsetIn(isel, vi); |
| 924 | | const part_size = part_vi.size(isel); |
| 925 | | const part_end = part_offset + part_size; |
| 926 | | if (part_end <= used_bytes) continue; |
| 927 | | if (part_size > isel.gprSize()) continue; |
| 928 | | |
| 929 | | walker.skipChildren(part_vi); |
| 930 | | |
| 931 | | const part_mat = try part_vi.mat(isel, .{ .pref = .only_reg }); |
| 932 | | try isel.fillUnusedBits( |
| 933 | | part_mat.reg(), |
| 934 | | part_mat.reg(), |
| 935 | | dst_ext, |
| 936 | | src_ext, |
| 937 | | @intCast(unused_bits - ((vi.size(isel) - part_end) * 8)), |
| 938 | | ); |
| 939 | | try part_mat.finish(isel); |
| 940 | | if (hit) unreachable; // TODO |
| 941 | | hit = true; |
| 942 | | } |
| 916 | try isel.failUnimplemented("unimplemented sign-extend width > GPR", .{}); |
| 917 | return; |
| 943 | 918 | } |
| 944 | 919 | } |
| 945 | 920 | |
| ... | ... | @@ -1325,7 +1300,6 @@ pub const Value = struct { |
| 1325 | 1300 | |
| 1326 | 1301 | /// Materializes a value |
| 1327 | 1302 | fn mat(vi: Value.Index, isel: *Select, opts: MatOptions) codegen.Error!Mat { |
| 1328 | | // try vi.split(isel, true); |
| 1329 | 1303 | const mat_size = @min(opts.size, @as(u32, @intCast(vi.size(isel) - opts.offset))); |
| 1330 | 1304 | const loc_pref = if (opts.extension == .garbage) |
| 1331 | 1305 | opts.pref |
| ... | ... | @@ -2124,13 +2098,6 @@ pub const Value = struct { |
| 2124 | 2098 | .large => value.location_payload.large.stack_slot = vi.allocStackSlot(isel), |
| 2125 | 2099 | } |
| 2126 | 2100 | } |
| 2127 | | switch (value.flags.location_tag) { |
| 2128 | | .extreme => unreachable, |
| 2129 | | .small => {}, |
| 2130 | | .large => { |
| 2131 | | try vi.reextendAdvanced(isel, vi.bitSize(isel), mat.extension, vi.extension(isel)); |
| 2132 | | }, |
| 2133 | | } |
| 2134 | 2101 | const vi_loc = vi.location(isel).?; |
| 2135 | 2102 | const maybe_loc_reg = vi_loc.asRegister(); |
| 2136 | 2103 | if (maybe_loc_reg) |loc_reg| { |
| ... | ... | @@ -2152,6 +2119,13 @@ pub const Value = struct { |
| 2152 | 2119 | assert(loc_live.* == .allocating); |
| 2153 | 2120 | loc_live.* = vi; |
| 2154 | 2121 | } |
| 2122 | switch (value.flags.location_tag) { |
| 2123 | .extreme => unreachable, |
| 2124 | .small => {}, |
| 2125 | .large => { |
| 2126 | try vi.reextendAdvanced(isel, vi.bitSize(isel), mat.extension, vi.extension(isel)); |
| 2127 | }, |
| 2128 | } |
| 2155 | 2129 | }, |
| 2156 | 2130 | .value => unreachable, |
| 2157 | 2131 | .address => |addr_vi| { |
| ... | ... | @@ -2405,6 +2379,8 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 2405 | 2379 | .div_trunc_optimized, |
| 2406 | 2380 | .div_floor, |
| 2407 | 2381 | .div_floor_optimized, |
| 2382 | .div_ceil, |
| 2383 | .div_ceil_optimized, |
| 2408 | 2384 | .div_exact, |
| 2409 | 2385 | .div_exact_optimized, |
| 2410 | 2386 | .rem, |
| ... | ... | @@ -2758,6 +2734,33 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 2758 | 2734 | try isel.analyzeUse(arg); |
| 2759 | 2735 | } |
| 2760 | 2736 | }, |
| 2737 | .legalize_compiler_rt_call => { |
| 2738 | const compiler_rt_call = isel.air.unwrapCompilerRtCall(air_inst_index); |
| 2739 | |
| 2740 | for (compiler_rt_call.args) |arg| |
| 2741 | try isel.analyzeUse(arg); |
| 2742 | |
| 2743 | var cc_it: CallAbiIterator = .{ |
| 2744 | .isel = isel, |
| 2745 | .cc = &compiler_rt_call.func.@"callconv"(isel.target), |
| 2746 | }; |
| 2747 | if (try cc_it.resolve(compiler_rt_call.func.returnType(), true)) |ret_vi| { |
| 2748 | tracking_log.debug("{f} <- %{d} (call return)", .{ ret_vi, @backingInt(air_inst_index) }); |
| 2749 | switch (ret_vi.parent(isel)) { |
| 2750 | .none => {}, |
| 2751 | .value, .constant => unreachable, |
| 2752 | .address => |address_vi| { |
| 2753 | defer address_vi.deref(isel); |
| 2754 | const ret_value = ret_vi.get(isel); |
| 2755 | ret_value.flags.parent_tag = .none; |
| 2756 | ret_value.parent_payload = .{ .none = {} }; |
| 2757 | }, |
| 2758 | } |
| 2759 | try isel.live_values.putNoClobber(gpa, air_inst_index, ret_vi); |
| 2760 | |
| 2761 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); |
| 2762 | } |
| 2763 | }, |
| 2761 | 2764 | .cond_br => { |
| 2762 | 2765 | const pl_op = air_data[@backingInt(air_inst_index)].pl_op; |
| 2763 | 2766 | const extra = isel.air.extraData(Air.CondBr, pl_op.payload); |
| ... | ... | @@ -3804,6 +3807,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void |
| 3804 | 3807 | 64 => .@"movfr2gr.d"(dst_reg, src_reg), |
| 3805 | 3808 | }); |
| 3806 | 3809 | try src_mat.finish(isel); |
| 3810 | } else if ((dst_ty.isAbiInt(zcu) and src_tag == .float) or ((dst_tag == .float and src_ty.isAbiInt(zcu)))) { |
| 3811 | try dst_vi.value.defMove(isel, ty_op.operand); |
| 3807 | 3812 | } else if (dst_ty.isAbiInt(zcu) and src_tag == .array and src_ty.childType(zcu).isAbiInt(zcu)) { |
| 3808 | 3813 | const dst_int_info = dst_ty.intInfo(zcu); |
| 3809 | 3814 | const src_child_int_info = src_ty.childType(zcu).intInfo(zcu); |
| ... | ... | @@ -4058,9 +4063,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void |
| 4058 | 4063 | .{ 0, @as(u32, @intCast(payload_size)) }; |
| 4059 | 4064 | |
| 4060 | 4065 | const opt_vi = try isel.use(un_op); |
| 4061 | | const has_value_mat = try opt_vi.mat(isel, .{ |
| 4062 | | .offset = has_value_offset, |
| 4063 | | .size = has_value_size, |
| 4066 | const has_value_vi = try opt_vi.partExact(isel, has_value_offset, has_value_size); |
| 4067 | const has_value_mat = try has_value_vi.mat(isel, .{ |
| 4064 | 4068 | .pref = .only_reg, |
| 4065 | 4069 | .reg_mod = .integer, |
| 4066 | 4070 | .extension = .zero_ext, |
| ... | ... | @@ -4109,7 +4113,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void |
| 4109 | 4113 | if (!ty.isRuntimeFloat()) { |
| 4110 | 4114 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) }); |
| 4111 | 4115 | const int_info = ty.intInfo(zcu); |
| 4112 | | if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); |
| 4116 | if (int_info.bits > 64) { |
| 4117 | _ = res_vi.value.takeLocationMarkWritten(isel); |
| 4118 | try isel.failUnimplemented("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }); |
| 4119 | break :unused; |
| 4120 | } |
| 4113 | 4121 | |
| 4114 | 4122 | try res_vi.value.reextendToGarbage(isel); |
| 4115 | 4123 | const res_reg = try res_vi.value.defRegMod(isel, .integer) orelse break :unused; |
| ... | ... | @@ -6534,7 +6542,28 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini |
| 6534 | 6542 | } |
| 6535 | 6543 | }, |
| 6536 | 6544 | .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int }, |
| 6537 | | .float => return isel.fail("float unimplemented", .{}), |
| 6545 | .float => |float| { |
| 6546 | if (isel.canUseFprForFloat(ZigType.fromInterned(float.ty).floatBits(isel.target))) { |
| 6547 | return isel.fail("float unimplemented", .{}); |
| 6548 | } else { |
| 6549 | switch (float.ty) { |
| 6550 | .f16_type => continue :constant_key .{ .int = .{ |
| 6551 | .ty = .u16_type, |
| 6552 | .storage = .{ .u64 = @as(u16, @bitCast(float.storage.f16)) }, |
| 6553 | } }, |
| 6554 | .f32_type => continue :constant_key .{ .int = .{ |
| 6555 | .ty = .u32_type, |
| 6556 | .storage = .{ .u64 = @as(u32, @bitCast(float.storage.f32)) }, |
| 6557 | } }, |
| 6558 | .f64_type => continue :constant_key .{ .int = .{ |
| 6559 | .ty = .u64_type, |
| 6560 | .storage = .{ .u64 = @as(u64, @bitCast(float.storage.f64)) }, |
| 6561 | } }, |
| 6562 | .f80_type, .f128_type => {}, |
| 6563 | else => unreachable, |
| 6564 | } |
| 6565 | } |
| 6566 | }, |
| 6538 | 6567 | .ptr => |ptr| { |
| 6539 | 6568 | assert(offset == 0 and size == isel.gprSize()); |
| 6540 | 6569 | const dst_ra: Register.Alias, const use_tmp_reg = select_tmp: { |
| ... | ... | @@ -6615,8 +6644,23 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini |
| 6615 | 6644 | .field => |field_idx| { |
| 6616 | 6645 | var base_ptr = ip.indexToKey(field_idx.base).ptr; |
| 6617 | 6646 | const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child); |
| 6618 | | base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field_idx.index), zcu) + ptr.byte_offset; |
| 6619 | | continue :constant_key .{ .ptr = base_ptr }; |
| 6647 | switch (ip.indexToKey(agg_ty.toIntern())) { |
| 6648 | .ptr_type => |ptr_ty| { |
| 6649 | assert(ptr_ty.flags.size == .slice); |
| 6650 | const field_offset = switch (field_idx.index) { |
| 6651 | Constant.slice_ptr_index => 0, |
| 6652 | Constant.slice_len_index => isel.gprSize(), |
| 6653 | else => unreachable, |
| 6654 | }; |
| 6655 | base_ptr.byte_offset += ptr.byte_offset + field_offset; |
| 6656 | continue :constant_key .{ .ptr = base_ptr }; |
| 6657 | }, |
| 6658 | .struct_type, .tuple_type, .union_type => { |
| 6659 | base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field_idx.index), zcu) + ptr.byte_offset; |
| 6660 | continue :constant_key .{ .ptr = base_ptr }; |
| 6661 | }, |
| 6662 | else => unreachable, |
| 6663 | } |
| 6620 | 6664 | }, |
| 6621 | 6665 | .comptime_alloc, .comptime_field, .arr_elem => unreachable, |
| 6622 | 6666 | }; |
| ... | ... | @@ -7056,7 +7100,7 @@ pub const CallAbiIterator = struct { |
| 7056 | 7100 | .signedness = .unsigned, |
| 7057 | 7101 | .bits = zcu.errorSetBits(), |
| 7058 | 7102 | } }, |
| 7059 | | .f16, .f32, .f64 => { |
| 7103 | .f16, .f32, .f64, .c_longdouble => { |
| 7060 | 7104 | const bits = ty.floatBits(isel.target); |
| 7061 | 7105 | if (isel.canUseFprForFloat(bits)) { |
| 7062 | 7106 | if (it.allocReg(.fpr)) |reg| { |
| ... | ... | @@ -7071,7 +7115,6 @@ pub const CallAbiIterator = struct { |
| 7071 | 7115 | continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = bits } }; |
| 7072 | 7116 | } |
| 7073 | 7117 | }, |
| 7074 | | .c_longdouble => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}), |
| 7075 | 7118 | else => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}), |
| 7076 | 7119 | }, |
| 7077 | 7120 | .struct_type => { |
| ... | ... | @@ -7370,7 +7413,7 @@ fn gprAlignment(isel: *Select) std.mem.Alignment { |
| 7370 | 7413 | }; |
| 7371 | 7414 | } |
| 7372 | 7415 | |
| 7373 | | fn fprBits(isel: *Select) u7 { |
| 7416 | fn targetFprBits(isel: *Select) u7 { |
| 7374 | 7417 | const cpu = &isel.target.cpu; |
| 7375 | 7418 | if (cpu.has(.loongarch, .d)) { |
| 7376 | 7419 | return 64; |
| ... | ... | @@ -7388,12 +7431,12 @@ fn vectorBits(isel: *Select) u7 { |
| 7388 | 7431 | } else if (cpu.has(.loongarch, .lsx)) { |
| 7389 | 7432 | return 128; |
| 7390 | 7433 | } else { |
| 7391 | | return isel.fprBits(); |
| 7434 | return isel.targetFprBits(); |
| 7392 | 7435 | } |
| 7393 | 7436 | } |
| 7394 | 7437 | |
| 7395 | 7438 | fn canUseFprForFloat(isel: *Select, bits: u16) bool { |
| 7396 | | return bits <= isel.fprBits(); |
| 7439 | return bits <= isel.targetFprBits(); |
| 7397 | 7440 | } |
| 7398 | 7441 | |
| 7399 | 7442 | fn typeOfField(isel: *Select, ty: ZigType, offset: u64) ?ZigType { |