| ... | @@ -2844,6 +2844,9 @@ fn genBinOp( | ... | @@ -2844,6 +2844,9 @@ fn genBinOp( |
| 2844 | .cmp_gt, | 2844 | .cmp_gt, |
| 2845 | .cmp_gte, | 2845 | .cmp_gte, |
| 2846 | => { | 2846 | => { |
| | 2847 | try func.truncateRegister(lhs_ty, lhs_reg); |
| | 2848 | try func.truncateRegister(rhs_ty, rhs_reg); |
| | 2849 | |
| 2847 | _ = try func.addInst(.{ | 2850 | _ = try func.addInst(.{ |
| 2848 | .tag = .pseudo_compare, | 2851 | .tag = .pseudo_compare, |
| 2849 | .data = .{ | 2852 | .data = .{ |
| ... | @@ -3925,10 +3928,6 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3925,10 +3928,6 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 3925 | const base_ptr_ty = func.typeOf(extra.lhs); | 3928 | const base_ptr_ty = func.typeOf(extra.lhs); |
| 3926 | | 3929 | |
| 3927 | if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) { | 3930 | if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) { |
| 3928 | // break :result if (func.reuseOperand(inst, extra.lhs, 0, base_ptr_mcv)) | | |
| 3929 | // base_ptr_mcv | | |
| 3930 | // else | | |
| 3931 | // try func.copyToNewRegister(inst, base_ptr_mcv); | | |
| 3932 | @panic("audit"); | 3931 | @panic("audit"); |
| 3933 | } | 3932 | } |
| 3934 | | 3933 | |
| ... | @@ -3992,7 +3991,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3992,7 +3991,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 3992 | defer func.register_manager.unlockReg(result_lock); | 3991 | defer func.register_manager.unlockReg(result_lock); |
| 3993 | | 3992 | |
| 3994 | switch (frame_mcv) { | 3993 | switch (frame_mcv) { |
| 3995 | .load_frame => |frame_addr| { | 3994 | .load_frame => { |
| 3996 | if (tag_abi_size <= 8) { | 3995 | if (tag_abi_size <= 8) { |
| 3997 | const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align)) | 3996 | const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align)) |
| 3998 | @intCast(layout.payload_size) | 3997 | @intCast(layout.payload_size) |
| ... | @@ -4002,7 +4001,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4002,7 +4001,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 4002 | try func.genCopy( | 4001 | try func.genCopy( |
| 4003 | tag_ty, | 4002 | tag_ty, |
| 4004 | .{ .register = result_reg }, | 4003 | .{ .register = result_reg }, |
| 4005 | .{ .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off } }, | 4004 | frame_mcv.offset(off), |
| 4006 | ); | 4005 | ); |
| 4007 | } else { | 4006 | } else { |
| 4008 | return func.fail( | 4007 | return func.fail( |
| ... | @@ -4081,7 +4080,37 @@ fn airCtz(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4081,7 +4080,37 @@ fn airCtz(func: *Func, inst: Air.Inst.Index) !void { |
| 4081 | | 4080 | |
| 4082 | fn airPopcount(func: *Func, inst: Air.Inst.Index) !void { | 4081 | fn airPopcount(func: *Func, inst: Air.Inst.Index) !void { |
| 4083 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 4082 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4084 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airPopcount for {}", .{func.target.cpu.arch}); | 4083 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| | 4084 | const pt = func.pt; |
| | 4085 | |
| | 4086 | const operand = try func.resolveInst(ty_op.operand); |
| | 4087 | const src_ty = func.typeOf(ty_op.operand); |
| | 4088 | const operand_reg, const operand_lock = try func.promoteReg(src_ty, operand); |
| | 4089 | defer if (operand_lock) |lock| func.register_manager.unlockReg(lock); |
| | 4090 | |
| | 4091 | const dst_reg, const dst_lock = try func.allocReg(.int); |
| | 4092 | defer func.register_manager.unlockReg(dst_lock); |
| | 4093 | |
| | 4094 | const bit_size = src_ty.bitSize(pt); |
| | 4095 | switch (bit_size) { |
| | 4096 | 32, 64 => {}, |
| | 4097 | 1...31, 33...63 => try func.truncateRegister(src_ty, operand_reg), |
| | 4098 | else => return func.fail("TODO: airPopcount > 64 bits", .{}), |
| | 4099 | } |
| | 4100 | |
| | 4101 | _ = try func.addInst(.{ |
| | 4102 | .tag = if (bit_size <= 32) .cpopw else .cpop, |
| | 4103 | .data = .{ |
| | 4104 | .r_type = .{ |
| | 4105 | .rd = dst_reg, |
| | 4106 | .rs1 = operand_reg, |
| | 4107 | .rs2 = @enumFromInt(0b00010), // this is the cpop funct5 |
| | 4108 | }, |
| | 4109 | }, |
| | 4110 | }); |
| | 4111 | |
| | 4112 | break :result .{ .register = dst_reg }; |
| | 4113 | }; |
| 4085 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 4114 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 4086 | } | 4115 | } |
| 4087 | | 4116 | |
| ... | @@ -5630,7 +5659,6 @@ fn lowerBlock(func: *Func, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! | ... | @@ -5630,7 +5659,6 @@ fn lowerBlock(func: *Func, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! |
| 5630 | | 5659 | |
| 5631 | fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | 5660 | fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5632 | const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; | 5661 | const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 5633 | const condition = try func.resolveInst(pl_op.operand); | | |
| 5634 | const condition_ty = func.typeOf(pl_op.operand); | 5662 | const condition_ty = func.typeOf(pl_op.operand); |
| 5635 | const switch_br = func.air.extraData(Air.SwitchBr, pl_op.payload); | 5663 | const switch_br = func.air.extraData(Air.SwitchBr, pl_op.payload); |
| 5636 | var extra_index: usize = switch_br.end; | 5664 | var extra_index: usize = switch_br.end; |
| ... | @@ -5638,6 +5666,8 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5638,6 +5666,8 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5638 | const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.data.cases_len + 1); | 5666 | const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.data.cases_len + 1); |
| 5639 | defer func.gpa.free(liveness.deaths); | 5667 | defer func.gpa.free(liveness.deaths); |
| 5640 | | 5668 | |
| | 5669 | const condition = try func.resolveInst(pl_op.operand); |
| | 5670 | |
| 5641 | // If the condition dies here in this switch instruction, process | 5671 | // If the condition dies here in this switch instruction, process |
| 5642 | // that death now instead of later as this has an effect on | 5672 | // that death now instead of later as this has an effect on |
| 5643 | // whether it needs to be spilled in the branches | 5673 | // whether it needs to be spilled in the branches |
| ... | @@ -5660,9 +5690,14 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5660,9 +5690,14 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5660 | defer func.gpa.free(relocs); | 5690 | defer func.gpa.free(relocs); |
| 5661 | | 5691 | |
| 5662 | for (items, relocs, 0..) |item, *reloc, i| { | 5692 | for (items, relocs, 0..) |item, *reloc, i| { |
| 5663 | // switch branches must be comptime-known, so this is stored in an immediate | | |
| 5664 | const item_mcv = try func.resolveInst(item); | 5693 | const item_mcv = try func.resolveInst(item); |
| 5665 | | 5694 | |
| | 5695 | const cond_lock = switch (condition) { |
| | 5696 | .register => func.register_manager.lockRegAssumeUnused(condition.register), |
| | 5697 | else => null, |
| | 5698 | }; |
| | 5699 | defer if (cond_lock) |lock| func.register_manager.unlockReg(lock); |
| | 5700 | |
| 5666 | const cmp_reg, const cmp_lock = try func.allocReg(.int); | 5701 | const cmp_reg, const cmp_lock = try func.allocReg(.int); |
| 5667 | defer func.register_manager.unlockReg(cmp_lock); | 5702 | defer func.register_manager.unlockReg(cmp_lock); |
| 5668 | | 5703 | |
| ... | @@ -7110,57 +7145,58 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -7110,57 +7145,58 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { |
| 7110 | const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; | 7145 | const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 7111 | const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; | 7146 | const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 7112 | | 7147 | |
| 7113 | const op = extra.op(); | 7148 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 7114 | const order = extra.ordering(); | 7149 | const op = extra.op(); |
| | 7150 | const order = extra.ordering(); |
| 7115 | | 7151 | |
| 7116 | const ptr_ty = func.typeOf(pl_op.operand); | 7152 | const ptr_ty = func.typeOf(pl_op.operand); |
| 7117 | const ptr_mcv = try func.resolveInst(pl_op.operand); | 7153 | const ptr_mcv = try func.resolveInst(pl_op.operand); |
| 7118 | | 7154 | |
| 7119 | const val_ty = func.typeOf(extra.operand); | 7155 | const val_ty = func.typeOf(extra.operand); |
| 7120 | const val_size = val_ty.abiSize(pt); | 7156 | const val_size = val_ty.abiSize(pt); |
| 7121 | const val_mcv = try func.resolveInst(extra.operand); | 7157 | const val_mcv = try func.resolveInst(extra.operand); |
| 7122 | | 7158 | |
| 7123 | if (!math.isPowerOfTwo(val_size)) | 7159 | if (!math.isPowerOfTwo(val_size)) |
| 7124 | return func.fail("TODO: airAtomicRmw non-pow 2", .{}); | 7160 | return func.fail("TODO: airAtomicRmw non-pow 2", .{}); |
| 7125 | | 7161 | |
| 7126 | switch (val_ty.zigTypeTag(pt.zcu)) { | 7162 | switch (val_ty.zigTypeTag(pt.zcu)) { |
| 7127 | .Int => {}, | 7163 | .Int => {}, |
| 7128 | inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}), | 7164 | inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}), |
| 7129 | else => unreachable, | 7165 | else => unreachable, |
| 7130 | } | 7166 | } |
| 7131 | | 7167 | |
| 7132 | const method: enum { amo, loop } = switch (val_size) { | 7168 | const method: enum { amo, loop } = switch (val_size) { |
| 7133 | 1, 2 => .loop, | 7169 | 1, 2 => .loop, |
| 7134 | 4, 8 => .amo, | 7170 | 4, 8 => .amo, |
| 7135 | else => unreachable, | 7171 | else => unreachable, |
| 7136 | }; | 7172 | }; |
| 7137 | | 7173 | |
| 7138 | const ptr_register, const ptr_lock = try func.promoteReg(ptr_ty, ptr_mcv); | 7174 | const ptr_register, const ptr_lock = try func.promoteReg(ptr_ty, ptr_mcv); |
| 7139 | defer if (ptr_lock) |lock| func.register_manager.unlockReg(lock); | 7175 | defer if (ptr_lock) |lock| func.register_manager.unlockReg(lock); |
| 7140 | | 7176 | |
| 7141 | const val_register, const val_lock = try func.promoteReg(val_ty, val_mcv); | 7177 | const val_register, const val_lock = try func.promoteReg(val_ty, val_mcv); |
| 7142 | defer if (val_lock) |lock| func.register_manager.unlockReg(lock); | 7178 | defer if (val_lock) |lock| func.register_manager.unlockReg(lock); |
| 7143 | | 7179 | |
| 7144 | const result_mcv = try func.allocRegOrMem(val_ty, inst, true); | 7180 | const result_mcv = try func.allocRegOrMem(val_ty, inst, true); |
| 7145 | assert(result_mcv == .register); // should fit into 8 bytes | 7181 | assert(result_mcv == .register); // should fit into 8 bytes |
| 7146 | const result_reg = result_mcv.register; | 7182 | const result_reg = result_mcv.register; |
| 7147 | | 7183 | |
| 7148 | const aq, const rl = switch (order) { | 7184 | const aq, const rl = switch (order) { |
| 7149 | .unordered => unreachable, | 7185 | .unordered => unreachable, |
| 7150 | .monotonic => .{ false, false }, | 7186 | .monotonic => .{ false, false }, |
| 7151 | .acquire => .{ true, false }, | 7187 | .acquire => .{ true, false }, |
| 7152 | .release => .{ false, true }, | 7188 | .release => .{ false, true }, |
| 7153 | .acq_rel => .{ true, true }, | 7189 | .acq_rel => .{ true, true }, |
| 7154 | .seq_cst => .{ true, true }, | 7190 | .seq_cst => .{ true, true }, |
| 7155 | }; | 7191 | }; |
| 7156 | | 7192 | |
| 7157 | switch (method) { | 7193 | switch (method) { |
| 7158 | .amo => { | 7194 | .amo => { |
| 7159 | const is_d = val_ty.abiSize(pt) == 8; | 7195 | const is_d = val_ty.abiSize(pt) == 8; |
| 7160 | const is_un = val_ty.isUnsignedInt(zcu); | 7196 | const is_un = val_ty.isUnsignedInt(zcu); |
| 7161 | | 7197 | |
| 7162 | const mnem: Mnemonic = switch (op) { | 7198 | const mnem: Mnemonic = switch (op) { |
| 7163 | // zig fmt: off | 7199 | // zig fmt: off |
| 7164 | .Xchg => if (is_d) .amoswapd else .amoswapw, | 7200 | .Xchg => if (is_d) .amoswapd else .amoswapw, |
| 7165 | .Add => if (is_d) .amoaddd else .amoaddw, | 7201 | .Add => if (is_d) .amoaddd else .amoaddw, |
| 7166 | .And => if (is_d) .amoandd else .amoandw, | 7202 | .And => if (is_d) .amoandd else .amoandw, |
| ... | @@ -7170,82 +7206,79 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -7170,82 +7206,79 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { |
| 7170 | .Min => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw, | 7206 | .Min => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw, |
| 7171 | else => return func.fail("TODO: airAtomicRmw amo {s}", .{@tagName(op)}), | 7207 | else => return func.fail("TODO: airAtomicRmw amo {s}", .{@tagName(op)}), |
| 7172 | // zig fmt: on | 7208 | // zig fmt: on |
| 7173 | }; | 7209 | }; |
| 7174 | | 7210 | |
| 7175 | _ = try func.addInst(.{ | 7211 | _ = try func.addInst(.{ |
| 7176 | .tag = mnem, | 7212 | .tag = mnem, |
| 7177 | .data = .{ .amo = .{ | 7213 | .data = .{ .amo = .{ |
| 7178 | .rd = result_reg, | 7214 | .rd = result_reg, |
| 7179 | .rs1 = ptr_register, | 7215 | .rs1 = ptr_register, |
| 7180 | .rs2 = val_register, | 7216 | .rs2 = val_register, |
| 7181 | .aq = if (aq) .aq else .none, | 7217 | .aq = if (aq) .aq else .none, |
| 7182 | .rl = if (rl) .rl else .none, | 7218 | .rl = if (rl) .rl else .none, |
| 7183 | } }, | 7219 | } }, |
| 7184 | }); | 7220 | }); |
| 7185 | }, | 7221 | }, |
| 7186 | .loop => { | 7222 | .loop => { |
| 7187 | // where we'll jump back when the sc fails | 7223 | // where we'll jump back when the sc fails |
| 7188 | const jump_back = try func.addInst(.{ | 7224 | const jump_back = try func.addInst(.{ |
| 7189 | .tag = .lrw, | 7225 | .tag = .lrw, |
| 7190 | .data = .{ .amo = .{ | 7226 | .data = .{ .amo = .{ |
| 7191 | .rd = result_reg, | 7227 | .rd = result_reg, |
| 7192 | .rs1 = ptr_register, | 7228 | .rs1 = ptr_register, |
| 7193 | .rs2 = .zero, | 7229 | .rs2 = .zero, |
| 7194 | .aq = if (aq) .aq else .none, | 7230 | .aq = if (aq) .aq else .none, |
| 7195 | .rl = if (rl) .rl else .none, | 7231 | .rl = if (rl) .rl else .none, |
| 7196 | } }, | 7232 | } }, |
| 7197 | }); | 7233 | }); |
| 7198 | | 7234 | |
| 7199 | const after_reg, const after_lock = try func.allocReg(.int); | 7235 | const after_reg, const after_lock = try func.allocReg(.int); |
| 7200 | defer func.register_manager.unlockReg(after_lock); | 7236 | defer func.register_manager.unlockReg(after_lock); |
| 7201 | | 7237 | |
| 7202 | switch (op) { | 7238 | switch (op) { |
| 7203 | .Add => { | 7239 | .Add, .Sub => |tag| { |
| 7204 | _ = try func.genBinOp( | 7240 | _ = try func.genBinOp( |
| 7205 | .add, | 7241 | switch (tag) { |
| 7206 | .{ .register = result_reg }, | 7242 | .Add => .add, |
| 7207 | val_ty, | 7243 | .Sub => .sub, |
| 7208 | .{ .register = val_register }, | 7244 | else => unreachable, |
| 7209 | val_ty, | 7245 | }, |
| 7210 | after_reg, | 7246 | .{ .register = result_reg }, |
| 7211 | ); | 7247 | val_ty, |
| 7212 | }, | 7248 | .{ .register = val_register }, |
| 7213 | .Sub => { | 7249 | val_ty, |
| 7214 | _ = try func.genBinOp( | 7250 | after_reg, |
| 7215 | .sub, | 7251 | ); |
| 7216 | .{ .register = result_reg }, | 7252 | }, |
| 7217 | val_ty, | | |
| 7218 | .{ .register = val_register }, | | |
| 7219 | val_ty, | | |
| 7220 | after_reg, | | |
| 7221 | ); | | |
| 7222 | }, | | |
| 7223 | else => return func.fail("TODO: airAtomicRmw loop {s}", .{@tagName(op)}), | | |
| 7224 | } | | |
| 7225 | | 7253 | |
| 7226 | _ = try func.addInst(.{ | 7254 | else => return func.fail("TODO: airAtomicRmw loop {s}", .{@tagName(op)}), |
| 7227 | .tag = .scw, | 7255 | } |
| 7228 | .data = .{ .amo = .{ | | |
| 7229 | .rd = after_reg, | | |
| 7230 | .rs1 = ptr_register, | | |
| 7231 | .rs2 = after_reg, | | |
| 7232 | .aq = if (aq) .aq else .none, | | |
| 7233 | .rl = if (rl) .rl else .none, | | |
| 7234 | } }, | | |
| 7235 | }); | | |
| 7236 | | 7256 | |
| 7237 | _ = try func.addInst(.{ | 7257 | _ = try func.addInst(.{ |
| 7238 | .tag = .bne, | 7258 | .tag = .scw, |
| 7239 | .data = .{ .b_type = .{ | 7259 | .data = .{ .amo = .{ |
| 7240 | .inst = jump_back, | 7260 | .rd = after_reg, |
| 7241 | .rs1 = after_reg, | 7261 | .rs1 = ptr_register, |
| 7242 | .rs2 = .zero, | 7262 | .rs2 = after_reg, |
| 7243 | } }, | 7263 | .aq = if (aq) .aq else .none, |
| 7244 | }); | 7264 | .rl = if (rl) .rl else .none, |
| 7245 | }, | 7265 | } }, |
| 7246 | } | 7266 | }); |
| | 7267 | |
| | 7268 | _ = try func.addInst(.{ |
| | 7269 | .tag = .bne, |
| | 7270 | .data = .{ .b_type = .{ |
| | 7271 | .inst = jump_back, |
| | 7272 | .rs1 = after_reg, |
| | 7273 | .rs2 = .zero, |
| | 7274 | } }, |
| | 7275 | }); |
| | 7276 | }, |
| | 7277 | } |
| | 7278 | break :result result_mcv; |
| | 7279 | }; |
| 7247 | | 7280 | |
| 7248 | return func.finishAir(inst, result_mcv, .{ pl_op.operand, extra.operand, .none }); | 7281 | return func.finishAir(inst, result, .{ pl_op.operand, extra.operand, .none }); |
| 7249 | } | 7282 | } |
| 7250 | | 7283 | |
| 7251 | fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void { | 7284 | fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void { |