| ... | ... | @@ -193,6 +193,11 @@ pub const MCValue = union(enum) { |
| 193 | 193 | /// The value is in memory at a hard-coded address. |
| 194 | 194 | /// If the type is a pointer, it means the pointer address is stored at this memory location. |
| 195 | 195 | memory: u64, |
| 196 | /// The value is in memory at an address not-yet-allocated by the linker. |
| 197 | /// This traditionally corresponds to a relocation emitted in a relocatable object file. |
| 198 | load_symbol: u32, |
| 199 | /// The address of the memory location not-yet-allocated by the linker. |
| 200 | lea_symbol: u32, |
| 196 | 201 | /// The value is in memory at a constant offset from the address in a register. |
| 197 | 202 | indirect: RegisterOffset, |
| 198 | 203 | /// The value is in memory. |
| ... | ... | @@ -207,12 +212,6 @@ pub const MCValue = union(enum) { |
| 207 | 212 | /// The value is a pointer to a value referenced indirectly via GOT. |
| 208 | 213 | /// Payload is a symbol index. |
| 209 | 214 | lea_got: u32, |
| 210 | | /// The value is an extern variable referenced via GOT. |
| 211 | | /// Payload is a symbol index. |
| 212 | | load_extern_got: u32, |
| 213 | | /// The value is a pointer to an extern variable referenced via GOT. |
| 214 | | /// Payload is a symbol index. |
| 215 | | lea_extern_got: u32, |
| 216 | 215 | /// The value is a threadlocal variable. |
| 217 | 216 | /// Payload is a symbol index. |
| 218 | 217 | load_tlv: u32, |
| ... | ... | @@ -299,9 +298,9 @@ pub const MCValue = union(enum) { |
| 299 | 298 | .register_pair, |
| 300 | 299 | .register_offset, |
| 301 | 300 | .register_overflow, |
| 301 | .lea_symbol, |
| 302 | 302 | .lea_direct, |
| 303 | 303 | .lea_got, |
| 304 | | .lea_extern_got, |
| 305 | 304 | .lea_tlv, |
| 306 | 305 | .lea_frame, |
| 307 | 306 | .reserved_frame, |
| ... | ... | @@ -315,8 +314,8 @@ pub const MCValue = union(enum) { |
| 315 | 314 | .load_direct => |sym_index| .{ .lea_direct = sym_index }, |
| 316 | 315 | .load_got => |sym_index| .{ .lea_got = sym_index }, |
| 317 | 316 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, |
| 318 | | .load_extern_got => |sym_index| .{ .lea_extern_got = sym_index }, |
| 319 | 317 | .load_frame => |frame_addr| .{ .lea_frame = frame_addr }, |
| 318 | .load_symbol => |sym_index| .{ .lea_symbol = sym_index }, |
| 320 | 319 | }; |
| 321 | 320 | } |
| 322 | 321 | |
| ... | ... | @@ -333,9 +332,9 @@ pub const MCValue = union(enum) { |
| 333 | 332 | .indirect, |
| 334 | 333 | .load_direct, |
| 335 | 334 | .load_got, |
| 336 | | .load_extern_got, |
| 337 | 335 | .load_tlv, |
| 338 | 336 | .load_frame, |
| 337 | .load_symbol, |
| 339 | 338 | .reserved_frame, |
| 340 | 339 | .air_ref, |
| 341 | 340 | => unreachable, // not dereferenceable |
| ... | ... | @@ -344,9 +343,9 @@ pub const MCValue = union(enum) { |
| 344 | 343 | .register_offset => |reg_off| .{ .indirect = reg_off }, |
| 345 | 344 | .lea_direct => |sym_index| .{ .load_direct = sym_index }, |
| 346 | 345 | .lea_got => |sym_index| .{ .load_got = sym_index }, |
| 347 | | .lea_extern_got => |sym_index| .{ .load_extern_got = sym_index }, |
| 348 | 346 | .lea_tlv => |sym_index| .{ .load_tlv = sym_index }, |
| 349 | 347 | .lea_frame => |frame_addr| .{ .load_frame = frame_addr }, |
| 348 | .lea_symbol => |sym_index| .{ .load_symbol = sym_index }, |
| 350 | 349 | }; |
| 351 | 350 | } |
| 352 | 351 | |
| ... | ... | @@ -368,11 +367,11 @@ pub const MCValue = union(enum) { |
| 368 | 367 | .lea_direct, |
| 369 | 368 | .load_got, |
| 370 | 369 | .lea_got, |
| 371 | | .load_extern_got, |
| 372 | | .lea_extern_got, |
| 373 | 370 | .load_tlv, |
| 374 | 371 | .lea_tlv, |
| 375 | 372 | .load_frame, |
| 373 | .load_symbol, |
| 374 | .lea_symbol, |
| 376 | 375 | => switch (off) { |
| 377 | 376 | 0 => mcv, |
| 378 | 377 | else => unreachable, // not offsettable |
| ... | ... | @@ -404,13 +403,13 @@ pub const MCValue = union(enum) { |
| 404 | 403 | .lea_direct, |
| 405 | 404 | .load_got, |
| 406 | 405 | .lea_got, |
| 407 | | .load_extern_got, |
| 408 | | .lea_extern_got, |
| 409 | 406 | .load_tlv, |
| 410 | 407 | .lea_tlv, |
| 411 | 408 | .lea_frame, |
| 412 | 409 | .reserved_frame, |
| 413 | 410 | .air_ref, |
| 411 | .load_symbol, |
| 412 | .lea_symbol, |
| 414 | 413 | => unreachable, |
| 415 | 414 | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| |
| 416 | 415 | Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr }) |
| ... | ... | @@ -448,14 +447,14 @@ pub const MCValue = union(enum) { |
| 448 | 447 | .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), |
| 449 | 448 | .load_got => |pl| try writer.print("[got:{d}]", .{pl}), |
| 450 | 449 | .lea_got => |pl| try writer.print("got:{d}", .{pl}), |
| 451 | | .load_extern_got => |pl| try writer.print("[extern_got:{d}]", .{pl}), |
| 452 | | .lea_extern_got => |pl| try writer.print("extern_got:{d}", .{pl}), |
| 453 | 450 | .load_tlv => |pl| try writer.print("[tlv:{d}]", .{pl}), |
| 454 | 451 | .lea_tlv => |pl| try writer.print("tlv:{d}", .{pl}), |
| 455 | 452 | .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }), |
| 456 | 453 | .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }), |
| 457 | 454 | .reserved_frame => |pl| try writer.print("(dead:{})", .{pl}), |
| 458 | 455 | .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}), |
| 456 | .load_symbol => |pl| try writer.print("[symbol:{d}]", .{pl}), |
| 457 | .lea_symbol => |pl| try writer.print("symbol:{d}", .{pl}), |
| 459 | 458 | } |
| 460 | 459 | } |
| 461 | 460 | }; |
| ... | ... | @@ -477,12 +476,12 @@ const InstTracking = struct { |
| 477 | 476 | .lea_direct, |
| 478 | 477 | .load_got, |
| 479 | 478 | .lea_got, |
| 480 | | .load_extern_got, |
| 481 | | .lea_extern_got, |
| 482 | 479 | .load_tlv, |
| 483 | 480 | .lea_tlv, |
| 484 | 481 | .load_frame, |
| 485 | 482 | .lea_frame, |
| 483 | .load_symbol, |
| 484 | .lea_symbol, |
| 486 | 485 | => result, |
| 487 | 486 | .dead, |
| 488 | 487 | .reserved_frame, |
| ... | ... | @@ -538,12 +537,12 @@ const InstTracking = struct { |
| 538 | 537 | .lea_direct, |
| 539 | 538 | .load_got, |
| 540 | 539 | .lea_got, |
| 541 | | .load_extern_got, |
| 542 | | .lea_extern_got, |
| 543 | 540 | .load_tlv, |
| 544 | 541 | .lea_tlv, |
| 545 | 542 | .load_frame, |
| 546 | 543 | .lea_frame, |
| 544 | .load_symbol, |
| 545 | .lea_symbol, |
| 547 | 546 | => self.long, |
| 548 | 547 | .dead, |
| 549 | 548 | .eflags, |
| ... | ... | @@ -575,11 +574,11 @@ const InstTracking = struct { |
| 575 | 574 | .lea_direct, |
| 576 | 575 | .load_got, |
| 577 | 576 | .lea_got, |
| 578 | | .load_extern_got, |
| 579 | | .lea_extern_got, |
| 580 | 577 | .load_tlv, |
| 581 | 578 | .lea_tlv, |
| 582 | 579 | .lea_frame, |
| 580 | .load_symbol, |
| 581 | .lea_symbol, |
| 583 | 582 | => assert(std.meta.eql(self.long, target.long)), |
| 584 | 583 | .load_frame, |
| 585 | 584 | .reserved_frame, |
| ... | ... | @@ -883,6 +882,7 @@ pub fn generate( |
| 883 | 882 | |
| 884 | 883 | var emit = Emit{ |
| 885 | 884 | .lower = .{ |
| 885 | .bin_file = bin_file, |
| 886 | 886 | .allocator = bin_file.allocator, |
| 887 | 887 | .mir = mir, |
| 888 | 888 | .cc = cc, |
| ... | ... | @@ -970,6 +970,7 @@ pub fn generateLazy( |
| 970 | 970 | |
| 971 | 971 | var emit = Emit{ |
| 972 | 972 | .lower = .{ |
| 973 | .bin_file = bin_file, |
| 973 | 974 | .allocator = bin_file.allocator, |
| 974 | 975 | .mir = mir, |
| 975 | 976 | .cc = abi.resolveCallingConvention(.Unspecified, function.target.*), |
| ... | ... | @@ -1060,6 +1061,7 @@ fn formatWipMir( |
| 1060 | 1061 | writer: anytype, |
| 1061 | 1062 | ) @TypeOf(writer).Error!void { |
| 1062 | 1063 | var lower = Lower{ |
| 1064 | .bin_file = data.self.bin_file, |
| 1063 | 1065 | .allocator = data.self.gpa, |
| 1064 | 1066 | .mir = .{ |
| 1065 | 1067 | .instructions = data.self.mir_instructions.slice(), |
| ... | ... | @@ -3261,25 +3263,51 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3261 | 3263 | defer self.register_manager.unlockReg(tmp_lock); |
| 3262 | 3264 | |
| 3263 | 3265 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 3264 | | if (lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 3266 | const mat_lhs_mcv = switch (lhs_mcv) { |
| 3267 | .load_symbol => mat_lhs_mcv: { |
| 3268 | // TODO clean this up! |
| 3269 | const addr_reg = try self.copyToTmpRegister(Type.usize, lhs_mcv.address()); |
| 3270 | break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 3271 | }, |
| 3272 | else => lhs_mcv, |
| 3273 | }; |
| 3274 | const mat_lhs_lock = switch (mat_lhs_mcv) { |
| 3275 | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 3276 | else => null, |
| 3277 | }; |
| 3278 | defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3279 | if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 3265 | 3280 | .{ ._, .mov }, |
| 3266 | 3281 | tmp_reg, |
| 3267 | | lhs_mcv.address().offset(8).deref().mem(.qword), |
| 3282 | mat_lhs_mcv.address().offset(8).deref().mem(.qword), |
| 3268 | 3283 | ) else try self.asmRegisterRegister( |
| 3269 | 3284 | .{ ._, .mov }, |
| 3270 | 3285 | tmp_reg, |
| 3271 | | lhs_mcv.register_pair[1], |
| 3286 | mat_lhs_mcv.register_pair[1], |
| 3272 | 3287 | ); |
| 3273 | 3288 | |
| 3274 | 3289 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 3275 | | if (rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 3290 | const mat_rhs_mcv = switch (rhs_mcv) { |
| 3291 | .load_symbol => mat_rhs_mcv: { |
| 3292 | // TODO clean this up! |
| 3293 | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 3294 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 3295 | }, |
| 3296 | else => rhs_mcv, |
| 3297 | }; |
| 3298 | const mat_rhs_lock = switch (mat_rhs_mcv) { |
| 3299 | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 3300 | else => null, |
| 3301 | }; |
| 3302 | defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3303 | if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 3276 | 3304 | .{ ._, .xor }, |
| 3277 | 3305 | tmp_reg, |
| 3278 | | rhs_mcv.address().offset(8).deref().mem(.qword), |
| 3306 | mat_rhs_mcv.address().offset(8).deref().mem(.qword), |
| 3279 | 3307 | ) else try self.asmRegisterRegister( |
| 3280 | 3308 | .{ ._, .xor }, |
| 3281 | 3309 | tmp_reg, |
| 3282 | | rhs_mcv.register_pair[1], |
| 3310 | mat_rhs_mcv.register_pair[1], |
| 3283 | 3311 | ); |
| 3284 | 3312 | const reloc = try self.asmJccReloc(.ns, undefined); |
| 3285 | 3313 | |
| ... | ... | @@ -3353,20 +3381,37 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3353 | 3381 | defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); |
| 3354 | 3382 | |
| 3355 | 3383 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 3384 | const mat_rhs_mcv = switch (rhs_mcv) { |
| 3385 | .load_symbol => mat_rhs_mcv: { |
| 3386 | // TODO clean this up! |
| 3387 | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 3388 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 3389 | }, |
| 3390 | else => rhs_mcv, |
| 3391 | }; |
| 3392 | const mat_rhs_lock = switch (mat_rhs_mcv) { |
| 3393 | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 3394 | else => null, |
| 3395 | }; |
| 3396 | defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3356 | 3397 | |
| 3357 | 3398 | for (tmp_regs, dst_regs) |tmp_reg, dst_reg| |
| 3358 | 3399 | try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_reg); |
| 3359 | | if (rhs_mcv.isMemory()) { |
| 3360 | | try self.asmRegisterMemory(.{ ._, .add }, tmp_regs[0], rhs_mcv.mem(.qword)); |
| 3400 | if (mat_rhs_mcv.isMemory()) { |
| 3401 | try self.asmRegisterMemory( |
| 3402 | .{ ._, .add }, |
| 3403 | tmp_regs[0], |
| 3404 | mat_rhs_mcv.mem(.qword), |
| 3405 | ); |
| 3361 | 3406 | try self.asmRegisterMemory( |
| 3362 | 3407 | .{ ._, .adc }, |
| 3363 | 3408 | tmp_regs[1], |
| 3364 | | rhs_mcv.address().offset(8).deref().mem(.qword), |
| 3409 | mat_rhs_mcv.address().offset(8).deref().mem(.qword), |
| 3365 | 3410 | ); |
| 3366 | 3411 | } else for ( |
| 3367 | 3412 | [_]Mir.Inst.Tag{ .add, .adc }, |
| 3368 | 3413 | tmp_regs, |
| 3369 | | rhs_mcv.register_pair, |
| 3414 | mat_rhs_mcv.register_pair, |
| 3370 | 3415 | ) |op, tmp_reg, rhs_reg| |
| 3371 | 3416 | try self.asmRegisterRegister(.{ ._, op }, tmp_reg, rhs_reg); |
| 3372 | 3417 | try self.asmRegisterRegister(.{ ._, .@"test" }, dst_regs[1], dst_regs[1]); |
| ... | ... | @@ -3871,39 +3916,65 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3871 | 3916 | |
| 3872 | 3917 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 3873 | 3918 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 3919 | const mat_lhs_mcv = switch (lhs_mcv) { |
| 3920 | .load_symbol => mat_lhs_mcv: { |
| 3921 | // TODO clean this up! |
| 3922 | const addr_reg = try self.copyToTmpRegister(Type.usize, lhs_mcv.address()); |
| 3923 | break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 3924 | }, |
| 3925 | else => lhs_mcv, |
| 3926 | }; |
| 3927 | const mat_lhs_lock = switch (mat_lhs_mcv) { |
| 3928 | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 3929 | else => null, |
| 3930 | }; |
| 3931 | defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3932 | const mat_rhs_mcv = switch (rhs_mcv) { |
| 3933 | .load_symbol => mat_rhs_mcv: { |
| 3934 | // TODO clean this up! |
| 3935 | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 3936 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 3937 | }, |
| 3938 | else => rhs_mcv, |
| 3939 | }; |
| 3940 | const mat_rhs_lock = switch (mat_rhs_mcv) { |
| 3941 | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 3942 | else => null, |
| 3943 | }; |
| 3944 | defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3874 | 3945 | |
| 3875 | | if (lhs_mcv.isMemory()) |
| 3876 | | try self.asmRegisterMemory(.{ ._, .mov }, .rax, lhs_mcv.mem(.qword)) |
| 3946 | if (mat_lhs_mcv.isMemory()) |
| 3947 | try self.asmRegisterMemory(.{ ._, .mov }, .rax, mat_lhs_mcv.mem(.qword)) |
| 3877 | 3948 | else |
| 3878 | | try self.asmRegisterRegister(.{ ._, .mov }, .rax, lhs_mcv.register_pair[0]); |
| 3879 | | if (rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 3949 | try self.asmRegisterRegister(.{ ._, .mov }, .rax, mat_lhs_mcv.register_pair[0]); |
| 3950 | if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 3880 | 3951 | .{ ._, .mov }, |
| 3881 | 3952 | tmp_regs[0], |
| 3882 | | rhs_mcv.address().offset(8).deref().mem(.qword), |
| 3953 | mat_rhs_mcv.address().offset(8).deref().mem(.qword), |
| 3883 | 3954 | ) else try self.asmRegisterRegister( |
| 3884 | 3955 | .{ ._, .mov }, |
| 3885 | 3956 | tmp_regs[0], |
| 3886 | | rhs_mcv.register_pair[1], |
| 3957 | mat_rhs_mcv.register_pair[1], |
| 3887 | 3958 | ); |
| 3888 | 3959 | try self.asmRegisterRegister(.{ ._, .@"test" }, tmp_regs[0], tmp_regs[0]); |
| 3889 | 3960 | try self.asmSetccRegister(.nz, tmp_regs[1].to8()); |
| 3890 | 3961 | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_regs[0], .rax); |
| 3891 | 3962 | try self.asmSetccRegister(.o, tmp_regs[2].to8()); |
| 3892 | | if (rhs_mcv.isMemory()) |
| 3893 | | try self.asmMemory(.{ ._, .mul }, rhs_mcv.mem(.qword)) |
| 3963 | if (mat_rhs_mcv.isMemory()) |
| 3964 | try self.asmMemory(.{ ._, .mul }, mat_rhs_mcv.mem(.qword)) |
| 3894 | 3965 | else |
| 3895 | | try self.asmRegister(.{ ._, .mul }, rhs_mcv.register_pair[0]); |
| 3966 | try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]); |
| 3896 | 3967 | try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_regs[0]); |
| 3897 | 3968 | try self.asmSetccRegister(.c, tmp_regs[3].to8()); |
| 3898 | 3969 | try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[2].to8(), tmp_regs[3].to8()); |
| 3899 | | if (lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 3970 | if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 3900 | 3971 | .{ ._, .mov }, |
| 3901 | 3972 | tmp_regs[0], |
| 3902 | | lhs_mcv.address().offset(8).deref().mem(.qword), |
| 3973 | mat_lhs_mcv.address().offset(8).deref().mem(.qword), |
| 3903 | 3974 | ) else try self.asmRegisterRegister( |
| 3904 | 3975 | .{ ._, .mov }, |
| 3905 | 3976 | tmp_regs[0], |
| 3906 | | lhs_mcv.register_pair[1], |
| 3977 | mat_lhs_mcv.register_pair[1], |
| 3907 | 3978 | ); |
| 3908 | 3979 | try self.asmRegisterRegister(.{ ._, .@"test" }, tmp_regs[0], tmp_regs[0]); |
| 3909 | 3980 | try self.asmSetccRegister(.nz, tmp_regs[3].to8()); |
| ... | ... | @@ -3913,13 +3984,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3913 | 3984 | tmp_regs[3].to8(), |
| 3914 | 3985 | ); |
| 3915 | 3986 | try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[1].to8(), tmp_regs[2].to8()); |
| 3916 | | if (rhs_mcv.isMemory()) |
| 3917 | | try self.asmRegisterMemory(.{ .i_, .mul }, tmp_regs[0], rhs_mcv.mem(.qword)) |
| 3987 | if (mat_rhs_mcv.isMemory()) |
| 3988 | try self.asmRegisterMemory(.{ .i_, .mul }, tmp_regs[0], mat_rhs_mcv.mem(.qword)) |
| 3918 | 3989 | else |
| 3919 | 3990 | try self.asmRegisterRegister( |
| 3920 | 3991 | .{ .i_, .mul }, |
| 3921 | 3992 | tmp_regs[0], |
| 3922 | | rhs_mcv.register_pair[0], |
| 3993 | mat_rhs_mcv.register_pair[0], |
| 3923 | 3994 | ); |
| 3924 | 3995 | try self.asmSetccRegister(.o, tmp_regs[2].to8()); |
| 3925 | 3996 | try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[1].to8(), tmp_regs[2].to8()); |
| ... | ... | @@ -4729,12 +4800,12 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4729 | 4800 | Memory.sib(.qword, .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off }), |
| 4730 | 4801 | ), |
| 4731 | 4802 | .memory, |
| 4803 | .load_symbol, |
| 4732 | 4804 | .load_direct, |
| 4733 | 4805 | .load_got, |
| 4734 | | .load_extern_got, |
| 4735 | 4806 | .load_tlv, |
| 4736 | 4807 | => try self.genSetReg(addr_reg, Type.usize, array.address()), |
| 4737 | | .lea_direct, .lea_tlv => unreachable, |
| 4808 | .lea_symbol, .lea_direct, .lea_tlv => unreachable, |
| 4738 | 4809 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| 4739 | 4810 | } |
| 4740 | 4811 | |
| ... | ... | @@ -6327,17 +6398,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 6327 | 6398 | .immediate, |
| 6328 | 6399 | .register, |
| 6329 | 6400 | .register_offset, |
| 6401 | .lea_symbol, |
| 6330 | 6402 | .lea_direct, |
| 6331 | 6403 | .lea_got, |
| 6332 | | .lea_extern_got, |
| 6333 | 6404 | .lea_tlv, |
| 6334 | 6405 | .lea_frame, |
| 6335 | 6406 | => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()), |
| 6336 | 6407 | .memory, |
| 6337 | 6408 | .indirect, |
| 6409 | .load_symbol, |
| 6338 | 6410 | .load_direct, |
| 6339 | 6411 | .load_got, |
| 6340 | | .load_extern_got, |
| 6341 | 6412 | .load_tlv, |
| 6342 | 6413 | .load_frame, |
| 6343 | 6414 | => { |
| ... | ... | @@ -6476,17 +6547,17 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 6476 | 6547 | .immediate, |
| 6477 | 6548 | .register, |
| 6478 | 6549 | .register_offset, |
| 6550 | .lea_symbol, |
| 6479 | 6551 | .lea_direct, |
| 6480 | 6552 | .lea_got, |
| 6481 | | .lea_extern_got, |
| 6482 | 6553 | .lea_tlv, |
| 6483 | 6554 | .lea_frame, |
| 6484 | 6555 | => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv), |
| 6485 | 6556 | .memory, |
| 6486 | 6557 | .indirect, |
| 6558 | .load_symbol, |
| 6487 | 6559 | .load_direct, |
| 6488 | 6560 | .load_got, |
| 6489 | | .load_extern_got, |
| 6490 | 6561 | .load_tlv, |
| 6491 | 6562 | .load_frame, |
| 6492 | 6563 | => { |
| ... | ... | @@ -6587,12 +6658,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 6587 | 6658 | const src_reg_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 6588 | 6659 | defer self.register_manager.unlockReg(src_reg_lock); |
| 6589 | 6660 | |
| 6590 | | const dst_reg = if (field_rc.supersetOf(container_rc) and |
| 6591 | | self.reuseOperand(inst, operand, 0, src_mcv)) |
| 6661 | const src_in_field_rc = |
| 6662 | field_rc.isSet(RegisterManager.indexOfRegIntoTracked(src_reg).?); |
| 6663 | const dst_reg = if (src_in_field_rc and self.reuseOperand(inst, operand, 0, src_mcv)) |
| 6592 | 6664 | src_reg |
| 6665 | else if (field_off == 0) |
| 6666 | (try self.copyToRegisterWithInstTracking(inst, field_ty, src_mcv)).register |
| 6593 | 6667 | else |
| 6594 | 6668 | try self.copyToTmpRegister(Type.usize, .{ .register = src_reg }); |
| 6595 | | const dst_mcv = MCValue{ .register = dst_reg }; |
| 6669 | const dst_mcv: MCValue = .{ .register = dst_reg }; |
| 6596 | 6670 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 6597 | 6671 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 6598 | 6672 | |
| ... | ... | @@ -6602,9 +6676,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 6602 | 6676 | dst_mcv, |
| 6603 | 6677 | .{ .immediate = field_off }, |
| 6604 | 6678 | ); |
| 6605 | | if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg); |
| 6679 | if (abi.RegisterClass.gp.isSet(RegisterManager.indexOfRegIntoTracked(dst_reg).?) and |
| 6680 | container_ty.abiSize(mod) * 8 > field_ty.bitSize(mod)) |
| 6681 | try self.truncateRegister(field_ty, dst_reg); |
| 6606 | 6682 | |
| 6607 | | break :result if (field_rc.supersetOf(abi.RegisterClass.gp)) |
| 6683 | break :result if (field_off == 0 or field_rc.supersetOf(abi.RegisterClass.gp)) |
| 6608 | 6684 | dst_mcv |
| 6609 | 6685 | else |
| 6610 | 6686 | try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv); |
| ... | ... | @@ -6908,15 +6984,15 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC |
| 6908 | 6984 | .register_overflow, |
| 6909 | 6985 | .lea_direct, |
| 6910 | 6986 | .lea_got, |
| 6911 | | .lea_extern_got, |
| 6912 | 6987 | .lea_tlv, |
| 6913 | 6988 | .lea_frame, |
| 6914 | 6989 | .reserved_frame, |
| 6915 | 6990 | .air_ref, |
| 6991 | .lea_symbol, |
| 6916 | 6992 | => unreachable, // unmodifiable destination |
| 6917 | 6993 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), |
| 6918 | 6994 | .register_pair => unreachable, // unimplemented |
| 6919 | | .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => { |
| 6995 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => { |
| 6920 | 6996 | const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 6921 | 6997 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 6922 | 6998 | defer self.register_manager.unlockReg(addr_reg_lock); |
| ... | ... | @@ -7352,34 +7428,61 @@ fn genMulDivBinOp( |
| 7352 | 7428 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 7353 | 7429 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 7354 | 7430 | |
| 7431 | const mat_lhs_mcv = switch (lhs_mcv) { |
| 7432 | .load_symbol => mat_lhs_mcv: { |
| 7433 | // TODO clean this up! |
| 7434 | const addr_reg = try self.copyToTmpRegister(Type.usize, lhs_mcv.address()); |
| 7435 | break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 7436 | }, |
| 7437 | else => lhs_mcv, |
| 7438 | }; |
| 7439 | const mat_lhs_lock = switch (mat_lhs_mcv) { |
| 7440 | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 7441 | else => null, |
| 7442 | }; |
| 7443 | defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 7444 | const mat_rhs_mcv = switch (rhs_mcv) { |
| 7445 | .load_symbol => mat_rhs_mcv: { |
| 7446 | // TODO clean this up! |
| 7447 | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 7448 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 7449 | }, |
| 7450 | else => rhs_mcv, |
| 7451 | }; |
| 7452 | const mat_rhs_lock = switch (mat_rhs_mcv) { |
| 7453 | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 7454 | else => null, |
| 7455 | }; |
| 7456 | defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 7457 | |
| 7355 | 7458 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 7356 | 7459 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 7357 | 7460 | defer self.register_manager.unlockReg(tmp_lock); |
| 7358 | 7461 | |
| 7359 | | if (lhs_mcv.isMemory()) |
| 7360 | | try self.asmRegisterMemory(.{ ._, .mov }, .rax, lhs_mcv.mem(.qword)) |
| 7462 | if (mat_lhs_mcv.isMemory()) |
| 7463 | try self.asmRegisterMemory(.{ ._, .mov }, .rax, mat_lhs_mcv.mem(.qword)) |
| 7361 | 7464 | else |
| 7362 | | try self.asmRegisterRegister(.{ ._, .mov }, .rax, lhs_mcv.register_pair[0]); |
| 7363 | | if (rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 7465 | try self.asmRegisterRegister(.{ ._, .mov }, .rax, mat_lhs_mcv.register_pair[0]); |
| 7466 | if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 7364 | 7467 | .{ ._, .mov }, |
| 7365 | 7468 | tmp_reg, |
| 7366 | | rhs_mcv.address().offset(8).deref().mem(.qword), |
| 7367 | | ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, rhs_mcv.register_pair[1]); |
| 7469 | mat_rhs_mcv.address().offset(8).deref().mem(.qword), |
| 7470 | ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_rhs_mcv.register_pair[1]); |
| 7368 | 7471 | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, .rax); |
| 7369 | | if (rhs_mcv.isMemory()) |
| 7370 | | try self.asmMemory(.{ ._, .mul }, rhs_mcv.mem(.qword)) |
| 7472 | if (mat_rhs_mcv.isMemory()) |
| 7473 | try self.asmMemory(.{ ._, .mul }, mat_rhs_mcv.mem(.qword)) |
| 7371 | 7474 | else |
| 7372 | | try self.asmRegister(.{ ._, .mul }, rhs_mcv.register_pair[0]); |
| 7475 | try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]); |
| 7373 | 7476 | try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg); |
| 7374 | | if (lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 7477 | if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 7375 | 7478 | .{ ._, .mov }, |
| 7376 | 7479 | tmp_reg, |
| 7377 | | lhs_mcv.address().offset(8).deref().mem(.qword), |
| 7378 | | ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, lhs_mcv.register_pair[1]); |
| 7379 | | if (rhs_mcv.isMemory()) |
| 7380 | | try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, rhs_mcv.mem(.qword)) |
| 7480 | mat_lhs_mcv.address().offset(8).deref().mem(.qword), |
| 7481 | ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_lhs_mcv.register_pair[1]); |
| 7482 | if (mat_rhs_mcv.isMemory()) |
| 7483 | try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, mat_rhs_mcv.mem(.qword)) |
| 7381 | 7484 | else |
| 7382 | | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, rhs_mcv.register_pair[0]); |
| 7485 | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, mat_rhs_mcv.register_pair[0]); |
| 7383 | 7486 | try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg); |
| 7384 | 7487 | return .{ .register_pair = .{ .rax, .rdx } }; |
| 7385 | 7488 | } |
| ... | ... | @@ -7968,12 +8071,12 @@ fn genBinOp( |
| 7968 | 8071 | .immediate, |
| 7969 | 8072 | .eflags, |
| 7970 | 8073 | .register_offset, |
| 8074 | .load_symbol, |
| 8075 | .lea_symbol, |
| 7971 | 8076 | .load_direct, |
| 7972 | 8077 | .lea_direct, |
| 7973 | 8078 | .load_got, |
| 7974 | 8079 | .lea_got, |
| 7975 | | .load_extern_got, |
| 7976 | | .lea_extern_got, |
| 7977 | 8080 | .load_tlv, |
| 7978 | 8081 | .lea_tlv, |
| 7979 | 8082 | .lea_frame, |
| ... | ... | @@ -8026,12 +8129,12 @@ fn genBinOp( |
| 8026 | 8129 | .register_pair, |
| 8027 | 8130 | .register_offset, |
| 8028 | 8131 | .register_overflow, |
| 8132 | .load_symbol, |
| 8133 | .lea_symbol, |
| 8029 | 8134 | .load_direct, |
| 8030 | 8135 | .lea_direct, |
| 8031 | 8136 | .load_got, |
| 8032 | 8137 | .lea_got, |
| 8033 | | .load_extern_got, |
| 8034 | | .lea_extern_got, |
| 8035 | 8138 | .load_tlv, |
| 8036 | 8139 | .lea_tlv, |
| 8037 | 8140 | .lea_frame, |
| ... | ... | @@ -9159,9 +9262,9 @@ fn genBinOpMir( |
| 9159 | 9262 | .register_overflow, |
| 9160 | 9263 | .lea_direct, |
| 9161 | 9264 | .lea_got, |
| 9162 | | .lea_extern_got, |
| 9163 | 9265 | .lea_tlv, |
| 9164 | 9266 | .lea_frame, |
| 9267 | .lea_symbol, |
| 9165 | 9268 | .reserved_frame, |
| 9166 | 9269 | .air_ref, |
| 9167 | 9270 | => unreachable, // unmodifiable destination |
| ... | ... | @@ -9244,12 +9347,12 @@ fn genBinOpMir( |
| 9244 | 9347 | .register_offset, |
| 9245 | 9348 | .memory, |
| 9246 | 9349 | .indirect, |
| 9350 | .load_symbol, |
| 9351 | .lea_symbol, |
| 9247 | 9352 | .load_direct, |
| 9248 | 9353 | .lea_direct, |
| 9249 | 9354 | .load_got, |
| 9250 | 9355 | .lea_got, |
| 9251 | | .load_extern_got, |
| 9252 | | .lea_extern_got, |
| 9253 | 9356 | .load_tlv, |
| 9254 | 9357 | .lea_tlv, |
| 9255 | 9358 | .load_frame, |
| ... | ... | @@ -9280,9 +9383,9 @@ fn genBinOpMir( |
| 9280 | 9383 | switch (src_mcv) { |
| 9281 | 9384 | .eflags, |
| 9282 | 9385 | .register_offset, |
| 9386 | .lea_symbol, |
| 9283 | 9387 | .lea_direct, |
| 9284 | 9388 | .lea_got, |
| 9285 | | .lea_extern_got, |
| 9286 | 9389 | .lea_tlv, |
| 9287 | 9390 | .lea_frame, |
| 9288 | 9391 | => { |
| ... | ... | @@ -9296,9 +9399,9 @@ fn genBinOpMir( |
| 9296 | 9399 | ); |
| 9297 | 9400 | }, |
| 9298 | 9401 | .memory, |
| 9402 | .load_symbol, |
| 9299 | 9403 | .load_direct, |
| 9300 | 9404 | .load_got, |
| 9301 | | .load_extern_got, |
| 9302 | 9405 | .load_tlv, |
| 9303 | 9406 | => { |
| 9304 | 9407 | const ptr_ty = try mod.singleConstPtrType(ty); |
| ... | ... | @@ -9319,13 +9422,13 @@ fn genBinOpMir( |
| 9319 | 9422 | } |
| 9320 | 9423 | } |
| 9321 | 9424 | }, |
| 9322 | | .memory, .indirect, .load_got, .load_extern_got, .load_direct, .load_tlv, .load_frame => { |
| 9425 | .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_tlv, .load_frame => { |
| 9323 | 9426 | const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock }; |
| 9324 | 9427 | const limb_abi_size: u32 = @min(abi_size, 8); |
| 9325 | 9428 | |
| 9326 | 9429 | const dst_info: OpInfo = switch (dst_mcv) { |
| 9327 | 9430 | else => unreachable, |
| 9328 | | .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => dst: { |
| 9431 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: { |
| 9329 | 9432 | const dst_addr_reg = |
| 9330 | 9433 | (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); |
| 9331 | 9434 | const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); |
| ... | ... | @@ -9359,17 +9462,17 @@ fn genBinOpMir( |
| 9359 | 9462 | .indirect, |
| 9360 | 9463 | .lea_direct, |
| 9361 | 9464 | .lea_got, |
| 9362 | | .lea_extern_got, |
| 9363 | 9465 | .lea_tlv, |
| 9364 | 9466 | .load_frame, |
| 9365 | 9467 | .lea_frame, |
| 9468 | .lea_symbol, |
| 9366 | 9469 | => null, |
| 9367 | | .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => src: { |
| 9470 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: { |
| 9368 | 9471 | switch (resolved_src_mcv) { |
| 9369 | 9472 | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr))) != null and |
| 9370 | 9473 | math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null) |
| 9371 | 9474 | break :src null, |
| 9372 | | .load_got, .load_extern_got, .load_direct, .load_tlv => {}, |
| 9475 | .load_symbol, .load_got, .load_direct, .load_tlv => {}, |
| 9373 | 9476 | else => unreachable, |
| 9374 | 9477 | } |
| 9375 | 9478 | |
| ... | ... | @@ -9411,8 +9514,8 @@ fn genBinOpMir( |
| 9411 | 9514 | Memory.PtrSize.fromSize(limb_abi_size), |
| 9412 | 9515 | switch (dst_mcv) { |
| 9413 | 9516 | .memory, |
| 9517 | .load_symbol, |
| 9414 | 9518 | .load_got, |
| 9415 | | .load_extern_got, |
| 9416 | 9519 | .load_direct, |
| 9417 | 9520 | .load_tlv, |
| 9418 | 9521 | => .{ .base = .{ .reg = dst_info.?.addr_reg }, .disp = off }, |
| ... | ... | @@ -9493,12 +9596,12 @@ fn genBinOpMir( |
| 9493 | 9596 | .eflags, |
| 9494 | 9597 | .memory, |
| 9495 | 9598 | .indirect, |
| 9599 | .load_symbol, |
| 9600 | .lea_symbol, |
| 9496 | 9601 | .load_direct, |
| 9497 | 9602 | .lea_direct, |
| 9498 | 9603 | .load_got, |
| 9499 | 9604 | .lea_got, |
| 9500 | | .load_extern_got, |
| 9501 | | .lea_extern_got, |
| 9502 | 9605 | .load_tlv, |
| 9503 | 9606 | .lea_tlv, |
| 9504 | 9607 | .load_frame, |
| ... | ... | @@ -9512,9 +9615,9 @@ fn genBinOpMir( |
| 9512 | 9615 | }, |
| 9513 | 9616 | .eflags, |
| 9514 | 9617 | .register_offset, |
| 9618 | .lea_symbol, |
| 9515 | 9619 | .lea_direct, |
| 9516 | 9620 | .lea_got, |
| 9517 | | .lea_extern_got, |
| 9518 | 9621 | .lea_tlv, |
| 9519 | 9622 | .lea_frame, |
| 9520 | 9623 | => switch (limb_i) { |
| ... | ... | @@ -9563,9 +9666,9 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 9563 | 9666 | .eflags, |
| 9564 | 9667 | .register_offset, |
| 9565 | 9668 | .register_overflow, |
| 9669 | .lea_symbol, |
| 9566 | 9670 | .lea_direct, |
| 9567 | 9671 | .lea_got, |
| 9568 | | .lea_extern_got, |
| 9569 | 9672 | .lea_tlv, |
| 9570 | 9673 | .lea_frame, |
| 9571 | 9674 | .reserved_frame, |
| ... | ... | @@ -9610,12 +9713,12 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 9610 | 9713 | }, |
| 9611 | 9714 | .register_offset, |
| 9612 | 9715 | .eflags, |
| 9716 | .load_symbol, |
| 9717 | .lea_symbol, |
| 9613 | 9718 | .load_direct, |
| 9614 | 9719 | .lea_direct, |
| 9615 | 9720 | .load_got, |
| 9616 | 9721 | .lea_got, |
| 9617 | | .load_extern_got, |
| 9618 | | .lea_extern_got, |
| 9619 | 9722 | .load_tlv, |
| 9620 | 9723 | .lea_tlv, |
| 9621 | 9724 | .lea_frame, |
| ... | ... | @@ -9654,7 +9757,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 9654 | 9757 | } |
| 9655 | 9758 | }, |
| 9656 | 9759 | .register_pair => unreachable, // unimplemented |
| 9657 | | .memory, .indirect, .load_direct, .load_got, .load_extern_got, .load_tlv, .load_frame => { |
| 9760 | .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_tlv, .load_frame => { |
| 9658 | 9761 | const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); |
| 9659 | 9762 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| 9660 | 9763 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| ... | ... | @@ -9674,17 +9777,25 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 9674 | 9777 | self.arg_index = arg_index + 1; |
| 9675 | 9778 | |
| 9676 | 9779 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 9677 | | const dst_mcv = self.args[arg_index]; |
| 9678 | | switch (dst_mcv) { |
| 9679 | | .register, .register_pair, .load_frame => for (dst_mcv.getRegs()) |reg| |
| 9680 | | self.register_manager.getRegAssumeFree(reg, inst), |
| 9681 | | else => return self.fail("TODO implement arg for {}", .{dst_mcv}), |
| 9682 | | } |
| 9780 | const arg_ty = self.typeOfIndex(inst); |
| 9781 | const src_mcv = self.args[arg_index]; |
| 9782 | const dst_mcv = switch (src_mcv) { |
| 9783 | .register, .register_pair, .load_frame => dst: { |
| 9784 | for (src_mcv.getRegs()) |reg| self.register_manager.getRegAssumeFree(reg, inst); |
| 9785 | break :dst src_mcv; |
| 9786 | }, |
| 9787 | .indirect => |reg_off| dst: { |
| 9788 | self.register_manager.getRegAssumeFree(reg_off.reg, inst); |
| 9789 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 9790 | try self.genCopy(arg_ty, dst_mcv, src_mcv); |
| 9791 | break :dst dst_mcv; |
| 9792 | }, |
| 9793 | else => return self.fail("TODO implement arg for {}", .{src_mcv}), |
| 9794 | }; |
| 9683 | 9795 | |
| 9684 | | const ty = self.typeOfIndex(inst); |
| 9685 | 9796 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 9686 | 9797 | const name = mod.getParamName(self.owner.func_index, src_index); |
| 9687 | | try self.genArgDbgInfo(ty, name, dst_mcv); |
| 9798 | try self.genArgDbgInfo(arg_ty, name, src_mcv); |
| 9688 | 9799 | |
| 9689 | 9800 | break :result dst_mcv; |
| 9690 | 9801 | }; |
| ... | ... | @@ -9746,8 +9857,8 @@ fn genVarDbgInfo( |
| 9746 | 9857 | // .offset = -off, |
| 9747 | 9858 | //} }, |
| 9748 | 9859 | .memory => |address| .{ .memory = address }, |
| 9860 | .load_symbol => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } }, // TODO |
| 9749 | 9861 | .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } }, |
| 9750 | | .load_extern_got => |sym_index| .{ .linker_load = .{ .type = .extern_got, .sym_index = sym_index } }, |
| 9751 | 9862 | .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } }, |
| 9752 | 9863 | .immediate => |x| .{ .immediate = x }, |
| 9753 | 9864 | .undef => .undef, |
| ... | ... | @@ -9863,7 +9974,8 @@ fn genCall(self: *Self, info: union(enum) { |
| 9863 | 9974 | |
| 9864 | 9975 | const ExpectedContents = extern struct { |
| 9865 | 9976 | var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)), |
| 9866 | | arg_regs: [16][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)), |
| 9977 | frame_indices: [16]FrameIndex, |
| 9978 | reg_locks: [16][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)), |
| 9867 | 9979 | }; |
| 9868 | 9980 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = |
| 9869 | 9981 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| ... | ... | @@ -9873,10 +9985,13 @@ fn genCall(self: *Self, info: union(enum) { |
| 9873 | 9985 | defer allocator.free(var_args); |
| 9874 | 9986 | for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty; |
| 9875 | 9987 | |
| 9876 | | var arg_locks = std.ArrayList(?RegisterLock).init(allocator); |
| 9877 | | defer arg_locks.deinit(); |
| 9878 | | try arg_locks.ensureTotalCapacity(16); |
| 9879 | | defer for (arg_locks.items) |arg_lock| if (arg_lock) |lock| self.register_manager.unlockReg(lock); |
| 9988 | const frame_indices = try allocator.alloc(FrameIndex, args.len); |
| 9989 | defer allocator.free(frame_indices); |
| 9990 | |
| 9991 | var reg_locks = std.ArrayList(?RegisterLock).init(allocator); |
| 9992 | defer reg_locks.deinit(); |
| 9993 | try reg_locks.ensureTotalCapacity(16); |
| 9994 | defer for (reg_locks.items) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 9880 | 9995 | |
| 9881 | 9996 | var call_info = try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); |
| 9882 | 9997 | defer call_info.deinit(self); |
| ... | ... | @@ -9908,44 +10023,69 @@ fn genCall(self: *Self, info: union(enum) { |
| 9908 | 10023 | .indirect => |reg_off| try self.spillRegisters(&.{reg_off.reg}), |
| 9909 | 10024 | else => unreachable, |
| 9910 | 10025 | } |
| 9911 | | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { |
| 9912 | | .none => {}, |
| 9913 | | .register => |reg| { |
| 9914 | | try self.spillRegisters(&.{reg}); |
| 9915 | | try arg_locks.append(self.register_manager.lockReg(reg)); |
| 9916 | | }, |
| 9917 | | .register_pair => |regs| { |
| 9918 | | try self.spillRegisters(&regs); |
| 9919 | | try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs)); |
| 9920 | | }, |
| 9921 | | .load_frame => { |
| 9922 | | try self.genCopy(arg_ty, dst_arg, src_arg); |
| 9923 | | try self.freeValue(src_arg); |
| 9924 | | }, |
| 9925 | | else => unreachable, |
| 9926 | | }; |
| 10026 | for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, *frame_index| |
| 10027 | switch (dst_arg) { |
| 10028 | .none => {}, |
| 10029 | .register => |reg| { |
| 10030 | try self.spillRegisters(&.{reg}); |
| 10031 | try reg_locks.append(self.register_manager.lockReg(reg)); |
| 10032 | }, |
| 10033 | .register_pair => |regs| { |
| 10034 | try self.spillRegisters(&regs); |
| 10035 | try reg_locks.appendSlice(&self.register_manager.lockRegs(2, regs)); |
| 10036 | }, |
| 10037 | .indirect => |reg_off| { |
| 10038 | frame_index.* = try self.allocFrameIndex(FrameAlloc.initType(arg_ty, mod)); |
| 10039 | try self.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg); |
| 10040 | try self.spillRegisters(&.{reg_off.reg}); |
| 10041 | try reg_locks.append(self.register_manager.lockReg(reg_off.reg)); |
| 10042 | }, |
| 10043 | .load_frame => { |
| 10044 | try self.genCopy(arg_ty, dst_arg, src_arg); |
| 10045 | try self.freeValue(src_arg); |
| 10046 | }, |
| 10047 | else => unreachable, |
| 10048 | }; |
| 9927 | 10049 | |
| 9928 | 10050 | // now we are free to set register arguments |
| 9929 | | const ret_lock = switch (call_info.return_value.long) { |
| 9930 | | .none, .unreach => null, |
| 9931 | | .indirect => |reg_off| lock: { |
| 10051 | switch (call_info.return_value.long) { |
| 10052 | .none, .unreach => {}, |
| 10053 | .indirect => |reg_off| { |
| 9932 | 10054 | const ret_ty = fn_info.return_type.toType(); |
| 9933 | 10055 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ret_ty, mod)); |
| 9934 | 10056 | try self.genSetReg(reg_off.reg, Type.usize, .{ |
| 9935 | 10057 | .lea_frame = .{ .index = frame_index, .off = -reg_off.off }, |
| 9936 | 10058 | }); |
| 9937 | 10059 | call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } }; |
| 9938 | | break :lock self.register_manager.lockRegAssumeUnused(reg_off.reg); |
| 10060 | try reg_locks.append(self.register_manager.lockReg(reg_off.reg)); |
| 9939 | 10061 | }, |
| 9940 | 10062 | else => unreachable, |
| 9941 | | }; |
| 9942 | | defer if (ret_lock) |lock| self.register_manager.unlockReg(lock); |
| 10063 | } |
| 9943 | 10064 | |
| 9944 | | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { |
| 9945 | | .none, .load_frame => {}, |
| 9946 | | .register, .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 9947 | | else => unreachable, |
| 9948 | | }; |
| 10065 | for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, frame_index| |
| 10066 | switch (dst_arg) { |
| 10067 | .none, .load_frame => {}, |
| 10068 | .register => |dst_reg| switch (fn_info.cc) { |
| 10069 | else => try self.genSetReg( |
| 10070 | registerAlias(dst_reg, @intCast(arg_ty.abiSize(mod))), |
| 10071 | arg_ty, |
| 10072 | src_arg, |
| 10073 | ), |
| 10074 | .C, .SysV, .Win64 => { |
| 10075 | const promoted_ty = self.promoteInt(arg_ty); |
| 10076 | const promoted_abi_size: u32 = @intCast(promoted_ty.abiSize(mod)); |
| 10077 | const dst_alias = registerAlias(dst_reg, promoted_abi_size); |
| 10078 | try self.genSetReg(dst_alias, promoted_ty, src_arg); |
| 10079 | if (promoted_ty.toIntern() != arg_ty.toIntern()) |
| 10080 | try self.truncateRegister(arg_ty, dst_alias); |
| 10081 | }, |
| 10082 | }, |
| 10083 | .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 10084 | .indirect => |reg_off| try self.genSetReg(reg_off.reg, Type.usize, .{ |
| 10085 | .lea_frame = .{ .index = frame_index, .off = -reg_off.off }, |
| 10086 | }), |
| 10087 | else => unreachable, |
| 10088 | }; |
| 9949 | 10089 | |
| 9950 | 10090 | if (fn_info.is_var_args) |
| 9951 | 10091 | try self.asmRegisterImmediate(.{ ._, .mov }, .al, Immediate.u(call_info.fp_count)); |
| ... | ... | @@ -9969,12 +10109,12 @@ fn genCall(self: *Self, info: union(enum) { |
| 9969 | 10109 | const sym = elf_file.symbol(sym_index); |
| 9970 | 10110 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); |
| 9971 | 10111 | if (self.bin_file.options.pic) { |
| 9972 | | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym.esym_index }); |
| 10112 | try self.genSetReg(.rax, Type.usize, .{ .load_symbol = sym.esym_index }); |
| 9973 | 10113 | try self.asmRegister(.{ ._, .call }, .rax); |
| 9974 | 10114 | } else { |
| 9975 | 10115 | _ = try self.addInst(.{ |
| 9976 | 10116 | .tag = .call, |
| 9977 | | .ops = .direct_got_reloc, |
| 10117 | .ops = .linker_reloc, |
| 9978 | 10118 | .data = .{ .reloc = .{ |
| 9979 | 10119 | .atom_index = try self.owner.getSymbolIndex(self), |
| 9980 | 10120 | .sym_index = sym.esym_index, |
| ... | ... | @@ -10054,7 +10194,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 10054 | 10194 | const ptr_ty = self.typeOf(un_op); |
| 10055 | 10195 | switch (self.ret_mcv.short) { |
| 10056 | 10196 | .none => {}, |
| 10057 | | .register => try self.load(self.ret_mcv.short, ptr_ty, ptr), |
| 10197 | .register, .register_pair => try self.load(self.ret_mcv.short, ptr_ty, ptr), |
| 10058 | 10198 | .indirect => |reg_off| try self.genSetReg(reg_off.reg, ptr_ty, ptr), |
| 10059 | 10199 | else => unreachable, |
| 10060 | 10200 | } |
| ... | ... | @@ -10115,20 +10255,28 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 10115 | 10255 | try self.spillEflagsIfOccupied(); |
| 10116 | 10256 | |
| 10117 | 10257 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 10118 | | const lhs_lock = switch (lhs_mcv) { |
| 10119 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 10120 | | .register_offset => |ro| self.register_manager.lockRegAssumeUnused(ro.reg), |
| 10121 | | else => null, |
| 10258 | const lhs_locks: [2]?RegisterLock = switch (lhs_mcv) { |
| 10259 | .register => |lhs_reg| .{ self.register_manager.lockRegAssumeUnused(lhs_reg), null }, |
| 10260 | .register_pair => |lhs_regs| locks: { |
| 10261 | const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs); |
| 10262 | break :locks .{ locks[0], locks[1] }; |
| 10263 | }, |
| 10264 | .register_offset => |lhs_ro| .{ |
| 10265 | self.register_manager.lockRegAssumeUnused(lhs_ro.reg), |
| 10266 | null, |
| 10267 | }, |
| 10268 | else => .{null} ** 2, |
| 10122 | 10269 | }; |
| 10123 | | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 10270 | defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 10124 | 10271 | |
| 10125 | 10272 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 10126 | | const rhs_lock = switch (rhs_mcv) { |
| 10127 | | .register => |reg| self.register_manager.lockReg(reg), |
| 10128 | | .register_offset => |ro| self.register_manager.lockReg(ro.reg), |
| 10129 | | else => null, |
| 10273 | const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) { |
| 10274 | .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null }, |
| 10275 | .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs), |
| 10276 | .register_offset => |rhs_ro| .{ self.register_manager.lockReg(rhs_ro.reg), null }, |
| 10277 | else => .{null} ** 2, |
| 10130 | 10278 | }; |
| 10131 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 10279 | defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 10132 | 10280 | |
| 10133 | 10281 | switch (ty.zigTypeTag(mod)) { |
| 10134 | 10282 | else => { |
| ... | ... | @@ -10159,7 +10307,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 10159 | 10307 | if (dst_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 10160 | 10308 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 10161 | 10309 | |
| 10162 | | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| 10310 | const src_mcv = try self.resolveInst(if (flipped) bin_op.lhs else bin_op.rhs); |
| 10163 | 10311 | const src_lock = |
| 10164 | 10312 | if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 10165 | 10313 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -10191,14 +10339,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 10191 | 10339 | .indirect, |
| 10192 | 10340 | .lea_direct, |
| 10193 | 10341 | .lea_got, |
| 10194 | | .lea_extern_got, |
| 10195 | 10342 | .lea_tlv, |
| 10196 | 10343 | .lea_frame, |
| 10344 | .lea_symbol, |
| 10197 | 10345 | .reserved_frame, |
| 10198 | 10346 | .air_ref, |
| 10199 | 10347 | => unreachable, |
| 10200 | 10348 | .register_pair, .load_frame => null, |
| 10201 | | .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => dst: { |
| 10349 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: { |
| 10202 | 10350 | switch (resolved_dst_mcv) { |
| 10203 | 10351 | .memory => |addr| if (math.cast( |
| 10204 | 10352 | i32, |
| ... | ... | @@ -10207,7 +10355,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 10207 | 10355 | i32, |
| 10208 | 10356 | @as(i64, @bitCast(addr)) + abi_size - 8, |
| 10209 | 10357 | ) != null) break :dst null, |
| 10210 | | .load_got, .load_extern_got, .load_direct, .load_tlv => {}, |
| 10358 | .load_symbol, .load_got, .load_direct, .load_tlv => {}, |
| 10211 | 10359 | else => unreachable, |
| 10212 | 10360 | } |
| 10213 | 10361 | |
| ... | ... | @@ -10248,16 +10396,16 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 10248 | 10396 | .register_offset, |
| 10249 | 10397 | .register_overflow, |
| 10250 | 10398 | .indirect, |
| 10399 | .lea_symbol, |
| 10251 | 10400 | .lea_direct, |
| 10252 | 10401 | .lea_got, |
| 10253 | | .lea_extern_got, |
| 10254 | 10402 | .lea_tlv, |
| 10255 | 10403 | .lea_frame, |
| 10256 | 10404 | .reserved_frame, |
| 10257 | 10405 | .air_ref, |
| 10258 | 10406 | => unreachable, |
| 10259 | 10407 | .register_pair, .load_frame => null, |
| 10260 | | .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => src: { |
| 10408 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: { |
| 10261 | 10409 | switch (resolved_src_mcv) { |
| 10262 | 10410 | .memory => |addr| if (math.cast( |
| 10263 | 10411 | i32, |
| ... | ... | @@ -10266,7 +10414,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 10266 | 10414 | i32, |
| 10267 | 10415 | @as(i64, @bitCast(addr)) + abi_size - 8, |
| 10268 | 10416 | ) != null) break :src null, |
| 10269 | | .load_got, .load_extern_got, .load_direct, .load_tlv => {}, |
| 10417 | .load_symbol, .load_got, .load_direct, .load_tlv => {}, |
| 10270 | 10418 | else => unreachable, |
| 10271 | 10419 | } |
| 10272 | 10420 | |
| ... | ... | @@ -10350,13 +10498,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 10350 | 10498 | }, |
| 10351 | 10499 | ); |
| 10352 | 10500 | |
| 10353 | | if (limb_i > 0) try self.asmRegisterRegister( |
| 10354 | | .{ ._, .@"or" }, |
| 10355 | | acc_reg, |
| 10356 | | tmp_reg, |
| 10357 | | ); |
| 10501 | if (limb_i > 0) |
| 10502 | try self.asmRegisterRegister(.{ ._, .@"or" }, acc_reg, tmp_reg); |
| 10358 | 10503 | } |
| 10359 | | try self.asmRegisterRegister(.{ ._, .@"test" }, acc_reg, acc_reg); |
| 10504 | assert(limbs_len >= 2); // use flags from or |
| 10360 | 10505 | break :result_op flipped_op; |
| 10361 | 10506 | }, |
| 10362 | 10507 | }; |
| ... | ... | @@ -10692,9 +10837,9 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 10692 | 10837 | .register_overflow, |
| 10693 | 10838 | .lea_direct, |
| 10694 | 10839 | .lea_got, |
| 10695 | | .lea_extern_got, |
| 10696 | 10840 | .lea_tlv, |
| 10697 | 10841 | .lea_frame, |
| 10842 | .lea_symbol, |
| 10698 | 10843 | .reserved_frame, |
| 10699 | 10844 | .air_ref, |
| 10700 | 10845 | => unreachable, |
| ... | ... | @@ -10718,8 +10863,8 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 10718 | 10863 | }, |
| 10719 | 10864 | |
| 10720 | 10865 | .memory, |
| 10866 | .load_symbol, |
| 10721 | 10867 | .load_got, |
| 10722 | | .load_extern_got, |
| 10723 | 10868 | .load_direct, |
| 10724 | 10869 | .load_tlv, |
| 10725 | 10870 | => { |
| ... | ... | @@ -11316,7 +11461,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 11316 | 11461 | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_| |
| 11317 | 11462 | break :arg input_mcv, |
| 11318 | 11463 | .indirect, .load_frame => break :arg input_mcv, |
| 11319 | | .load_direct, .load_got, .load_extern_got, .load_tlv => {}, |
| 11464 | .load_symbol, .load_direct, .load_got, .load_tlv => {}, |
| 11320 | 11465 | else => { |
| 11321 | 11466 | const temp_mcv = try self.allocTempRegOrMem(ty, false); |
| 11322 | 11467 | try self.genCopy(ty, temp_mcv, input_mcv); |
| ... | ... | @@ -11578,6 +11723,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 11578 | 11723 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) } |
| 11579 | 11724 | else |
| 11580 | 11725 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 11726 | .load_symbol => |sym_index| if (mem.eql(u8, modifier, "P")) |
| 11727 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .load_symbol = sym_index }) } |
| 11728 | else |
| 11729 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 11581 | 11730 | else => return self.fail("invalid constraint: '{s}'", .{op_str}), |
| 11582 | 11731 | }; |
| 11583 | 11732 | } else if (mem.startsWith(u8, op_str, "$")) { |
| ... | ... | @@ -11798,6 +11947,7 @@ const MoveStrategy = union(enum) { |
| 11798 | 11947 | .move => |tag| try self.asmRegisterMemory(tag, dst_reg, src_mem), |
| 11799 | 11948 | .x87_load_store => { |
| 11800 | 11949 | try self.asmMemory(.{ .f_, .ld }, src_mem); |
| 11950 | assert(dst_reg != .st7); |
| 11801 | 11951 | try self.asmRegister(.{ .f_p, .st }, @enumFromInt(@intFromEnum(dst_reg) + 1)); |
| 11802 | 11952 | }, |
| 11803 | 11953 | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( |
| ... | ... | @@ -11831,188 +11981,284 @@ const MoveStrategy = union(enum) { |
| 11831 | 11981 | } |
| 11832 | 11982 | } |
| 11833 | 11983 | }; |
| 11834 | | fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 11984 | fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !MoveStrategy { |
| 11835 | 11985 | const mod = self.bin_file.options.module.?; |
| 11836 | | switch (ty.zigTypeTag(mod)) { |
| 11837 | | else => return .{ .move = .{ ._, .mov } }, |
| 11838 | | .Float => switch (ty.floatBits(self.target.*)) { |
| 11839 | | 16 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 11840 | | .insert = .{ .vp_w, .insr }, |
| 11841 | | .extract = .{ .vp_w, .extr }, |
| 11842 | | } } else .{ .insert_extract = .{ |
| 11843 | | .insert = .{ .p_w, .insr }, |
| 11844 | | .extract = .{ .p_w, .extr }, |
| 11845 | | } }, |
| 11846 | | 32 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov } }, |
| 11847 | | 64 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov } }, |
| 11848 | | 80 => return .x87_load_store, |
| 11849 | | 128 => return .{ .move = if (self.hasFeature(.avx)) |
| 11850 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 11851 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 11852 | | else => {}, |
| 11853 | | }, |
| 11854 | | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 11855 | | .Bool => return .{ .move = .{ ._, .mov } }, |
| 11856 | | .Int => switch (ty.childType(mod).intInfo(mod).bits) { |
| 11857 | | 8 => switch (ty.vectorLen(mod)) { |
| 11858 | | 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{ |
| 11859 | | .insert = .{ .vp_b, .insr }, |
| 11860 | | .extract = .{ .vp_b, .extr }, |
| 11861 | | } } else if (self.hasFeature(.sse4_2)) return .{ .insert_extract = .{ |
| 11862 | | .insert = .{ .p_b, .insr }, |
| 11863 | | .extract = .{ .p_b, .extr }, |
| 11864 | | } }, |
| 11865 | | 2 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 11866 | | .insert = .{ .vp_w, .insr }, |
| 11867 | | .extract = .{ .vp_w, .extr }, |
| 11868 | | } } else .{ .insert_extract = .{ |
| 11869 | | .insert = .{ .p_w, .insr }, |
| 11870 | | .extract = .{ .p_w, .extr }, |
| 11871 | | } }, |
| 11872 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 11873 | | .{ .v_d, .mov } |
| 11874 | | else |
| 11875 | | .{ ._d, .mov } }, |
| 11876 | | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 11877 | | .{ .v_q, .mov } |
| 11878 | | else |
| 11879 | | .{ ._q, .mov } }, |
| 11880 | | 9...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 11881 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 11882 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 11883 | | 17...32 => if (self.hasFeature(.avx)) |
| 11884 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 11885 | | else => {}, |
| 11886 | | }, |
| 11887 | | 16 => switch (ty.vectorLen(mod)) { |
| 11888 | | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 11889 | | .insert = .{ .vp_w, .insr }, |
| 11890 | | .extract = .{ .vp_w, .extr }, |
| 11891 | | } } else .{ .insert_extract = .{ |
| 11892 | | .insert = .{ .p_w, .insr }, |
| 11893 | | .extract = .{ .p_w, .extr }, |
| 11894 | | } }, |
| 11895 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 11896 | | .{ .v_d, .mov } |
| 11897 | | else |
| 11898 | | .{ ._d, .mov } }, |
| 11899 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 11900 | | .{ .v_q, .mov } |
| 11901 | | else |
| 11902 | | .{ ._q, .mov } }, |
| 11903 | | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 11904 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 11905 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 11906 | | 9...16 => if (self.hasFeature(.avx)) |
| 11907 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 11908 | | else => {}, |
| 11909 | | }, |
| 11910 | | 32 => switch (ty.vectorLen(mod)) { |
| 11911 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 11912 | | .{ .v_d, .mov } |
| 11913 | | else |
| 11914 | | .{ ._d, .mov } }, |
| 11915 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 11916 | | .{ .v_q, .mov } |
| 11917 | | else |
| 11918 | | .{ ._q, .mov } }, |
| 11919 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 11920 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 11921 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 11922 | | 5...8 => if (self.hasFeature(.avx)) |
| 11923 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 11924 | | else => {}, |
| 11925 | | }, |
| 11926 | | 64 => switch (ty.vectorLen(mod)) { |
| 11927 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 11928 | | .{ .v_q, .mov } |
| 11929 | | else |
| 11930 | | .{ ._q, .mov } }, |
| 11931 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 11932 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 11933 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 11934 | | 3...4 => if (self.hasFeature(.avx)) |
| 11935 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 11936 | | else => {}, |
| 11937 | | }, |
| 11938 | | 128 => switch (ty.vectorLen(mod)) { |
| 11939 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 11940 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 11941 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 11942 | | 2 => if (self.hasFeature(.avx)) |
| 11943 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 11944 | | else => {}, |
| 11945 | | }, |
| 11946 | | 256 => switch (ty.vectorLen(mod)) { |
| 11947 | | 1 => if (self.hasFeature(.avx)) |
| 11948 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 11949 | | else => {}, |
| 11986 | switch (class) { |
| 11987 | .general_purpose, .segment => return .{ .move = .{ ._, .mov } }, |
| 11988 | .x87 => return .x87_load_store, |
| 11989 | .mmx => {}, |
| 11990 | .sse => { |
| 11991 | switch (ty.zigTypeTag(mod)) { |
| 11992 | else => { |
| 11993 | const classes = mem.sliceTo(&abi.classifySystemV(ty, mod, .other), .none); |
| 11994 | assert(std.mem.indexOfNone(abi.Class, classes, &.{ |
| 11995 | .integer, .sse, .float, .float_combine, |
| 11996 | }) == null); |
| 11997 | const abi_size = ty.abiSize(mod); |
| 11998 | if (abi_size < 4 or |
| 11999 | std.mem.indexOfScalar(abi.Class, classes, .integer) != null) switch (abi_size) { |
| 12000 | 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{ |
| 12001 | .insert = .{ .vp_b, .insr }, |
| 12002 | .extract = .{ .vp_b, .extr }, |
| 12003 | } } else if (self.hasFeature(.sse4_2)) return .{ .insert_extract = .{ |
| 12004 | .insert = .{ .p_b, .insr }, |
| 12005 | .extract = .{ .p_b, .extr }, |
| 12006 | } }, |
| 12007 | 2 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 12008 | .insert = .{ .vp_w, .insr }, |
| 12009 | .extract = .{ .vp_w, .extr }, |
| 12010 | } } else .{ .insert_extract = .{ |
| 12011 | .insert = .{ .p_w, .insr }, |
| 12012 | .extract = .{ .p_w, .extr }, |
| 12013 | } }, |
| 12014 | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 12015 | .{ .v_d, .mov } |
| 12016 | else |
| 12017 | .{ ._d, .mov } }, |
| 12018 | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 12019 | .{ .v_q, .mov } |
| 12020 | else |
| 12021 | .{ ._q, .mov } }, |
| 12022 | 9...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 12023 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12024 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12025 | 17...32 => if (self.hasFeature(.avx)) |
| 12026 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 12027 | else => {}, |
| 12028 | } else switch (abi_size) { |
| 12029 | 4 => return .{ .move = if (self.hasFeature(.avx)) |
| 12030 | .{ .v_ss, .mov } |
| 12031 | else |
| 12032 | .{ ._ss, .mov } }, |
| 12033 | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 12034 | .{ .v_sd, .mov } |
| 12035 | else |
| 12036 | .{ ._sd, .mov } }, |
| 12037 | 9...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 12038 | if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } |
| 12039 | else if (aligned) .{ ._pd, .mova } else .{ ._pd, .movu } }, |
| 12040 | 17...32 => if (self.hasFeature(.avx)) return .{ .move = if (aligned) |
| 12041 | .{ .v_pd, .mova } |
| 12042 | else |
| 12043 | .{ .v_pd, .movu } }, |
| 12044 | else => {}, |
| 12045 | } |
| 11950 | 12046 | }, |
| 11951 | | else => {}, |
| 11952 | | }, |
| 11953 | | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 11954 | | 16 => switch (ty.vectorLen(mod)) { |
| 11955 | | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 12047 | .Float => switch (ty.floatBits(self.target.*)) { |
| 12048 | 16 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 11956 | 12049 | .insert = .{ .vp_w, .insr }, |
| 11957 | 12050 | .extract = .{ .vp_w, .extr }, |
| 11958 | 12051 | } } else .{ .insert_extract = .{ |
| 11959 | 12052 | .insert = .{ .p_w, .insr }, |
| 11960 | 12053 | .extract = .{ .p_w, .extr }, |
| 11961 | 12054 | } }, |
| 11962 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 11963 | | .{ .v_d, .mov } |
| 11964 | | else |
| 11965 | | .{ ._d, .mov } }, |
| 11966 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 11967 | | .{ .v_q, .mov } |
| 11968 | | else |
| 11969 | | .{ ._q, .mov } }, |
| 11970 | | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 11971 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 11972 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 11973 | | 9...16 => if (self.hasFeature(.avx)) |
| 11974 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 11975 | | else => {}, |
| 11976 | | }, |
| 11977 | | 32 => switch (ty.vectorLen(mod)) { |
| 11978 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12055 | 32 => return .{ .move = if (self.hasFeature(.avx)) |
| 11979 | 12056 | .{ .v_ss, .mov } |
| 11980 | 12057 | else |
| 11981 | 12058 | .{ ._ss, .mov } }, |
| 11982 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 11983 | | .{ .v_sd, .mov } |
| 11984 | | else |
| 11985 | | .{ ._sd, .mov } }, |
| 11986 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 11987 | | if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } |
| 11988 | | else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } }, |
| 11989 | | 5...8 => if (self.hasFeature(.avx)) |
| 11990 | | return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } }, |
| 11991 | | else => {}, |
| 11992 | | }, |
| 11993 | | 64 => switch (ty.vectorLen(mod)) { |
| 11994 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12059 | 64 => return .{ .move = if (self.hasFeature(.avx)) |
| 11995 | 12060 | .{ .v_sd, .mov } |
| 11996 | 12061 | else |
| 11997 | 12062 | .{ ._sd, .mov } }, |
| 11998 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 11999 | | if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } |
| 12000 | | else if (aligned) .{ ._pd, .mova } else .{ ._pd, .movu } }, |
| 12001 | | 3...4 => if (self.hasFeature(.avx)) |
| 12002 | | return .{ .move = if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } }, |
| 12003 | | else => {}, |
| 12004 | | }, |
| 12005 | | 128 => switch (ty.vectorLen(mod)) { |
| 12006 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12063 | 128 => return .{ .move = if (self.hasFeature(.avx)) |
| 12007 | 12064 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12008 | 12065 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12009 | | 2 => if (self.hasFeature(.avx)) |
| 12010 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 12011 | 12066 | else => {}, |
| 12012 | 12067 | }, |
| 12013 | | else => {}, |
| 12014 | | }, |
| 12015 | | else => {}, |
| 12068 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 12069 | .Bool => return .{ .move = .{ ._, .mov } }, |
| 12070 | .Int => switch (ty.childType(mod).intInfo(mod).bits) { |
| 12071 | 8 => switch (ty.vectorLen(mod)) { |
| 12072 | 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{ |
| 12073 | .insert = .{ .vp_b, .insr }, |
| 12074 | .extract = .{ .vp_b, .extr }, |
| 12075 | } } else if (self.hasFeature(.sse4_2)) return .{ .insert_extract = .{ |
| 12076 | .insert = .{ .p_b, .insr }, |
| 12077 | .extract = .{ .p_b, .extr }, |
| 12078 | } }, |
| 12079 | 2 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 12080 | .insert = .{ .vp_w, .insr }, |
| 12081 | .extract = .{ .vp_w, .extr }, |
| 12082 | } } else .{ .insert_extract = .{ |
| 12083 | .insert = .{ .p_w, .insr }, |
| 12084 | .extract = .{ .p_w, .extr }, |
| 12085 | } }, |
| 12086 | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 12087 | .{ .v_d, .mov } |
| 12088 | else |
| 12089 | .{ ._d, .mov } }, |
| 12090 | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 12091 | .{ .v_q, .mov } |
| 12092 | else |
| 12093 | .{ ._q, .mov } }, |
| 12094 | 9...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 12095 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12096 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12097 | 17...32 => if (self.hasFeature(.avx)) |
| 12098 | return .{ .move = if (aligned) |
| 12099 | .{ .v_, .movdqa } |
| 12100 | else |
| 12101 | .{ .v_, .movdqu } }, |
| 12102 | else => {}, |
| 12103 | }, |
| 12104 | 16 => switch (ty.vectorLen(mod)) { |
| 12105 | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 12106 | .insert = .{ .vp_w, .insr }, |
| 12107 | .extract = .{ .vp_w, .extr }, |
| 12108 | } } else .{ .insert_extract = .{ |
| 12109 | .insert = .{ .p_w, .insr }, |
| 12110 | .extract = .{ .p_w, .extr }, |
| 12111 | } }, |
| 12112 | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 12113 | .{ .v_d, .mov } |
| 12114 | else |
| 12115 | .{ ._d, .mov } }, |
| 12116 | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 12117 | .{ .v_q, .mov } |
| 12118 | else |
| 12119 | .{ ._q, .mov } }, |
| 12120 | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 12121 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12122 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12123 | 9...16 => if (self.hasFeature(.avx)) |
| 12124 | return .{ .move = if (aligned) |
| 12125 | .{ .v_, .movdqa } |
| 12126 | else |
| 12127 | .{ .v_, .movdqu } }, |
| 12128 | else => {}, |
| 12129 | }, |
| 12130 | 32 => switch (ty.vectorLen(mod)) { |
| 12131 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12132 | .{ .v_d, .mov } |
| 12133 | else |
| 12134 | .{ ._d, .mov } }, |
| 12135 | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 12136 | .{ .v_q, .mov } |
| 12137 | else |
| 12138 | .{ ._q, .mov } }, |
| 12139 | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 12140 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12141 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12142 | 5...8 => if (self.hasFeature(.avx)) |
| 12143 | return .{ .move = if (aligned) |
| 12144 | .{ .v_, .movdqa } |
| 12145 | else |
| 12146 | .{ .v_, .movdqu } }, |
| 12147 | else => {}, |
| 12148 | }, |
| 12149 | 64 => switch (ty.vectorLen(mod)) { |
| 12150 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12151 | .{ .v_q, .mov } |
| 12152 | else |
| 12153 | .{ ._q, .mov } }, |
| 12154 | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 12155 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12156 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12157 | 3...4 => if (self.hasFeature(.avx)) |
| 12158 | return .{ .move = if (aligned) |
| 12159 | .{ .v_, .movdqa } |
| 12160 | else |
| 12161 | .{ .v_, .movdqu } }, |
| 12162 | else => {}, |
| 12163 | }, |
| 12164 | 128 => switch (ty.vectorLen(mod)) { |
| 12165 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12166 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12167 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12168 | 2 => if (self.hasFeature(.avx)) |
| 12169 | return .{ .move = if (aligned) |
| 12170 | .{ .v_, .movdqa } |
| 12171 | else |
| 12172 | .{ .v_, .movdqu } }, |
| 12173 | else => {}, |
| 12174 | }, |
| 12175 | 256 => switch (ty.vectorLen(mod)) { |
| 12176 | 1 => if (self.hasFeature(.avx)) |
| 12177 | return .{ .move = if (aligned) |
| 12178 | .{ .v_, .movdqa } |
| 12179 | else |
| 12180 | .{ .v_, .movdqu } }, |
| 12181 | else => {}, |
| 12182 | }, |
| 12183 | else => {}, |
| 12184 | }, |
| 12185 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 12186 | 16 => switch (ty.vectorLen(mod)) { |
| 12187 | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 12188 | .insert = .{ .vp_w, .insr }, |
| 12189 | .extract = .{ .vp_w, .extr }, |
| 12190 | } } else .{ .insert_extract = .{ |
| 12191 | .insert = .{ .p_w, .insr }, |
| 12192 | .extract = .{ .p_w, .extr }, |
| 12193 | } }, |
| 12194 | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 12195 | .{ .v_d, .mov } |
| 12196 | else |
| 12197 | .{ ._d, .mov } }, |
| 12198 | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 12199 | .{ .v_q, .mov } |
| 12200 | else |
| 12201 | .{ ._q, .mov } }, |
| 12202 | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 12203 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12204 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12205 | 9...16 => if (self.hasFeature(.avx)) |
| 12206 | return .{ .move = if (aligned) |
| 12207 | .{ .v_, .movdqa } |
| 12208 | else |
| 12209 | .{ .v_, .movdqu } }, |
| 12210 | else => {}, |
| 12211 | }, |
| 12212 | 32 => switch (ty.vectorLen(mod)) { |
| 12213 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12214 | .{ .v_ss, .mov } |
| 12215 | else |
| 12216 | .{ ._ss, .mov } }, |
| 12217 | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 12218 | .{ .v_sd, .mov } |
| 12219 | else |
| 12220 | .{ ._sd, .mov } }, |
| 12221 | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 12222 | if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } |
| 12223 | else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } }, |
| 12224 | 5...8 => if (self.hasFeature(.avx)) |
| 12225 | return .{ .move = if (aligned) |
| 12226 | .{ .v_ps, .mova } |
| 12227 | else |
| 12228 | .{ .v_ps, .movu } }, |
| 12229 | else => {}, |
| 12230 | }, |
| 12231 | 64 => switch (ty.vectorLen(mod)) { |
| 12232 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12233 | .{ .v_sd, .mov } |
| 12234 | else |
| 12235 | .{ ._sd, .mov } }, |
| 12236 | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 12237 | if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } |
| 12238 | else if (aligned) .{ ._pd, .mova } else .{ ._pd, .movu } }, |
| 12239 | 3...4 => if (self.hasFeature(.avx)) |
| 12240 | return .{ .move = if (aligned) |
| 12241 | .{ .v_pd, .mova } |
| 12242 | else |
| 12243 | .{ .v_pd, .movu } }, |
| 12244 | else => {}, |
| 12245 | }, |
| 12246 | 128 => switch (ty.vectorLen(mod)) { |
| 12247 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 12248 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 12249 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 12250 | 2 => if (self.hasFeature(.avx)) |
| 12251 | return .{ .move = if (aligned) |
| 12252 | .{ .v_, .movdqa } |
| 12253 | else |
| 12254 | .{ .v_, .movdqu } }, |
| 12255 | else => {}, |
| 12256 | }, |
| 12257 | else => {}, |
| 12258 | }, |
| 12259 | else => {}, |
| 12260 | }, |
| 12261 | } |
| 12016 | 12262 | }, |
| 12017 | 12263 | } |
| 12018 | 12264 | return self.fail("TODO moveStrategy for {}", .{ty.fmt(mod)}); |
| ... | ... | @@ -12034,9 +12280,9 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError |
| 12034 | 12280 | .register_overflow, |
| 12035 | 12281 | .lea_direct, |
| 12036 | 12282 | .lea_got, |
| 12037 | | .lea_extern_got, |
| 12038 | 12283 | .lea_tlv, |
| 12039 | 12284 | .lea_frame, |
| 12285 | .lea_symbol, |
| 12040 | 12286 | .reserved_frame, |
| 12041 | 12287 | .air_ref, |
| 12042 | 12288 | => unreachable, // unmodifiable destination |
| ... | ... | @@ -12060,37 +12306,58 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError |
| 12060 | 12306 | } }, |
| 12061 | 12307 | }), |
| 12062 | 12308 | .register_pair => |dst_regs| { |
| 12063 | | switch (src_mcv) { |
| 12309 | const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) { |
| 12310 | .register_pair, .memory, .indirect, .load_frame => null, |
| 12311 | .load_symbol, .load_direct, .load_got, .load_tlv => src: { |
| 12312 | const src_addr_reg = |
| 12313 | (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); |
| 12314 | const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg); |
| 12315 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 12316 | |
| 12317 | try self.genSetReg(src_addr_reg, Type.usize, src_mcv.address()); |
| 12318 | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; |
| 12319 | }, |
| 12064 | 12320 | .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)), |
| 12065 | | else => {}, |
| 12066 | | } |
| 12321 | else => return self.fail("TODO implement genCopy for {s} of {}", .{ |
| 12322 | @tagName(src_mcv), ty.fmt(mod), |
| 12323 | }), |
| 12324 | }; |
| 12325 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); |
| 12326 | |
| 12067 | 12327 | const classes = mem.sliceTo(&abi.classifySystemV(ty, mod, .other), .none); |
| 12068 | 12328 | for (dst_regs, classes, 0..) |dst_reg, class, dst_reg_i| { |
| 12069 | 12329 | const class_ty = switch (class) { |
| 12070 | 12330 | .integer => Type.usize, |
| 12071 | | .sse => Type.f64, |
| 12331 | .sse, .float, .float_combine => Type.f64, |
| 12072 | 12332 | else => unreachable, |
| 12073 | 12333 | }; |
| 12334 | const off: i32 = @intCast(dst_reg_i * 8); |
| 12074 | 12335 | switch (src_mcv) { |
| 12075 | 12336 | .register_pair => |src_regs| try self.genSetReg( |
| 12076 | 12337 | dst_reg, |
| 12077 | 12338 | class_ty, |
| 12078 | 12339 | .{ .register = src_regs[dst_reg_i] }, |
| 12079 | 12340 | ), |
| 12080 | | else => try self.genSetReg( |
| 12341 | .memory, .indirect, .load_frame => try self.genSetReg( |
| 12342 | dst_reg, |
| 12343 | class_ty, |
| 12344 | src_mcv.address().offset(off).deref(), |
| 12345 | ), |
| 12346 | .load_symbol, .load_direct, .load_got, .load_tlv => try self.genSetReg( |
| 12081 | 12347 | dst_reg, |
| 12082 | 12348 | class_ty, |
| 12083 | | src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(), |
| 12349 | .{ .indirect = .{ .reg = src_info.?.addr_reg, .off = off } }, |
| 12084 | 12350 | ), |
| 12351 | else => unreachable, |
| 12085 | 12352 | } |
| 12086 | 12353 | } |
| 12087 | 12354 | }, |
| 12088 | 12355 | .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv), |
| 12089 | | .memory, .load_direct, .load_got, .load_extern_got, .load_tlv => { |
| 12356 | .memory, .load_symbol, .load_direct, .load_got, .load_tlv => { |
| 12090 | 12357 | switch (dst_mcv) { |
| 12091 | 12358 | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| |
| 12092 | 12359 | return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv), |
| 12093 | | .load_direct, .load_got, .load_extern_got, .load_tlv => {}, |
| 12360 | .load_symbol, .load_direct, .load_got, .load_tlv => {}, |
| 12094 | 12361 | else => unreachable, |
| 12095 | 12362 | } |
| 12096 | 12363 | |
| ... | ... | @@ -12157,6 +12424,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 12157 | 12424 | registerAlias(dst_reg, abi_size), |
| 12158 | 12425 | src_reg, |
| 12159 | 12426 | ), |
| 12427 | .x87, .mmx => unreachable, |
| 12160 | 12428 | .sse => try self.asmRegisterRegister( |
| 12161 | 12429 | switch (abi_size) { |
| 12162 | 12430 | 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, |
| ... | ... | @@ -12166,17 +12434,30 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 12166 | 12434 | registerAlias(dst_reg, @max(abi_size, 4)), |
| 12167 | 12435 | src_reg.to128(), |
| 12168 | 12436 | ), |
| 12169 | | .x87, .mmx => unreachable, |
| 12170 | 12437 | }, |
| 12171 | 12438 | .segment => try self.asmRegisterRegister( |
| 12172 | 12439 | .{ ._, .mov }, |
| 12173 | 12440 | dst_reg, |
| 12174 | 12441 | switch (src_reg.class()) { |
| 12175 | 12442 | .general_purpose, .segment => registerAlias(src_reg, abi_size), |
| 12176 | | .sse => try self.copyToTmpRegister(ty, src_mcv), |
| 12177 | 12443 | .x87, .mmx => unreachable, |
| 12444 | .sse => try self.copyToTmpRegister(ty, src_mcv), |
| 12178 | 12445 | }, |
| 12179 | 12446 | ), |
| 12447 | .x87 => switch (src_reg.class()) { |
| 12448 | .general_purpose, .segment => unreachable, |
| 12449 | .x87 => switch (src_reg) { |
| 12450 | .st0 => try self.asmRegister(.{ .f_, .st }, dst_reg), |
| 12451 | .st1, .st2, .st3, .st4, .st5, .st6 => { |
| 12452 | try self.asmRegister(.{ .f_, .ld }, src_reg); |
| 12453 | assert(dst_reg != .st7); |
| 12454 | try self.asmRegister(.{ .f_p, .st }, @enumFromInt(@intFromEnum(dst_reg) + 1)); |
| 12455 | }, |
| 12456 | else => unreachable, |
| 12457 | }, |
| 12458 | .mmx, .sse => unreachable, |
| 12459 | }, |
| 12460 | .mmx => unreachable, |
| 12180 | 12461 | .sse => switch (src_reg.class()) { |
| 12181 | 12462 | .general_purpose => try self.asmRegisterRegister( |
| 12182 | 12463 | switch (abi_size) { |
| ... | ... | @@ -12192,6 +12473,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 12192 | 12473 | ty, |
| 12193 | 12474 | .{ .register = try self.copyToTmpRegister(ty, src_mcv) }, |
| 12194 | 12475 | ), |
| 12476 | .x87, .mmx => unreachable, |
| 12195 | 12477 | .sse => try self.asmRegisterRegister( |
| 12196 | 12478 | @as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) { |
| 12197 | 12479 | else => switch (abi_size) { |
| ... | ... | @@ -12217,9 +12499,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 12217 | 12499 | registerAlias(dst_reg, abi_size), |
| 12218 | 12500 | registerAlias(src_reg, abi_size), |
| 12219 | 12501 | ), |
| 12220 | | .x87, .mmx => unreachable, |
| 12221 | 12502 | }, |
| 12222 | | .x87, .mmx => unreachable, |
| 12223 | 12503 | }, |
| 12224 | 12504 | .register_pair => |src_regs| try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }), |
| 12225 | 12505 | .register_offset, |
| ... | ... | @@ -12231,9 +12511,10 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 12231 | 12511 | 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }), |
| 12232 | 12512 | else => .{ .move = .{ ._, .lea } }, |
| 12233 | 12513 | }, |
| 12234 | | .indirect => try self.moveStrategy(ty, false), |
| 12514 | .indirect => try self.moveStrategy(ty, dst_reg.class(), false), |
| 12235 | 12515 | .load_frame => |frame_addr| try self.moveStrategy( |
| 12236 | 12516 | ty, |
| 12517 | dst_reg.class(), |
| 12237 | 12518 | self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)), |
| 12238 | 12519 | ), |
| 12239 | 12520 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| ... | ... | @@ -12252,18 +12533,19 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 12252 | 12533 | else => unreachable, |
| 12253 | 12534 | }, |
| 12254 | 12535 | )), |
| 12255 | | .memory, .load_direct, .load_got, .load_extern_got, .load_tlv => { |
| 12536 | .memory, .load_symbol, .load_direct, .load_got, .load_tlv => { |
| 12256 | 12537 | switch (src_mcv) { |
| 12257 | 12538 | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| |
| 12258 | 12539 | return (try self.moveStrategy( |
| 12259 | 12540 | ty, |
| 12541 | dst_reg.class(), |
| 12260 | 12542 | ty.abiAlignment(mod).check(@as(u32, @bitCast(small_addr))), |
| 12261 | 12543 | )).read(self, registerAlias(dst_reg, abi_size), Memory.sib( |
| 12262 | 12544 | self.memPtrSize(ty), |
| 12263 | 12545 | .{ .base = .{ .reg = .ds }, .disp = small_addr }, |
| 12264 | 12546 | )), |
| 12265 | | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { |
| 12266 | | else => { |
| 12547 | .load_direct => |sym_index| switch (dst_reg.class()) { |
| 12548 | .general_purpose => { |
| 12267 | 12549 | const atom_index = try self.owner.getSymbolIndex(self); |
| 12268 | 12550 | _ = try self.addInst(.{ |
| 12269 | 12551 | .tag = .mov, |
| ... | ... | @@ -12278,9 +12560,10 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 12278 | 12560 | }); |
| 12279 | 12561 | return; |
| 12280 | 12562 | }, |
| 12281 | | .Float, .Vector => {}, |
| 12563 | .segment, .mmx => unreachable, |
| 12564 | .x87, .sse => {}, |
| 12282 | 12565 | }, |
| 12283 | | .load_got, .load_extern_got, .load_tlv => {}, |
| 12566 | .load_symbol, .load_got, .load_tlv => {}, |
| 12284 | 12567 | else => unreachable, |
| 12285 | 12568 | } |
| 12286 | 12569 | |
| ... | ... | @@ -12288,34 +12571,47 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 12288 | 12571 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 12289 | 12572 | defer self.register_manager.unlockReg(addr_lock); |
| 12290 | 12573 | |
| 12291 | | try (try self.moveStrategy(ty, false)).read( |
| 12574 | try (try self.moveStrategy(ty, dst_reg.class(), false)).read( |
| 12292 | 12575 | self, |
| 12293 | 12576 | registerAlias(dst_reg, abi_size), |
| 12294 | 12577 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .{ .reg = addr_reg } }), |
| 12295 | 12578 | ); |
| 12296 | 12579 | }, |
| 12297 | | .lea_direct, .lea_got, .lea_extern_got => |sym_index| { |
| 12580 | .lea_symbol, .lea_direct, .lea_got => |sym_index| { |
| 12298 | 12581 | const atom_index = try self.owner.getSymbolIndex(self); |
| 12299 | | _ = try self.addInst(.{ |
| 12300 | | .tag = switch (src_mcv) { |
| 12301 | | .lea_direct => .lea, |
| 12302 | | .lea_got, .lea_extern_got => .mov, |
| 12303 | | else => unreachable, |
| 12304 | | }, |
| 12305 | | .ops = switch (src_mcv) { |
| 12306 | | .lea_direct => .direct_reloc, |
| 12307 | | .lea_got => .got_reloc, |
| 12308 | | .lea_extern_got => .extern_got_reloc, |
| 12309 | | else => unreachable, |
| 12310 | | }, |
| 12311 | | .data = .{ .rx = .{ |
| 12312 | | .r1 = dst_reg.to64(), |
| 12313 | | .payload = try self.addExtra(Mir.Reloc{ |
| 12314 | | .atom_index = atom_index, |
| 12315 | | .sym_index = sym_index, |
| 12316 | | }), |
| 12317 | | } }, |
| 12318 | | }); |
| 12582 | if (self.bin_file.cast(link.File.Elf)) |_| { |
| 12583 | _ = try self.addInst(.{ |
| 12584 | .tag = .lea, |
| 12585 | .ops = .linker_reloc, |
| 12586 | .data = .{ .rx = .{ |
| 12587 | .r1 = dst_reg.to64(), |
| 12588 | .payload = try self.addExtra(Mir.Reloc{ |
| 12589 | .atom_index = atom_index, |
| 12590 | .sym_index = sym_index, |
| 12591 | }), |
| 12592 | } }, |
| 12593 | }); |
| 12594 | } else { |
| 12595 | _ = try self.addInst(.{ |
| 12596 | .tag = switch (src_mcv) { |
| 12597 | .lea_direct => .lea, |
| 12598 | .lea_got => .mov, |
| 12599 | else => unreachable, |
| 12600 | }, |
| 12601 | .ops = switch (src_mcv) { |
| 12602 | .lea_direct => .direct_reloc, |
| 12603 | .lea_got => .got_reloc, |
| 12604 | else => unreachable, |
| 12605 | }, |
| 12606 | .data = .{ .rx = .{ |
| 12607 | .r1 = dst_reg.to64(), |
| 12608 | .payload = try self.addExtra(Mir.Reloc{ |
| 12609 | .atom_index = atom_index, |
| 12610 | .sym_index = sym_index, |
| 12611 | }), |
| 12612 | } }, |
| 12613 | }); |
| 12614 | } |
| 12319 | 12615 | }, |
| 12320 | 12616 | .lea_tlv => |sym_index| { |
| 12321 | 12617 | const atom_index = try self.owner.getSymbolIndex(self); |
| ... | ... | @@ -12393,7 +12689,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 12393 | 12689 | }, |
| 12394 | 12690 | }, |
| 12395 | 12691 | .eflags => |cc| try self.asmSetccMemory(cc, Memory.sib(.byte, .{ .base = base, .disp = disp })), |
| 12396 | | .register => |src_reg| try (try self.moveStrategy(ty, switch (base) { |
| 12692 | .register => |src_reg| try (try self.moveStrategy(ty, src_reg.class(), switch (base) { |
| 12397 | 12693 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 12398 | 12694 | .reg => |reg| switch (reg) { |
| 12399 | 12695 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| ... | ... | @@ -12408,17 +12704,21 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 12408 | 12704 | registerAlias(src_reg, abi_size), |
| 12409 | 12705 | ), |
| 12410 | 12706 | .register_pair => |src_regs| for (src_regs, 0..) |src_reg, src_reg_i| { |
| 12411 | | const part_size = @min(abi_size - src_reg_i * 8, 8); |
| 12412 | | try (try self.moveStrategy(ty, switch (base) { |
| 12413 | | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 12414 | | .reg => |reg| switch (reg) { |
| 12415 | | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 12416 | | else => false, |
| 12707 | const part_size: u16 = @min(abi_size - src_reg_i * 8, 8); |
| 12708 | try (try self.moveStrategy( |
| 12709 | try mod.intType(.unsigned, part_size * 8), |
| 12710 | src_reg.class(), |
| 12711 | switch (base) { |
| 12712 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 12713 | .reg => |reg| switch (reg) { |
| 12714 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 12715 | else => false, |
| 12716 | }, |
| 12717 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 12718 | .{ .index = frame_index, .off = disp }, |
| 12719 | ).compare(.gte, ty.abiAlignment(mod)), |
| 12417 | 12720 | }, |
| 12418 | | .frame => |frame_index| self.getFrameAddrAlignment( |
| 12419 | | .{ .index = frame_index, .off = disp }, |
| 12420 | | ).compare(.gte, ty.abiAlignment(mod)), |
| 12421 | | })).write(self, Memory.sib( |
| 12721 | )).write(self, Memory.sib( |
| 12422 | 12722 | Memory.PtrSize.fromSize(part_size), |
| 12423 | 12723 | .{ .base = base, .disp = disp + @as(i32, @intCast(src_reg_i * 8)) }, |
| 12424 | 12724 | ), registerAlias(src_reg, part_size)); |
| ... | ... | @@ -12460,12 +12760,12 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 12460 | 12760 | .lea_direct, |
| 12461 | 12761 | .load_got, |
| 12462 | 12762 | .lea_got, |
| 12463 | | .load_extern_got, |
| 12464 | | .lea_extern_got, |
| 12465 | 12763 | .load_tlv, |
| 12466 | 12764 | .lea_tlv, |
| 12467 | 12765 | .load_frame, |
| 12468 | 12766 | .lea_frame, |
| 12767 | .load_symbol, |
| 12768 | .lea_symbol, |
| 12469 | 12769 | => switch (abi_size) { |
| 12470 | 12770 | 0 => {}, |
| 12471 | 12771 | 1, 2, 4, 8 => { |
| ... | ... | @@ -12482,9 +12782,9 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 12482 | 12782 | } |
| 12483 | 12783 | |
| 12484 | 12784 | fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue) InnerError!void { |
| 12485 | | try self.spillRegisters(&.{ .rdi, .rsi, .rcx }); |
| 12486 | | try self.genSetReg(.rdi, Type.usize, dst_ptr); |
| 12785 | try self.spillRegisters(&.{ .rsi, .rdi, .rcx }); |
| 12487 | 12786 | try self.genSetReg(.rsi, Type.usize, src_ptr); |
| 12787 | try self.genSetReg(.rdi, Type.usize, dst_ptr); |
| 12488 | 12788 | try self.genSetReg(.rcx, Type.usize, len); |
| 12489 | 12789 | try self.asmOpOnly(.{ .@"rep _sb", .mov }); |
| 12490 | 12790 | } |
| ... | ... | @@ -12556,8 +12856,8 @@ fn genLazySymbolRef( |
| 12556 | 12856 | |
| 12557 | 12857 | if (self.bin_file.options.pic) { |
| 12558 | 12858 | switch (tag) { |
| 12559 | | .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym.esym_index }), |
| 12560 | | .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym.esym_index }), |
| 12859 | .lea, .call => try self.genSetReg(reg, Type.usize, .{ .load_symbol = sym.esym_index }), |
| 12860 | .mov => try self.genSetReg(reg, Type.usize, .{ .load_symbol = sym.esym_index }), |
| 12561 | 12861 | else => unreachable, |
| 12562 | 12862 | } |
| 12563 | 12863 | switch (tag) { |
| ... | ... | @@ -12573,7 +12873,7 @@ fn genLazySymbolRef( |
| 12573 | 12873 | switch (tag) { |
| 12574 | 12874 | .lea, .mov => _ = try self.addInst(.{ |
| 12575 | 12875 | .tag = .mov, |
| 12576 | | .ops = .direct_got_reloc, |
| 12876 | .ops = .linker_reloc, |
| 12577 | 12877 | .data = .{ .rx = .{ |
| 12578 | 12878 | .r1 = reg.to64(), |
| 12579 | 12879 | .payload = try self.addExtra(reloc), |
| ... | ... | @@ -12581,20 +12881,11 @@ fn genLazySymbolRef( |
| 12581 | 12881 | }), |
| 12582 | 12882 | .call => _ = try self.addInst(.{ |
| 12583 | 12883 | .tag = .call, |
| 12584 | | .ops = .direct_got_reloc, |
| 12884 | .ops = .linker_reloc, |
| 12585 | 12885 | .data = .{ .reloc = reloc }, |
| 12586 | 12886 | }), |
| 12587 | 12887 | else => unreachable, |
| 12588 | 12888 | } |
| 12589 | | switch (tag) { |
| 12590 | | .lea, .call => {}, |
| 12591 | | .mov => try self.asmRegisterMemory( |
| 12592 | | .{ ._, tag }, |
| 12593 | | reg.to64(), |
| 12594 | | Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), |
| 12595 | | ), |
| 12596 | | else => unreachable, |
| 12597 | | } |
| 12598 | 12889 | } |
| 12599 | 12890 | } else if (self.bin_file.cast(link.File.Plan9)) |p9_file| { |
| 12600 | 12891 | const atom_index = p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| |
| ... | ... | @@ -14481,10 +14772,11 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |
| 14481 | 14772 | } else mcv: { |
| 14482 | 14773 | const ip_index = Air.refToInterned(ref).?; |
| 14483 | 14774 | const gop = try self.const_tracking.getOrPut(self.gpa, ip_index); |
| 14484 | | if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{ |
| 14775 | const mcv = try self.genTypedValue(.{ |
| 14485 | 14776 | .ty = ty, |
| 14486 | 14777 | .val = ip_index.toValue(), |
| 14487 | | })); |
| 14778 | }); |
| 14779 | if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(mcv); |
| 14488 | 14780 | break :mcv gop.value_ptr.short; |
| 14489 | 14781 | }; |
| 14490 | 14782 | |
| ... | ... | @@ -14531,9 +14823,9 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 14531 | 14823 | .undef => .undef, |
| 14532 | 14824 | .immediate => |imm| .{ .immediate = imm }, |
| 14533 | 14825 | .memory => |addr| .{ .memory = addr }, |
| 14826 | .load_symbol => |sym_index| .{ .load_symbol = sym_index }, |
| 14534 | 14827 | .load_direct => |sym_index| .{ .load_direct = sym_index }, |
| 14535 | 14828 | .load_got => |sym_index| .{ .lea_got = sym_index }, |
| 14536 | | .load_extern_got => |sym_index| .{ .lea_extern_got = sym_index }, |
| 14537 | 14829 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, |
| 14538 | 14830 | }, |
| 14539 | 14831 | .fail => |msg| { |
| ... | ... | @@ -14730,16 +15022,22 @@ fn resolveCallingConventionValues( |
| 14730 | 15022 | arg_mcv_i += 1; |
| 14731 | 15023 | }, |
| 14732 | 15024 | .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse), |
| 14733 | | .x87, .x87up, .complex_x87, .memory => break, |
| 14734 | | .none => unreachable, |
| 14735 | | .win_i128 => { |
| 14736 | | const param_int_reg = |
| 14737 | | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64(); |
| 14738 | | param_int_reg_i += 1; |
| 14739 | | |
| 14740 | | arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } }; |
| 14741 | | arg_mcv_i += 1; |
| 15025 | .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) { |
| 15026 | .SysV => switch (class) { |
| 15027 | .x87, .x87up, .complex_x87, .memory => break, |
| 15028 | else => unreachable, |
| 15029 | }, |
| 15030 | .Win64 => if (ty.abiSize(mod) > 8) { |
| 15031 | const param_int_reg = |
| 15032 | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64(); |
| 15033 | param_int_reg_i += 1; |
| 15034 | |
| 15035 | arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } }; |
| 15036 | arg_mcv_i += 1; |
| 15037 | } else break, |
| 15038 | else => unreachable, |
| 14742 | 15039 | }, |
| 15040 | .none => unreachable, |
| 14743 | 15041 | } else { |
| 14744 | 15042 | arg.* = switch (arg_mcv_i) { |
| 14745 | 15043 | else => unreachable, |
| ... | ... | @@ -15017,34 +15315,32 @@ fn floatLibcAbiSuffix(ty: Type) []const u8 { |
| 15017 | 15315 | }; |
| 15018 | 15316 | } |
| 15019 | 15317 | |
| 15020 | | fn promoteVarArg(self: *Self, ty: Type) Type { |
| 15318 | fn promoteInt(self: *Self, ty: Type) Type { |
| 15021 | 15319 | const mod = self.bin_file.options.module.?; |
| 15022 | | switch (ty.zigTypeTag(mod)) { |
| 15023 | | .Bool => return Type.c_int, |
| 15024 | | else => { |
| 15025 | | const int_info = ty.intInfo(mod); |
| 15026 | | for ([_]Type{ |
| 15027 | | Type.c_int, Type.c_uint, |
| 15028 | | Type.c_long, Type.c_ulong, |
| 15029 | | Type.c_longlong, Type.c_ulonglong, |
| 15030 | | }) |promote_ty| { |
| 15031 | | const promote_info = promote_ty.intInfo(mod); |
| 15032 | | if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue; |
| 15033 | | if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and |
| 15034 | | promote_info.signedness == .signed) <= promote_info.bits) return promote_ty; |
| 15035 | | } |
| 15036 | | unreachable; |
| 15037 | | }, |
| 15038 | | .Float => switch (ty.floatBits(self.target.*)) { |
| 15039 | | 32, 64 => return Type.f64, |
| 15040 | | else => |float_bits| { |
| 15041 | | assert(float_bits == self.target.c_type_bit_size(.longdouble)); |
| 15042 | | return Type.c_longdouble; |
| 15043 | | }, |
| 15044 | | }, |
| 15045 | | .Pointer => { |
| 15046 | | assert(!ty.isSlice(mod)); |
| 15047 | | return ty; |
| 15320 | const int_info: InternPool.Key.IntType = switch (ty.toIntern()) { |
| 15321 | .bool_type => .{ .signedness = .unsigned, .bits = 1 }, |
| 15322 | else => if (ty.isAbiInt(mod)) ty.intInfo(mod) else return ty, |
| 15323 | }; |
| 15324 | for ([_]Type{ |
| 15325 | Type.c_int, Type.c_uint, |
| 15326 | Type.c_long, Type.c_ulong, |
| 15327 | Type.c_longlong, Type.c_ulonglong, |
| 15328 | }) |promote_ty| { |
| 15329 | const promote_info = promote_ty.intInfo(mod); |
| 15330 | if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue; |
| 15331 | if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and |
| 15332 | promote_info.signedness == .signed) <= promote_info.bits) return promote_ty; |
| 15333 | } |
| 15334 | return ty; |
| 15335 | } |
| 15336 | |
| 15337 | fn promoteVarArg(self: *Self, ty: Type) Type { |
| 15338 | if (!ty.isRuntimeFloat()) return self.promoteInt(ty); |
| 15339 | switch (ty.floatBits(self.target.*)) { |
| 15340 | 32, 64 => return Type.f64, |
| 15341 | else => |float_bits| { |
| 15342 | assert(float_bits == self.target.c_type_bit_size(.longdouble)); |
| 15343 | return Type.c_longdouble; |
| 15048 | 15344 | }, |
| 15049 | 15345 | } |
| 15050 | 15346 | } |