| ... | ... | @@ -48,6 +48,7 @@ const RegisterLock = RegisterManager.RegisterLock; |
| 48 | 48 | const FrameIndex = bits.FrameIndex; |
| 49 | 49 | |
| 50 | 50 | const gp = abi.RegisterClass.gp; |
| 51 | const x87 = abi.RegisterClass.x87; |
| 51 | 52 | const sse = abi.RegisterClass.sse; |
| 52 | 53 | |
| 53 | 54 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| ... | ... | @@ -532,8 +533,8 @@ const InstTracking = struct { |
| 532 | 533 | }; |
| 533 | 534 | } |
| 534 | 535 | |
| 535 | | fn trackSpill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void { |
| 536 | | function.freeValue(self.short); |
| 536 | fn trackSpill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void { |
| 537 | try function.freeValue(self.short); |
| 537 | 538 | self.reuseFrame(); |
| 538 | 539 | tracking_log.debug("%{d} => {} (spilled)", .{ inst, self.* }); |
| 539 | 540 | } |
| ... | ... | @@ -618,8 +619,8 @@ const InstTracking = struct { |
| 618 | 619 | } |
| 619 | 620 | } |
| 620 | 621 | |
| 621 | | fn die(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void { |
| 622 | | function.freeValue(self.short); |
| 622 | fn die(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void { |
| 623 | try function.freeValue(self.short); |
| 623 | 624 | self.short = .{ .dead = function.scope_generation }; |
| 624 | 625 | tracking_log.debug("%{d} => {} (death)", .{ inst, self.* }); |
| 625 | 626 | } |
| ... | ... | @@ -980,7 +981,6 @@ fn formatWipMir( |
| 980 | 981 | _: std.fmt.FormatOptions, |
| 981 | 982 | writer: anytype, |
| 982 | 983 | ) @TypeOf(writer).Error!void { |
| 983 | | const mod = data.self.bin_file.options.module.?; |
| 984 | 984 | var lower = Lower{ |
| 985 | 985 | .allocator = data.self.gpa, |
| 986 | 986 | .mir = .{ |
| ... | ... | @@ -988,7 +988,7 @@ fn formatWipMir( |
| 988 | 988 | .extra = data.self.mir_extra.items, |
| 989 | 989 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), |
| 990 | 990 | }, |
| 991 | | .cc = mod.typeToFunc(data.self.fn_type).?.cc, |
| 991 | .cc = .Unspecified, |
| 992 | 992 | .src_loc = data.self.src_loc, |
| 993 | 993 | }; |
| 994 | 994 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { |
| ... | ... | @@ -2132,9 +2132,12 @@ fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { |
| 2132 | 2132 | self.register_manager.getRegAssumeFree(reg, inst); |
| 2133 | 2133 | } |
| 2134 | 2134 | |
| 2135 | | fn freeValue(self: *Self, value: MCValue) void { |
| 2135 | fn freeValue(self: *Self, value: MCValue) !void { |
| 2136 | 2136 | switch (value) { |
| 2137 | | .register => |reg| self.register_manager.freeReg(reg), |
| 2137 | .register => |reg| { |
| 2138 | if (reg.class() == .x87) try self.asmRegister(.{ .f_, .free }, reg); |
| 2139 | self.register_manager.freeReg(reg); |
| 2140 | }, |
| 2138 | 2141 | .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg), |
| 2139 | 2142 | .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg), |
| 2140 | 2143 | .register_overflow => |reg_ov| { |
| ... | ... | @@ -2146,13 +2149,13 @@ fn freeValue(self: *Self, value: MCValue) void { |
| 2146 | 2149 | } |
| 2147 | 2150 | } |
| 2148 | 2151 | |
| 2149 | | fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void { |
| 2150 | | if (bt.feed()) if (Air.refToIndex(operand)) |inst| self.processDeath(inst); |
| 2152 | fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) !void { |
| 2153 | if (bt.feed()) if (Air.refToIndex(operand)) |inst| try self.processDeath(inst); |
| 2151 | 2154 | } |
| 2152 | 2155 | |
| 2153 | 2156 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 2154 | | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 2155 | | self.inst_tracking.getPtr(inst).?.die(self, inst); |
| 2157 | fn processDeath(self: *Self, inst: Air.Inst.Index) !void { |
| 2158 | try self.inst_tracking.getPtr(inst).?.die(self, inst); |
| 2156 | 2159 | } |
| 2157 | 2160 | |
| 2158 | 2161 | /// Called when there are no operands, and the instruction is always unreferenced. |
| ... | ... | @@ -2177,13 +2180,18 @@ fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void { |
| 2177 | 2180 | self.finishAirBookkeeping(); |
| 2178 | 2181 | } |
| 2179 | 2182 | |
| 2180 | | fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void { |
| 2183 | fn finishAir( |
| 2184 | self: *Self, |
| 2185 | inst: Air.Inst.Index, |
| 2186 | result: MCValue, |
| 2187 | operands: [Liveness.bpi - 1]Air.Inst.Ref, |
| 2188 | ) !void { |
| 2181 | 2189 | var tomb_bits = self.liveness.getTombBits(inst); |
| 2182 | 2190 | for (operands) |op| { |
| 2183 | 2191 | const dies = @as(u1, @truncate(tomb_bits)) != 0; |
| 2184 | 2192 | tomb_bits >>= 1; |
| 2185 | 2193 | if (!dies) continue; |
| 2186 | | self.processDeath(Air.refToIndexAllowNone(op) orelse continue); |
| 2194 | try self.processDeath(Air.refToIndexAllowNone(op) orelse continue); |
| 2187 | 2195 | } |
| 2188 | 2196 | self.finishAirResult(inst, result); |
| 2189 | 2197 | } |
| ... | ... | @@ -2409,7 +2417,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2409 | 2417 | for ( |
| 2410 | 2418 | self.inst_tracking.keys()[state.inst_tracking_len..], |
| 2411 | 2419 | self.inst_tracking.values()[state.inst_tracking_len..], |
| 2412 | | ) |inst, *tracking| tracking.die(self, inst); |
| 2420 | ) |inst, *tracking| try tracking.die(self, inst); |
| 2413 | 2421 | self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len); |
| 2414 | 2422 | } |
| 2415 | 2423 | |
| ... | ... | @@ -2417,7 +2425,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2417 | 2425 | self.inst_tracking.keys()[0..state.inst_tracking_len], |
| 2418 | 2426 | self.inst_tracking.values()[0..state.inst_tracking_len], |
| 2419 | 2427 | ) |inst, *tracking| tracking.resurrect(inst, state.scope_generation); |
| 2420 | | for (deaths) |death| self.processDeath(death); |
| 2428 | for (deaths) |death| try self.processDeath(death); |
| 2421 | 2429 | |
| 2422 | 2430 | for (0..state.registers.len) |index| { |
| 2423 | 2431 | const current_maybe_inst = if (self.register_manager.free_registers.isSet(index)) |
| ... | ... | @@ -2444,7 +2452,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2444 | 2452 | } |
| 2445 | 2453 | if (opts.update_tracking) { |
| 2446 | 2454 | if (current_maybe_inst) |current_inst| { |
| 2447 | | self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst); |
| 2455 | try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst); |
| 2448 | 2456 | } |
| 2449 | 2457 | { |
| 2450 | 2458 | const reg = RegisterManager.regAtTrackedIndex(@intCast(index)); |
| ... | ... | @@ -2463,7 +2471,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2463 | 2471 | try self.inst_tracking.getPtr(inst).?.spill(self, inst); |
| 2464 | 2472 | if (opts.update_tracking) if (self.eflags_inst) |inst| { |
| 2465 | 2473 | self.eflags_inst = null; |
| 2466 | | self.inst_tracking.getPtr(inst).?.trackSpill(self, inst); |
| 2474 | try self.inst_tracking.getPtr(inst).?.trackSpill(self, inst); |
| 2467 | 2475 | }; |
| 2468 | 2476 | |
| 2469 | 2477 | if (opts.update_tracking and std.debug.runtime_safety) { |
| ... | ... | @@ -2481,7 +2489,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 2481 | 2489 | if (tracked_reg.id() == reg.id()) break; |
| 2482 | 2490 | } else unreachable; // spilled reg not tracked with spilled instruciton |
| 2483 | 2491 | try tracking.spill(self, inst); |
| 2484 | | tracking.trackSpill(self, inst); |
| 2492 | try tracking.trackSpill(self, inst); |
| 2485 | 2493 | } |
| 2486 | 2494 | |
| 2487 | 2495 | pub fn spillEflagsIfOccupied(self: *Self) !void { |
| ... | ... | @@ -2490,7 +2498,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { |
| 2490 | 2498 | const tracking = self.inst_tracking.getPtr(inst).?; |
| 2491 | 2499 | assert(tracking.getCondition() != null); |
| 2492 | 2500 | try tracking.spill(self, inst); |
| 2493 | | tracking.trackSpill(self, inst); |
| 2501 | try tracking.trackSpill(self, inst); |
| 2494 | 2502 | } |
| 2495 | 2503 | } |
| 2496 | 2504 | |
| ... | ... | @@ -8428,8 +8436,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8428 | 8436 | const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals); |
| 8429 | 8437 | |
| 8430 | 8438 | var bt = self.liveness.iterateBigTomb(inst); |
| 8431 | | self.feed(&bt, pl_op.operand); |
| 8432 | | for (arg_refs) |arg_ref| self.feed(&bt, arg_ref); |
| 8439 | try self.feed(&bt, pl_op.operand); |
| 8440 | for (arg_refs) |arg_ref| try self.feed(&bt, arg_ref); |
| 8433 | 8441 | |
| 8434 | 8442 | const result = if (self.liveness.isUnused(inst)) .unreach else ret; |
| 8435 | 8443 | return self.finishAirResult(inst, result); |
| ... | ... | @@ -9086,13 +9094,13 @@ fn genTry( |
| 9086 | 9094 | const reloc = try self.genCondBrMir(Type.anyerror, is_err_mcv); |
| 9087 | 9095 | |
| 9088 | 9096 | if (self.liveness.operandDies(inst, 0)) { |
| 9089 | | if (Air.refToIndex(err_union)) |err_union_inst| self.processDeath(err_union_inst); |
| 9097 | if (Air.refToIndex(err_union)) |err_union_inst| try self.processDeath(err_union_inst); |
| 9090 | 9098 | } |
| 9091 | 9099 | |
| 9092 | 9100 | self.scope_generation += 1; |
| 9093 | 9101 | const state = try self.saveState(); |
| 9094 | 9102 | |
| 9095 | | for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand); |
| 9103 | for (liveness_cond_br.else_deaths) |operand| try self.processDeath(operand); |
| 9096 | 9104 | try self.genBody(body); |
| 9097 | 9105 | try self.restoreState(state, &.{}, .{ |
| 9098 | 9106 | .emit_instructions = false, |
| ... | ... | @@ -9103,7 +9111,7 @@ fn genTry( |
| 9103 | 9111 | |
| 9104 | 9112 | try self.performReloc(reloc); |
| 9105 | 9113 | |
| 9106 | | for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand); |
| 9114 | for (liveness_cond_br.then_deaths) |operand| try self.processDeath(operand); |
| 9107 | 9115 | |
| 9108 | 9116 | const result = if (self.liveness.isUnused(inst)) |
| 9109 | 9117 | .unreach |
| ... | ... | @@ -9196,13 +9204,13 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9196 | 9204 | // that death now instead of later as this has an effect on |
| 9197 | 9205 | // whether it needs to be spilled in the branches |
| 9198 | 9206 | if (self.liveness.operandDies(inst, 0)) { |
| 9199 | | if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); |
| 9207 | if (Air.refToIndex(pl_op.operand)) |op_inst| try self.processDeath(op_inst); |
| 9200 | 9208 | } |
| 9201 | 9209 | |
| 9202 | 9210 | self.scope_generation += 1; |
| 9203 | 9211 | const state = try self.saveState(); |
| 9204 | 9212 | |
| 9205 | | for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand); |
| 9213 | for (liveness_cond_br.then_deaths) |operand| try self.processDeath(operand); |
| 9206 | 9214 | try self.genBody(then_body); |
| 9207 | 9215 | try self.restoreState(state, &.{}, .{ |
| 9208 | 9216 | .emit_instructions = false, |
| ... | ... | @@ -9213,7 +9221,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9213 | 9221 | |
| 9214 | 9222 | try self.performReloc(reloc); |
| 9215 | 9223 | |
| 9216 | | for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand); |
| 9224 | for (liveness_cond_br.else_deaths) |operand| try self.processDeath(operand); |
| 9217 | 9225 | try self.genBody(else_body); |
| 9218 | 9226 | try self.restoreState(state, &.{}, .{ |
| 9219 | 9227 | .emit_instructions = false, |
| ... | ... | @@ -9580,7 +9588,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 9580 | 9588 | |
| 9581 | 9589 | if (std.debug.runtime_safety) assert(self.inst_tracking.getIndex(inst).? == inst_tracking_i); |
| 9582 | 9590 | const tracking = &self.inst_tracking.values()[inst_tracking_i]; |
| 9583 | | if (self.liveness.isUnused(inst)) tracking.die(self, inst); |
| 9591 | if (self.liveness.isUnused(inst)) try tracking.die(self, inst); |
| 9584 | 9592 | self.getValue(tracking.short, inst); |
| 9585 | 9593 | self.finishAirBookkeeping(); |
| 9586 | 9594 | } |
| ... | ... | @@ -9599,7 +9607,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9599 | 9607 | // that death now instead of later as this has an effect on |
| 9600 | 9608 | // whether it needs to be spilled in the branches |
| 9601 | 9609 | if (self.liveness.operandDies(inst, 0)) { |
| 9602 | | if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); |
| 9610 | if (Air.refToIndex(pl_op.operand)) |op_inst| try self.processDeath(op_inst); |
| 9603 | 9611 | } |
| 9604 | 9612 | |
| 9605 | 9613 | self.scope_generation += 1; |
| ... | ... | @@ -9622,7 +9630,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9622 | 9630 | reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne); |
| 9623 | 9631 | } |
| 9624 | 9632 | |
| 9625 | | for (liveness.deaths[case_i]) |operand| self.processDeath(operand); |
| 9633 | for (liveness.deaths[case_i]) |operand| try self.processDeath(operand); |
| 9626 | 9634 | |
| 9627 | 9635 | for (relocs[0 .. relocs.len - 1]) |reloc| try self.performReloc(reloc); |
| 9628 | 9636 | try self.genBody(case_body); |
| ... | ... | @@ -9640,7 +9648,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9640 | 9648 | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| 9641 | 9649 | |
| 9642 | 9650 | const else_deaths = liveness.deaths.len - 1; |
| 9643 | | for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand); |
| 9651 | for (liveness.deaths[else_deaths]) |operand| try self.processDeath(operand); |
| 9644 | 9652 | |
| 9645 | 9653 | try self.genBody(else_body); |
| 9646 | 9654 | try self.restoreState(state, &.{}, .{ |
| ... | ... | @@ -9704,7 +9712,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9704 | 9712 | |
| 9705 | 9713 | // Process operand death so that it is properly accounted for in the State below. |
| 9706 | 9714 | if (self.liveness.operandDies(inst, 0)) { |
| 9707 | | if (Air.refToIndex(br.operand)) |op_inst| self.processDeath(op_inst); |
| 9715 | if (Air.refToIndex(br.operand)) |op_inst| try self.processDeath(op_inst); |
| 9708 | 9716 | } |
| 9709 | 9717 | |
| 9710 | 9718 | if (first_br) { |
| ... | ... | @@ -9718,7 +9726,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9718 | 9726 | }); |
| 9719 | 9727 | |
| 9720 | 9728 | // Stop tracking block result without forgetting tracking info |
| 9721 | | self.freeValue(block_tracking.short); |
| 9729 | try self.freeValue(block_tracking.short); |
| 9722 | 9730 | |
| 9723 | 9731 | // Emit a jump with a relocation. It will be patched up after the block ends. |
| 9724 | 9732 | // Leave the jump offset undefined |
| ... | ... | @@ -10077,13 +10085,14 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 10077 | 10085 | return self.finishAir(inst, result, buf); |
| 10078 | 10086 | } |
| 10079 | 10087 | var bt = self.liveness.iterateBigTomb(inst); |
| 10080 | | for (outputs) |output| if (output != .none) self.feed(&bt, output); |
| 10081 | | for (inputs) |input| self.feed(&bt, input); |
| 10088 | for (outputs) |output| if (output != .none) try self.feed(&bt, output); |
| 10089 | for (inputs) |input| try self.feed(&bt, input); |
| 10082 | 10090 | return self.finishAirResult(inst, result); |
| 10083 | 10091 | } |
| 10084 | 10092 | |
| 10085 | 10093 | const MoveStrategy = union(enum) { |
| 10086 | 10094 | move: Mir.Inst.FixedTag, |
| 10095 | x87_load_store, |
| 10087 | 10096 | insert_extract: InsertExtract, |
| 10088 | 10097 | vex_insert_extract: InsertExtract, |
| 10089 | 10098 | |
| ... | ... | @@ -10091,6 +10100,44 @@ const MoveStrategy = union(enum) { |
| 10091 | 10100 | insert: Mir.Inst.FixedTag, |
| 10092 | 10101 | extract: Mir.Inst.FixedTag, |
| 10093 | 10102 | }; |
| 10103 | |
| 10104 | pub fn read(strat: MoveStrategy, self: *Self, dst_reg: Register, src_mem: Memory) !void { |
| 10105 | switch (strat) { |
| 10106 | .move => |tag| try self.asmRegisterMemory(tag, dst_reg, src_mem), |
| 10107 | .x87_load_store => { |
| 10108 | try self.asmMemory(.{ .f_, .ld }, src_mem); |
| 10109 | try self.asmRegister(.{ .f_p, .st }, @enumFromInt(@intFromEnum(dst_reg) + 1)); |
| 10110 | }, |
| 10111 | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( |
| 10112 | ie.insert, |
| 10113 | dst_reg, |
| 10114 | src_mem, |
| 10115 | Immediate.u(0), |
| 10116 | ), |
| 10117 | .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate( |
| 10118 | ie.insert, |
| 10119 | dst_reg, |
| 10120 | dst_reg, |
| 10121 | src_mem, |
| 10122 | Immediate.u(0), |
| 10123 | ), |
| 10124 | } |
| 10125 | } |
| 10126 | pub fn write(strat: MoveStrategy, self: *Self, dst_mem: Memory, src_reg: Register) !void { |
| 10127 | switch (strat) { |
| 10128 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_reg), |
| 10129 | .x87_load_store => { |
| 10130 | try self.asmRegister(.{ .f_, .ld }, src_reg); |
| 10131 | try self.asmMemory(.{ .f_p, .st }, dst_mem); |
| 10132 | }, |
| 10133 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| 10134 | ie.extract, |
| 10135 | dst_mem, |
| 10136 | src_reg, |
| 10137 | Immediate.u(0), |
| 10138 | ), |
| 10139 | } |
| 10140 | } |
| 10094 | 10141 | }; |
| 10095 | 10142 | fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 10096 | 10143 | const mod = self.bin_file.options.module.?; |
| ... | ... | @@ -10106,6 +10153,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 10106 | 10153 | } }, |
| 10107 | 10154 | 32 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov } }, |
| 10108 | 10155 | 64 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov } }, |
| 10156 | 80 => return .x87_load_store, |
| 10109 | 10157 | 128 => return .{ .move = if (self.hasFeature(.avx)) |
| 10110 | 10158 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 10111 | 10159 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| ... | ... | @@ -10370,7 +10418,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError |
| 10370 | 10418 | fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void { |
| 10371 | 10419 | const mod = self.bin_file.options.module.?; |
| 10372 | 10420 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 10373 | | if (abi_size * 8 > dst_reg.bitSize()) |
| 10421 | if (ty.bitSize(mod) > dst_reg.bitSize()) |
| 10374 | 10422 | return self.fail("genSetReg called with a value larger than dst_reg", .{}); |
| 10375 | 10423 | switch (src_mcv) { |
| 10376 | 10424 | .none, |
| ... | ... | @@ -10486,9 +10534,21 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10486 | 10534 | .indirect, |
| 10487 | 10535 | .load_frame, |
| 10488 | 10536 | .lea_frame, |
| 10489 | | => { |
| 10490 | | const dst_alias = registerAlias(dst_reg, abi_size); |
| 10491 | | const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) { |
| 10537 | => try @as(MoveStrategy, switch (src_mcv) { |
| 10538 | .register_offset => |reg_off| switch (reg_off.off) { |
| 10539 | 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }), |
| 10540 | else => .{ .move = .{ ._, .lea } }, |
| 10541 | }, |
| 10542 | .indirect => try self.moveStrategy(ty, false), |
| 10543 | .load_frame => |frame_addr| try self.moveStrategy( |
| 10544 | ty, |
| 10545 | self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)), |
| 10546 | ), |
| 10547 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| 10548 | else => unreachable, |
| 10549 | }).read(self, registerAlias(dst_reg, abi_size), Memory.sib( |
| 10550 | self.memPtrSize(ty), |
| 10551 | switch (src_mcv) { |
| 10492 | 10552 | .register_offset, .indirect => |reg_off| .{ |
| 10493 | 10553 | .base = .{ .reg = reg_off.reg }, |
| 10494 | 10554 | .disp = reg_off.off, |
| ... | ... | @@ -10498,64 +10558,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10498 | 10558 | .disp = frame_addr.off, |
| 10499 | 10559 | }, |
| 10500 | 10560 | else => unreachable, |
| 10501 | | }); |
| 10502 | | switch (@as(MoveStrategy, switch (src_mcv) { |
| 10503 | | .register_offset => |reg_off| switch (reg_off.off) { |
| 10504 | | 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }), |
| 10505 | | else => .{ .move = .{ ._, .lea } }, |
| 10506 | | }, |
| 10507 | | .indirect => try self.moveStrategy(ty, false), |
| 10508 | | .load_frame => |frame_addr| try self.moveStrategy( |
| 10509 | | ty, |
| 10510 | | self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)), |
| 10511 | | ), |
| 10512 | | .lea_frame => .{ .move = .{ ._, .lea } }, |
| 10513 | | else => unreachable, |
| 10514 | | })) { |
| 10515 | | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), |
| 10516 | | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( |
| 10517 | | ie.insert, |
| 10518 | | dst_alias, |
| 10519 | | src_mem, |
| 10520 | | Immediate.u(0), |
| 10521 | | ), |
| 10522 | | .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate( |
| 10523 | | ie.insert, |
| 10524 | | dst_alias, |
| 10525 | | dst_alias, |
| 10526 | | src_mem, |
| 10527 | | Immediate.u(0), |
| 10528 | | ), |
| 10529 | | } |
| 10530 | | }, |
| 10561 | }, |
| 10562 | )), |
| 10531 | 10563 | .memory, .load_direct, .load_got, .load_tlv => { |
| 10532 | 10564 | switch (src_mcv) { |
| 10533 | | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| { |
| 10534 | | const dst_alias = registerAlias(dst_reg, abi_size); |
| 10535 | | const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| 10536 | | .base = .{ .reg = .ds }, |
| 10537 | | .disp = small_addr, |
| 10538 | | }); |
| 10539 | | switch (try self.moveStrategy(ty, ty.abiAlignment(mod).check( |
| 10540 | | @as(u32, @bitCast(small_addr)), |
| 10541 | | ))) { |
| 10542 | | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), |
| 10543 | | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( |
| 10544 | | ie.insert, |
| 10545 | | dst_alias, |
| 10546 | | src_mem, |
| 10547 | | Immediate.u(0), |
| 10548 | | ), |
| 10549 | | .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate( |
| 10550 | | ie.insert, |
| 10551 | | dst_alias, |
| 10552 | | dst_alias, |
| 10553 | | src_mem, |
| 10554 | | Immediate.u(0), |
| 10555 | | ), |
| 10556 | | } |
| 10557 | | return; |
| 10558 | | }, |
| 10565 | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| |
| 10566 | return (try self.moveStrategy( |
| 10567 | ty, |
| 10568 | ty.abiAlignment(mod).check(@as(u32, @bitCast(small_addr))), |
| 10569 | )).read(self, registerAlias(dst_reg, abi_size), Memory.sib( |
| 10570 | self.memPtrSize(ty), |
| 10571 | .{ .base = .{ .reg = .ds }, .disp = small_addr }, |
| 10572 | )), |
| 10559 | 10573 | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { |
| 10560 | 10574 | else => { |
| 10561 | 10575 | const atom_index = try self.owner.getSymbolIndex(self); |
| ... | ... | @@ -10582,26 +10596,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10582 | 10596 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 10583 | 10597 | defer self.register_manager.unlockReg(addr_lock); |
| 10584 | 10598 | |
| 10585 | | const dst_alias = registerAlias(dst_reg, abi_size); |
| 10586 | | const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| 10587 | | .base = .{ .reg = addr_reg }, |
| 10588 | | }); |
| 10589 | | switch (try self.moveStrategy(ty, false)) { |
| 10590 | | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), |
| 10591 | | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( |
| 10592 | | ie.insert, |
| 10593 | | dst_alias, |
| 10594 | | src_mem, |
| 10595 | | Immediate.u(0), |
| 10596 | | ), |
| 10597 | | .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate( |
| 10598 | | ie.insert, |
| 10599 | | dst_alias, |
| 10600 | | dst_alias, |
| 10601 | | src_mem, |
| 10602 | | Immediate.u(0), |
| 10603 | | ), |
| 10604 | | } |
| 10599 | try (try self.moveStrategy(ty, false)).read( |
| 10600 | self, |
| 10601 | registerAlias(dst_reg, abi_size), |
| 10602 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .{ .reg = addr_reg } }), |
| 10603 | ); |
| 10605 | 10604 | }, |
| 10606 | 10605 | .lea_direct, .lea_got => |sym_index| { |
| 10607 | 10606 | const atom_index = try self.owner.getSymbolIndex(self); |
| ... | ... | @@ -10698,39 +10697,23 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10698 | 10697 | }, |
| 10699 | 10698 | }, |
| 10700 | 10699 | .eflags => |cc| try self.asmSetccMemory(Memory.sib(.byte, .{ .base = base, .disp = disp }), cc), |
| 10701 | | .register => |src_reg| { |
| 10702 | | const dst_mem = Memory.sib( |
| 10703 | | Memory.PtrSize.fromSize(abi_size), |
| 10704 | | .{ .base = base, .disp = disp }, |
| 10705 | | ); |
| 10706 | | const src_alias = registerAlias(src_reg, abi_size); |
| 10707 | | switch (try self.moveStrategy(ty, switch (base) { |
| 10708 | | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10709 | | .reg => |reg| switch (reg) { |
| 10710 | | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10711 | | else => false, |
| 10712 | | }, |
| 10713 | | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10714 | | .{ .index = frame_index, .off = disp }, |
| 10715 | | ).compare(.gte, ty.abiAlignment(mod)), |
| 10716 | | })) { |
| 10717 | | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| 10718 | | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| 10719 | | ie.extract, |
| 10720 | | dst_mem, |
| 10721 | | src_alias, |
| 10722 | | Immediate.u(0), |
| 10723 | | ), |
| 10724 | | } |
| 10725 | | }, |
| 10700 | .register => |src_reg| try (try self.moveStrategy(ty, switch (base) { |
| 10701 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10702 | .reg => |reg| switch (reg) { |
| 10703 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10704 | else => false, |
| 10705 | }, |
| 10706 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10707 | .{ .index = frame_index, .off = disp }, |
| 10708 | ).compare(.gte, ty.abiAlignment(mod)), |
| 10709 | })).write( |
| 10710 | self, |
| 10711 | Memory.sib(self.memPtrSize(ty), .{ .base = base, .disp = disp }), |
| 10712 | registerAlias(src_reg, abi_size), |
| 10713 | ), |
| 10726 | 10714 | .register_pair => |src_regs| for (src_regs, 0..) |src_reg, src_reg_i| { |
| 10727 | 10715 | const part_size = @min(abi_size - src_reg_i * 8, 8); |
| 10728 | | const dst_mem = Memory.sib( |
| 10729 | | Memory.PtrSize.fromSize(part_size), |
| 10730 | | .{ .base = base, .disp = disp + @as(i32, @intCast(src_reg_i * 8)) }, |
| 10731 | | ); |
| 10732 | | const src_alias = registerAlias(src_reg, part_size); |
| 10733 | | switch (try self.moveStrategy(ty, switch (base) { |
| 10716 | try (try self.moveStrategy(ty, switch (base) { |
| 10734 | 10717 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10735 | 10718 | .reg => |reg| switch (reg) { |
| 10736 | 10719 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| ... | ... | @@ -10739,15 +10722,10 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10739 | 10722 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10740 | 10723 | .{ .index = frame_index, .off = disp }, |
| 10741 | 10724 | ).compare(.gte, ty.abiAlignment(mod)), |
| 10742 | | })) { |
| 10743 | | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| 10744 | | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| 10745 | | ie.extract, |
| 10746 | | dst_mem, |
| 10747 | | src_alias, |
| 10748 | | Immediate.u(0), |
| 10749 | | ), |
| 10750 | | } |
| 10725 | })).write(self, Memory.sib( |
| 10726 | Memory.PtrSize.fromSize(part_size), |
| 10727 | .{ .base = base, .disp = disp + @as(i32, @intCast(src_reg_i * 8)) }, |
| 10728 | ), registerAlias(src_reg, part_size)); |
| 10751 | 10729 | }, |
| 10752 | 10730 | .register_overflow => |ro| { |
| 10753 | 10731 | try self.genSetMem( |
| ... | ... | @@ -12229,7 +12207,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 12229 | 12207 | return self.finishAir(inst, result, buf); |
| 12230 | 12208 | } |
| 12231 | 12209 | var bt = self.liveness.iterateBigTomb(inst); |
| 12232 | | for (elements) |elem| self.feed(&bt, elem); |
| 12210 | for (elements) |elem| try self.feed(&bt, elem); |
| 12233 | 12211 | return self.finishAirResult(inst, result); |
| 12234 | 12212 | } |
| 12235 | 12213 | |
| ... | ... | @@ -12821,6 +12799,14 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 12821 | 12799 | }; |
| 12822 | 12800 | } |
| 12823 | 12801 | |
| 12802 | fn memPtrSize(self: *Self, ty: Type) Memory.PtrSize { |
| 12803 | const mod = self.bin_file.options.module.?; |
| 12804 | return switch (ty.zigTypeTag(mod)) { |
| 12805 | .Float => Memory.PtrSize.fromBitSize(ty.floatBits(self.target.*)), |
| 12806 | else => Memory.PtrSize.fromSize(@intCast(ty.abiSize(mod))), |
| 12807 | }; |
| 12808 | } |
| 12809 | |
| 12824 | 12810 | /// Truncates the value in the register in place. |
| 12825 | 12811 | /// Clobbers any remaining bits. |
| 12826 | 12812 | fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |