| ... | @@ -39,7 +39,7 @@ const RegisterLock = RegisterManager.RegisterLock; | ... | @@ -39,7 +39,7 @@ const RegisterLock = RegisterManager.RegisterLock; |
| 39 | const Register = bits.Register; | 39 | const Register = bits.Register; |
| 40 | | 40 | |
| 41 | const gp = abi.RegisterClass.gp; | 41 | const gp = abi.RegisterClass.gp; |
| 42 | const avx = abi.RegisterClass.avx; | 42 | const sse = abi.RegisterClass.sse; |
| 43 | | 43 | |
| 44 | const InnerError = error{ | 44 | const InnerError = error{ |
| 45 | OutOfMemory, | 45 | OutOfMemory, |
| ... | @@ -881,15 +881,18 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -881,15 +881,18 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 881 | switch (elem_ty.zigTypeTag()) { | 881 | switch (elem_ty.zigTypeTag()) { |
| 882 | .Vector => return self.fail("TODO allocRegOrMem for Vector type", .{}), | 882 | .Vector => return self.fail("TODO allocRegOrMem for Vector type", .{}), |
| 883 | .Float => { | 883 | .Float => { |
| 884 | // TODO check if AVX available | 884 | if (self.intrinsicsAllowed(elem_ty)) { |
| 885 | const ptr_bytes: u64 = 32; | 885 | const ptr_bytes: u64 = 32; |
| 886 | if (abi_size <= ptr_bytes) { | 886 | if (abi_size <= ptr_bytes) { |
| 887 | if (self.register_manager.tryAllocReg(inst, .{ | 887 | if (self.register_manager.tryAllocReg(inst, .{ |
| 888 | .selector_mask = avx, | 888 | .selector_mask = sse, |
| 889 | })) |reg| { | 889 | })) |reg| { |
| 890 | return MCValue{ .register = registerAlias(reg, abi_size) }; | 890 | return MCValue{ .register = registerAlias(reg, abi_size) }; |
| | 891 | } |
| 891 | } | 892 | } |
| 892 | } | 893 | } |
| | 894 | |
| | 895 | return self.fail("TODO allocRegOrMem for Float type without SSE/AVX support", .{}); |
| 893 | }, | 896 | }, |
| 894 | else => { | 897 | else => { |
| 895 | // Make sure the type can fit in a register before we try to allocate one. | 898 | // Make sure the type can fit in a register before we try to allocate one. |
| ... | @@ -969,8 +972,11 @@ pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [cou | ... | @@ -969,8 +972,11 @@ pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [cou |
| 969 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 972 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 970 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 973 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 971 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 974 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 972 | const mask = switch (ty.zigTypeTag()) { | 975 | const mask: RegisterManager.RegisterBitSet = switch (ty.zigTypeTag()) { |
| 973 | .Float => avx, | 976 | .Float => blk: { |
| | 977 | if (self.intrinsicsAllowed(ty)) break :blk sse; |
| | 978 | return self.fail("TODO copy {} to register", .{ty.fmtDebug()}); |
| | 979 | }, |
| 974 | else => gp, | 980 | else => gp, |
| 975 | }; | 981 | }; |
| 976 | const reg: Register = try self.register_manager.allocReg(null, .{ | 982 | const reg: Register = try self.register_manager.allocReg(null, .{ |
| ... | @@ -985,8 +991,11 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -985,8 +991,11 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 985 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 991 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 986 | /// WARNING make sure that the allocated register matches the returned MCValue from an instruction! | 992 | /// WARNING make sure that the allocated register matches the returned MCValue from an instruction! |
| 987 | fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue { | 993 | fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue { |
| 988 | const mask = switch (ty.zigTypeTag()) { | 994 | const mask: RegisterManager.RegisterBitSet = switch (ty.zigTypeTag()) { |
| 989 | .Float => avx, | 995 | .Float => blk: { |
| | 996 | if (self.intrinsicsAllowed(ty)) break :blk sse; |
| | 997 | return self.fail("TODO copy {} to register", .{ty.fmtDebug()}); |
| | 998 | }, |
| 990 | else => gp, | 999 | else => gp, |
| 991 | }; | 1000 | }; |
| 992 | const reg: Register = try self.register_manager.allocReg(reg_owner, .{ | 1001 | const reg: Register = try self.register_manager.allocReg(reg_owner, .{ |
| ... | @@ -3469,27 +3478,32 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu | ... | @@ -3469,27 +3478,32 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu |
| 3469 | }, | 3478 | }, |
| 3470 | .register => |src_reg| switch (dst_ty.zigTypeTag()) { | 3479 | .register => |src_reg| switch (dst_ty.zigTypeTag()) { |
| 3471 | .Float => { | 3480 | .Float => { |
| 3472 | const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) { | 3481 | if (self.intrinsicsAllowed(dst_ty)) { |
| 3473 | .f32 => switch (mir_tag) { | 3482 | const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) { |
| 3474 | .add => Mir.Inst.Tag.add_f32, | 3483 | .f32 => switch (mir_tag) { |
| 3475 | .cmp => Mir.Inst.Tag.cmp_f32, | 3484 | .add => Mir.Inst.Tag.add_f32_avx, |
| 3476 | else => return self.fail("TODO genBinOpMir for f32 register-register with MIR tag {}", .{mir_tag}), | 3485 | .cmp => Mir.Inst.Tag.cmp_f32_avx, |
| 3477 | }, | 3486 | else => return self.fail("TODO genBinOpMir for f32 register-register with MIR tag {}", .{mir_tag}), |
| 3478 | .f64 => switch (mir_tag) { | 3487 | }, |
| 3479 | .add => Mir.Inst.Tag.add_f64, | 3488 | .f64 => switch (mir_tag) { |
| 3480 | .cmp => Mir.Inst.Tag.cmp_f64, | 3489 | .add => Mir.Inst.Tag.add_f64_avx, |
| 3481 | else => return self.fail("TODO genBinOpMir for f64 register-register with MIR tag {}", .{mir_tag}), | 3490 | .cmp => Mir.Inst.Tag.cmp_f64_avx, |
| 3482 | }, | 3491 | else => return self.fail("TODO genBinOpMir for f64 register-register with MIR tag {}", .{mir_tag}), |
| 3483 | else => return self.fail("TODO genBinOpMir for float register-register and type {}", .{dst_ty.fmtDebug()}), | 3492 | }, |
| 3484 | }; | 3493 | else => return self.fail("TODO genBinOpMir for float register-register and type {}", .{dst_ty.fmtDebug()}), |
| 3485 | _ = try self.addInst(.{ | 3494 | }; |
| 3486 | .tag = actual_tag, | 3495 | _ = try self.addInst(.{ |
| 3487 | .ops = Mir.Inst.Ops.encode(.{ | 3496 | .tag = actual_tag, |
| 3488 | .reg1 = dst_reg.to128(), | 3497 | .ops = Mir.Inst.Ops.encode(.{ |
| 3489 | .reg2 = src_reg.to128(), | 3498 | .reg1 = dst_reg.to128(), |
| 3490 | }), | 3499 | .reg2 = src_reg.to128(), |
| 3491 | .data = undefined, | 3500 | }), |
| 3492 | }); | 3501 | .data = undefined, |
| | 3502 | }); |
| | 3503 | return; |
| | 3504 | } |
| | 3505 | |
| | 3506 | return self.fail("TODO genBinOpMir for float register-register and no intrinsics", .{}); |
| 3493 | }, | 3507 | }, |
| 3494 | else => { | 3508 | else => { |
| 3495 | _ = try self.addInst(.{ | 3509 | _ = try self.addInst(.{ |
| ... | @@ -5326,24 +5340,29 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -5326,24 +5340,29 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 5326 | .register => |reg| { | 5340 | .register => |reg| { |
| 5327 | switch (ty.zigTypeTag()) { | 5341 | switch (ty.zigTypeTag()) { |
| 5328 | .Float => { | 5342 | .Float => { |
| 5329 | const tag: Mir.Inst.Tag = switch (ty.tag()) { | 5343 | if (self.intrinsicsAllowed(ty)) { |
| 5330 | .f32 => .mov_f32, | 5344 | const tag: Mir.Inst.Tag = switch (ty.tag()) { |
| 5331 | .f64 => .mov_f64, | 5345 | .f32 => .mov_f32_avx, |
| 5332 | else => return self.fail("TODO genSetStackArg for register for type {}", .{ty.fmtDebug()}), | 5346 | .f64 => .mov_f64_avx, |
| 5333 | }; | 5347 | else => return self.fail("TODO genSetStackArg for register for type {}", .{ty.fmtDebug()}), |
| 5334 | _ = try self.addInst(.{ | 5348 | }; |
| 5335 | .tag = tag, | 5349 | _ = try self.addInst(.{ |
| 5336 | .ops = Mir.Inst.Ops.encode(.{ | 5350 | .tag = tag, |
| 5337 | .reg1 = switch (ty.tag()) { | 5351 | .ops = Mir.Inst.Ops.encode(.{ |
| 5338 | .f32 => .esp, | 5352 | .reg1 = switch (ty.tag()) { |
| 5339 | .f64 => .rsp, | 5353 | .f32 => .esp, |
| 5340 | else => unreachable, | 5354 | .f64 => .rsp, |
| 5341 | }, | 5355 | else => unreachable, |
| 5342 | .reg2 = reg.to128(), | 5356 | }, |
| 5343 | .flags = 0b01, | 5357 | .reg2 = reg.to128(), |
| 5344 | }), | 5358 | .flags = 0b01, |
| 5345 | .data = .{ .imm = @bitCast(u32, -stack_offset) }, | 5359 | }), |
| 5346 | }); | 5360 | .data = .{ .imm = @bitCast(u32, -stack_offset) }, |
| | 5361 | }); |
| | 5362 | return; |
| | 5363 | } |
| | 5364 | |
| | 5365 | return self.fail("TODO genSetStackArg for register with no intrinsics", .{}); |
| 5347 | }, | 5366 | }, |
| 5348 | else => { | 5367 | else => { |
| 5349 | _ = try self.addInst(.{ | 5368 | _ = try self.addInst(.{ |
| ... | @@ -5505,24 +5524,29 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -5505,24 +5524,29 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5505 | | 5524 | |
| 5506 | switch (ty.zigTypeTag()) { | 5525 | switch (ty.zigTypeTag()) { |
| 5507 | .Float => { | 5526 | .Float => { |
| 5508 | const tag: Mir.Inst.Tag = switch (ty.tag()) { | 5527 | if (self.intrinsicsAllowed(ty)) { |
| 5509 | .f32 => .mov_f32, | 5528 | const tag: Mir.Inst.Tag = switch (ty.tag()) { |
| 5510 | .f64 => .mov_f64, | 5529 | .f32 => .mov_f32_avx, |
| 5511 | else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}), | 5530 | .f64 => .mov_f64_avx, |
| 5512 | }; | 5531 | else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}), |
| 5513 | _ = try self.addInst(.{ | 5532 | }; |
| 5514 | .tag = tag, | 5533 | _ = try self.addInst(.{ |
| 5515 | .ops = Mir.Inst.Ops.encode(.{ | 5534 | .tag = tag, |
| 5516 | .reg1 = switch (ty.tag()) { | 5535 | .ops = Mir.Inst.Ops.encode(.{ |
| 5517 | .f32 => base_reg.to32(), | 5536 | .reg1 = switch (ty.tag()) { |
| 5518 | .f64 => base_reg.to64(), | 5537 | .f32 => base_reg.to32(), |
| 5519 | else => unreachable, | 5538 | .f64 => base_reg.to64(), |
| 5520 | }, | 5539 | else => unreachable, |
| 5521 | .reg2 = reg.to128(), | 5540 | }, |
| 5522 | .flags = 0b01, | 5541 | .reg2 = reg.to128(), |
| 5523 | }), | 5542 | .flags = 0b01, |
| 5524 | .data = .{ .imm = @bitCast(u32, -stack_offset) }, | 5543 | }), |
| 5525 | }); | 5544 | .data = .{ .imm = @bitCast(u32, -stack_offset) }, |
| | 5545 | }); |
| | 5546 | return; |
| | 5547 | } |
| | 5548 | |
| | 5549 | return self.fail("TODO genSetStack for register for type float with no intrinsics", .{}); |
| 5526 | }, | 5550 | }, |
| 5527 | else => { | 5551 | else => { |
| 5528 | if (!math.isPowerOfTwo(abi_size)) { | 5552 | if (!math.isPowerOfTwo(abi_size)) { |
| ... | @@ -6026,21 +6050,25 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -6026,21 +6050,25 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6026 | }, | 6050 | }, |
| 6027 | }, | 6051 | }, |
| 6028 | .Float => { | 6052 | .Float => { |
| 6029 | const tag: Mir.Inst.Tag = switch (ty.tag()) { | 6053 | if (self.intrinsicsAllowed(ty)) { |
| 6030 | .f32 => .mov_f32, | 6054 | const tag: Mir.Inst.Tag = switch (ty.tag()) { |
| 6031 | .f64 => .mov_f64, | 6055 | .f32 => .mov_f32_avx, |
| 6032 | else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}), | 6056 | .f64 => .mov_f64_avx, |
| 6033 | }; | 6057 | else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}), |
| 6034 | _ = try self.addInst(.{ | 6058 | }; |
| 6035 | .tag = tag, | 6059 | _ = try self.addInst(.{ |
| 6036 | .ops = Mir.Inst.Ops.encode(.{ | 6060 | .tag = tag, |
| 6037 | .reg1 = reg.to128(), | 6061 | .ops = Mir.Inst.Ops.encode(.{ |
| 6038 | .reg2 = src_reg.to128(), | 6062 | .reg1 = reg.to128(), |
| 6039 | .flags = 0b10, | 6063 | .reg2 = src_reg.to128(), |
| 6040 | }), | 6064 | .flags = 0b10, |
| 6041 | .data = undefined, | 6065 | }), |
| 6042 | }); | 6066 | .data = undefined, |
| 6043 | return; | 6067 | }); |
| | 6068 | return; |
| | 6069 | } |
| | 6070 | |
| | 6071 | return self.fail("TODO genSetReg from register for float with no intrinsics", .{}); |
| 6044 | }, | 6072 | }, |
| 6045 | else => {}, | 6073 | else => {}, |
| 6046 | } | 6074 | } |
| ... | @@ -6073,24 +6101,29 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -6073,24 +6101,29 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6073 | const base_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp }); | 6101 | const base_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp }); |
| 6074 | try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); | 6102 | try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); |
| 6075 | | 6103 | |
| 6076 | const tag: Mir.Inst.Tag = switch (ty.tag()) { | 6104 | if (self.intrinsicsAllowed(ty)) { |
| 6077 | .f32 => .mov_f32, | 6105 | const tag: Mir.Inst.Tag = switch (ty.tag()) { |
| 6078 | .f64 => .mov_f64, | 6106 | .f32 => .mov_f32_avx, |
| 6079 | else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}), | 6107 | .f64 => .mov_f64_avx, |
| 6080 | }; | 6108 | else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}), |
| | 6109 | }; |
| 6081 | | 6110 | |
| 6082 | _ = try self.addInst(.{ | 6111 | _ = try self.addInst(.{ |
| 6083 | .tag = tag, | 6112 | .tag = tag, |
| 6084 | .ops = Mir.Inst.Ops.encode(.{ | 6113 | .ops = Mir.Inst.Ops.encode(.{ |
| 6085 | .reg1 = reg.to128(), | 6114 | .reg1 = reg.to128(), |
| 6086 | .reg2 = switch (ty.tag()) { | 6115 | .reg2 = switch (ty.tag()) { |
| 6087 | .f32 => base_reg.to32(), | 6116 | .f32 => base_reg.to32(), |
| 6088 | .f64 => base_reg.to64(), | 6117 | .f64 => base_reg.to64(), |
| 6089 | else => unreachable, | 6118 | else => unreachable, |
| 6090 | }, | 6119 | }, |
| 6091 | }), | 6120 | }), |
| 6092 | .data = .{ .imm = 0 }, | 6121 | .data = .{ .imm = 0 }, |
| 6093 | }); | 6122 | }); |
| | 6123 | return; |
| | 6124 | } |
| | 6125 | |
| | 6126 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); |
| 6094 | }, | 6127 | }, |
| 6095 | else => { | 6128 | else => { |
| 6096 | if (x <= math.maxInt(i32)) { | 6129 | if (x <= math.maxInt(i32)) { |
| ... | @@ -6183,24 +6216,27 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -6183,24 +6216,27 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6183 | }, | 6216 | }, |
| 6184 | }, | 6217 | }, |
| 6185 | .Float => { | 6218 | .Float => { |
| 6186 | const tag: Mir.Inst.Tag = switch (ty.tag()) { | 6219 | if (self.intrinsicsAllowed(ty)) { |
| 6187 | .f32 => .mov_f32, | 6220 | const tag: Mir.Inst.Tag = switch (ty.tag()) { |
| 6188 | .f64 => .mov_f64, | 6221 | .f32 => .mov_f32_avx, |
| 6189 | else => return self.fail("TODO genSetReg from stack offset for {}", .{ty.fmtDebug()}), | 6222 | .f64 => .mov_f64_avx, |
| 6190 | }; | 6223 | else => return self.fail("TODO genSetReg from stack offset for {}", .{ty.fmtDebug()}), |
| 6191 | _ = try self.addInst(.{ | 6224 | }; |
| 6192 | .tag = tag, | 6225 | _ = try self.addInst(.{ |
| 6193 | .ops = Mir.Inst.Ops.encode(.{ | 6226 | .tag = tag, |
| 6194 | .reg1 = reg.to128(), | 6227 | .ops = Mir.Inst.Ops.encode(.{ |
| 6195 | .reg2 = switch (ty.tag()) { | 6228 | .reg1 = reg.to128(), |
| 6196 | .f32 => .ebp, | 6229 | .reg2 = switch (ty.tag()) { |
| 6197 | .f64 => .rbp, | 6230 | .f32 => .ebp, |
| 6198 | else => unreachable, | 6231 | .f64 => .rbp, |
| 6199 | }, | 6232 | else => unreachable, |
| 6200 | }), | 6233 | }, |
| 6201 | .data = .{ .imm = @bitCast(u32, -off) }, | 6234 | }), |
| 6202 | }); | 6235 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 6203 | return; | 6236 | }); |
| | 6237 | return; |
| | 6238 | } |
| | 6239 | return self.fail("TODO genSetReg from stack offset for float with no intrinsics", .{}); |
| 6204 | }, | 6240 | }, |
| 6205 | else => {}, | 6241 | else => {}, |
| 6206 | } | 6242 | } |
| ... | @@ -6995,3 +7031,12 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | ... | @@ -6995,3 +7031,12 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 6995 | }, | 7031 | }, |
| 6996 | } | 7032 | } |
| 6997 | } | 7033 | } |
| | 7034 | |
| | 7035 | fn intrinsicsAllowed(self: *Self, ty: Type) bool { |
| | 7036 | return switch (ty.tag()) { |
| | 7037 | .f32, |
| | 7038 | .f64, |
| | 7039 | => Target.x86.featureSetHasAny(self.target.cpu.features, .{ .avx, .avx2 }), |
| | 7040 | else => unreachable, // TODO finish this off |
| | 7041 | }; |
| | 7042 | } |