| ... | @@ -14162,9 +14162,8 @@ fn atomicOp( | ... | @@ -14162,9 +14162,8 @@ fn atomicOp( |
| 14162 | }; | 14162 | }; |
| 14163 | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); | 14163 | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); |
| 14164 | | 14164 | |
| 14165 | const method: enum { lock, loop, libcall } = if (val_ty.isRuntimeFloat()) | 14165 | const use_sse = rmw_op orelse .Xchg != .Xchg and val_ty.isRuntimeFloat(); |
| 14166 | .loop | 14166 | const strat: enum { lock, loop, libcall } = if (use_sse) .loop else switch (rmw_op orelse .Xchg) { |
| 14167 | else switch (rmw_op orelse .Xchg) { | | |
| 14168 | .Xchg, | 14167 | .Xchg, |
| 14169 | .Add, | 14168 | .Add, |
| 14170 | .Sub, | 14169 | .Sub, |
| ... | @@ -14178,7 +14177,7 @@ fn atomicOp( | ... | @@ -14178,7 +14177,7 @@ fn atomicOp( |
| 14178 | .Min, | 14177 | .Min, |
| 14179 | => if (val_abi_size <= 16) .loop else .libcall, | 14178 | => if (val_abi_size <= 16) .loop else .libcall, |
| 14180 | }; | 14179 | }; |
| 14181 | switch (method) { | 14180 | switch (strat) { |
| 14182 | .lock => { | 14181 | .lock => { |
| 14183 | const tag: Mir.Inst.Tag = if (rmw_op) |op| switch (op) { | 14182 | const tag: Mir.Inst.Tag = if (rmw_op) |op| switch (op) { |
| 14184 | .Xchg => if (unused) .mov else .xchg, | 14183 | .Xchg => if (unused) .mov else .xchg, |
| ... | @@ -14216,6 +14215,14 @@ fn atomicOp( | ... | @@ -14216,6 +14215,14 @@ fn atomicOp( |
| 14216 | return if (unused) .unreach else dst_mcv; | 14215 | return if (unused) .unreach else dst_mcv; |
| 14217 | }, | 14216 | }, |
| 14218 | .loop => _ = if (val_abi_size <= 8) { | 14217 | .loop => _ = if (val_abi_size <= 8) { |
| | 14218 | const sse_reg: Register = if (use_sse) |
| | 14219 | try self.register_manager.allocReg(null, abi.RegisterClass.sse) |
| | 14220 | else |
| | 14221 | undefined; |
| | 14222 | const sse_lock = |
| | 14223 | if (use_sse) self.register_manager.lockRegAssumeUnused(sse_reg) else undefined; |
| | 14224 | defer if (use_sse) self.register_manager.unlockReg(sse_lock); |
| | 14225 | |
| 14219 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); | 14226 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 14220 | const tmp_mcv = MCValue{ .register = tmp_reg }; | 14227 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| 14221 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); | 14228 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| ... | @@ -14223,10 +14230,67 @@ fn atomicOp( | ... | @@ -14223,10 +14230,67 @@ fn atomicOp( |
| 14223 | | 14230 | |
| 14224 | try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(.rax, val_abi_size), ptr_mem); | 14231 | try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(.rax, val_abi_size), ptr_mem); |
| 14225 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); | 14232 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 14226 | if (rmw_op != std.builtin.AtomicRmwOp.Xchg) { | 14233 | if (!use_sse and rmw_op orelse .Xchg != .Xchg) { |
| 14227 | try self.genSetReg(tmp_reg, val_ty, .{ .register = .rax }); | 14234 | try self.genSetReg(tmp_reg, val_ty, .{ .register = .rax }); |
| 14228 | } | 14235 | } |
| 14229 | if (rmw_op) |op| switch (op) { | 14236 | if (rmw_op) |op| if (use_sse) { |
| | 14237 | const mir_tag = @as(?Mir.Inst.FixedTag, switch (op) { |
| | 14238 | .Add => switch (val_ty.floatBits(self.target.*)) { |
| | 14239 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add }, |
| | 14240 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add }, |
| | 14241 | else => null, |
| | 14242 | }, |
| | 14243 | .Sub => switch (val_ty.floatBits(self.target.*)) { |
| | 14244 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub }, |
| | 14245 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub }, |
| | 14246 | else => null, |
| | 14247 | }, |
| | 14248 | .Min => switch (val_ty.floatBits(self.target.*)) { |
| | 14249 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .min } else .{ ._ss, .min }, |
| | 14250 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .min } else .{ ._sd, .min }, |
| | 14251 | else => null, |
| | 14252 | }, |
| | 14253 | .Max => switch (val_ty.floatBits(self.target.*)) { |
| | 14254 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .max } else .{ ._ss, .max }, |
| | 14255 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .max } else .{ ._sd, .max }, |
| | 14256 | else => null, |
| | 14257 | }, |
| | 14258 | else => unreachable, |
| | 14259 | }) orelse return self.fail("TODO implement atomicOp of {s} for {}", .{ |
| | 14260 | @tagName(op), val_ty.fmt(mod), |
| | 14261 | }); |
| | 14262 | try self.genSetReg(sse_reg, val_ty, .{ .register = .rax }); |
| | 14263 | switch (mir_tag[0]) { |
| | 14264 | .v_ss, .v_sd => if (val_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| | 14265 | mir_tag, |
| | 14266 | sse_reg.to128(), |
| | 14267 | sse_reg.to128(), |
| | 14268 | try val_mcv.mem(self, self.memSize(val_ty)), |
| | 14269 | ) else try self.asmRegisterRegisterRegister( |
| | 14270 | mir_tag, |
| | 14271 | sse_reg.to128(), |
| | 14272 | sse_reg.to128(), |
| | 14273 | (if (val_mcv.isRegister()) |
| | 14274 | val_mcv.getReg().? |
| | 14275 | else |
| | 14276 | try self.copyToTmpRegister(val_ty, val_mcv)).to128(), |
| | 14277 | ), |
| | 14278 | ._ss, ._sd => if (val_mcv.isMemory()) try self.asmRegisterMemory( |
| | 14279 | mir_tag, |
| | 14280 | sse_reg.to128(), |
| | 14281 | try val_mcv.mem(self, self.memSize(val_ty)), |
| | 14282 | ) else try self.asmRegisterRegister( |
| | 14283 | mir_tag, |
| | 14284 | sse_reg.to128(), |
| | 14285 | (if (val_mcv.isRegister()) |
| | 14286 | val_mcv.getReg().? |
| | 14287 | else |
| | 14288 | try self.copyToTmpRegister(val_ty, val_mcv)).to128(), |
| | 14289 | ), |
| | 14290 | else => unreachable, |
| | 14291 | } |
| | 14292 | try self.genSetReg(tmp_reg, val_ty, .{ .register = sse_reg }); |
| | 14293 | } else switch (op) { |
| 14230 | .Xchg => try self.genSetReg(tmp_reg, val_ty, val_mcv), | 14294 | .Xchg => try self.genSetReg(tmp_reg, val_ty, val_mcv), |
| 14231 | .Add => try self.genBinOpMir(.{ ._, .add }, val_ty, tmp_mcv, val_mcv), | 14295 | .Add => try self.genBinOpMir(.{ ._, .add }, val_ty, tmp_mcv, val_mcv), |
| 14232 | .Sub => try self.genBinOpMir(.{ ._, .sub }, val_ty, tmp_mcv, val_mcv), | 14296 | .Sub => try self.genBinOpMir(.{ ._, .sub }, val_ty, tmp_mcv, val_mcv), |
| ... | @@ -14362,9 +14426,32 @@ fn atomicOp( | ... | @@ -14362,9 +14426,32 @@ fn atomicOp( |
| 14362 | try self.asmRegisterMemory(.{ ._, .xor }, .rbx, val_lo_mem); | 14426 | try self.asmRegisterMemory(.{ ._, .xor }, .rbx, val_lo_mem); |
| 14363 | try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem); | 14427 | try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem); |
| 14364 | }, | 14428 | }, |
| 14365 | else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{ | 14429 | .Min, .Max => { |
| 14366 | val_ty.fmt(mod), @tagName(op), | 14430 | const cc: Condition = switch (if (val_ty.isAbiInt(mod)) |
| 14367 | }), | 14431 | val_ty.intInfo(mod).signedness |
| | 14432 | else |
| | 14433 | .unsigned) { |
| | 14434 | .unsigned => switch (op) { |
| | 14435 | .Min => .a, |
| | 14436 | .Max => .b, |
| | 14437 | else => unreachable, |
| | 14438 | }, |
| | 14439 | .signed => switch (op) { |
| | 14440 | .Min => .g, |
| | 14441 | .Max => .l, |
| | 14442 | else => unreachable, |
| | 14443 | }, |
| | 14444 | }; |
| | 14445 | |
| | 14446 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .register = .rcx }); |
| | 14447 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| | 14448 | defer self.register_manager.unlockReg(tmp_lock); |
| | 14449 | |
| | 14450 | try self.asmRegisterMemory(.{ ._, .cmp }, .rbx, val_lo_mem); |
| | 14451 | try self.asmRegisterMemory(.{ ._, .sbb }, tmp_reg, val_hi_mem); |
| | 14452 | try self.asmCmovccRegisterMemory(cc, .rbx, val_lo_mem); |
| | 14453 | try self.asmCmovccRegisterMemory(cc, .rcx, val_hi_mem); |
| | 14454 | }, |
| 14368 | }; | 14455 | }; |
| 14369 | try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem); | 14456 | try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem); |
| 14370 | _ = try self.asmJccReloc(.ne, loop); | 14457 | _ = try self.asmJccReloc(.ne, loop); |