| ... | ... | @@ -1,41 +1,26 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | | const build_options = @import("build_options"); |
| 3 | | const builtin = @import("builtin"); |
| 4 | 2 | const assert = std.debug.assert; |
| 5 | 3 | const codegen = @import("../../codegen.zig"); |
| 6 | | const leb128 = std.leb; |
| 7 | 4 | const link = @import("../../link.zig"); |
| 8 | 5 | const log = std.log.scoped(.codegen); |
| 9 | 6 | const tracking_log = std.log.scoped(.tracking); |
| 10 | 7 | const verbose_tracking_log = std.log.scoped(.verbose_tracking); |
| 11 | 8 | const wip_mir_log = std.log.scoped(.wip_mir); |
| 12 | | const math = std.math; |
| 13 | | const mem = std.mem; |
| 14 | | const target_util = @import("../../target.zig"); |
| 15 | | const trace = @import("../../tracy.zig").trace; |
| 16 | 9 | |
| 17 | 10 | const Air = @import("../../Air.zig"); |
| 18 | | const Allocator = mem.Allocator; |
| 19 | | const CodeGenError = codegen.CodeGenError; |
| 20 | | const Compilation = @import("../../Compilation.zig"); |
| 21 | | const ErrorMsg = Zcu.ErrorMsg; |
| 11 | const Allocator = std.mem.Allocator; |
| 22 | 12 | const Emit = @import("Emit.zig"); |
| 23 | 13 | const Liveness = @import("../../Liveness.zig"); |
| 24 | 14 | const Lower = @import("Lower.zig"); |
| 25 | 15 | const Mir = @import("Mir.zig"); |
| 26 | | const Package = @import("../../Package.zig"); |
| 27 | 16 | const Zcu = @import("../../Zcu.zig"); |
| 17 | const Module = @import("../../Package/Module.zig"); |
| 28 | 18 | const InternPool = @import("../../InternPool.zig"); |
| 29 | | const Alignment = InternPool.Alignment; |
| 30 | | const Target = std.Target; |
| 31 | 19 | const Type = @import("../../Type.zig"); |
| 32 | 20 | const Value = @import("../../Value.zig"); |
| 33 | | const Instruction = @import("encoder.zig").Instruction; |
| 34 | 21 | |
| 35 | 22 | const abi = @import("abi.zig"); |
| 36 | 23 | const bits = @import("bits.zig"); |
| 37 | | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 38 | | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 39 | 24 | const encoder = @import("encoder.zig"); |
| 40 | 25 | |
| 41 | 26 | const Condition = bits.Condition; |
| ... | ... | @@ -46,7 +31,7 @@ const RegisterManager = abi.RegisterManager; |
| 46 | 31 | const RegisterLock = RegisterManager.RegisterLock; |
| 47 | 32 | const FrameIndex = bits.FrameIndex; |
| 48 | 33 | |
| 49 | | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 34 | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; |
| 50 | 35 | |
| 51 | 36 | gpa: Allocator, |
| 52 | 37 | pt: Zcu.PerThread, |
| ... | ... | @@ -57,7 +42,7 @@ debug_output: link.File.DebugInfoOutput, |
| 57 | 42 | target: *const std.Target, |
| 58 | 43 | owner: Owner, |
| 59 | 44 | inline_func: InternPool.Index, |
| 60 | | mod: *Package.Module, |
| 45 | mod: *Module, |
| 61 | 46 | arg_index: u32, |
| 62 | 47 | args: []MCValue, |
| 63 | 48 | va_info: union { |
| ... | ... | @@ -76,9 +61,10 @@ src_loc: Zcu.LazySrcLoc, |
| 76 | 61 | eflags_inst: ?Air.Inst.Index = null, |
| 77 | 62 | |
| 78 | 63 | /// MIR Instructions |
| 79 | | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| 64 | mir_instructions: std.MultiArrayList(Mir.Inst) = .empty, |
| 80 | 65 | /// MIR extra data |
| 81 | 66 | mir_extra: std.ArrayListUnmanaged(u32) = .empty, |
| 67 | mir_table: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty, |
| 82 | 68 | |
| 83 | 69 | /// Byte offset within the source file of the ending curly. |
| 84 | 70 | end_di_line: u32, |
| ... | ... | @@ -87,10 +73,11 @@ end_di_column: u32, |
| 87 | 73 | /// The value is an offset into the `Function` `code` from the beginning. |
| 88 | 74 | /// To perform the reloc, write 32-bit signed little-endian integer |
| 89 | 75 | /// which is a relative jump, based on the address following the reloc. |
| 90 | | exitlude_jump_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty, |
| 76 | epilogue_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty, |
| 91 | 77 | |
| 92 | | const_tracking: ConstTrackingMap = .{}, |
| 93 | | inst_tracking: InstTrackingMap = .{}, |
| 78 | reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined, |
| 79 | const_tracking: ConstTrackingMap = .empty, |
| 80 | inst_tracking: InstTrackingMap = .empty, |
| 94 | 81 | |
| 95 | 82 | // Key is the block instruction |
| 96 | 83 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .empty, |
| ... | ... | @@ -100,27 +87,35 @@ register_manager: RegisterManager = .{}, |
| 100 | 87 | /// Generation of the current scope, increments by 1 for every entered scope. |
| 101 | 88 | scope_generation: u32 = 0, |
| 102 | 89 | |
| 103 | | frame_allocs: std.MultiArrayList(FrameAlloc) = .{}, |
| 90 | frame_allocs: std.MultiArrayList(FrameAlloc) = .empty, |
| 104 | 91 | free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .empty, |
| 105 | | frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{}, |
| 92 | frame_locs: std.MultiArrayList(Mir.FrameLoc) = .empty, |
| 106 | 93 | |
| 107 | 94 | loops: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { |
| 108 | 95 | /// The state to restore before branching. |
| 109 | 96 | state: State, |
| 110 | 97 | /// The branch target. |
| 111 | | jmp_target: Mir.Inst.Index, |
| 112 | | }) = .{}, |
| 113 | | |
| 114 | | /// Debug field, used to find bugs in the compiler. |
| 115 | | air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, |
| 98 | target: Mir.Inst.Index, |
| 99 | }) = .empty, |
| 100 | loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { |
| 101 | start: u31, |
| 102 | len: u11, |
| 103 | min: Value, |
| 104 | else_relocs: union(enum) { |
| 105 | @"unreachable", |
| 106 | forward: std.ArrayListUnmanaged(Mir.Inst.Index), |
| 107 | backward: Mir.Inst.Index, |
| 108 | }, |
| 109 | }) = .empty, |
| 116 | 110 | |
| 117 | | const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; |
| 111 | next_temp_index: Temp.Index = @enumFromInt(0), |
| 112 | temp_type: [Temp.Index.max]Type = undefined, |
| 118 | 113 | |
| 119 | 114 | const Owner = union(enum) { |
| 120 | 115 | nav_index: InternPool.Nav.Index, |
| 121 | 116 | lazy_sym: link.File.LazySymbol, |
| 122 | 117 | |
| 123 | | fn getSymbolIndex(owner: Owner, ctx: *Self) !u32 { |
| 118 | fn getSymbolIndex(owner: Owner, ctx: *CodeGen) !u32 { |
| 124 | 119 | const pt = ctx.pt; |
| 125 | 120 | switch (owner) { |
| 126 | 121 | .nav_index => |nav_index| if (ctx.bin_file.cast(.elf)) |elf_file| { |
| ... | ... | @@ -151,6 +146,9 @@ const Owner = union(enum) { |
| 151 | 146 | } |
| 152 | 147 | }; |
| 153 | 148 | |
| 149 | const MaskKind = enum(u1) { sign, all }; |
| 150 | const MaskInfo = packed struct { kind: MaskKind, inverted: bool, scalar: Memory.Size }; |
| 151 | |
| 154 | 152 | pub const MCValue = union(enum) { |
| 155 | 153 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. |
| 156 | 154 | /// TODO Look into deleting this tag and using `dead` instead, since every use |
| ... | ... | @@ -172,10 +170,16 @@ pub const MCValue = union(enum) { |
| 172 | 170 | register: Register, |
| 173 | 171 | /// The value is split across two registers. |
| 174 | 172 | register_pair: [2]Register, |
| 173 | /// The value is split across three registers. |
| 174 | register_triple: [3]Register, |
| 175 | /// The value is split across four registers. |
| 176 | register_quadruple: [4]Register, |
| 175 | 177 | /// The value is a constant offset from the value in a register. |
| 176 | 178 | register_offset: bits.RegisterOffset, |
| 177 | 179 | /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register. |
| 178 | 180 | register_overflow: struct { reg: Register, eflags: Condition }, |
| 181 | /// The value is a bool vector stored in a vector register with a different scalar type. |
| 182 | register_mask: struct { reg: Register, info: MaskInfo }, |
| 179 | 183 | /// The value is in memory at a hard-coded address. |
| 180 | 184 | /// If the type is a pointer, it means the pointer address is stored at this memory location. |
| 181 | 185 | memory: u64, |
| ... | ... | @@ -211,7 +215,7 @@ pub const MCValue = union(enum) { |
| 211 | 215 | /// Payload is a frame address. |
| 212 | 216 | lea_frame: bits.FrameAddr, |
| 213 | 217 | /// Supports integer_per_element abi |
| 214 | | elementwise_regs_then_frame: packed struct { regs: u3 = 0, frame_off: i29 = 0, frame_index: FrameIndex }, |
| 218 | elementwise_regs_then_frame: packed struct { regs: u3, frame_off: i29, frame_index: FrameIndex }, |
| 215 | 219 | /// This indicates that we have already allocated a frame index for this instruction, |
| 216 | 220 | /// but it has not been spilled there yet in the current control flow. |
| 217 | 221 | /// Payload is a frame index. |
| ... | ... | @@ -226,6 +230,7 @@ pub const MCValue = union(enum) { |
| 226 | 230 | .undef, |
| 227 | 231 | .immediate, |
| 228 | 232 | .register_offset, |
| 233 | .register_mask, |
| 229 | 234 | .eflags, |
| 230 | 235 | .register_overflow, |
| 231 | 236 | .lea_symbol, |
| ... | ... | @@ -239,6 +244,8 @@ pub const MCValue = union(enum) { |
| 239 | 244 | => false, |
| 240 | 245 | .register, |
| 241 | 246 | .register_pair, |
| 247 | .register_triple, |
| 248 | .register_quadruple, |
| 242 | 249 | .memory, |
| 243 | 250 | .load_symbol, |
| 244 | 251 | .load_got, |
| ... | ... | @@ -250,13 +257,21 @@ pub const MCValue = union(enum) { |
| 250 | 257 | }; |
| 251 | 258 | } |
| 252 | 259 | |
| 253 | | fn isMemory(mcv: MCValue) bool { |
| 260 | // hack around linker relocation bugs |
| 261 | fn isBase(mcv: MCValue) bool { |
| 254 | 262 | return switch (mcv) { |
| 255 | 263 | .memory, .indirect, .load_frame => true, |
| 256 | 264 | else => false, |
| 257 | 265 | }; |
| 258 | 266 | } |
| 259 | 267 | |
| 268 | fn isMemory(mcv: MCValue) bool { |
| 269 | return switch (mcv) { |
| 270 | .memory, .indirect, .load_frame, .load_symbol => true, |
| 271 | else => false, |
| 272 | }; |
| 273 | } |
| 274 | |
| 260 | 275 | fn isImmediate(mcv: MCValue) bool { |
| 261 | 276 | return switch (mcv) { |
| 262 | 277 | .immediate => true, |
| ... | ... | @@ -284,16 +299,23 @@ pub const MCValue = union(enum) { |
| 284 | 299 | .register => |reg| reg, |
| 285 | 300 | .register_offset, .indirect => |ro| ro.reg, |
| 286 | 301 | .register_overflow => |ro| ro.reg, |
| 302 | .register_mask => |rm| rm.reg, |
| 287 | 303 | else => null, |
| 288 | 304 | }; |
| 289 | 305 | } |
| 290 | 306 | |
| 291 | 307 | fn getRegs(mcv: *const MCValue) []const Register { |
| 292 | 308 | return switch (mcv.*) { |
| 293 | | .register => |*reg| @as(*const [1]Register, reg), |
| 294 | | .register_pair => |*regs| regs, |
| 295 | | .register_offset, .indirect => |*ro| @as(*const [1]Register, &ro.reg), |
| 296 | | .register_overflow => |*ro| @as(*const [1]Register, &ro.reg), |
| 309 | .register => |*reg| reg[0..1], |
| 310 | inline .register_pair, |
| 311 | .register_triple, |
| 312 | .register_quadruple, |
| 313 | => |*regs| regs, |
| 314 | inline .register_offset, |
| 315 | .indirect, |
| 316 | .register_overflow, |
| 317 | .register_mask, |
| 318 | => |*pl| (&pl.reg)[0..1], |
| 297 | 319 | else => &.{}, |
| 298 | 320 | }; |
| 299 | 321 | } |
| ... | ... | @@ -306,6 +328,13 @@ pub const MCValue = union(enum) { |
| 306 | 328 | }; |
| 307 | 329 | } |
| 308 | 330 | |
| 331 | fn isAddress(mcv: MCValue) bool { |
| 332 | return switch (mcv) { |
| 333 | .immediate, .register, .register_offset, .lea_frame => true, |
| 334 | else => false, |
| 335 | }; |
| 336 | } |
| 337 | |
| 309 | 338 | fn address(mcv: MCValue) MCValue { |
| 310 | 339 | return switch (mcv) { |
| 311 | 340 | .none, |
| ... | ... | @@ -316,8 +345,11 @@ pub const MCValue = union(enum) { |
| 316 | 345 | .eflags, |
| 317 | 346 | .register, |
| 318 | 347 | .register_pair, |
| 348 | .register_triple, |
| 349 | .register_quadruple, |
| 319 | 350 | .register_offset, |
| 320 | 351 | .register_overflow, |
| 352 | .register_mask, |
| 321 | 353 | .lea_symbol, |
| 322 | 354 | .lea_direct, |
| 323 | 355 | .lea_got, |
| ... | ... | @@ -348,7 +380,10 @@ pub const MCValue = union(enum) { |
| 348 | 380 | .undef, |
| 349 | 381 | .eflags, |
| 350 | 382 | .register_pair, |
| 383 | .register_triple, |
| 384 | .register_quadruple, |
| 351 | 385 | .register_overflow, |
| 386 | .register_mask, |
| 352 | 387 | .memory, |
| 353 | 388 | .indirect, |
| 354 | 389 | .load_direct, |
| ... | ... | @@ -383,7 +418,10 @@ pub const MCValue = union(enum) { |
| 383 | 418 | => unreachable, // not valid |
| 384 | 419 | .eflags, |
| 385 | 420 | .register_pair, |
| 421 | .register_triple, |
| 422 | .register_quadruple, |
| 386 | 423 | .register_overflow, |
| 424 | .register_mask, |
| 387 | 425 | .memory, |
| 388 | 426 | .indirect, |
| 389 | 427 | .load_direct, |
| ... | ... | @@ -410,7 +448,7 @@ pub const MCValue = union(enum) { |
| 410 | 448 | }; |
| 411 | 449 | } |
| 412 | 450 | |
| 413 | | fn mem(mcv: MCValue, function: *Self, size: Memory.Size) !Memory { |
| 451 | fn mem(mcv: MCValue, function: *CodeGen, mod_rm: Memory.Mod.Rm) !Memory { |
| 414 | 452 | return switch (mcv) { |
| 415 | 453 | .none, |
| 416 | 454 | .unreach, |
| ... | ... | @@ -420,8 +458,11 @@ pub const MCValue = union(enum) { |
| 420 | 458 | .eflags, |
| 421 | 459 | .register, |
| 422 | 460 | .register_pair, |
| 461 | .register_triple, |
| 462 | .register_quadruple, |
| 423 | 463 | .register_offset, |
| 424 | 464 | .register_overflow, |
| 465 | .register_mask, |
| 425 | 466 | .load_direct, |
| 426 | 467 | .lea_direct, |
| 427 | 468 | .load_got, |
| ... | ... | @@ -433,25 +474,31 @@ pub const MCValue = union(enum) { |
| 433 | 474 | .reserved_frame, |
| 434 | 475 | .lea_symbol, |
| 435 | 476 | => unreachable, |
| 436 | | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{ |
| 477 | .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{ |
| 437 | 478 | .base = .{ .reg = .ds }, |
| 438 | 479 | .mod = .{ .rm = .{ |
| 439 | | .size = size, |
| 440 | | .disp = small_addr, |
| 480 | .size = mod_rm.size, |
| 481 | .index = mod_rm.index, |
| 482 | .scale = mod_rm.scale, |
| 483 | .disp = small_addr + mod_rm.disp, |
| 441 | 484 | } }, |
| 442 | 485 | } else .{ .base = .{ .reg = .ds }, .mod = .{ .off = addr } }, |
| 443 | 486 | .indirect => |reg_off| .{ |
| 444 | | .base = .{ .reg = reg_off.reg }, |
| 487 | .base = .{ .reg = registerAlias(reg_off.reg, @divExact(function.target.ptrBitWidth(), 8)) }, |
| 445 | 488 | .mod = .{ .rm = .{ |
| 446 | | .size = size, |
| 447 | | .disp = reg_off.off, |
| 489 | .size = mod_rm.size, |
| 490 | .index = mod_rm.index, |
| 491 | .scale = mod_rm.scale, |
| 492 | .disp = reg_off.off + mod_rm.disp, |
| 448 | 493 | } }, |
| 449 | 494 | }, |
| 450 | 495 | .load_frame => |frame_addr| .{ |
| 451 | 496 | .base = .{ .frame = frame_addr.index }, |
| 452 | 497 | .mod = .{ .rm = .{ |
| 453 | | .size = size, |
| 454 | | .disp = frame_addr.off, |
| 498 | .size = mod_rm.size, |
| 499 | .index = mod_rm.index, |
| 500 | .scale = mod_rm.scale, |
| 501 | .disp = frame_addr.off + mod_rm.disp, |
| 455 | 502 | } }, |
| 456 | 503 | }, |
| 457 | 504 | .load_symbol => |sym_off| { |
| ... | ... | @@ -459,12 +506,14 @@ pub const MCValue = union(enum) { |
| 459 | 506 | return .{ |
| 460 | 507 | .base = .{ .reloc = sym_off.sym_index }, |
| 461 | 508 | .mod = .{ .rm = .{ |
| 462 | | .size = size, |
| 463 | | .disp = sym_off.off, |
| 509 | .size = mod_rm.size, |
| 510 | .index = mod_rm.index, |
| 511 | .scale = mod_rm.scale, |
| 512 | .disp = sym_off.off + mod_rm.disp, |
| 464 | 513 | } }, |
| 465 | 514 | }; |
| 466 | 515 | }, |
| 467 | | .air_ref => |ref| (try function.resolveInst(ref)).mem(function, size), |
| 516 | .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm), |
| 468 | 517 | }; |
| 469 | 518 | } |
| 470 | 519 | |
| ... | ... | @@ -480,12 +529,25 @@ pub const MCValue = union(enum) { |
| 480 | 529 | .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}), |
| 481 | 530 | inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}), |
| 482 | 531 | .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }), |
| 532 | .register_triple => |pl| try writer.print("{s}:{s}:{s}", .{ |
| 533 | @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]), |
| 534 | }), |
| 535 | .register_quadruple => |pl| try writer.print("{s}:{s}:{s}:{s}", .{ |
| 536 | @tagName(pl[3]), @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]), |
| 537 | }), |
| 483 | 538 | .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }), |
| 484 | 539 | .register_overflow => |pl| try writer.print("{s}:{s}", .{ |
| 485 | | @tagName(pl.eflags), @tagName(pl.reg), |
| 540 | @tagName(pl.eflags), |
| 541 | @tagName(pl.reg), |
| 486 | 542 | }), |
| 487 | | .load_symbol => |pl| try writer.print("[{} + 0x{x}]", .{ pl.sym_index, pl.off }), |
| 488 | | .lea_symbol => |pl| try writer.print("{} + 0x{x}", .{ pl.sym_index, pl.off }), |
| 543 | .register_mask => |pl| try writer.print("mask({s},{}):{c}{s}", .{ |
| 544 | @tagName(pl.info.kind), |
| 545 | pl.info.scalar, |
| 546 | @as(u8, if (pl.info.inverted) '!' else ' '), |
| 547 | @tagName(pl.reg), |
| 548 | }), |
| 549 | .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }), |
| 550 | .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }), |
| 489 | 551 | .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), |
| 490 | 552 | .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}), |
| 491 | 553 | .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), |
| ... | ... | @@ -494,7 +556,9 @@ pub const MCValue = union(enum) { |
| 494 | 556 | .load_tlv => |pl| try writer.print("[tlv:{d}]", .{pl}), |
| 495 | 557 | .lea_tlv => |pl| try writer.print("tlv:{d}", .{pl}), |
| 496 | 558 | .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }), |
| 497 | | .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{ pl.regs, pl.frame_index, pl.frame_off }), |
| 559 | .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{ |
| 560 | pl.regs, pl.frame_index, pl.frame_off, |
| 561 | }), |
| 498 | 562 | .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }), |
| 499 | 563 | .reserved_frame => |pl| try writer.print("(dead:{})", .{pl}), |
| 500 | 564 | .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}), |
| ... | ... | @@ -534,8 +598,11 @@ const InstTracking = struct { |
| 534 | 598 | .eflags, |
| 535 | 599 | .register, |
| 536 | 600 | .register_pair, |
| 601 | .register_triple, |
| 602 | .register_quadruple, |
| 537 | 603 | .register_offset, |
| 538 | 604 | .register_overflow, |
| 605 | .register_mask, |
| 539 | 606 | .indirect, |
| 540 | 607 | => .none, |
| 541 | 608 | }, .short = result }; |
| ... | ... | @@ -553,64 +620,48 @@ const InstTracking = struct { |
| 553 | 620 | return self.short.getCondition(); |
| 554 | 621 | } |
| 555 | 622 | |
| 556 | | fn spill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void { |
| 623 | fn spill(self: *InstTracking, cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 557 | 624 | if (std.meta.eql(self.long, self.short)) return; // Already spilled |
| 558 | 625 | // Allocate or reuse frame index |
| 559 | 626 | switch (self.long) { |
| 560 | | .none => self.long = try function.allocRegOrMem(inst, false), |
| 627 | .none => self.long = try cg.allocRegOrMem(inst, false), |
| 561 | 628 | .load_frame => {}, |
| 562 | 629 | .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } }, |
| 563 | 630 | else => unreachable, |
| 564 | 631 | } |
| 565 | | tracking_log.debug("spill %{d} from {} to {}", .{ inst, self.short, self.long }); |
| 566 | | try function.genCopy(function.typeOfIndex(inst), self.long, self.short, .{}); |
| 632 | tracking_log.debug("spill {} from {} to {}", .{ inst, self.short, self.long }); |
| 633 | try cg.genCopy(cg.typeOfIndex(inst), self.long, self.short, .{}); |
| 567 | 634 | } |
| 568 | 635 | |
| 569 | 636 | fn reuseFrame(self: *InstTracking) void { |
| 570 | | switch (self.long) { |
| 571 | | .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } }, |
| 572 | | else => {}, |
| 573 | | } |
| 574 | | self.short = switch (self.long) { |
| 575 | | .none, |
| 576 | | .unreach, |
| 577 | | .undef, |
| 578 | | .immediate, |
| 579 | | .memory, |
| 580 | | .load_direct, |
| 581 | | .lea_direct, |
| 582 | | .load_got, |
| 583 | | .lea_got, |
| 584 | | .load_tlv, |
| 585 | | .lea_tlv, |
| 586 | | .load_frame, |
| 587 | | .lea_frame, |
| 588 | | .load_symbol, |
| 589 | | .lea_symbol, |
| 590 | | => self.long, |
| 591 | | .dead, |
| 592 | | .eflags, |
| 593 | | .register, |
| 594 | | .register_pair, |
| 595 | | .register_offset, |
| 596 | | .register_overflow, |
| 597 | | .indirect, |
| 598 | | .elementwise_regs_then_frame, |
| 599 | | .reserved_frame, |
| 600 | | .air_ref, |
| 601 | | => unreachable, |
| 602 | | }; |
| 637 | self.* = .init(switch (self.long) { |
| 638 | .none => switch (self.short) { |
| 639 | .dead => .none, |
| 640 | else => |short| short, |
| 641 | }, |
| 642 | .reserved_frame => |index| .{ .load_frame = .{ .index = index } }, |
| 643 | else => |long| long, |
| 644 | }); |
| 603 | 645 | } |
| 604 | 646 | |
| 605 | | fn trackSpill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void { |
| 647 | fn trackSpill(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) !void { |
| 606 | 648 | try function.freeValue(self.short); |
| 607 | 649 | self.reuseFrame(); |
| 608 | | tracking_log.debug("%{d} => {} (spilled)", .{ inst, self.* }); |
| 650 | tracking_log.debug("{} => {} (spilled)", .{ inst, self.* }); |
| 609 | 651 | } |
| 610 | 652 | |
| 611 | 653 | fn verifyMaterialize(self: InstTracking, target: InstTracking) void { |
| 612 | 654 | switch (self.long) { |
| 613 | 655 | .none, |
| 656 | .load_frame, |
| 657 | .reserved_frame, |
| 658 | => switch (target.long) { |
| 659 | .none, |
| 660 | .load_frame, |
| 661 | .reserved_frame, |
| 662 | => {}, |
| 663 | else => unreachable, |
| 664 | }, |
| 614 | 665 | .unreach, |
| 615 | 666 | .undef, |
| 616 | 667 | .immediate, |
| ... | ... | @@ -625,21 +676,15 @@ const InstTracking = struct { |
| 625 | 676 | .load_symbol, |
| 626 | 677 | .lea_symbol, |
| 627 | 678 | => assert(std.meta.eql(self.long, target.long)), |
| 628 | | .load_frame, |
| 629 | | .reserved_frame, |
| 630 | | => switch (target.long) { |
| 631 | | .none, |
| 632 | | .load_frame, |
| 633 | | .reserved_frame, |
| 634 | | => {}, |
| 635 | | else => unreachable, |
| 636 | | }, |
| 637 | 679 | .dead, |
| 638 | 680 | .eflags, |
| 639 | 681 | .register, |
| 640 | 682 | .register_pair, |
| 683 | .register_triple, |
| 684 | .register_quadruple, |
| 641 | 685 | .register_offset, |
| 642 | 686 | .register_overflow, |
| 687 | .register_mask, |
| 643 | 688 | .indirect, |
| 644 | 689 | .elementwise_regs_then_frame, |
| 645 | 690 | .air_ref, |
| ... | ... | @@ -649,7 +694,7 @@ const InstTracking = struct { |
| 649 | 694 | |
| 650 | 695 | fn materialize( |
| 651 | 696 | self: *InstTracking, |
| 652 | | function: *Self, |
| 697 | function: *CodeGen, |
| 653 | 698 | inst: Air.Inst.Index, |
| 654 | 699 | target: InstTracking, |
| 655 | 700 | ) !void { |
| ... | ... | @@ -659,7 +704,7 @@ const InstTracking = struct { |
| 659 | 704 | |
| 660 | 705 | fn materializeUnsafe( |
| 661 | 706 | self: InstTracking, |
| 662 | | function: *Self, |
| 707 | function: *CodeGen, |
| 663 | 708 | inst: Air.Inst.Index, |
| 664 | 709 | target: InstTracking, |
| 665 | 710 | ) !void { |
| ... | ... | @@ -678,43 +723,42 @@ const InstTracking = struct { |
| 678 | 723 | else => target.long, |
| 679 | 724 | } else target.long; |
| 680 | 725 | self.short = target.short; |
| 681 | | tracking_log.debug("%{d} => {} (materialize)", .{ inst, self.* }); |
| 726 | tracking_log.debug("{} => {} (materialize)", .{ inst, self.* }); |
| 682 | 727 | } |
| 683 | 728 | |
| 684 | | fn resurrect(self: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void { |
| 729 | fn resurrect(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index, scope_generation: u32) !void { |
| 685 | 730 | switch (self.short) { |
| 686 | 731 | .dead => |die_generation| if (die_generation >= scope_generation) { |
| 687 | 732 | self.reuseFrame(); |
| 688 | | tracking_log.debug("%{d} => {} (resurrect)", .{ inst, self.* }); |
| 733 | try function.getValue(self.short, inst); |
| 734 | tracking_log.debug("{} => {} (resurrect)", .{ inst, self.* }); |
| 689 | 735 | }, |
| 690 | 736 | else => {}, |
| 691 | 737 | } |
| 692 | 738 | } |
| 693 | 739 | |
| 694 | | fn die(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void { |
| 740 | fn die(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) !void { |
| 695 | 741 | if (self.short == .dead) return; |
| 696 | 742 | try function.freeValue(self.short); |
| 743 | if (self.long == .none) self.long = self.short; |
| 697 | 744 | self.short = .{ .dead = function.scope_generation }; |
| 698 | | tracking_log.debug("%{d} => {} (death)", .{ inst, self.* }); |
| 745 | tracking_log.debug("{} => {} (death)", .{ inst, self.* }); |
| 699 | 746 | } |
| 700 | 747 | |
| 701 | 748 | fn reuse( |
| 702 | 749 | self: *InstTracking, |
| 703 | | function: *Self, |
| 750 | function: *CodeGen, |
| 704 | 751 | new_inst: ?Air.Inst.Index, |
| 705 | 752 | old_inst: Air.Inst.Index, |
| 706 | 753 | ) void { |
| 707 | 754 | self.short = .{ .dead = function.scope_generation }; |
| 708 | | if (new_inst) |inst| |
| 709 | | tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, self.*, old_inst }) |
| 710 | | else |
| 711 | | tracking_log.debug("tmp => {} (reuse %{d})", .{ self.*, old_inst }); |
| 755 | tracking_log.debug("{?} => {} (reuse {})", .{ new_inst, self.*, old_inst }); |
| 712 | 756 | } |
| 713 | 757 | |
| 714 | | fn liveOut(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void { |
| 758 | fn liveOut(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) void { |
| 715 | 759 | for (self.getRegs()) |reg| { |
| 716 | 760 | if (function.register_manager.isRegFree(reg)) { |
| 717 | | tracking_log.debug("%{d} => {} (live-out)", .{ inst, self.* }); |
| 761 | tracking_log.debug("{} => {} (live-out)", .{ inst, self.* }); |
| 718 | 762 | continue; |
| 719 | 763 | } |
| 720 | 764 | |
| ... | ... | @@ -741,28 +785,28 @@ const InstTracking = struct { |
| 741 | 785 | // Perform side-effects of freeValue manually. |
| 742 | 786 | function.register_manager.freeReg(reg); |
| 743 | 787 | |
| 744 | | tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, self.*, tracked_inst }); |
| 788 | tracking_log.debug("{} => {} (live-out {})", .{ inst, self.*, tracked_inst }); |
| 745 | 789 | } |
| 746 | 790 | } |
| 747 | 791 | |
| 748 | 792 | pub fn format( |
| 749 | | self: InstTracking, |
| 793 | tracking: InstTracking, |
| 750 | 794 | comptime _: []const u8, |
| 751 | 795 | _: std.fmt.FormatOptions, |
| 752 | 796 | writer: anytype, |
| 753 | 797 | ) @TypeOf(writer).Error!void { |
| 754 | | if (!std.meta.eql(self.long, self.short)) try writer.print("|{}| ", .{self.long}); |
| 755 | | try writer.print("{}", .{self.short}); |
| 798 | if (!std.meta.eql(tracking.long, tracking.short)) try writer.print("|{}| ", .{tracking.long}); |
| 799 | try writer.print("{}", .{tracking.short}); |
| 756 | 800 | } |
| 757 | 801 | }; |
| 758 | 802 | |
| 759 | 803 | const FrameAlloc = struct { |
| 760 | 804 | abi_size: u31, |
| 761 | 805 | spill_pad: u3, |
| 762 | | abi_align: Alignment, |
| 806 | abi_align: InternPool.Alignment, |
| 763 | 807 | ref_count: u16, |
| 764 | 808 | |
| 765 | | fn init(alloc_abi: struct { size: u64, pad: u3 = 0, alignment: Alignment }) FrameAlloc { |
| 809 | fn init(alloc_abi: struct { size: u64, pad: u3 = 0, alignment: InternPool.Alignment }) FrameAlloc { |
| 766 | 810 | return .{ |
| 767 | 811 | .abi_size = @intCast(alloc_abi.size), |
| 768 | 812 | .spill_pad = alloc_abi.pad, |
| ... | ... | @@ -779,14 +823,14 @@ const FrameAlloc = struct { |
| 779 | 823 | fn initSpill(ty: Type, zcu: *Zcu) FrameAlloc { |
| 780 | 824 | const abi_size = ty.abiSize(zcu); |
| 781 | 825 | const spill_size = if (abi_size < 8) |
| 782 | | math.ceilPowerOfTwoAssert(u64, abi_size) |
| 826 | std.math.ceilPowerOfTwoAssert(u64, abi_size) |
| 783 | 827 | else |
| 784 | 828 | std.mem.alignForward(u64, abi_size, 8); |
| 785 | 829 | return init(.{ |
| 786 | 830 | .size = spill_size, |
| 787 | 831 | .pad = @intCast(spill_size - abi_size), |
| 788 | 832 | .alignment = ty.abiAlignment(zcu).maxStrict( |
| 789 | | Alignment.fromNonzeroByteUnits(@min(spill_size, 8)), |
| 833 | .fromNonzeroByteUnits(@min(spill_size, 8)), |
| 790 | 834 | ), |
| 791 | 835 | }); |
| 792 | 836 | } |
| ... | ... | @@ -808,7 +852,7 @@ const BlockData = struct { |
| 808 | 852 | } |
| 809 | 853 | }; |
| 810 | 854 | |
| 811 | | const Self = @This(); |
| 855 | const CodeGen = @This(); |
| 812 | 856 | |
| 813 | 857 | pub fn generate( |
| 814 | 858 | bin_file: *link.File, |
| ... | ... | @@ -819,16 +863,16 @@ pub fn generate( |
| 819 | 863 | liveness: Liveness, |
| 820 | 864 | code: *std.ArrayListUnmanaged(u8), |
| 821 | 865 | debug_output: link.File.DebugInfoOutput, |
| 822 | | ) CodeGenError!void { |
| 866 | ) codegen.CodeGenError!void { |
| 823 | 867 | const zcu = pt.zcu; |
| 824 | 868 | const comp = zcu.comp; |
| 825 | 869 | const gpa = zcu.gpa; |
| 826 | 870 | const ip = &zcu.intern_pool; |
| 827 | 871 | const func = zcu.funcInfo(func_index); |
| 828 | | const fn_type = Type.fromInterned(func.ty); |
| 872 | const fn_type: Type = .fromInterned(func.ty); |
| 829 | 873 | const mod = zcu.navFileScope(func.owner_nav).mod; |
| 830 | 874 | |
| 831 | | var function: Self = .{ |
| 875 | var function: CodeGen = .{ |
| 832 | 876 | .gpa = gpa, |
| 833 | 877 | .pt = pt, |
| 834 | 878 | .air = air, |
| ... | ... | @@ -853,14 +897,21 @@ pub fn generate( |
| 853 | 897 | function.free_frame_indices.deinit(gpa); |
| 854 | 898 | function.frame_locs.deinit(gpa); |
| 855 | 899 | function.loops.deinit(gpa); |
| 900 | function.loop_switches.deinit(gpa); |
| 856 | 901 | var block_it = function.blocks.valueIterator(); |
| 857 | 902 | while (block_it.next()) |block| block.deinit(gpa); |
| 858 | 903 | function.blocks.deinit(gpa); |
| 859 | 904 | function.inst_tracking.deinit(gpa); |
| 860 | 905 | function.const_tracking.deinit(gpa); |
| 861 | | function.exitlude_jump_relocs.deinit(gpa); |
| 906 | function.epilogue_relocs.deinit(gpa); |
| 862 | 907 | function.mir_instructions.deinit(gpa); |
| 863 | 908 | function.mir_extra.deinit(gpa); |
| 909 | function.mir_table.deinit(gpa); |
| 910 | } |
| 911 | try function.inst_tracking.ensureTotalCapacity(gpa, Temp.Index.max); |
| 912 | for (0..Temp.Index.max) |temp_index| { |
| 913 | const temp: Temp.Index = @enumFromInt(temp_index); |
| 914 | function.inst_tracking.putAssumeCapacityNoClobber(temp.toIndex(), .init(.none)); |
| 864 | 915 | } |
| 865 | 916 | |
| 866 | 917 | wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)}); |
| ... | ... | @@ -868,15 +919,14 @@ pub fn generate( |
| 868 | 919 | try function.frame_allocs.resize(gpa, FrameIndex.named_count); |
| 869 | 920 | function.frame_allocs.set( |
| 870 | 921 | @intFromEnum(FrameIndex.stack_frame), |
| 871 | | FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }), |
| 922 | .init(.{ .size = 0, .alignment = .@"1" }), |
| 872 | 923 | ); |
| 873 | 924 | function.frame_allocs.set( |
| 874 | 925 | @intFromEnum(FrameIndex.call_frame), |
| 875 | | FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }), |
| 926 | .init(.{ .size = 0, .alignment = .@"1" }), |
| 876 | 927 | ); |
| 877 | 928 | |
| 878 | 929 | const fn_info = zcu.typeToFunc(fn_type).?; |
| 879 | | const cc = abi.resolveCallingConvention(fn_info.cc, function.target.*); |
| 880 | 930 | var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) { |
| 881 | 931 | error.CodegenFail => return error.CodegenFail, |
| 882 | 932 | else => |e| return e, |
| ... | ... | @@ -885,25 +935,24 @@ pub fn generate( |
| 885 | 935 | |
| 886 | 936 | function.args = call_info.args; |
| 887 | 937 | function.ret_mcv = call_info.return_value; |
| 888 | | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{ |
| 938 | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), .init(.{ |
| 889 | 939 | .size = Type.usize.abiSize(zcu), |
| 890 | 940 | .alignment = Type.usize.abiAlignment(zcu).min(call_info.stack_align), |
| 891 | 941 | })); |
| 892 | | function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{ |
| 942 | function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), .init(.{ |
| 893 | 943 | .size = Type.usize.abiSize(zcu), |
| 894 | | .alignment = Alignment.min( |
| 895 | | call_info.stack_align, |
| 896 | | Alignment.fromNonzeroByteUnits(function.target.stackAlignment()), |
| 944 | .alignment = call_info.stack_align.min( |
| 945 | .fromNonzeroByteUnits(function.target.stackAlignment()), |
| 897 | 946 | ), |
| 898 | 947 | })); |
| 899 | 948 | function.frame_allocs.set( |
| 900 | 949 | @intFromEnum(FrameIndex.args_frame), |
| 901 | | FrameAlloc.init(.{ |
| 950 | .init(.{ |
| 902 | 951 | .size = call_info.stack_byte_count, |
| 903 | 952 | .alignment = call_info.stack_align, |
| 904 | 953 | }), |
| 905 | 954 | ); |
| 906 | | function.va_info = switch (cc) { |
| 955 | function.va_info = switch (fn_info.cc) { |
| 907 | 956 | else => undefined, |
| 908 | 957 | .x86_64_sysv => .{ .sysv = .{ |
| 909 | 958 | .gp_count = call_info.gp_count, |
| ... | ... | @@ -923,6 +972,7 @@ pub fn generate( |
| 923 | 972 | var mir: Mir = .{ |
| 924 | 973 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 925 | 974 | .extra = try function.mir_extra.toOwnedSlice(gpa), |
| 975 | .table = try function.mir_table.toOwnedSlice(gpa), |
| 926 | 976 | .frame_locs = function.frame_locs.toOwnedSlice(), |
| 927 | 977 | }; |
| 928 | 978 | defer mir.deinit(gpa); |
| ... | ... | @@ -931,9 +981,10 @@ pub fn generate( |
| 931 | 981 | .air = function.air, |
| 932 | 982 | .lower = .{ |
| 933 | 983 | .bin_file = bin_file, |
| 984 | .target = function.target, |
| 934 | 985 | .allocator = gpa, |
| 935 | 986 | .mir = mir, |
| 936 | | .cc = cc, |
| 987 | .cc = fn_info.cc, |
| 937 | 988 | .src_loc = src_loc, |
| 938 | 989 | .output_mode = comp.config.output_mode, |
| 939 | 990 | .link_mode = comp.config.link_mode, |
| ... | ... | @@ -956,7 +1007,6 @@ pub fn generate( |
| 956 | 1007 | }, |
| 957 | 1008 | .prev_di_pc = 0, |
| 958 | 1009 | }; |
| 959 | | defer emit.deinit(); |
| 960 | 1010 | emit.emitMir() catch |err| switch (err) { |
| 961 | 1011 | error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?), |
| 962 | 1012 | |
| ... | ... | @@ -972,12 +1022,12 @@ pub fn generateLazy( |
| 972 | 1022 | lazy_sym: link.File.LazySymbol, |
| 973 | 1023 | code: *std.ArrayListUnmanaged(u8), |
| 974 | 1024 | debug_output: link.File.DebugInfoOutput, |
| 975 | | ) CodeGenError!void { |
| 1025 | ) codegen.CodeGenError!void { |
| 976 | 1026 | const comp = bin_file.comp; |
| 977 | 1027 | const gpa = comp.gpa; |
| 978 | 1028 | // This function is for generating global code, so we use the root module. |
| 979 | 1029 | const mod = comp.root_mod; |
| 980 | | var function: Self = .{ |
| 1030 | var function: CodeGen = .{ |
| 981 | 1031 | .gpa = gpa, |
| 982 | 1032 | .pt = pt, |
| 983 | 1033 | .air = undefined, |
| ... | ... | @@ -1000,6 +1050,7 @@ pub fn generateLazy( |
| 1000 | 1050 | defer { |
| 1001 | 1051 | function.mir_instructions.deinit(gpa); |
| 1002 | 1052 | function.mir_extra.deinit(gpa); |
| 1053 | function.mir_table.deinit(gpa); |
| 1003 | 1054 | } |
| 1004 | 1055 | |
| 1005 | 1056 | function.genLazy(lazy_sym) catch |err| switch (err) { |
| ... | ... | @@ -1011,6 +1062,7 @@ pub fn generateLazy( |
| 1011 | 1062 | var mir: Mir = .{ |
| 1012 | 1063 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 1013 | 1064 | .extra = try function.mir_extra.toOwnedSlice(gpa), |
| 1065 | .table = try function.mir_table.toOwnedSlice(gpa), |
| 1014 | 1066 | .frame_locs = function.frame_locs.toOwnedSlice(), |
| 1015 | 1067 | }; |
| 1016 | 1068 | defer mir.deinit(gpa); |
| ... | ... | @@ -1019,9 +1071,10 @@ pub fn generateLazy( |
| 1019 | 1071 | .air = function.air, |
| 1020 | 1072 | .lower = .{ |
| 1021 | 1073 | .bin_file = bin_file, |
| 1074 | .target = function.target, |
| 1022 | 1075 | .allocator = gpa, |
| 1023 | 1076 | .mir = mir, |
| 1024 | | .cc = abi.resolveCallingConvention(.auto, function.target.*), |
| 1077 | .cc = .auto, |
| 1025 | 1078 | .src_loc = src_loc, |
| 1026 | 1079 | .output_mode = comp.config.output_mode, |
| 1027 | 1080 | .link_mode = comp.config.link_mode, |
| ... | ... | @@ -1036,7 +1089,6 @@ pub fn generateLazy( |
| 1036 | 1089 | .prev_di_loc = undefined, // no debug info yet |
| 1037 | 1090 | .prev_di_pc = undefined, // no debug info yet |
| 1038 | 1091 | }; |
| 1039 | | defer emit.deinit(); |
| 1040 | 1092 | emit.emitMir() catch |err| switch (err) { |
| 1041 | 1093 | error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?), |
| 1042 | 1094 | error.InvalidInstruction => return function.fail("failed to find a viable x86 instruction (Zig compiler bug)", .{}), |
| ... | ... | @@ -1065,7 +1117,7 @@ fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Format |
| 1065 | 1117 | } |
| 1066 | 1118 | |
| 1067 | 1119 | const FormatAirData = struct { |
| 1068 | | self: *Self, |
| 1120 | self: *CodeGen, |
| 1069 | 1121 | inst: Air.Inst.Index, |
| 1070 | 1122 | }; |
| 1071 | 1123 | fn formatAir( |
| ... | ... | @@ -1081,12 +1133,12 @@ fn formatAir( |
| 1081 | 1133 | data.self.liveness, |
| 1082 | 1134 | ); |
| 1083 | 1135 | } |
| 1084 | | fn fmtAir(self: *Self, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { |
| 1136 | fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { |
| 1085 | 1137 | return .{ .data = .{ .self = self, .inst = inst } }; |
| 1086 | 1138 | } |
| 1087 | 1139 | |
| 1088 | 1140 | const FormatWipMirData = struct { |
| 1089 | | self: *Self, |
| 1141 | self: *CodeGen, |
| 1090 | 1142 | inst: Mir.Inst.Index, |
| 1091 | 1143 | }; |
| 1092 | 1144 | fn formatWipMir( |
| ... | ... | @@ -1099,10 +1151,12 @@ fn formatWipMir( |
| 1099 | 1151 | const mod = comp.root_mod; |
| 1100 | 1152 | var lower: Lower = .{ |
| 1101 | 1153 | .bin_file = data.self.bin_file, |
| 1154 | .target = data.self.target, |
| 1102 | 1155 | .allocator = data.self.gpa, |
| 1103 | 1156 | .mir = .{ |
| 1104 | 1157 | .instructions = data.self.mir_instructions.slice(), |
| 1105 | 1158 | .extra = data.self.mir_extra.items, |
| 1159 | .table = data.self.mir_table.items, |
| 1106 | 1160 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), |
| 1107 | 1161 | }, |
| 1108 | 1162 | .cc = .auto, |
| ... | ... | @@ -1169,14 +1223,14 @@ fn formatWipMir( |
| 1169 | 1223 | lower.mir.extraData(Mir.Imm64, mir_inst.data.ai.i).data.decode(), |
| 1170 | 1224 | }), |
| 1171 | 1225 | .pseudo_dbg_local_as => { |
| 1172 | | const mem_op: Instruction.Operand = .{ .mem = .initSib(.qword, .{ |
| 1226 | const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ |
| 1173 | 1227 | .base = .{ .reloc = mir_inst.data.as.sym_index }, |
| 1174 | 1228 | }) }; |
| 1175 | 1229 | try writer.print(" {}, {}", .{ mir_inst.data.as.air_inst, mem_op.fmt(.m) }); |
| 1176 | 1230 | }, |
| 1177 | 1231 | .pseudo_dbg_local_aso => { |
| 1178 | 1232 | const sym_off = lower.mir.extraData(bits.SymbolOffset, mir_inst.data.ax.payload).data; |
| 1179 | | const mem_op: Instruction.Operand = .{ .mem = .initSib(.qword, .{ |
| 1233 | const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ |
| 1180 | 1234 | .base = .{ .reloc = sym_off.sym_index }, |
| 1181 | 1235 | .disp = sym_off.off, |
| 1182 | 1236 | }) }; |
| ... | ... | @@ -1184,7 +1238,7 @@ fn formatWipMir( |
| 1184 | 1238 | }, |
| 1185 | 1239 | .pseudo_dbg_local_aro => { |
| 1186 | 1240 | const air_off = lower.mir.extraData(Mir.AirOffset, mir_inst.data.rx.payload).data; |
| 1187 | | const mem_op: Instruction.Operand = .{ .mem = .initSib(.qword, .{ |
| 1241 | const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ |
| 1188 | 1242 | .base = .{ .reg = mir_inst.data.rx.r1 }, |
| 1189 | 1243 | .disp = air_off.off, |
| 1190 | 1244 | }) }; |
| ... | ... | @@ -1192,14 +1246,14 @@ fn formatWipMir( |
| 1192 | 1246 | }, |
| 1193 | 1247 | .pseudo_dbg_local_af => { |
| 1194 | 1248 | const frame_addr = lower.mir.extraData(bits.FrameAddr, mir_inst.data.ax.payload).data; |
| 1195 | | const mem_op: Instruction.Operand = .{ .mem = .initSib(.qword, .{ |
| 1249 | const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ |
| 1196 | 1250 | .base = .{ .frame = frame_addr.index }, |
| 1197 | 1251 | .disp = frame_addr.off, |
| 1198 | 1252 | }) }; |
| 1199 | | try writer.print(" {}, {d}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) }); |
| 1253 | try writer.print(" {}, {}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) }); |
| 1200 | 1254 | }, |
| 1201 | 1255 | .pseudo_dbg_local_am => { |
| 1202 | | const mem_op: Instruction.Operand = .{ |
| 1256 | const mem_op: encoder.Instruction.Operand = .{ |
| 1203 | 1257 | .mem = lower.mir.extraData(Mir.Memory, mir_inst.data.ax.payload).data.decode(), |
| 1204 | 1258 | }; |
| 1205 | 1259 | try writer.print(" {}, {}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) }); |
| ... | ... | @@ -1207,12 +1261,12 @@ fn formatWipMir( |
| 1207 | 1261 | } |
| 1208 | 1262 | } |
| 1209 | 1263 | } |
| 1210 | | fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) { |
| 1264 | fn fmtWipMir(self: *CodeGen, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) { |
| 1211 | 1265 | return .{ .data = .{ .self = self, .inst = inst } }; |
| 1212 | 1266 | } |
| 1213 | 1267 | |
| 1214 | 1268 | const FormatTrackingData = struct { |
| 1215 | | self: *Self, |
| 1269 | self: *CodeGen, |
| 1216 | 1270 | }; |
| 1217 | 1271 | fn formatTracking( |
| 1218 | 1272 | data: FormatTrackingData, |
| ... | ... | @@ -1221,28 +1275,28 @@ fn formatTracking( |
| 1221 | 1275 | writer: anytype, |
| 1222 | 1276 | ) @TypeOf(writer).Error!void { |
| 1223 | 1277 | var it = data.self.inst_tracking.iterator(); |
| 1224 | | while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* }); |
| 1278 | while (it.next()) |entry| try writer.print("\n{} = {}", .{ entry.key_ptr.*, entry.value_ptr.* }); |
| 1225 | 1279 | } |
| 1226 | | fn fmtTracking(self: *Self) std.fmt.Formatter(formatTracking) { |
| 1280 | fn fmtTracking(self: *CodeGen) std.fmt.Formatter(formatTracking) { |
| 1227 | 1281 | return .{ .data = .{ .self = self } }; |
| 1228 | 1282 | } |
| 1229 | 1283 | |
| 1230 | | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 1284 | fn addInst(self: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 1231 | 1285 | const gpa = self.gpa; |
| 1232 | 1286 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| 1233 | 1287 | const result_index: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 1234 | 1288 | self.mir_instructions.appendAssumeCapacity(inst); |
| 1235 | | wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}); |
| 1289 | if (inst.ops != .pseudo_dead_none) wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}); |
| 1236 | 1290 | return result_index; |
| 1237 | 1291 | } |
| 1238 | 1292 | |
| 1239 | | fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 { |
| 1293 | fn addExtra(self: *CodeGen, extra: anytype) Allocator.Error!u32 { |
| 1240 | 1294 | const fields = std.meta.fields(@TypeOf(extra)); |
| 1241 | 1295 | try self.mir_extra.ensureUnusedCapacity(self.gpa, fields.len); |
| 1242 | 1296 | return self.addExtraAssumeCapacity(extra); |
| 1243 | 1297 | } |
| 1244 | 1298 | |
| 1245 | | fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 1299 | fn addExtraAssumeCapacity(self: *CodeGen, extra: anytype) u32 { |
| 1246 | 1300 | const fields = std.meta.fields(@TypeOf(extra)); |
| 1247 | 1301 | const result: u32 = @intCast(self.mir_extra.items.len); |
| 1248 | 1302 | inline for (fields) |field| { |
| ... | ... | @@ -1256,9 +1310,83 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 1256 | 1310 | return result; |
| 1257 | 1311 | } |
| 1258 | 1312 | |
| 1313 | fn asmOps(self: *CodeGen, tag: Mir.Inst.FixedTag, ops: [4]Operand) !void { |
| 1314 | return switch (ops[0]) { |
| 1315 | .none => self.asmOpOnly(tag), |
| 1316 | .reg => |reg0| switch (ops[1]) { |
| 1317 | .none => self.asmRegister(tag, reg0), |
| 1318 | .reg => |reg1| switch (ops[2]) { |
| 1319 | .none => self.asmRegisterRegister(tag, reg0, reg1), |
| 1320 | .reg => |reg2| switch (ops[3]) { |
| 1321 | .none => self.asmRegisterRegisterRegister(tag, reg0, reg1, reg2), |
| 1322 | .reg => |reg3| self.asmRegisterRegisterRegisterRegister(tag, reg0, reg1, reg2, reg3), |
| 1323 | .imm => |imm3| self.asmRegisterRegisterRegisterImmediate(tag, reg0, reg1, reg2, imm3), |
| 1324 | else => error.InvalidInstruction, |
| 1325 | }, |
| 1326 | .mem => |mem2| switch (ops[3]) { |
| 1327 | .none => self.asmRegisterRegisterMemory(tag, reg0, reg1, mem2), |
| 1328 | .reg => |reg3| self.asmRegisterRegisterMemoryRegister(tag, reg0, reg1, mem2, reg3), |
| 1329 | .imm => |imm3| self.asmRegisterRegisterMemoryImmediate(tag, reg0, reg1, mem2, imm3), |
| 1330 | else => error.InvalidInstruction, |
| 1331 | }, |
| 1332 | .imm => |imm2| switch (ops[3]) { |
| 1333 | .none => self.asmRegisterRegisterImmediate(tag, reg0, reg1, imm2), |
| 1334 | else => error.InvalidInstruction, |
| 1335 | }, |
| 1336 | else => error.InvalidInstruction, |
| 1337 | }, |
| 1338 | .mem => |mem1| switch (ops[2]) { |
| 1339 | .none => self.asmRegisterMemory(tag, reg0, mem1), |
| 1340 | .reg => |reg2| switch (ops[3]) { |
| 1341 | .none => self.asmRegisterMemoryRegister(tag, reg0, mem1, reg2), |
| 1342 | else => error.InvalidInstruction, |
| 1343 | }, |
| 1344 | .imm => |imm2| switch (ops[3]) { |
| 1345 | .none => self.asmRegisterMemoryImmediate(tag, reg0, mem1, imm2), |
| 1346 | else => error.InvalidInstruction, |
| 1347 | }, |
| 1348 | else => error.InvalidInstruction, |
| 1349 | }, |
| 1350 | .imm => |imm1| switch (ops[2]) { |
| 1351 | .none => self.asmRegisterImmediate(tag, reg0, imm1), |
| 1352 | else => error.InvalidInstruction, |
| 1353 | }, |
| 1354 | else => error.InvalidInstruction, |
| 1355 | }, |
| 1356 | .mem => |mem0| switch (ops[1]) { |
| 1357 | .none => self.asmMemory(tag, mem0), |
| 1358 | .reg => |reg1| switch (ops[2]) { |
| 1359 | .none => self.asmMemoryRegister(tag, mem0, reg1), |
| 1360 | .reg => |reg2| switch (ops[3]) { |
| 1361 | .none => self.asmMemoryRegisterRegister(tag, mem0, reg1, reg2), |
| 1362 | else => error.InvalidInstruction, |
| 1363 | }, |
| 1364 | .imm => |imm2| switch (ops[3]) { |
| 1365 | .none => self.asmMemoryRegisterImmediate(tag, mem0, reg1, imm2), |
| 1366 | else => error.InvalidInstruction, |
| 1367 | }, |
| 1368 | else => error.InvalidInstruction, |
| 1369 | }, |
| 1370 | .imm => |imm1| switch (ops[2]) { |
| 1371 | .none => self.asmMemoryImmediate(tag, mem0, imm1), |
| 1372 | else => error.InvalidInstruction, |
| 1373 | }, |
| 1374 | else => error.InvalidInstruction, |
| 1375 | }, |
| 1376 | .imm => |imm0| switch (ops[1]) { |
| 1377 | .none => self.asmImmediate(tag, imm0), |
| 1378 | else => error.InvalidInstruction, |
| 1379 | }, |
| 1380 | .inst => |inst0| switch (ops[1]) { |
| 1381 | .none => self.asmReloc(tag, inst0), |
| 1382 | else => error.InvalidInstruction, |
| 1383 | }, |
| 1384 | }; |
| 1385 | } |
| 1386 | |
| 1259 | 1387 | /// A `cc` of `.z_and_np` clobbers `reg2`! |
| 1260 | | fn asmCmovccRegisterRegister(self: *Self, cc: Condition, reg1: Register, reg2: Register) !void { |
| 1261 | | _ = try self.addInst(.{ |
| 1388 | fn asmCmovccRegisterRegister(self: *CodeGen, cc: Condition, reg1: Register, reg2: Register) !void { |
| 1389 | if (self.hasFeature(.cmov)) _ = try self.addInst(.{ |
| 1262 | 1390 | .tag = switch (cc) { |
| 1263 | 1391 | else => .cmov, |
| 1264 | 1392 | .z_and_np, .nz_or_p => .pseudo, |
| ... | ... | @@ -1270,18 +1398,22 @@ fn asmCmovccRegisterRegister(self: *Self, cc: Condition, reg1: Register, reg2: R |
| 1270 | 1398 | }, |
| 1271 | 1399 | .data = .{ .rr = .{ |
| 1272 | 1400 | .fixes = switch (cc) { |
| 1273 | | else => Mir.Inst.Fixes.fromCondition(cc), |
| 1401 | else => .fromCondition(cc), |
| 1274 | 1402 | .z_and_np, .nz_or_p => ._, |
| 1275 | 1403 | }, |
| 1276 | 1404 | .r1 = reg1, |
| 1277 | 1405 | .r2 = reg2, |
| 1278 | 1406 | } }, |
| 1279 | | }); |
| 1407 | }) else { |
| 1408 | const reloc = try self.asmJccReloc(cc.negate(), undefined); |
| 1409 | try self.asmRegisterRegister(.{ ._, .mov }, reg1, reg2); |
| 1410 | self.performReloc(reloc); |
| 1411 | } |
| 1280 | 1412 | } |
| 1281 | 1413 | |
| 1282 | 1414 | /// A `cc` of `.z_and_np` is not supported by this encoding! |
| 1283 | | fn asmCmovccRegisterMemory(self: *Self, cc: Condition, reg: Register, m: Memory) !void { |
| 1284 | | _ = try self.addInst(.{ |
| 1415 | fn asmCmovccRegisterMemory(self: *CodeGen, cc: Condition, reg: Register, m: Memory) !void { |
| 1416 | if (self.hasFeature(.cmov)) _ = try self.addInst(.{ |
| 1285 | 1417 | .tag = switch (cc) { |
| 1286 | 1418 | else => .cmov, |
| 1287 | 1419 | .z_and_np => unreachable, |
| ... | ... | @@ -1294,17 +1426,21 @@ fn asmCmovccRegisterMemory(self: *Self, cc: Condition, reg: Register, m: Memory) |
| 1294 | 1426 | }, |
| 1295 | 1427 | .data = .{ .rx = .{ |
| 1296 | 1428 | .fixes = switch (cc) { |
| 1297 | | else => Mir.Inst.Fixes.fromCondition(cc), |
| 1429 | else => .fromCondition(cc), |
| 1298 | 1430 | .z_and_np => unreachable, |
| 1299 | 1431 | .nz_or_p => ._, |
| 1300 | 1432 | }, |
| 1301 | 1433 | .r1 = reg, |
| 1302 | 1434 | .payload = try self.addExtra(Mir.Memory.encode(m)), |
| 1303 | 1435 | } }, |
| 1304 | | }); |
| 1436 | }) else { |
| 1437 | const reloc = try self.asmJccReloc(cc.negate(), undefined); |
| 1438 | try self.asmRegisterMemory(.{ ._, .mov }, reg, m); |
| 1439 | self.performReloc(reloc); |
| 1440 | } |
| 1305 | 1441 | } |
| 1306 | 1442 | |
| 1307 | | fn asmSetccRegister(self: *Self, cc: Condition, reg: Register) !void { |
| 1443 | fn asmSetccRegister(self: *CodeGen, cc: Condition, reg: Register) !void { |
| 1308 | 1444 | _ = try self.addInst(.{ |
| 1309 | 1445 | .tag = switch (cc) { |
| 1310 | 1446 | else => .set, |
| ... | ... | @@ -1317,7 +1453,7 @@ fn asmSetccRegister(self: *Self, cc: Condition, reg: Register) !void { |
| 1317 | 1453 | }, |
| 1318 | 1454 | .data = switch (cc) { |
| 1319 | 1455 | else => .{ .r = .{ |
| 1320 | | .fixes = Mir.Inst.Fixes.fromCondition(cc), |
| 1456 | .fixes = .fromCondition(cc), |
| 1321 | 1457 | .r1 = reg, |
| 1322 | 1458 | } }, |
| 1323 | 1459 | .z_and_np, .nz_or_p => .{ .rr = .{ |
| ... | ... | @@ -1328,7 +1464,7 @@ fn asmSetccRegister(self: *Self, cc: Condition, reg: Register) !void { |
| 1328 | 1464 | }); |
| 1329 | 1465 | } |
| 1330 | 1466 | |
| 1331 | | fn asmSetccMemory(self: *Self, cc: Condition, m: Memory) !void { |
| 1467 | fn asmSetccMemory(self: *CodeGen, cc: Condition, m: Memory) !void { |
| 1332 | 1468 | const payload = try self.addExtra(Mir.Memory.encode(m)); |
| 1333 | 1469 | _ = try self.addInst(.{ |
| 1334 | 1470 | .tag = switch (cc) { |
| ... | ... | @@ -1342,7 +1478,7 @@ fn asmSetccMemory(self: *Self, cc: Condition, m: Memory) !void { |
| 1342 | 1478 | }, |
| 1343 | 1479 | .data = switch (cc) { |
| 1344 | 1480 | else => .{ .x = .{ |
| 1345 | | .fixes = Mir.Inst.Fixes.fromCondition(cc), |
| 1481 | .fixes = .fromCondition(cc), |
| 1346 | 1482 | .payload = payload, |
| 1347 | 1483 | } }, |
| 1348 | 1484 | .z_and_np, .nz_or_p => .{ .rx = .{ |
| ... | ... | @@ -1353,7 +1489,7 @@ fn asmSetccMemory(self: *Self, cc: Condition, m: Memory) !void { |
| 1353 | 1489 | }); |
| 1354 | 1490 | } |
| 1355 | 1491 | |
| 1356 | | fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index { |
| 1492 | fn asmJmpReloc(self: *CodeGen, target: Mir.Inst.Index) !Mir.Inst.Index { |
| 1357 | 1493 | return self.addInst(.{ |
| 1358 | 1494 | .tag = .jmp, |
| 1359 | 1495 | .ops = .inst, |
| ... | ... | @@ -1363,7 +1499,7 @@ fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index { |
| 1363 | 1499 | }); |
| 1364 | 1500 | } |
| 1365 | 1501 | |
| 1366 | | fn asmJccReloc(self: *Self, cc: Condition, target: Mir.Inst.Index) !Mir.Inst.Index { |
| 1502 | fn asmJccReloc(self: *CodeGen, cc: Condition, target: Mir.Inst.Index) !Mir.Inst.Index { |
| 1367 | 1503 | return self.addInst(.{ |
| 1368 | 1504 | .tag = switch (cc) { |
| 1369 | 1505 | else => .j, |
| ... | ... | @@ -1376,7 +1512,7 @@ fn asmJccReloc(self: *Self, cc: Condition, target: Mir.Inst.Index) !Mir.Inst.Ind |
| 1376 | 1512 | }, |
| 1377 | 1513 | .data = .{ .inst = .{ |
| 1378 | 1514 | .fixes = switch (cc) { |
| 1379 | | else => Mir.Inst.Fixes.fromCondition(cc), |
| 1515 | else => .fromCondition(cc), |
| 1380 | 1516 | .z_and_np, .nz_or_p => ._, |
| 1381 | 1517 | }, |
| 1382 | 1518 | .inst = target, |
| ... | ... | @@ -1384,7 +1520,7 @@ fn asmJccReloc(self: *Self, cc: Condition, target: Mir.Inst.Index) !Mir.Inst.Ind |
| 1384 | 1520 | }); |
| 1385 | 1521 | } |
| 1386 | 1522 | |
| 1387 | | fn asmReloc(self: *Self, tag: Mir.Inst.FixedTag, target: Mir.Inst.Index) !void { |
| 1523 | fn asmReloc(self: *CodeGen, tag: Mir.Inst.FixedTag, target: Mir.Inst.Index) !void { |
| 1388 | 1524 | _ = try self.addInst(.{ |
| 1389 | 1525 | .tag = tag[1], |
| 1390 | 1526 | .ops = .inst, |
| ... | ... | @@ -1395,7 +1531,7 @@ fn asmReloc(self: *Self, tag: Mir.Inst.FixedTag, target: Mir.Inst.Index) !void { |
| 1395 | 1531 | }); |
| 1396 | 1532 | } |
| 1397 | 1533 | |
| 1398 | | fn asmPlaceholder(self: *Self) !Mir.Inst.Index { |
| 1534 | fn asmPlaceholder(self: *CodeGen) !Mir.Inst.Index { |
| 1399 | 1535 | return self.addInst(.{ |
| 1400 | 1536 | .tag = .pseudo, |
| 1401 | 1537 | .ops = .pseudo_dead_none, |
| ... | ... | @@ -1405,7 +1541,7 @@ fn asmPlaceholder(self: *Self) !Mir.Inst.Index { |
| 1405 | 1541 | |
| 1406 | 1542 | const MirTagAir = enum { dbg_local }; |
| 1407 | 1543 | |
| 1408 | | fn asmAir(self: *Self, tag: MirTagAir, inst: Air.Inst.Index) !void { |
| 1544 | fn asmAir(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index) !void { |
| 1409 | 1545 | _ = try self.addInst(.{ |
| 1410 | 1546 | .tag = .pseudo, |
| 1411 | 1547 | .ops = switch (tag) { |
| ... | ... | @@ -1415,7 +1551,7 @@ fn asmAir(self: *Self, tag: MirTagAir, inst: Air.Inst.Index) !void { |
| 1415 | 1551 | }); |
| 1416 | 1552 | } |
| 1417 | 1553 | |
| 1418 | | fn asmAirImmediate(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, imm: Immediate) !void { |
| 1554 | fn asmAirImmediate(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index, imm: Immediate) !void { |
| 1419 | 1555 | switch (imm) { |
| 1420 | 1556 | .signed => |s| _ = try self.addInst(.{ |
| 1421 | 1557 | .tag = .pseudo, |
| ... | ... | @@ -1427,7 +1563,7 @@ fn asmAirImmediate(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, imm: Immed |
| 1427 | 1563 | .i = @bitCast(s), |
| 1428 | 1564 | } }, |
| 1429 | 1565 | }), |
| 1430 | | .unsigned => |u| _ = if (math.cast(u32, u)) |small| try self.addInst(.{ |
| 1566 | .unsigned => |u| _ = if (std.math.cast(u32, u)) |small| try self.addInst(.{ |
| 1431 | 1567 | .tag = .pseudo, |
| 1432 | 1568 | .ops = switch (tag) { |
| 1433 | 1569 | .dbg_local => .pseudo_dbg_local_ai_u, |
| ... | ... | @@ -1469,7 +1605,7 @@ fn asmAirImmediate(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, imm: Immed |
| 1469 | 1605 | } |
| 1470 | 1606 | |
| 1471 | 1607 | fn asmAirRegisterImmediate( |
| 1472 | | self: *Self, |
| 1608 | self: *CodeGen, |
| 1473 | 1609 | tag: MirTagAir, |
| 1474 | 1610 | inst: Air.Inst.Index, |
| 1475 | 1611 | reg: Register, |
| ... | ... | @@ -1491,7 +1627,7 @@ fn asmAirRegisterImmediate( |
| 1491 | 1627 | } |
| 1492 | 1628 | |
| 1493 | 1629 | fn asmAirFrameAddress( |
| 1494 | | self: *Self, |
| 1630 | self: *CodeGen, |
| 1495 | 1631 | tag: MirTagAir, |
| 1496 | 1632 | inst: Air.Inst.Index, |
| 1497 | 1633 | frame_addr: bits.FrameAddr, |
| ... | ... | @@ -1508,7 +1644,7 @@ fn asmAirFrameAddress( |
| 1508 | 1644 | }); |
| 1509 | 1645 | } |
| 1510 | 1646 | |
| 1511 | | fn asmAirMemory(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, m: Memory) !void { |
| 1647 | fn asmAirMemory(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index, m: Memory) !void { |
| 1512 | 1648 | _ = try self.addInst(.{ |
| 1513 | 1649 | .tag = .pseudo, |
| 1514 | 1650 | .ops = switch (tag) { |
| ... | ... | @@ -1521,7 +1657,7 @@ fn asmAirMemory(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, m: Memory) !v |
| 1521 | 1657 | }); |
| 1522 | 1658 | } |
| 1523 | 1659 | |
| 1524 | | fn asmOpOnly(self: *Self, tag: Mir.Inst.FixedTag) !void { |
| 1660 | fn asmOpOnly(self: *CodeGen, tag: Mir.Inst.FixedTag) !void { |
| 1525 | 1661 | _ = try self.addInst(.{ |
| 1526 | 1662 | .tag = tag[1], |
| 1527 | 1663 | .ops = .none, |
| ... | ... | @@ -1531,7 +1667,7 @@ fn asmOpOnly(self: *Self, tag: Mir.Inst.FixedTag) !void { |
| 1531 | 1667 | }); |
| 1532 | 1668 | } |
| 1533 | 1669 | |
| 1534 | | fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void { |
| 1670 | fn asmPseudo(self: *CodeGen, ops: Mir.Inst.Ops) !void { |
| 1535 | 1671 | assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and |
| 1536 | 1672 | std.mem.endsWith(u8, @tagName(ops), "_none")); |
| 1537 | 1673 | _ = try self.addInst(.{ |
| ... | ... | @@ -1541,7 +1677,7 @@ fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void { |
| 1541 | 1677 | }); |
| 1542 | 1678 | } |
| 1543 | 1679 | |
| 1544 | | fn asmPseudoRegister(self: *Self, ops: Mir.Inst.Ops, reg: Register) !void { |
| 1680 | fn asmPseudoRegister(self: *CodeGen, ops: Mir.Inst.Ops, reg: Register) !void { |
| 1545 | 1681 | assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and |
| 1546 | 1682 | std.mem.endsWith(u8, @tagName(ops), "_r")); |
| 1547 | 1683 | _ = try self.addInst(.{ |
| ... | ... | @@ -1551,7 +1687,7 @@ fn asmPseudoRegister(self: *Self, ops: Mir.Inst.Ops, reg: Register) !void { |
| 1551 | 1687 | }); |
| 1552 | 1688 | } |
| 1553 | 1689 | |
| 1554 | | fn asmPseudoImmediate(self: *Self, ops: Mir.Inst.Ops, imm: Immediate) !void { |
| 1690 | fn asmPseudoImmediate(self: *CodeGen, ops: Mir.Inst.Ops, imm: Immediate) !void { |
| 1555 | 1691 | assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and |
| 1556 | 1692 | std.mem.endsWith(u8, @tagName(ops), "_i_s")); |
| 1557 | 1693 | _ = try self.addInst(.{ |
| ... | ... | @@ -1561,7 +1697,7 @@ fn asmPseudoImmediate(self: *Self, ops: Mir.Inst.Ops, imm: Immediate) !void { |
| 1561 | 1697 | }); |
| 1562 | 1698 | } |
| 1563 | 1699 | |
| 1564 | | fn asmPseudoRegisterRegister(self: *Self, ops: Mir.Inst.Ops, reg1: Register, reg2: Register) !void { |
| 1700 | fn asmPseudoRegisterRegister(self: *CodeGen, ops: Mir.Inst.Ops, reg1: Register, reg2: Register) !void { |
| 1565 | 1701 | assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and |
| 1566 | 1702 | std.mem.endsWith(u8, @tagName(ops), "_rr")); |
| 1567 | 1703 | _ = try self.addInst(.{ |
| ... | ... | @@ -1571,7 +1707,7 @@ fn asmPseudoRegisterRegister(self: *Self, ops: Mir.Inst.Ops, reg1: Register, reg |
| 1571 | 1707 | }); |
| 1572 | 1708 | } |
| 1573 | 1709 | |
| 1574 | | fn asmPseudoRegisterImmediate(self: *Self, ops: Mir.Inst.Ops, reg: Register, imm: Immediate) !void { |
| 1710 | fn asmPseudoRegisterImmediate(self: *CodeGen, ops: Mir.Inst.Ops, reg: Register, imm: Immediate) !void { |
| 1575 | 1711 | assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and |
| 1576 | 1712 | std.mem.endsWith(u8, @tagName(ops), "_ri_s")); |
| 1577 | 1713 | _ = try self.addInst(.{ |
| ... | ... | @@ -1581,7 +1717,7 @@ fn asmPseudoRegisterImmediate(self: *Self, ops: Mir.Inst.Ops, reg: Register, imm |
| 1581 | 1717 | }); |
| 1582 | 1718 | } |
| 1583 | 1719 | |
| 1584 | | fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void { |
| 1720 | fn asmRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, reg: Register) !void { |
| 1585 | 1721 | _ = try self.addInst(.{ |
| 1586 | 1722 | .tag = tag[1], |
| 1587 | 1723 | .ops = .r, |
| ... | ... | @@ -1592,7 +1728,7 @@ fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void { |
| 1592 | 1728 | }); |
| 1593 | 1729 | } |
| 1594 | 1730 | |
| 1595 | | fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void { |
| 1731 | fn asmImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, imm: Immediate) !void { |
| 1596 | 1732 | _ = try self.addInst(.{ |
| 1597 | 1733 | .tag = tag[1], |
| 1598 | 1734 | .ops = switch (imm) { |
| ... | ... | @@ -1617,7 +1753,7 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void { |
| 1617 | 1753 | }); |
| 1618 | 1754 | } |
| 1619 | 1755 | |
| 1620 | | fn asmRegisterRegister(self: *Self, tag: Mir.Inst.FixedTag, reg1: Register, reg2: Register) !void { |
| 1756 | fn asmRegisterRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, reg1: Register, reg2: Register) !void { |
| 1621 | 1757 | _ = try self.addInst(.{ |
| 1622 | 1758 | .tag = tag[1], |
| 1623 | 1759 | .ops = .rr, |
| ... | ... | @@ -1629,10 +1765,10 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.FixedTag, reg1: Register, reg2 |
| 1629 | 1765 | }); |
| 1630 | 1766 | } |
| 1631 | 1767 | |
| 1632 | | fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: Immediate) !void { |
| 1768 | fn asmRegisterImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, reg: Register, imm: Immediate) !void { |
| 1633 | 1769 | const ops: Mir.Inst.Ops, const i: u32 = switch (imm) { |
| 1634 | 1770 | .signed => |s| .{ .ri_s, @bitCast(s) }, |
| 1635 | | .unsigned => |u| if (math.cast(u32, u)) |small| |
| 1771 | .unsigned => |u| if (std.math.cast(u32, u)) |small| |
| 1636 | 1772 | .{ .ri_u, small } |
| 1637 | 1773 | else |
| 1638 | 1774 | .{ .ri_64, try self.addExtra(Mir.Imm64.encode(imm.unsigned)) }, |
| ... | ... | @@ -1650,7 +1786,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: |
| 1650 | 1786 | } |
| 1651 | 1787 | |
| 1652 | 1788 | fn asmRegisterRegisterRegister( |
| 1653 | | self: *Self, |
| 1789 | self: *CodeGen, |
| 1654 | 1790 | tag: Mir.Inst.FixedTag, |
| 1655 | 1791 | reg1: Register, |
| 1656 | 1792 | reg2: Register, |
| ... | ... | @@ -1669,7 +1805,7 @@ fn asmRegisterRegisterRegister( |
| 1669 | 1805 | } |
| 1670 | 1806 | |
| 1671 | 1807 | fn asmRegisterRegisterRegisterRegister( |
| 1672 | | self: *Self, |
| 1808 | self: *CodeGen, |
| 1673 | 1809 | tag: Mir.Inst.FixedTag, |
| 1674 | 1810 | reg1: Register, |
| 1675 | 1811 | reg2: Register, |
| ... | ... | @@ -1690,7 +1826,7 @@ fn asmRegisterRegisterRegisterRegister( |
| 1690 | 1826 | } |
| 1691 | 1827 | |
| 1692 | 1828 | fn asmRegisterRegisterRegisterImmediate( |
| 1693 | | self: *Self, |
| 1829 | self: *CodeGen, |
| 1694 | 1830 | tag: Mir.Inst.FixedTag, |
| 1695 | 1831 | reg1: Register, |
| 1696 | 1832 | reg2: Register, |
| ... | ... | @@ -1715,7 +1851,7 @@ fn asmRegisterRegisterRegisterImmediate( |
| 1715 | 1851 | } |
| 1716 | 1852 | |
| 1717 | 1853 | fn asmRegisterRegisterImmediate( |
| 1718 | | self: *Self, |
| 1854 | self: *CodeGen, |
| 1719 | 1855 | tag: Mir.Inst.FixedTag, |
| 1720 | 1856 | reg1: Register, |
| 1721 | 1857 | reg2: Register, |
| ... | ... | @@ -1742,7 +1878,7 @@ fn asmRegisterRegisterImmediate( |
| 1742 | 1878 | } |
| 1743 | 1879 | |
| 1744 | 1880 | fn asmRegisterRegisterMemory( |
| 1745 | | self: *Self, |
| 1881 | self: *CodeGen, |
| 1746 | 1882 | tag: Mir.Inst.FixedTag, |
| 1747 | 1883 | reg1: Register, |
| 1748 | 1884 | reg2: Register, |
| ... | ... | @@ -1761,7 +1897,7 @@ fn asmRegisterRegisterMemory( |
| 1761 | 1897 | } |
| 1762 | 1898 | |
| 1763 | 1899 | fn asmRegisterRegisterMemoryRegister( |
| 1764 | | self: *Self, |
| 1900 | self: *CodeGen, |
| 1765 | 1901 | tag: Mir.Inst.FixedTag, |
| 1766 | 1902 | reg1: Register, |
| 1767 | 1903 | reg2: Register, |
| ... | ... | @@ -1781,7 +1917,7 @@ fn asmRegisterRegisterMemoryRegister( |
| 1781 | 1917 | }); |
| 1782 | 1918 | } |
| 1783 | 1919 | |
| 1784 | | fn asmMemory(self: *Self, tag: Mir.Inst.FixedTag, m: Memory) !void { |
| 1920 | fn asmMemory(self: *CodeGen, tag: Mir.Inst.FixedTag, m: Memory) !void { |
| 1785 | 1921 | _ = try self.addInst(.{ |
| 1786 | 1922 | .tag = tag[1], |
| 1787 | 1923 | .ops = .m, |
| ... | ... | @@ -1792,7 +1928,7 @@ fn asmMemory(self: *Self, tag: Mir.Inst.FixedTag, m: Memory) !void { |
| 1792 | 1928 | }); |
| 1793 | 1929 | } |
| 1794 | 1930 | |
| 1795 | | fn asmRegisterMemory(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, m: Memory) !void { |
| 1931 | fn asmRegisterMemory(self: *CodeGen, tag: Mir.Inst.FixedTag, reg: Register, m: Memory) !void { |
| 1796 | 1932 | _ = try self.addInst(.{ |
| 1797 | 1933 | .tag = tag[1], |
| 1798 | 1934 | .ops = .rm, |
| ... | ... | @@ -1805,7 +1941,7 @@ fn asmRegisterMemory(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, m: Memo |
| 1805 | 1941 | } |
| 1806 | 1942 | |
| 1807 | 1943 | fn asmRegisterMemoryRegister( |
| 1808 | | self: *Self, |
| 1944 | self: *CodeGen, |
| 1809 | 1945 | tag: Mir.Inst.FixedTag, |
| 1810 | 1946 | reg1: Register, |
| 1811 | 1947 | m: Memory, |
| ... | ... | @@ -1824,15 +1960,15 @@ fn asmRegisterMemoryRegister( |
| 1824 | 1960 | } |
| 1825 | 1961 | |
| 1826 | 1962 | fn asmRegisterMemoryImmediate( |
| 1827 | | self: *Self, |
| 1963 | self: *CodeGen, |
| 1828 | 1964 | tag: Mir.Inst.FixedTag, |
| 1829 | 1965 | reg: Register, |
| 1830 | 1966 | m: Memory, |
| 1831 | 1967 | imm: Immediate, |
| 1832 | 1968 | ) !void { |
| 1833 | 1969 | if (switch (imm) { |
| 1834 | | .signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null, |
| 1835 | | .unsigned => |u| math.cast(u16, u), |
| 1970 | .signed => |s| if (std.math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null, |
| 1971 | .unsigned => |u| std.math.cast(u16, u), |
| 1836 | 1972 | .reloc => unreachable, |
| 1837 | 1973 | }) |small_imm| { |
| 1838 | 1974 | _ = try self.addInst(.{ |
| ... | ... | @@ -1869,7 +2005,7 @@ fn asmRegisterMemoryImmediate( |
| 1869 | 2005 | } |
| 1870 | 2006 | |
| 1871 | 2007 | fn asmRegisterRegisterMemoryImmediate( |
| 1872 | | self: *Self, |
| 2008 | self: *CodeGen, |
| 1873 | 2009 | tag: Mir.Inst.FixedTag, |
| 1874 | 2010 | reg1: Register, |
| 1875 | 2011 | reg2: Register, |
| ... | ... | @@ -1889,7 +2025,7 @@ fn asmRegisterRegisterMemoryImmediate( |
| 1889 | 2025 | }); |
| 1890 | 2026 | } |
| 1891 | 2027 | |
| 1892 | | fn asmMemoryRegister(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, reg: Register) !void { |
| 2028 | fn asmMemoryRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, m: Memory, reg: Register) !void { |
| 1893 | 2029 | _ = try self.addInst(.{ |
| 1894 | 2030 | .tag = tag[1], |
| 1895 | 2031 | .ops = .mr, |
| ... | ... | @@ -1901,7 +2037,7 @@ fn asmMemoryRegister(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, reg: Regist |
| 1901 | 2037 | }); |
| 1902 | 2038 | } |
| 1903 | 2039 | |
| 1904 | | fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immediate) !void { |
| 2040 | fn asmMemoryImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, m: Memory, imm: Immediate) !void { |
| 1905 | 2041 | const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { |
| 1906 | 2042 | .signed => |s| @bitCast(s), |
| 1907 | 2043 | .unsigned => |u| @intCast(u), |
| ... | ... | @@ -1923,7 +2059,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed |
| 1923 | 2059 | } |
| 1924 | 2060 | |
| 1925 | 2061 | fn asmMemoryRegisterRegister( |
| 1926 | | self: *Self, |
| 2062 | self: *CodeGen, |
| 1927 | 2063 | tag: Mir.Inst.FixedTag, |
| 1928 | 2064 | m: Memory, |
| 1929 | 2065 | reg1: Register, |
| ... | ... | @@ -1942,7 +2078,7 @@ fn asmMemoryRegisterRegister( |
| 1942 | 2078 | } |
| 1943 | 2079 | |
| 1944 | 2080 | fn asmMemoryRegisterImmediate( |
| 1945 | | self: *Self, |
| 2081 | self: *CodeGen, |
| 1946 | 2082 | tag: Mir.Inst.FixedTag, |
| 1947 | 2083 | m: Memory, |
| 1948 | 2084 | reg: Register, |
| ... | ... | @@ -1960,15 +2096,14 @@ fn asmMemoryRegisterImmediate( |
| 1960 | 2096 | }); |
| 1961 | 2097 | } |
| 1962 | 2098 | |
| 1963 | | fn gen(self: *Self) InnerError!void { |
| 2099 | fn gen(self: *CodeGen) InnerError!void { |
| 1964 | 2100 | const pt = self.pt; |
| 1965 | 2101 | const zcu = pt.zcu; |
| 1966 | 2102 | const fn_info = zcu.typeToFunc(self.fn_type).?; |
| 1967 | | const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); |
| 1968 | | if (cc != .naked) { |
| 2103 | if (fn_info.cc != .naked) { |
| 1969 | 2104 | try self.asmRegister(.{ ._, .push }, .rbp); |
| 1970 | | try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, Immediate.s(8)); |
| 1971 | | try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, Immediate.s(0)); |
| 2105 | try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, .s(8)); |
| 2106 | try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, .s(0)); |
| 1972 | 2107 | try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp); |
| 1973 | 2108 | try self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, .rbp); |
| 1974 | 2109 | const backpatch_push_callee_preserved_regs = try self.asmPlaceholder(); |
| ... | ... | @@ -1983,11 +2118,11 @@ fn gen(self: *Self) InnerError!void { |
| 1983 | 2118 | // The address where to store the return value for the caller is in a |
| 1984 | 2119 | // register which the callee is free to clobber. Therefore, we purposely |
| 1985 | 2120 | // spill it to stack immediately. |
| 1986 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(Type.usize, zcu)); |
| 2121 | const frame_index = try self.allocFrameIndex(.initSpill(.usize, zcu)); |
| 1987 | 2122 | try self.genSetMem( |
| 1988 | 2123 | .{ .frame = frame_index }, |
| 1989 | 2124 | 0, |
| 1990 | | Type.usize, |
| 2125 | .usize, |
| 1991 | 2126 | self.ret_mcv.long.address().offset(-self.ret_mcv.short.indirect.off), |
| 1992 | 2127 | .{}, |
| 1993 | 2128 | ); |
| ... | ... | @@ -1997,10 +2132,10 @@ fn gen(self: *Self) InnerError!void { |
| 1997 | 2132 | else => unreachable, |
| 1998 | 2133 | } |
| 1999 | 2134 | |
| 2000 | | if (fn_info.is_var_args) switch (cc) { |
| 2135 | if (fn_info.is_var_args) switch (fn_info.cc) { |
| 2001 | 2136 | .x86_64_sysv => { |
| 2002 | 2137 | const info = &self.va_info.sysv; |
| 2003 | | const reg_save_area_fi = try self.allocFrameIndex(FrameAlloc.init(.{ |
| 2138 | const reg_save_area_fi = try self.allocFrameIndex(.init(.{ |
| 2004 | 2139 | .size = abi.SysV.c_abi_int_param_regs.len * 8 + |
| 2005 | 2140 | abi.SysV.c_abi_sse_param_regs.len * 16, |
| 2006 | 2141 | .alignment = .@"16", |
| ... | ... | @@ -2008,15 +2143,9 @@ fn gen(self: *Self) InnerError!void { |
| 2008 | 2143 | info.reg_save_area = .{ .index = reg_save_area_fi }; |
| 2009 | 2144 | |
| 2010 | 2145 | for (abi.SysV.c_abi_int_param_regs[info.gp_count..], info.gp_count..) |reg, reg_i| |
| 2011 | | try self.genSetMem( |
| 2012 | | .{ .frame = reg_save_area_fi }, |
| 2013 | | @intCast(reg_i * 8), |
| 2014 | | Type.usize, |
| 2015 | | .{ .register = reg }, |
| 2016 | | .{}, |
| 2017 | | ); |
| 2146 | try self.genSetMem(.{ .frame = reg_save_area_fi }, @intCast(reg_i * 8), .usize, .{ .register = reg }, .{}); |
| 2018 | 2147 | |
| 2019 | | try self.asmRegisterImmediate(.{ ._, .cmp }, .al, Immediate.u(info.fp_count)); |
| 2148 | try self.asmRegisterImmediate(.{ ._, .cmp }, .al, .u(info.fp_count)); |
| 2020 | 2149 | const skip_sse_reloc = try self.asmJccReloc(.na, undefined); |
| 2021 | 2150 | |
| 2022 | 2151 | const vec_2_f64 = try pt.vectorType(.{ .len = 2, .child = .f64_type }); |
| ... | ... | @@ -2032,38 +2161,38 @@ fn gen(self: *Self) InnerError!void { |
| 2032 | 2161 | self.performReloc(skip_sse_reloc); |
| 2033 | 2162 | }, |
| 2034 | 2163 | .x86_64_win => return self.fail("TODO implement gen var arg function for Win64", .{}), |
| 2035 | | else => unreachable, |
| 2164 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 2036 | 2165 | }; |
| 2037 | 2166 | |
| 2038 | 2167 | try self.asmPseudo(.pseudo_dbg_prologue_end_none); |
| 2039 | 2168 | |
| 2040 | 2169 | try self.genBody(self.air.getMainBody()); |
| 2041 | 2170 | |
| 2042 | | // TODO can single exitlude jump reloc be elided? What if it is not at the end of the code? |
| 2043 | | // Example: |
| 2044 | | // pub fn main() void { |
| 2045 | | // maybeErr() catch return; |
| 2046 | | // unreachable; |
| 2047 | | // } |
| 2048 | | // Eliding the reloc will cause a miscompilation in this case. |
| 2049 | | for (self.exitlude_jump_relocs.items) |jmp_reloc| { |
| 2050 | | self.mir_instructions.items(.data)[jmp_reloc].inst.inst = |
| 2051 | | @intCast(self.mir_instructions.len); |
| 2052 | | } |
| 2171 | const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: { |
| 2172 | const epilogue_relocs_last_index = self.epilogue_relocs.items.len - 1; |
| 2173 | for (if (self.epilogue_relocs.items[epilogue_relocs_last_index] == self.mir_instructions.len - 1) epilogue_relocs: { |
| 2174 | _ = self.mir_instructions.pop(); |
| 2175 | break :epilogue_relocs self.epilogue_relocs.items[0..epilogue_relocs_last_index]; |
| 2176 | } else self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc); |
| 2177 | |
| 2178 | try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); |
| 2179 | const backpatch_stack_dealloc = try self.asmPlaceholder(); |
| 2180 | const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder(); |
| 2181 | try self.asmRegister(.{ ._, .pop }, .rbp); |
| 2182 | try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, .s(8)); |
| 2183 | try self.asmOpOnly(.{ ._, .ret }); |
| 2184 | break :epilogue .{ |
| 2185 | .backpatch_stack_dealloc = backpatch_stack_dealloc, |
| 2186 | .backpatch_pop_callee_preserved_regs = backpatch_pop_callee_preserved_regs, |
| 2187 | }; |
| 2188 | } else null; |
| 2053 | 2189 | |
| 2054 | | try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); |
| 2055 | | const backpatch_stack_dealloc = try self.asmPlaceholder(); |
| 2056 | | const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder(); |
| 2057 | | try self.asmRegister(.{ ._, .pop }, .rbp); |
| 2058 | | try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, Immediate.s(8)); |
| 2059 | | try self.asmOpOnly(.{ ._, .ret }); |
| 2060 | | |
| 2061 | | const frame_layout = try self.computeFrameLayout(cc); |
| 2062 | | const need_frame_align = frame_layout.stack_mask != math.maxInt(u32); |
| 2190 | const frame_layout = try self.computeFrameLayout(fn_info.cc); |
| 2191 | const need_frame_align = frame_layout.stack_mask != std.math.maxInt(u32); |
| 2063 | 2192 | const need_stack_adjust = frame_layout.stack_adjust > 0; |
| 2064 | 2193 | const need_save_reg = frame_layout.save_reg_list.count() > 0; |
| 2065 | 2194 | if (need_frame_align) { |
| 2066 | | const page_align = @as(u32, math.maxInt(u32)) << 12; |
| 2195 | const page_align = @as(u32, std.math.maxInt(u32)) << 12; |
| 2067 | 2196 | self.mir_instructions.set(backpatch_frame_align, .{ |
| 2068 | 2197 | .tag = .@"and", |
| 2069 | 2198 | .ops = .ri_s, |
| ... | ... | @@ -2106,12 +2235,13 @@ fn gen(self: *Self) InnerError!void { |
| 2106 | 2235 | } }, |
| 2107 | 2236 | }); |
| 2108 | 2237 | } else { |
| 2238 | const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc); |
| 2109 | 2239 | self.mir_instructions.set(backpatch_stack_alloc, .{ |
| 2110 | 2240 | .tag = .pseudo, |
| 2111 | 2241 | .ops = .pseudo_probe_adjust_setup_rri_s, |
| 2112 | 2242 | .data = .{ .rri = .{ |
| 2113 | 2243 | .r1 = .rsp, |
| 2114 | | .r2 = .rax, |
| 2244 | .r2 = scratch_reg, |
| 2115 | 2245 | .i = frame_layout.stack_adjust, |
| 2116 | 2246 | } }, |
| 2117 | 2247 | }); |
| ... | ... | @@ -2120,34 +2250,44 @@ fn gen(self: *Self) InnerError!void { |
| 2120 | 2250 | .ops = .pseudo_probe_adjust_loop_rr, |
| 2121 | 2251 | .data = .{ .rr = .{ |
| 2122 | 2252 | .r1 = .rsp, |
| 2123 | | .r2 = .rax, |
| 2253 | .r2 = scratch_reg, |
| 2124 | 2254 | } }, |
| 2125 | 2255 | }); |
| 2126 | 2256 | } |
| 2127 | 2257 | } |
| 2128 | | if (need_frame_align or need_stack_adjust) { |
| 2129 | | self.mir_instructions.set(backpatch_stack_dealloc, .{ |
| 2130 | | .tag = .lea, |
| 2131 | | .ops = .rm, |
| 2132 | | .data = .{ .rx = .{ |
| 2133 | | .r1 = .rsp, |
| 2134 | | .payload = try self.addExtra(Mir.Memory.encode(.{ |
| 2135 | | .base = .{ .reg = .rbp }, |
| 2136 | | .mod = .{ .rm = .{ |
| 2137 | | .size = .qword, |
| 2138 | | .disp = -frame_layout.save_reg_list.size(), |
| 2139 | | } }, |
| 2140 | | })), |
| 2141 | | } }, |
| 2258 | if (epilogue) |e| if (need_frame_align or need_stack_adjust) { |
| 2259 | self.mir_instructions.set(e.backpatch_stack_dealloc, switch (-frame_layout.save_reg_list.size(self.target)) { |
| 2260 | 0 => .{ |
| 2261 | .tag = .mov, |
| 2262 | .ops = .rr, |
| 2263 | .data = .{ .rr = .{ |
| 2264 | .r1 = .rsp, |
| 2265 | .r2 = .rbp, |
| 2266 | } }, |
| 2267 | }, |
| 2268 | else => |disp| .{ |
| 2269 | .tag = .lea, |
| 2270 | .ops = .rm, |
| 2271 | .data = .{ .rx = .{ |
| 2272 | .r1 = .rsp, |
| 2273 | .payload = try self.addExtra(Mir.Memory.encode(.{ |
| 2274 | .base = .{ .reg = .rbp }, |
| 2275 | .mod = .{ .rm = .{ |
| 2276 | .size = .qword, |
| 2277 | .disp = disp, |
| 2278 | } }, |
| 2279 | })), |
| 2280 | } }, |
| 2281 | }, |
| 2142 | 2282 | }); |
| 2143 | | } |
| 2283 | }; |
| 2144 | 2284 | if (need_save_reg) { |
| 2145 | 2285 | self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{ |
| 2146 | 2286 | .tag = .pseudo, |
| 2147 | 2287 | .ops = .pseudo_push_reg_list, |
| 2148 | 2288 | .data = .{ .reg_list = frame_layout.save_reg_list }, |
| 2149 | 2289 | }); |
| 2150 | | self.mir_instructions.set(backpatch_pop_callee_preserved_regs, .{ |
| 2290 | if (epilogue) |e| self.mir_instructions.set(e.backpatch_pop_callee_preserved_regs, .{ |
| 2151 | 2291 | .tag = .pseudo, |
| 2152 | 2292 | .ops = .pseudo_pop_reg_list, |
| 2153 | 2293 | .data = .{ .reg_list = frame_layout.save_reg_list }, |
| ... | ... | @@ -2170,97 +2310,85 @@ fn gen(self: *Self) InnerError!void { |
| 2170 | 2310 | }); |
| 2171 | 2311 | } |
| 2172 | 2312 | |
| 2173 | | fn checkInvariantsAfterAirInst(self: *Self, inst: Air.Inst.Index, old_air_bookkeeping: @TypeOf(air_bookkeeping_init)) void { |
| 2313 | fn checkInvariantsAfterAirInst(self: *CodeGen) void { |
| 2174 | 2314 | assert(!self.register_manager.lockedRegsExist()); |
| 2175 | 2315 | |
| 2176 | 2316 | if (std.debug.runtime_safety) { |
| 2177 | | if (self.air_bookkeeping < old_air_bookkeeping + 1) { |
| 2178 | | std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, self.air.instructions.items(.tag)[@intFromEnum(inst)] }); |
| 2179 | | } |
| 2180 | | |
| 2181 | | { // check consistency of tracked registers |
| 2182 | | var it = self.register_manager.free_registers.iterator(.{ .kind = .unset }); |
| 2183 | | while (it.next()) |index| { |
| 2184 | | const tracked_inst = self.register_manager.registers[index]; |
| 2185 | | const tracking = self.getResolvedInstValue(tracked_inst); |
| 2186 | | for (tracking.getRegs()) |reg| { |
| 2187 | | if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; |
| 2188 | | } else unreachable; // tracked register not in use |
| 2189 | | } |
| 2317 | // check consistency of tracked registers |
| 2318 | var it = self.register_manager.free_registers.iterator(.{ .kind = .unset }); |
| 2319 | while (it.next()) |index| { |
| 2320 | const tracked_inst = self.register_manager.registers[index]; |
| 2321 | const tracking = self.getResolvedInstValue(tracked_inst); |
| 2322 | for (tracking.getRegs()) |reg| { |
| 2323 | if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; |
| 2324 | } else unreachable; // tracked register not in use |
| 2190 | 2325 | } |
| 2191 | 2326 | } |
| 2192 | 2327 | } |
| 2193 | 2328 | |
| 2194 | | fn genBodyBlock(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2329 | fn genBodyBlock(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2195 | 2330 | try self.asmPseudo(.pseudo_dbg_enter_block_none); |
| 2196 | 2331 | try self.genBody(body); |
| 2197 | 2332 | try self.asmPseudo(.pseudo_dbg_leave_block_none); |
| 2198 | 2333 | } |
| 2199 | 2334 | |
| 2200 | | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2201 | | const pt = self.pt; |
| 2335 | fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2336 | @setEvalBranchQuota(1_700); |
| 2337 | const pt = cg.pt; |
| 2202 | 2338 | const zcu = pt.zcu; |
| 2203 | 2339 | const ip = &zcu.intern_pool; |
| 2204 | | const air_tags = self.air.instructions.items(.tag); |
| 2340 | const air_tags = cg.air.instructions.items(.tag); |
| 2341 | const air_datas = cg.air.instructions.items(.data); |
| 2342 | const use_old = cg.target.ofmt == .coff; |
| 2205 | 2343 | |
| 2206 | | self.arg_index = 0; |
| 2344 | cg.arg_index = 0; |
| 2207 | 2345 | for (body) |inst| switch (air_tags[@intFromEnum(inst)]) { |
| 2208 | 2346 | .arg => { |
| 2209 | | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); |
| 2210 | | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); |
| 2347 | wip_mir_log.debug("{}", .{cg.fmtAir(inst)}); |
| 2348 | verbose_tracking_log.debug("{}", .{cg.fmtTracking()}); |
| 2211 | 2349 | |
| 2212 | | const old_air_bookkeeping = self.air_bookkeeping; |
| 2213 | | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); |
| 2350 | cg.reused_operands = .initEmpty(); |
| 2351 | try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1); |
| 2214 | 2352 | |
| 2215 | | try self.airArg(inst); |
| 2353 | try cg.airArg(inst); |
| 2216 | 2354 | |
| 2217 | | self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping); |
| 2355 | cg.resetTemps(); |
| 2356 | cg.checkInvariantsAfterAirInst(); |
| 2218 | 2357 | }, |
| 2219 | 2358 | else => break, |
| 2220 | 2359 | }; |
| 2221 | 2360 | |
| 2222 | | if (self.arg_index == 0) try self.airDbgVarArgs(); |
| 2223 | | self.arg_index = 0; |
| 2361 | if (cg.arg_index == 0) try cg.airDbgVarArgs(); |
| 2362 | cg.arg_index = 0; |
| 2224 | 2363 | for (body) |inst| { |
| 2225 | | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue; |
| 2226 | | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); |
| 2227 | | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); |
| 2364 | if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue; |
| 2365 | wip_mir_log.debug("{}", .{cg.fmtAir(inst)}); |
| 2366 | verbose_tracking_log.debug("{}", .{cg.fmtTracking()}); |
| 2228 | 2367 | |
| 2229 | | const old_air_bookkeeping = self.air_bookkeeping; |
| 2230 | | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); |
| 2368 | cg.reused_operands = .initEmpty(); |
| 2369 | try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1); |
| 2231 | 2370 | switch (air_tags[@intFromEnum(inst)]) { |
| 2232 | 2371 | // zig fmt: off |
| 2233 | | .not, |
| 2234 | | => |tag| try self.airUnOp(inst, tag), |
| 2235 | | |
| 2236 | 2372 | .add, |
| 2237 | 2373 | .add_wrap, |
| 2238 | 2374 | .sub, |
| 2239 | 2375 | .sub_wrap, |
| 2240 | | .bool_and, |
| 2241 | | .bool_or, |
| 2242 | | .bit_and, |
| 2243 | | .bit_or, |
| 2244 | | .xor, |
| 2245 | 2376 | .min, |
| 2246 | 2377 | .max, |
| 2247 | | => |tag| try self.airBinOp(inst, tag), |
| 2378 | => |air_tag| try cg.airBinOp(inst, air_tag), |
| 2248 | 2379 | |
| 2249 | | .ptr_add, .ptr_sub => |tag| try self.airPtrArithmetic(inst, tag), |
| 2380 | .shr, .shr_exact => try cg.airShlShrBinOp(inst), |
| 2381 | .shl, .shl_exact => try cg.airShlShrBinOp(inst), |
| 2250 | 2382 | |
| 2251 | | .shr, .shr_exact => try self.airShlShrBinOp(inst), |
| 2252 | | .shl, .shl_exact => try self.airShlShrBinOp(inst), |
| 2383 | .mul => try cg.airMulDivBinOp(inst), |
| 2384 | .mul_wrap => try cg.airMulDivBinOp(inst), |
| 2385 | .rem => try cg.airMulDivBinOp(inst), |
| 2386 | .mod => try cg.airMulDivBinOp(inst), |
| 2253 | 2387 | |
| 2254 | | .mul => try self.airMulDivBinOp(inst), |
| 2255 | | .mul_wrap => try self.airMulDivBinOp(inst), |
| 2256 | | .rem => try self.airMulDivBinOp(inst), |
| 2257 | | .mod => try self.airMulDivBinOp(inst), |
| 2258 | | |
| 2259 | | .add_sat => try self.airAddSat(inst), |
| 2260 | | .sub_sat => try self.airSubSat(inst), |
| 2261 | | .mul_sat => try self.airMulSat(inst), |
| 2262 | | .shl_sat => try self.airShlSat(inst), |
| 2263 | | .slice => try self.airSlice(inst), |
| 2388 | .add_sat => try cg.airAddSat(inst), |
| 2389 | .sub_sat => try cg.airSubSat(inst), |
| 2390 | .mul_sat => try cg.airMulSat(inst), |
| 2391 | .shl_sat => try cg.airShlSat(inst), |
| 2264 | 2392 | |
| 2265 | 2393 | .sin, |
| 2266 | 2394 | .cos, |
| ... | ... | @@ -2271,162 +2399,80 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2271 | 2399 | .log2, |
| 2272 | 2400 | .log10, |
| 2273 | 2401 | .round, |
| 2274 | | => |tag| try self.airUnaryMath(inst, tag), |
| 2275 | | |
| 2276 | | .floor => try self.airRound(inst, .{ .mode = .down, .precision = .inexact }), |
| 2277 | | .ceil => try self.airRound(inst, .{ .mode = .up, .precision = .inexact }), |
| 2278 | | .trunc_float => try self.airRound(inst, .{ .mode = .zero, .precision = .inexact }), |
| 2279 | | .sqrt => try self.airSqrt(inst), |
| 2280 | | .neg => try self.airFloatSign(inst), |
| 2281 | | |
| 2282 | | .abs => try self.airAbs(inst), |
| 2283 | | |
| 2284 | | .add_with_overflow => try self.airAddSubWithOverflow(inst), |
| 2285 | | .sub_with_overflow => try self.airAddSubWithOverflow(inst), |
| 2286 | | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 2287 | | .shl_with_overflow => try self.airShlWithOverflow(inst), |
| 2288 | | |
| 2289 | | .div_float, .div_trunc, .div_floor, .div_exact => try self.airMulDivBinOp(inst), |
| 2290 | | |
| 2291 | | .cmp_lt => try self.airCmp(inst, .lt), |
| 2292 | | .cmp_lte => try self.airCmp(inst, .lte), |
| 2293 | | .cmp_eq => try self.airCmp(inst, .eq), |
| 2294 | | .cmp_gte => try self.airCmp(inst, .gte), |
| 2295 | | .cmp_gt => try self.airCmp(inst, .gt), |
| 2296 | | .cmp_neq => try self.airCmp(inst, .neq), |
| 2297 | | |
| 2298 | | .cmp_vector => try self.airCmpVector(inst), |
| 2299 | | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 2300 | | |
| 2301 | | .alloc => try self.airAlloc(inst), |
| 2302 | | .ret_ptr => try self.airRetPtr(inst), |
| 2303 | | .arg => try self.airDbgArg(inst), |
| 2304 | | .assembly => try self.airAsm(inst), |
| 2305 | | .bitcast => try self.airBitCast(inst), |
| 2306 | | .block => try self.airBlock(inst), |
| 2307 | | .br => try self.airBr(inst), |
| 2308 | | .repeat => try self.airRepeat(inst), |
| 2309 | | .switch_dispatch => try self.airSwitchDispatch(inst), |
| 2310 | | .trap => try self.airTrap(), |
| 2311 | | .breakpoint => try self.airBreakpoint(), |
| 2312 | | .ret_addr => try self.airRetAddr(inst), |
| 2313 | | .frame_addr => try self.airFrameAddress(inst), |
| 2314 | | .cond_br => try self.airCondBr(inst), |
| 2315 | | .fptrunc => try self.airFptrunc(inst), |
| 2316 | | .fpext => try self.airFpext(inst), |
| 2317 | | .intcast => try self.airIntCast(inst), |
| 2318 | | .trunc => try self.airTrunc(inst), |
| 2319 | | .int_from_bool => try self.airIntFromBool(inst), |
| 2320 | | .is_non_null => try self.airIsNonNull(inst), |
| 2321 | | .is_non_null_ptr => try self.airIsNonNullPtr(inst), |
| 2322 | | .is_null => try self.airIsNull(inst), |
| 2323 | | .is_null_ptr => try self.airIsNullPtr(inst), |
| 2324 | | .is_non_err => try self.airIsNonErr(inst), |
| 2325 | | .is_non_err_ptr => try self.airIsNonErrPtr(inst), |
| 2326 | | .is_err => try self.airIsErr(inst), |
| 2327 | | .is_err_ptr => try self.airIsErrPtr(inst), |
| 2328 | | .load => try self.airLoad(inst), |
| 2329 | | .loop => try self.airLoop(inst), |
| 2330 | | .int_from_ptr => try self.airIntFromPtr(inst), |
| 2331 | | .ret => try self.airRet(inst, false), |
| 2332 | | .ret_safe => try self.airRet(inst, true), |
| 2333 | | .ret_load => try self.airRetLoad(inst), |
| 2334 | | .store => try self.airStore(inst, false), |
| 2335 | | .store_safe => try self.airStore(inst, true), |
| 2336 | | .struct_field_ptr=> try self.airStructFieldPtr(inst), |
| 2337 | | .struct_field_val=> try self.airStructFieldVal(inst), |
| 2338 | | .array_to_slice => try self.airArrayToSlice(inst), |
| 2339 | | .float_from_int => try self.airFloatFromInt(inst), |
| 2340 | | .int_from_float => try self.airIntFromFloat(inst), |
| 2341 | | .cmpxchg_strong => try self.airCmpxchg(inst), |
| 2342 | | .cmpxchg_weak => try self.airCmpxchg(inst), |
| 2343 | | .atomic_rmw => try self.airAtomicRmw(inst), |
| 2344 | | .atomic_load => try self.airAtomicLoad(inst), |
| 2345 | | .memcpy => try self.airMemcpy(inst), |
| 2346 | | .memset => try self.airMemset(inst, false), |
| 2347 | | .memset_safe => try self.airMemset(inst, true), |
| 2348 | | .set_union_tag => try self.airSetUnionTag(inst), |
| 2349 | | .get_union_tag => try self.airGetUnionTag(inst), |
| 2350 | | .clz => try self.airClz(inst), |
| 2351 | | .ctz => try self.airCtz(inst), |
| 2352 | | .popcount => try self.airPopCount(inst), |
| 2353 | | .byte_swap => try self.airByteSwap(inst), |
| 2354 | | .bit_reverse => try self.airBitReverse(inst), |
| 2355 | | .tag_name => try self.airTagName(inst), |
| 2356 | | .error_name => try self.airErrorName(inst), |
| 2357 | | .splat => try self.airSplat(inst), |
| 2358 | | .select => try self.airSelect(inst), |
| 2359 | | .shuffle => try self.airShuffle(inst), |
| 2360 | | .reduce => try self.airReduce(inst), |
| 2361 | | .aggregate_init => try self.airAggregateInit(inst), |
| 2362 | | .union_init => try self.airUnionInit(inst), |
| 2363 | | .prefetch => try self.airPrefetch(inst), |
| 2364 | | .mul_add => try self.airMulAdd(inst), |
| 2365 | | .addrspace_cast => return self.fail("TODO implement addrspace_cast", .{}), |
| 2366 | | |
| 2367 | | .@"try" => try self.airTry(inst), |
| 2368 | | .try_cold => try self.airTry(inst), // TODO |
| 2369 | | .try_ptr => try self.airTryPtr(inst), |
| 2370 | | .try_ptr_cold => try self.airTryPtr(inst), // TODO |
| 2371 | | |
| 2372 | | .dbg_stmt => try self.airDbgStmt(inst), |
| 2373 | | .dbg_empty_stmt => try self.airDbgEmptyStmt(), |
| 2374 | | .dbg_inline_block => try self.airDbgInlineBlock(inst), |
| 2375 | | .dbg_var_ptr, |
| 2376 | | .dbg_var_val, |
| 2377 | | .dbg_arg_inline, |
| 2378 | | => try self.airDbgVar(inst), |
| 2379 | | |
| 2380 | | .call => try self.airCall(inst, .auto), |
| 2381 | | .call_always_tail => try self.airCall(inst, .always_tail), |
| 2382 | | .call_never_tail => try self.airCall(inst, .never_tail), |
| 2383 | | .call_never_inline => try self.airCall(inst, .never_inline), |
| 2384 | | |
| 2385 | | .atomic_store_unordered => try self.airAtomicStore(inst, .unordered), |
| 2386 | | .atomic_store_monotonic => try self.airAtomicStore(inst, .monotonic), |
| 2387 | | .atomic_store_release => try self.airAtomicStore(inst, .release), |
| 2388 | | .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst), |
| 2389 | | |
| 2390 | | .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0), |
| 2391 | | .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1), |
| 2392 | | .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2), |
| 2393 | | .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3), |
| 2394 | | |
| 2395 | | .field_parent_ptr => try self.airFieldParentPtr(inst), |
| 2396 | | |
| 2397 | | .switch_br => try self.airSwitchBr(inst), |
| 2398 | | .loop_switch_br => try self.airLoopSwitchBr(inst), |
| 2399 | | .slice_ptr => try self.airSlicePtr(inst), |
| 2400 | | .slice_len => try self.airSliceLen(inst), |
| 2401 | | |
| 2402 | | .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst), |
| 2403 | | .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst), |
| 2404 | | |
| 2405 | | .array_elem_val => try self.airArrayElemVal(inst), |
| 2406 | | .slice_elem_val => try self.airSliceElemVal(inst), |
| 2407 | | .slice_elem_ptr => try self.airSliceElemPtr(inst), |
| 2408 | | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 2409 | | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 2410 | | |
| 2411 | | .inferred_alloc, .inferred_alloc_comptime => unreachable, |
| 2412 | | .unreach => self.finishAirBookkeeping(), |
| 2413 | | |
| 2414 | | .optional_payload => try self.airOptionalPayload(inst), |
| 2415 | | .optional_payload_ptr => try self.airOptionalPayloadPtr(inst), |
| 2416 | | .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst), |
| 2417 | | .unwrap_errunion_err => try self.airUnwrapErrUnionErr(inst), |
| 2418 | | .unwrap_errunion_payload => try self.airUnwrapErrUnionPayload(inst), |
| 2419 | | .unwrap_errunion_err_ptr => try self.airUnwrapErrUnionErrPtr(inst), |
| 2420 | | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrUnionPayloadPtr(inst), |
| 2421 | | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| 2422 | | .err_return_trace => try self.airErrReturnTrace(inst), |
| 2423 | | .set_err_return_trace => try self.airSetErrReturnTrace(inst), |
| 2424 | | .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst), |
| 2425 | | |
| 2426 | | .wrap_optional => try self.airWrapOptional(inst), |
| 2427 | | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 2428 | | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 2402 | => |air_tag| try cg.airUnaryMath(inst, air_tag), |
| 2403 | |
| 2404 | .floor => try cg.airRound(inst, .{ .mode = .down, .precision = .inexact }), |
| 2405 | .ceil => try cg.airRound(inst, .{ .mode = .up, .precision = .inexact }), |
| 2406 | .trunc_float => try cg.airRound(inst, .{ .mode = .zero, .precision = .inexact }), |
| 2407 | .sqrt => try cg.airSqrt(inst), |
| 2408 | .neg => try cg.airFloatSign(inst), |
| 2409 | |
| 2410 | .abs => try cg.airAbs(inst), |
| 2411 | |
| 2412 | .add_with_overflow => try cg.airAddSubWithOverflow(inst), |
| 2413 | .sub_with_overflow => try cg.airAddSubWithOverflow(inst), |
| 2414 | .mul_with_overflow => try cg.airMulWithOverflow(inst), |
| 2415 | .shl_with_overflow => try cg.airShlWithOverflow(inst), |
| 2416 | |
| 2417 | .div_float, .div_trunc, .div_floor, .div_exact => try cg.airMulDivBinOp(inst), |
| 2418 | |
| 2419 | .cmp_lt_errors_len => try cg.airCmpLtErrorsLen(inst), |
| 2420 | |
| 2421 | .bitcast => try cg.airBitCast(inst), |
| 2422 | .fptrunc => try cg.airFptrunc(inst), |
| 2423 | .fpext => try cg.airFpext(inst), |
| 2424 | .intcast => try cg.airIntCast(inst), |
| 2425 | .trunc => try cg.airTrunc(inst), |
| 2426 | .is_non_null => try cg.airIsNonNull(inst), |
| 2427 | .is_null => try cg.airIsNull(inst), |
| 2428 | .is_non_err => try cg.airIsNonErr(inst), |
| 2429 | .is_err => try cg.airIsErr(inst), |
| 2430 | .float_from_int => try cg.airFloatFromInt(inst), |
| 2431 | .int_from_float => try cg.airIntFromFloat(inst), |
| 2432 | .cmpxchg_strong => try cg.airCmpxchg(inst), |
| 2433 | .cmpxchg_weak => try cg.airCmpxchg(inst), |
| 2434 | .atomic_rmw => try cg.airAtomicRmw(inst), |
| 2435 | .atomic_load => try cg.airAtomicLoad(inst), |
| 2436 | .memcpy => try cg.airMemcpy(inst), |
| 2437 | .memset => try cg.airMemset(inst, false), |
| 2438 | .memset_safe => try cg.airMemset(inst, true), |
| 2439 | .ctz => try cg.airCtz(inst), |
| 2440 | .popcount => try cg.airPopCount(inst), |
| 2441 | .byte_swap => try cg.airByteSwap(inst), |
| 2442 | .bit_reverse => try cg.airBitReverse(inst), |
| 2443 | .tag_name => try cg.airTagName(inst), |
| 2444 | .error_name => try cg.airErrorName(inst), |
| 2445 | .splat => try cg.airSplat(inst), |
| 2446 | .select => try cg.airSelect(inst), |
| 2447 | .shuffle => try cg.airShuffle(inst), |
| 2448 | .reduce => try cg.airReduce(inst), |
| 2449 | .aggregate_init => try cg.airAggregateInit(inst), |
| 2450 | .prefetch => try cg.airPrefetch(inst), |
| 2451 | .mul_add => try cg.airMulAdd(inst), |
| 2452 | |
| 2453 | .atomic_store_unordered => try cg.airAtomicStore(inst, .unordered), |
| 2454 | .atomic_store_monotonic => try cg.airAtomicStore(inst, .monotonic), |
| 2455 | .atomic_store_release => try cg.airAtomicStore(inst, .release), |
| 2456 | .atomic_store_seq_cst => try cg.airAtomicStore(inst, .seq_cst), |
| 2457 | |
| 2458 | .array_elem_val => try cg.airArrayElemVal(inst), |
| 2459 | |
| 2460 | .optional_payload => try cg.airOptionalPayload(inst), |
| 2461 | .unwrap_errunion_err => try cg.airUnwrapErrUnionErr(inst), |
| 2462 | .unwrap_errunion_payload => try cg.airUnwrapErrUnionPayload(inst), |
| 2463 | .err_return_trace => try cg.airErrReturnTrace(inst), |
| 2464 | .set_err_return_trace => try cg.airSetErrReturnTrace(inst), |
| 2465 | .save_err_return_trace_index=> try cg.airSaveErrReturnTraceIndex(inst), |
| 2466 | |
| 2467 | .wrap_optional => try cg.airWrapOptional(inst), |
| 2468 | .wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst), |
| 2469 | .wrap_errunion_err => try cg.airWrapErrUnionErr(inst), |
| 2470 | // zig fmt: on |
| 2429 | 2471 | |
| 2472 | .add_safe, |
| 2473 | .sub_safe, |
| 2474 | .mul_safe, |
| 2475 | => return cg.fail("TODO implement safety_checked_instructions", .{}), |
| 2430 | 2476 | .add_optimized, |
| 2431 | 2477 | .sub_optimized, |
| 2432 | 2478 | .mul_optimized, |
| ... | ... | @@ -2437,179 +2483,7698 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2437 | 2483 | .rem_optimized, |
| 2438 | 2484 | .mod_optimized, |
| 2439 | 2485 | .neg_optimized, |
| 2440 | | .cmp_lt_optimized, |
| 2441 | | .cmp_lte_optimized, |
| 2442 | | .cmp_eq_optimized, |
| 2443 | | .cmp_gte_optimized, |
| 2444 | | .cmp_gt_optimized, |
| 2445 | | .cmp_neq_optimized, |
| 2446 | | .cmp_vector_optimized, |
| 2447 | 2486 | .reduce_optimized, |
| 2448 | 2487 | .int_from_float_optimized, |
| 2449 | | => return self.fail("TODO implement optimized float mode", .{}), |
| 2450 | | |
| 2451 | | .add_safe, |
| 2452 | | .sub_safe, |
| 2453 | | .mul_safe, |
| 2454 | | => return self.fail("TODO implement safety_checked_instructions", .{}), |
| 2455 | | |
| 2456 | | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), |
| 2457 | | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), |
| 2458 | | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), |
| 2459 | | |
| 2460 | | .c_va_arg => try self.airVaArg(inst), |
| 2461 | | .c_va_copy => try self.airVaCopy(inst), |
| 2462 | | .c_va_end => try self.airVaEnd(inst), |
| 2463 | | .c_va_start => try self.airVaStart(inst), |
| 2464 | | |
| 2465 | | .wasm_memory_size => unreachable, |
| 2466 | | .wasm_memory_grow => unreachable, |
| 2467 | | |
| 2468 | | .work_item_id => unreachable, |
| 2469 | | .work_group_size => unreachable, |
| 2470 | | .work_group_id => unreachable, |
| 2471 | | // zig fmt: on |
| 2472 | | } |
| 2473 | | self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping); |
| 2474 | | } |
| 2475 | | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); |
| 2476 | | } |
| 2477 | | |
| 2478 | | fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2479 | | const pt = self.pt; |
| 2480 | | const zcu = pt.zcu; |
| 2481 | | const ip = &zcu.intern_pool; |
| 2482 | | switch (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu)) { |
| 2483 | | .@"enum" => { |
| 2484 | | const enum_ty = Type.fromInterned(lazy_sym.ty); |
| 2485 | | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)}); |
| 2486 | | |
| 2487 | | const resolved_cc = abi.resolveCallingConvention(.auto, self.target.*); |
| 2488 | | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 2489 | | const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); |
| 2490 | | defer for (param_locks) |lock| self.register_manager.unlockReg(lock); |
| 2491 | | |
| 2492 | | const ret_reg = param_regs[0]; |
| 2493 | | const enum_mcv = MCValue{ .register = param_regs[1] }; |
| 2494 | | |
| 2495 | | const exitlude_jump_relocs = try self.gpa.alloc(Mir.Inst.Index, enum_ty.enumFieldCount(zcu)); |
| 2496 | | defer self.gpa.free(exitlude_jump_relocs); |
| 2497 | | |
| 2498 | | const data_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 2499 | | const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); |
| 2500 | | defer self.register_manager.unlockReg(data_lock); |
| 2501 | | try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty.toIntern() }); |
| 2502 | | |
| 2503 | | var data_off: i32 = 0; |
| 2504 | | const tag_names = enum_ty.enumFields(zcu); |
| 2505 | | for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, tag_index| { |
| 2506 | | const tag_name_len = tag_names.get(ip)[tag_index].length(ip); |
| 2507 | | const tag_val = try pt.enumValueFieldIndex(enum_ty, @intCast(tag_index)); |
| 2508 | | const tag_mcv = try self.genTypedValue(tag_val); |
| 2509 | | try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv); |
| 2510 | | const skip_reloc = try self.asmJccReloc(.ne, undefined); |
| 2511 | | |
| 2512 | | try self.genSetMem( |
| 2513 | | .{ .reg = ret_reg }, |
| 2514 | | 0, |
| 2515 | | Type.usize, |
| 2516 | | .{ .register_offset = .{ .reg = data_reg, .off = data_off } }, |
| 2517 | | .{}, |
| 2518 | | ); |
| 2519 | | try self.genSetMem( |
| 2520 | | .{ .reg = ret_reg }, |
| 2521 | | 8, |
| 2522 | | Type.usize, |
| 2523 | | .{ .immediate = tag_name_len }, |
| 2524 | | .{}, |
| 2525 | | ); |
| 2526 | | |
| 2527 | | exitlude_jump_reloc.* = try self.asmJmpReloc(undefined); |
| 2528 | | self.performReloc(skip_reloc); |
| 2529 | | |
| 2530 | | data_off += @intCast(tag_name_len + 1); |
| 2531 | | } |
| 2532 | | |
| 2533 | | try self.airTrap(); |
| 2534 | | |
| 2535 | | for (exitlude_jump_relocs) |reloc| self.performReloc(reloc); |
| 2536 | | try self.asmOpOnly(.{ ._, .ret }); |
| 2537 | | }, |
| 2538 | | else => return self.fail( |
| 2539 | | "TODO implement {s} for {}", |
| 2540 | | .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) }, |
| 2541 | | ), |
| 2542 | | } |
| 2543 | | } |
| 2544 | | |
| 2545 | | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) !void { |
| 2546 | | for (value.getRegs()) |reg| try self.register_manager.getReg(reg, inst); |
| 2547 | | } |
| 2548 | | |
| 2549 | | fn getValueIfFree(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { |
| 2550 | | for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg)) |
| 2551 | | self.register_manager.getRegAssumeFree(reg, inst); |
| 2552 | | } |
| 2553 | | |
| 2554 | | fn freeValue(self: *Self, value: MCValue) !void { |
| 2555 | | switch (value) { |
| 2556 | | .register => |reg| { |
| 2557 | | self.register_manager.freeReg(reg); |
| 2558 | | if (reg.class() == .x87) try self.asmRegister(.{ .f_, .free }, reg); |
| 2559 | | }, |
| 2560 | | .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg), |
| 2561 | | .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg), |
| 2562 | | .register_overflow => |reg_ov| { |
| 2563 | | self.register_manager.freeReg(reg_ov.reg); |
| 2564 | | self.eflags_inst = null; |
| 2565 | | }, |
| 2566 | | .eflags => self.eflags_inst = null, |
| 2567 | | else => {}, // TODO process stack allocation death |
| 2568 | | } |
| 2569 | | } |
| 2570 | | |
| 2571 | | fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) !void { |
| 2572 | | if (bt.feed()) if (operand.toIndex()) |inst| try self.processDeath(inst); |
| 2488 | => return cg.fail("TODO implement optimized float mode", .{}), |
| 2489 | |
| 2490 | .arg => try cg.airDbgArg(inst), |
| 2491 | .ptr_add => |air_tag| if (use_old) try cg.airPtrArithmetic(inst, air_tag) else { |
| 2492 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 2493 | const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2494 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 2495 | try ops[0].toSlicePtr(cg); |
| 2496 | var res: [1]Temp = undefined; |
| 2497 | if (ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{ |
| 2498 | .patterns = &.{ |
| 2499 | .{ .src = .{ .to_gpr, .simm32 } }, |
| 2500 | }, |
| 2501 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2502 | .each = .{ .once = &.{ |
| 2503 | .{ ._, ._, .lea, .dst0p, .leaa(.none, .src0, .add_src0_elem_size_times_src1), ._, ._ }, |
| 2504 | } }, |
| 2505 | }, .{ |
| 2506 | .dst_constraints = .{.{ .elem_size_is = 1 }}, |
| 2507 | .patterns = &.{ |
| 2508 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2509 | }, |
| 2510 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2511 | .each = .{ .once = &.{ |
| 2512 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .src1), ._, ._ }, |
| 2513 | } }, |
| 2514 | }, .{ |
| 2515 | .dst_constraints = .{.{ .elem_size_is = 2 }}, |
| 2516 | .patterns = &.{ |
| 2517 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2518 | }, |
| 2519 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2520 | .each = .{ .once = &.{ |
| 2521 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"2", .src1), ._, ._ }, |
| 2522 | } }, |
| 2523 | }, .{ |
| 2524 | .dst_constraints = .{.{ .elem_size_is = 2 + 1 }}, |
| 2525 | .patterns = &.{ |
| 2526 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2527 | }, |
| 2528 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2529 | .each = .{ .once = &.{ |
| 2530 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"2", .src1), ._, ._ }, |
| 2531 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ }, |
| 2532 | } }, |
| 2533 | }, .{ |
| 2534 | .dst_constraints = .{.{ .elem_size_is = 4 }}, |
| 2535 | .patterns = &.{ |
| 2536 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2537 | }, |
| 2538 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2539 | .each = .{ .once = &.{ |
| 2540 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"4", .src1), ._, ._ }, |
| 2541 | } }, |
| 2542 | }, .{ |
| 2543 | .dst_constraints = .{.{ .elem_size_is = 4 + 1 }}, |
| 2544 | .patterns = &.{ |
| 2545 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2546 | }, |
| 2547 | .dst_temps = .{.{ .ref = .src1 }}, |
| 2548 | .each = .{ .once = &.{ |
| 2549 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"4", .src1), ._, ._ }, |
| 2550 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ }, |
| 2551 | } }, |
| 2552 | }, .{ |
| 2553 | .required_features = .{ .@"64bit", null, null, null }, |
| 2554 | .dst_constraints = .{.{ .elem_size_is = 8 }}, |
| 2555 | .patterns = &.{ |
| 2556 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2557 | }, |
| 2558 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2559 | .each = .{ .once = &.{ |
| 2560 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"8", .src1), ._, ._ }, |
| 2561 | } }, |
| 2562 | }, .{ |
| 2563 | .required_features = .{ .@"64bit", null, null, null }, |
| 2564 | .dst_constraints = .{.{ .elem_size_is = 8 + 1 }}, |
| 2565 | .patterns = &.{ |
| 2566 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2567 | }, |
| 2568 | .dst_temps = .{.{ .ref = .src1 }}, |
| 2569 | .each = .{ .once = &.{ |
| 2570 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"8", .src1), ._, ._ }, |
| 2571 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ }, |
| 2572 | } }, |
| 2573 | }, .{ |
| 2574 | .dst_constraints = .{.po2_elem_size}, |
| 2575 | .patterns = &.{ |
| 2576 | .{ .src = .{ .to_gpr, .to_mut_gpr } }, |
| 2577 | }, |
| 2578 | .dst_temps = .{.{ .ref = .src1 }}, |
| 2579 | .clobbers = .{ .eflags = true }, |
| 2580 | .each = .{ .once = &.{ |
| 2581 | .{ ._, ._l, .sh, .src1p, .sa(.none, .add_log2_src0_elem_size), ._, ._ }, |
| 2582 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .src1), ._, ._ }, |
| 2583 | } }, |
| 2584 | }, .{ |
| 2585 | .patterns = &.{ |
| 2586 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2587 | }, |
| 2588 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2589 | .clobbers = .{ .eflags = true }, |
| 2590 | .each = .{ .once = &.{ |
| 2591 | .{ ._, .i_, .mul, .dst0p, .src1p, .sa(.none, .add_src0_elem_size), ._ }, |
| 2592 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ }, |
| 2593 | } }, |
| 2594 | } }) catch |err| switch (err) { |
| 2595 | error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ |
| 2596 | @tagName(air_tag), |
| 2597 | cg.typeOf(bin_op.lhs).fmt(pt), |
| 2598 | ops[0].tracking(cg), |
| 2599 | ops[1].tracking(cg), |
| 2600 | }), |
| 2601 | else => |e| return e, |
| 2602 | } else { // hack around Sema OPV bugs |
| 2603 | res[0] = ops[0]; |
| 2604 | } |
| 2605 | for (ops) |op| for (res) |r| { |
| 2606 | if (op.index == r.index) break; |
| 2607 | } else try op.die(cg); |
| 2608 | try res[0].moveTo(inst, cg); |
| 2609 | }, |
| 2610 | .ptr_sub => |air_tag| if (use_old) try cg.airPtrArithmetic(inst, air_tag) else { |
| 2611 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 2612 | const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2613 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 2614 | try ops[0].toSlicePtr(cg); |
| 2615 | var res: [1]Temp = undefined; |
| 2616 | if (ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{ |
| 2617 | .patterns = &.{ |
| 2618 | .{ .src = .{ .to_gpr, .simm32 } }, |
| 2619 | }, |
| 2620 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2621 | .each = .{ .once = &.{ |
| 2622 | .{ ._, ._, .lea, .dst0p, .leaa(.none, .src0, .sub_src0_elem_size_times_src1), ._, ._ }, |
| 2623 | } }, |
| 2624 | }, .{ |
| 2625 | .dst_constraints = .{.{ .elem_size_is = 1 }}, |
| 2626 | .patterns = &.{ |
| 2627 | .{ .src = .{ .to_gpr, .to_mut_gpr } }, |
| 2628 | }, |
| 2629 | .dst_temps = .{.{ .ref = .src1 }}, |
| 2630 | .clobbers = .{ .eflags = true }, |
| 2631 | .each = .{ .once = &.{ |
| 2632 | .{ ._, ._, .neg, .src1p, ._, ._, ._ }, |
| 2633 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .src1), ._, ._ }, |
| 2634 | } }, |
| 2635 | }, .{ |
| 2636 | .dst_constraints = .{.{ .elem_size_is = 2 }}, |
| 2637 | .patterns = &.{ |
| 2638 | .{ .src = .{ .to_gpr, .to_mut_gpr } }, |
| 2639 | }, |
| 2640 | .dst_temps = .{.{ .ref = .src1 }}, |
| 2641 | .clobbers = .{ .eflags = true }, |
| 2642 | .each = .{ .once = &.{ |
| 2643 | .{ ._, ._, .neg, .src1p, ._, ._, ._ }, |
| 2644 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"2", .src1), ._, ._ }, |
| 2645 | } }, |
| 2646 | }, .{ |
| 2647 | .dst_constraints = .{.{ .elem_size_is = 2 + 1 }}, |
| 2648 | .patterns = &.{ |
| 2649 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2650 | }, |
| 2651 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2652 | .clobbers = .{ .eflags = true }, |
| 2653 | .each = .{ .once = &.{ |
| 2654 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"2", .src1), ._, ._ }, |
| 2655 | .{ ._, ._, .neg, .dst0p, ._, ._, ._ }, |
| 2656 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ }, |
| 2657 | } }, |
| 2658 | }, .{ |
| 2659 | .dst_constraints = .{.{ .elem_size_is = 4 }}, |
| 2660 | .patterns = &.{ |
| 2661 | .{ .src = .{ .to_gpr, .to_mut_gpr } }, |
| 2662 | }, |
| 2663 | .dst_temps = .{.{ .ref = .src1 }}, |
| 2664 | .clobbers = .{ .eflags = true }, |
| 2665 | .each = .{ .once = &.{ |
| 2666 | .{ ._, ._, .neg, .src1p, ._, ._, ._ }, |
| 2667 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"4", .src1), ._, ._ }, |
| 2668 | } }, |
| 2669 | }, .{ |
| 2670 | .dst_constraints = .{.{ .elem_size_is = 4 + 1 }}, |
| 2671 | .patterns = &.{ |
| 2672 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2673 | }, |
| 2674 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2675 | .clobbers = .{ .eflags = true }, |
| 2676 | .each = .{ .once = &.{ |
| 2677 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"4", .src1), ._, ._ }, |
| 2678 | .{ ._, ._, .neg, .dst0p, ._, ._, ._ }, |
| 2679 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ }, |
| 2680 | } }, |
| 2681 | }, .{ |
| 2682 | .required_features = .{ .@"64bit", null, null, null }, |
| 2683 | .dst_constraints = .{.{ .elem_size_is = 8 }}, |
| 2684 | .patterns = &.{ |
| 2685 | .{ .src = .{ .to_gpr, .to_mut_gpr } }, |
| 2686 | }, |
| 2687 | .dst_temps = .{.{ .ref = .src1 }}, |
| 2688 | .clobbers = .{ .eflags = true }, |
| 2689 | .each = .{ .once = &.{ |
| 2690 | .{ ._, ._, .neg, .src1p, ._, ._, ._ }, |
| 2691 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"8", .src1), ._, ._ }, |
| 2692 | } }, |
| 2693 | }, .{ |
| 2694 | .required_features = .{ .@"64bit", null, null, null }, |
| 2695 | .dst_constraints = .{.{ .elem_size_is = 8 + 1 }}, |
| 2696 | .patterns = &.{ |
| 2697 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2698 | }, |
| 2699 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2700 | .clobbers = .{ .eflags = true }, |
| 2701 | .each = .{ .once = &.{ |
| 2702 | .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"8", .src1), ._, ._ }, |
| 2703 | .{ ._, ._, .neg, .dst0p, ._, ._, ._ }, |
| 2704 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ }, |
| 2705 | } }, |
| 2706 | }, .{ |
| 2707 | .dst_constraints = .{.po2_elem_size}, |
| 2708 | .patterns = &.{ |
| 2709 | .{ .src = .{ .to_gpr, .to_mut_gpr } }, |
| 2710 | }, |
| 2711 | .dst_temps = .{.{ .ref = .src1 }}, |
| 2712 | .clobbers = .{ .eflags = true }, |
| 2713 | .each = .{ .once = &.{ |
| 2714 | .{ ._, ._l, .sa, .src1p, .sa(.none, .add_log2_src0_elem_size), ._, ._ }, |
| 2715 | .{ ._, ._, .neg, .src1p, ._, ._, ._ }, |
| 2716 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .src1), ._, ._ }, |
| 2717 | } }, |
| 2718 | }, .{ |
| 2719 | .patterns = &.{ |
| 2720 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 2721 | }, |
| 2722 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 2723 | .clobbers = .{ .eflags = true }, |
| 2724 | .each = .{ .once = &.{ |
| 2725 | .{ ._, .i_, .mul, .dst0p, .src1p, .sa(.none, .sub_src0_elem_size), ._ }, |
| 2726 | .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ }, |
| 2727 | } }, |
| 2728 | } }) catch |err| switch (err) { |
| 2729 | error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ |
| 2730 | @tagName(air_tag), |
| 2731 | cg.typeOf(bin_op.lhs).fmt(pt), |
| 2732 | ops[0].tracking(cg), |
| 2733 | ops[1].tracking(cg), |
| 2734 | }), |
| 2735 | else => |e| return e, |
| 2736 | } else { |
| 2737 | // hack around Sema OPV bugs |
| 2738 | res[0] = ops[0]; |
| 2739 | } |
| 2740 | for (ops) |op| for (res) |r| { |
| 2741 | if (op.index == r.index) break; |
| 2742 | } else try op.die(cg); |
| 2743 | try res[0].moveTo(inst, cg); |
| 2744 | }, |
| 2745 | .alloc => if (use_old) try cg.airAlloc(inst) else { |
| 2746 | const ty = air_datas[@intFromEnum(inst)].ty; |
| 2747 | var slot = try cg.tempInit(ty, .{ .lea_frame = .{ |
| 2748 | .index = try cg.allocMemPtr(inst), |
| 2749 | } }); |
| 2750 | try slot.moveTo(inst, cg); |
| 2751 | }, |
| 2752 | .inferred_alloc, .inferred_alloc_comptime => unreachable, |
| 2753 | .ret_ptr => if (use_old) try cg.airRetPtr(inst) else { |
| 2754 | const ty = air_datas[@intFromEnum(inst)].ty; |
| 2755 | var slot = switch (cg.ret_mcv.long) { |
| 2756 | else => unreachable, |
| 2757 | .none => try cg.tempInit(ty, .{ .lea_frame = .{ |
| 2758 | .index = try cg.allocMemPtr(inst), |
| 2759 | } }), |
| 2760 | .load_frame => slot: { |
| 2761 | var slot = try cg.tempInit(ty, cg.ret_mcv.long); |
| 2762 | try slot.toOffset(cg.ret_mcv.short.indirect.off, cg); |
| 2763 | break :slot slot; |
| 2764 | }, |
| 2765 | }; |
| 2766 | try slot.moveTo(inst, cg); |
| 2767 | }, |
| 2768 | .assembly => try cg.airAsm(inst), |
| 2769 | .bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else { |
| 2770 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 2771 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 2772 | var res: [1]Temp = undefined; |
| 2773 | cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) { |
| 2774 | else => unreachable, |
| 2775 | .bit_and, .bool_and => .@"and", |
| 2776 | .bit_or, .bool_or => .@"or", |
| 2777 | .xor => .xor, |
| 2778 | })) { |
| 2779 | else => unreachable, |
| 2780 | inline .@"and", .@"or", .xor => |mir_tag| comptime &.{ .{ |
| 2781 | .src_constraints = .{ .{ .size = .byte }, .{ .size = .byte } }, |
| 2782 | .patterns = &.{ |
| 2783 | .{ .src = .{ .mut_mem, .imm8 } }, |
| 2784 | .{ .src = .{ .imm8, .mut_mem }, .commute = .{ 0, 1 } }, |
| 2785 | .{ .src = .{ .to_mut_gpr, .imm8 } }, |
| 2786 | .{ .src = .{ .imm8, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 2787 | .{ .src = .{ .mut_mem, .to_gpr } }, |
| 2788 | .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } }, |
| 2789 | .{ .src = .{ .to_mut_gpr, .mem } }, |
| 2790 | .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 2791 | .{ .src = .{ .to_mut_gpr, .to_gpr } }, |
| 2792 | }, |
| 2793 | .dst_temps = .{.{ .ref = .src0 }}, |
| 2794 | .clobbers = .{ .eflags = true }, |
| 2795 | .each = .{ .once = &.{ |
| 2796 | .{ ._, ._, mir_tag, .dst0b, .src1b, ._, ._ }, |
| 2797 | } }, |
| 2798 | }, .{ |
| 2799 | .src_constraints = .{ .{ .size = .word }, .{ .size = .word } }, |
| 2800 | .patterns = &.{ |
| 2801 | .{ .src = .{ .mut_mem, .imm16 } }, |
| 2802 | .{ .src = .{ .imm16, .mut_mem }, .commute = .{ 0, 1 } }, |
| 2803 | .{ .src = .{ .to_mut_gpr, .imm16 } }, |
| 2804 | .{ .src = .{ .imm16, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 2805 | .{ .src = .{ .mut_mem, .to_gpr } }, |
| 2806 | .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } }, |
| 2807 | .{ .src = .{ .to_mut_gpr, .mem } }, |
| 2808 | .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 2809 | .{ .src = .{ .to_mut_gpr, .to_gpr } }, |
| 2810 | }, |
| 2811 | .dst_temps = .{.{ .ref = .src0 }}, |
| 2812 | .clobbers = .{ .eflags = true }, |
| 2813 | .each = .{ .once = &.{ |
| 2814 | .{ ._, ._, mir_tag, .dst0w, .src1w, ._, ._ }, |
| 2815 | } }, |
| 2816 | }, .{ |
| 2817 | .src_constraints = .{ .{ .size = .dword }, .{ .size = .dword } }, |
| 2818 | .patterns = &.{ |
| 2819 | .{ .src = .{ .mut_mem, .imm32 } }, |
| 2820 | .{ .src = .{ .imm32, .mut_mem }, .commute = .{ 0, 1 } }, |
| 2821 | .{ .src = .{ .to_mut_gpr, .imm32 } }, |
| 2822 | .{ .src = .{ .imm32, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 2823 | .{ .src = .{ .mut_mem, .to_gpr } }, |
| 2824 | .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } }, |
| 2825 | .{ .src = .{ .to_mut_gpr, .mem } }, |
| 2826 | .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 2827 | .{ .src = .{ .to_mut_gpr, .to_gpr } }, |
| 2828 | }, |
| 2829 | .dst_temps = .{.{ .ref = .src0 }}, |
| 2830 | .clobbers = .{ .eflags = true }, |
| 2831 | .each = .{ .once = &.{ |
| 2832 | .{ ._, ._, mir_tag, .dst0d, .src1d, ._, ._ }, |
| 2833 | } }, |
| 2834 | }, .{ |
| 2835 | .required_features = .{ .@"64bit", null, null, null }, |
| 2836 | .src_constraints = .{ .{ .size = .qword }, .{ .size = .qword } }, |
| 2837 | .patterns = &.{ |
| 2838 | .{ .src = .{ .mut_mem, .simm32 } }, |
| 2839 | .{ .src = .{ .simm32, .mut_mem }, .commute = .{ 0, 1 } }, |
| 2840 | .{ .src = .{ .to_mut_gpr, .simm32 } }, |
| 2841 | .{ .src = .{ .simm32, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 2842 | .{ .src = .{ .mut_mem, .to_gpr } }, |
| 2843 | .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } }, |
| 2844 | .{ .src = .{ .to_mut_gpr, .mem } }, |
| 2845 | .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 2846 | .{ .src = .{ .to_mut_gpr, .to_gpr } }, |
| 2847 | }, |
| 2848 | .dst_temps = .{.{ .ref = .src0 }}, |
| 2849 | .clobbers = .{ .eflags = true }, |
| 2850 | .each = .{ .once = &.{ |
| 2851 | .{ ._, ._, mir_tag, .dst0q, .src1q, ._, ._ }, |
| 2852 | } }, |
| 2853 | }, .{ |
| 2854 | .required_features = .{ .mmx, null, null, null }, |
| 2855 | .src_constraints = .{ .{ .size = .qword }, .{ .size = .qword } }, |
| 2856 | .patterns = &.{ |
| 2857 | .{ .src = .{ .to_mut_mm, .mem } }, |
| 2858 | .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } }, |
| 2859 | .{ .src = .{ .to_mut_mm, .to_mm } }, |
| 2860 | }, |
| 2861 | .dst_temps = .{.{ .ref = .src0 }}, |
| 2862 | .each = .{ .once = &.{ |
| 2863 | .{ ._, .p_, mir_tag, .dst0q, .src1q, ._, ._ }, |
| 2864 | } }, |
| 2865 | }, .{ |
| 2866 | .required_features = .{ .avx, null, null, null }, |
| 2867 | .src_constraints = .{ .{ .size = .xword }, .{ .size = .xword } }, |
| 2868 | .patterns = &.{ |
| 2869 | .{ .src = .{ .to_xmm, .mem } }, |
| 2870 | .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } }, |
| 2871 | .{ .src = .{ .to_xmm, .to_xmm } }, |
| 2872 | }, |
| 2873 | .dst_temps = .{.{ .rc = .sse }}, |
| 2874 | .each = .{ .once = &.{ |
| 2875 | .{ ._, .vp_, mir_tag, .dst0x, .src0x, .src1x, ._ }, |
| 2876 | } }, |
| 2877 | }, .{ |
| 2878 | .required_features = .{ .sse2, null, null, null }, |
| 2879 | .src_constraints = .{ .{ .size = .xword }, .{ .size = .xword } }, |
| 2880 | .patterns = &.{ |
| 2881 | .{ .src = .{ .to_mut_xmm, .mem } }, |
| 2882 | .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } }, |
| 2883 | .{ .src = .{ .to_mut_xmm, .to_xmm } }, |
| 2884 | }, |
| 2885 | .dst_temps = .{.{ .ref = .src0 }}, |
| 2886 | .each = .{ .once = &.{ |
| 2887 | .{ ._, .p_, mir_tag, .dst0x, .src1x, ._, ._ }, |
| 2888 | } }, |
| 2889 | }, .{ |
| 2890 | .required_features = .{ .sse, null, null, null }, |
| 2891 | .src_constraints = .{ .{ .size = .xword }, .{ .size = .xword } }, |
| 2892 | .patterns = &.{ |
| 2893 | .{ .src = .{ .to_mut_xmm, .mem } }, |
| 2894 | .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } }, |
| 2895 | .{ .src = .{ .to_mut_xmm, .to_xmm } }, |
| 2896 | }, |
| 2897 | .dst_temps = .{.{ .ref = .src0 }}, |
| 2898 | .each = .{ .once = &.{ |
| 2899 | .{ ._, ._ps, mir_tag, .dst0x, .src1x, ._, ._ }, |
| 2900 | } }, |
| 2901 | }, .{ |
| 2902 | .required_features = .{ .avx2, null, null, null }, |
| 2903 | .src_constraints = .{ .{ .size = .yword }, .{ .size = .yword } }, |
| 2904 | .patterns = &.{ |
| 2905 | .{ .src = .{ .to_ymm, .mem } }, |
| 2906 | .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } }, |
| 2907 | .{ .src = .{ .to_ymm, .to_ymm } }, |
| 2908 | }, |
| 2909 | .dst_temps = .{.{ .rc = .sse }}, |
| 2910 | .each = .{ .once = &.{ |
| 2911 | .{ ._, .vp_, mir_tag, .dst0y, .src0y, .src1y, ._ }, |
| 2912 | } }, |
| 2913 | }, .{ |
| 2914 | .required_features = .{ .avx, null, null, null }, |
| 2915 | .src_constraints = .{ .{ .size = .yword }, .{ .size = .yword } }, |
| 2916 | .patterns = &.{ |
| 2917 | .{ .src = .{ .to_ymm, .mem } }, |
| 2918 | .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } }, |
| 2919 | .{ .src = .{ .to_ymm, .to_ymm } }, |
| 2920 | }, |
| 2921 | .dst_temps = .{.{ .rc = .sse }}, |
| 2922 | .each = .{ .once = &.{ |
| 2923 | .{ ._, .v_pd, mir_tag, .dst0y, .src0y, .src1y, ._ }, |
| 2924 | } }, |
| 2925 | }, .{ |
| 2926 | .required_features = .{ .avx2, null, null, null }, |
| 2927 | .src_constraints = .{ .{ .multiple_size = .yword }, .{ .multiple_size = .yword } }, |
| 2928 | .patterns = &.{ |
| 2929 | .{ .src = .{ .to_mem, .to_mem } }, |
| 2930 | }, |
| 2931 | .extra_temps = .{ |
| 2932 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 2933 | .{ .kind = .{ .rc = .sse } }, |
| 2934 | .unused, |
| 2935 | .unused, |
| 2936 | .unused, |
| 2937 | .unused, |
| 2938 | }, |
| 2939 | .dst_temps = .{.mem}, |
| 2940 | .clobbers = .{ .eflags = true }, |
| 2941 | .each = .{ .once = &.{ |
| 2942 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 2943 | .{ .@"0:", .v_dqu, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 2944 | .{ ._, .vp_, mir_tag, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 2945 | .{ ._, .v_dqu, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ }, |
| 2946 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 2947 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 2948 | } }, |
| 2949 | }, .{ |
| 2950 | .required_features = .{ .avx, null, null, null }, |
| 2951 | .src_constraints = .{ .{ .multiple_size = .yword }, .{ .multiple_size = .yword } }, |
| 2952 | .patterns = &.{ |
| 2953 | .{ .src = .{ .to_mem, .to_mem } }, |
| 2954 | }, |
| 2955 | .extra_temps = .{ |
| 2956 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 2957 | .{ .kind = .{ .rc = .sse } }, |
| 2958 | .unused, |
| 2959 | .unused, |
| 2960 | .unused, |
| 2961 | .unused, |
| 2962 | }, |
| 2963 | .dst_temps = .{.mem}, |
| 2964 | .clobbers = .{ .eflags = true }, |
| 2965 | .each = .{ .once = &.{ |
| 2966 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 2967 | .{ .@"0:", .v_pd, .movu, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 2968 | .{ ._, .v_pd, mir_tag, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 2969 | .{ ._, .v_pd, .movu, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ }, |
| 2970 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 2971 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 2972 | } }, |
| 2973 | }, .{ |
| 2974 | .required_features = .{ .avx, null, null, null }, |
| 2975 | .src_constraints = .{ .{ .multiple_size = .xword }, .{ .multiple_size = .xword } }, |
| 2976 | .patterns = &.{ |
| 2977 | .{ .src = .{ .to_mem, .to_mem } }, |
| 2978 | }, |
| 2979 | .extra_temps = .{ |
| 2980 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 2981 | .{ .kind = .{ .rc = .sse } }, |
| 2982 | .unused, |
| 2983 | .unused, |
| 2984 | .unused, |
| 2985 | .unused, |
| 2986 | }, |
| 2987 | .dst_temps = .{.mem}, |
| 2988 | .clobbers = .{ .eflags = true }, |
| 2989 | .each = .{ .once = &.{ |
| 2990 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 2991 | .{ .@"0:", .v_dqu, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 2992 | .{ ._, .vp_, mir_tag, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 2993 | .{ ._, .v_dqu, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ }, |
| 2994 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 2995 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 2996 | } }, |
| 2997 | }, .{ |
| 2998 | .required_features = .{ .sse2, null, null, null }, |
| 2999 | .src_constraints = .{ .{ .multiple_size = .xword }, .{ .multiple_size = .xword } }, |
| 3000 | .patterns = &.{ |
| 3001 | .{ .src = .{ .to_mem, .to_mem } }, |
| 3002 | }, |
| 3003 | .extra_temps = .{ |
| 3004 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3005 | .{ .kind = .{ .rc = .sse } }, |
| 3006 | .unused, |
| 3007 | .unused, |
| 3008 | .unused, |
| 3009 | .unused, |
| 3010 | }, |
| 3011 | .dst_temps = .{.mem}, |
| 3012 | .clobbers = .{ .eflags = true }, |
| 3013 | .each = .{ .once = &.{ |
| 3014 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3015 | .{ .@"0:", ._dqu, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 3016 | .{ ._, .p_, mir_tag, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 3017 | .{ ._, ._dqu, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ }, |
| 3018 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3019 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3020 | } }, |
| 3021 | }, .{ |
| 3022 | .required_features = .{ .sse, null, null, null }, |
| 3023 | .src_constraints = .{ .{ .multiple_size = .xword }, .{ .multiple_size = .xword } }, |
| 3024 | .patterns = &.{ |
| 3025 | .{ .src = .{ .to_mem, .to_mem } }, |
| 3026 | }, |
| 3027 | .extra_temps = .{ |
| 3028 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3029 | .{ .kind = .{ .rc = .sse } }, |
| 3030 | .unused, |
| 3031 | .unused, |
| 3032 | .unused, |
| 3033 | .unused, |
| 3034 | }, |
| 3035 | .dst_temps = .{.mem}, |
| 3036 | .clobbers = .{ .eflags = true }, |
| 3037 | .each = .{ .once = &.{ |
| 3038 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3039 | .{ .@"0:", ._ps, .movu, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 3040 | .{ ._, ._ps, mir_tag, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 3041 | .{ ._, ._ps, .movu, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ }, |
| 3042 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3043 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3044 | } }, |
| 3045 | }, .{ |
| 3046 | .required_features = .{ .mmx, null, null, null }, |
| 3047 | .src_constraints = .{ .{ .multiple_size = .qword }, .{ .multiple_size = .qword } }, |
| 3048 | .patterns = &.{ |
| 3049 | .{ .src = .{ .to_mem, .to_mem } }, |
| 3050 | }, |
| 3051 | .extra_temps = .{ |
| 3052 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3053 | .{ .kind = .{ .rc = .mmx } }, |
| 3054 | .unused, |
| 3055 | .unused, |
| 3056 | .unused, |
| 3057 | .unused, |
| 3058 | }, |
| 3059 | .dst_temps = .{.mem}, |
| 3060 | .clobbers = .{ .eflags = true }, |
| 3061 | .each = .{ .once = &.{ |
| 3062 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3063 | .{ .@"0:", ._q, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 3064 | .{ ._, .p_, mir_tag, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 3065 | .{ ._, ._q, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ }, |
| 3066 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3067 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3068 | } }, |
| 3069 | }, .{ |
| 3070 | .src_constraints = .{ .{ .multiple_size = .qword }, .{ .multiple_size = .qword } }, |
| 3071 | .patterns = &.{ |
| 3072 | .{ .src = .{ .to_mem, .to_mem } }, |
| 3073 | }, |
| 3074 | .extra_temps = .{ |
| 3075 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3076 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3077 | .unused, |
| 3078 | .unused, |
| 3079 | .unused, |
| 3080 | .unused, |
| 3081 | }, |
| 3082 | .dst_temps = .{.mem}, |
| 3083 | .clobbers = .{ .eflags = true }, |
| 3084 | .each = .{ .once = &.{ |
| 3085 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3086 | .{ .@"0:", ._, .mov, .tmp1p, .memia(.src0p, .tmp0, .add_size), ._, ._ }, |
| 3087 | .{ ._, ._, mir_tag, .tmp1p, .memia(.src1p, .tmp0, .add_size), ._, ._ }, |
| 3088 | .{ ._, ._, .mov, .memia(.dst0p, .tmp0, .add_size), .tmp1p, ._, ._ }, |
| 3089 | .{ ._, ._, .add, .tmp0p, .sa(.tmp1, .add_size), ._, ._ }, |
| 3090 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3091 | } }, |
| 3092 | } }, |
| 3093 | }) catch |err| switch (err) { |
| 3094 | error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ |
| 3095 | @tagName(air_tag), |
| 3096 | cg.typeOf(bin_op.lhs).fmt(pt), |
| 3097 | ops[0].tracking(cg), |
| 3098 | ops[1].tracking(cg), |
| 3099 | }), |
| 3100 | else => |e| return e, |
| 3101 | }; |
| 3102 | for (ops) |op| for (res) |r| { |
| 3103 | if (op.index == r.index) break; |
| 3104 | } else try op.die(cg); |
| 3105 | try res[0].moveTo(inst, cg); |
| 3106 | }, |
| 3107 | .not => |air_tag| if (use_old) try cg.airUnOp(inst, air_tag) else { |
| 3108 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 3109 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 3110 | var res: [1]Temp = undefined; |
| 3111 | cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{ |
| 3112 | .src_constraints = .{ .{ .signed_or_exact_int = .byte }, .any }, |
| 3113 | .patterns = &.{ |
| 3114 | .{ .src = .{ .mut_mem, .none } }, |
| 3115 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 3116 | }, |
| 3117 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3118 | .each = .{ .once = &.{ |
| 3119 | .{ ._, ._, .not, .dst0b, ._, ._, ._ }, |
| 3120 | } }, |
| 3121 | }, .{ |
| 3122 | .src_constraints = .{ .{ .unsigned_int = .byte }, .any }, |
| 3123 | .patterns = &.{ |
| 3124 | .{ .src = .{ .mut_mem, .none } }, |
| 3125 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 3126 | }, |
| 3127 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3128 | .clobbers = .{ .eflags = true }, |
| 3129 | .each = .{ .once = &.{ |
| 3130 | .{ ._, ._, .xor, .dst0b, .sa(.src0, .add_umax), ._, ._ }, |
| 3131 | } }, |
| 3132 | }, .{ |
| 3133 | .src_constraints = .{ .{ .signed_or_exact_int = .word }, .any }, |
| 3134 | .patterns = &.{ |
| 3135 | .{ .src = .{ .mut_mem, .none } }, |
| 3136 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 3137 | }, |
| 3138 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3139 | .each = .{ .once = &.{ |
| 3140 | .{ ._, ._, .not, .dst0w, ._, ._, ._ }, |
| 3141 | } }, |
| 3142 | }, .{ |
| 3143 | .src_constraints = .{ .{ .unsigned_int = .word }, .any }, |
| 3144 | .patterns = &.{ |
| 3145 | .{ .src = .{ .mut_mem, .none } }, |
| 3146 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 3147 | }, |
| 3148 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3149 | .clobbers = .{ .eflags = true }, |
| 3150 | .each = .{ .once = &.{ |
| 3151 | .{ ._, ._, .xor, .dst0w, .sa(.src0, .add_umax), ._, ._ }, |
| 3152 | } }, |
| 3153 | }, .{ |
| 3154 | .src_constraints = .{ .{ .signed_or_exact_int = .dword }, .any }, |
| 3155 | .patterns = &.{ |
| 3156 | .{ .src = .{ .mut_mem, .none } }, |
| 3157 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 3158 | }, |
| 3159 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3160 | .each = .{ .once = &.{ |
| 3161 | .{ ._, ._, .not, .dst0d, ._, ._, ._ }, |
| 3162 | } }, |
| 3163 | }, .{ |
| 3164 | .src_constraints = .{ .{ .unsigned_int = .dword }, .any }, |
| 3165 | .patterns = &.{ |
| 3166 | .{ .src = .{ .mut_mem, .none } }, |
| 3167 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 3168 | }, |
| 3169 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3170 | .clobbers = .{ .eflags = true }, |
| 3171 | .each = .{ .once = &.{ |
| 3172 | .{ ._, ._, .xor, .dst0d, .sa(.src0, .add_umax), ._, ._ }, |
| 3173 | } }, |
| 3174 | }, .{ |
| 3175 | .required_features = .{ .@"64bit", null, null, null }, |
| 3176 | .src_constraints = .{ .{ .signed_or_exact_int = .qword }, .any }, |
| 3177 | .patterns = &.{ |
| 3178 | .{ .src = .{ .mut_mem, .none } }, |
| 3179 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 3180 | }, |
| 3181 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3182 | .each = .{ .once = &.{ |
| 3183 | .{ ._, ._, .not, .dst0q, ._, ._, ._ }, |
| 3184 | } }, |
| 3185 | }, .{ |
| 3186 | .required_features = .{ .@"64bit", null, null, null }, |
| 3187 | .src_constraints = .{ .{ .unsigned_int = .qword }, .any }, |
| 3188 | .patterns = &.{ |
| 3189 | .{ .src = .{ .mem, .none } }, |
| 3190 | .{ .src = .{ .to_gpr, .none } }, |
| 3191 | }, |
| 3192 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 3193 | .each = .{ .once = &.{ |
| 3194 | .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ }, |
| 3195 | .{ ._, ._, .xor, .dst0q, .src0q, ._, ._ }, |
| 3196 | } }, |
| 3197 | }, .{ |
| 3198 | .required_features = .{ .mmx, null, null, null }, |
| 3199 | .src_constraints = .{ .{ .signed_or_exact_int = .qword }, .any }, |
| 3200 | .patterns = &.{ |
| 3201 | .{ .src = .{ .mem, .none } }, |
| 3202 | .{ .src = .{ .to_mm, .none } }, |
| 3203 | }, |
| 3204 | .dst_temps = .{.{ .rc = .mmx }}, |
| 3205 | .each = .{ .once = &.{ |
| 3206 | .{ ._, .p_d, .cmpeq, .dst0q, .dst0q, ._, ._ }, |
| 3207 | .{ ._, .p_, .xor, .dst0q, .src0q, ._, ._ }, |
| 3208 | } }, |
| 3209 | }, .{ |
| 3210 | .required_features = .{ .mmx, null, null, null }, |
| 3211 | .src_constraints = .{ .{ .unsigned_int = .qword }, .any }, |
| 3212 | .patterns = &.{ |
| 3213 | .{ .src = .{ .to_mut_mm, .none } }, |
| 3214 | }, |
| 3215 | .extra_temps = .{ |
| 3216 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3217 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 3218 | .unused, |
| 3219 | .unused, |
| 3220 | .unused, |
| 3221 | .unused, |
| 3222 | }, |
| 3223 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3224 | .each = .{ .once = &.{ |
| 3225 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 3226 | .{ ._, .p_, .xor, .dst0q, .lea(.qword, .tmp0), ._, ._ }, |
| 3227 | } }, |
| 3228 | }, .{ |
| 3229 | .required_features = .{ .avx, null, null, null }, |
| 3230 | .src_constraints = .{ .{ .signed_or_exact_int = .xword }, .any }, |
| 3231 | .patterns = &.{ |
| 3232 | .{ .src = .{ .mem, .none } }, |
| 3233 | .{ .src = .{ .to_xmm, .none } }, |
| 3234 | }, |
| 3235 | .dst_temps = .{.{ .rc = .sse }}, |
| 3236 | .each = .{ .once = &.{ |
| 3237 | .{ ._, .vp_q, .cmpeq, .dst0x, .dst0x, .dst0x, ._ }, |
| 3238 | .{ ._, .vp_, .xor, .dst0x, .dst0x, .src0x, ._ }, |
| 3239 | } }, |
| 3240 | }, .{ |
| 3241 | .required_features = .{ .avx, null, null, null }, |
| 3242 | .src_constraints = .{ .{ .unsigned_int = .xword }, .any }, |
| 3243 | .patterns = &.{ |
| 3244 | .{ .src = .{ .to_xmm, .none } }, |
| 3245 | }, |
| 3246 | .extra_temps = .{ |
| 3247 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3248 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 3249 | .unused, |
| 3250 | .unused, |
| 3251 | .unused, |
| 3252 | .unused, |
| 3253 | }, |
| 3254 | .dst_temps = .{.{ .rc = .sse }}, |
| 3255 | .each = .{ .once = &.{ |
| 3256 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 3257 | .{ ._, .vp_, .xor, .dst0x, .src0x, .lea(.xword, .tmp0), ._ }, |
| 3258 | } }, |
| 3259 | }, .{ |
| 3260 | .required_features = .{ .sse2, null, null, null }, |
| 3261 | .src_constraints = .{ .{ .signed_or_exact_int = .xword }, .any }, |
| 3262 | .patterns = &.{ |
| 3263 | .{ .src = .{ .mem, .none } }, |
| 3264 | .{ .src = .{ .to_xmm, .none } }, |
| 3265 | }, |
| 3266 | .dst_temps = .{.{ .rc = .sse }}, |
| 3267 | .each = .{ .once = &.{ |
| 3268 | .{ ._, .p_d, .cmpeq, .dst0x, .dst0x, ._, ._ }, |
| 3269 | .{ ._, .p_, .xor, .dst0x, .src0x, ._, ._ }, |
| 3270 | } }, |
| 3271 | }, .{ |
| 3272 | .required_features = .{ .sse2, null, null, null }, |
| 3273 | .src_constraints = .{ .{ .unsigned_int = .xword }, .any }, |
| 3274 | .patterns = &.{ |
| 3275 | .{ .src = .{ .to_mut_xmm, .none } }, |
| 3276 | }, |
| 3277 | .extra_temps = .{ |
| 3278 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3279 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 3280 | .unused, |
| 3281 | .unused, |
| 3282 | .unused, |
| 3283 | .unused, |
| 3284 | }, |
| 3285 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3286 | .each = .{ .once = &.{ |
| 3287 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 3288 | .{ ._, .p_, .xor, .dst0x, .lea(.xword, .tmp0), ._, ._ }, |
| 3289 | } }, |
| 3290 | }, .{ |
| 3291 | .required_features = .{ .sse, null, null, null }, |
| 3292 | .src_constraints = .{ .{ .int = .xword }, .any }, |
| 3293 | .patterns = &.{ |
| 3294 | .{ .src = .{ .to_mut_xmm, .none } }, |
| 3295 | }, |
| 3296 | .extra_temps = .{ |
| 3297 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3298 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 3299 | .unused, |
| 3300 | .unused, |
| 3301 | .unused, |
| 3302 | .unused, |
| 3303 | }, |
| 3304 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3305 | .each = .{ .once = &.{ |
| 3306 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 3307 | .{ ._, ._ps, .xor, .dst0x, .lea(.xword, .tmp0), ._, ._ }, |
| 3308 | } }, |
| 3309 | }, .{ |
| 3310 | .required_features = .{ .avx2, null, null, null }, |
| 3311 | .src_constraints = .{ .{ .signed_or_exact_int = .yword }, .any }, |
| 3312 | .patterns = &.{ |
| 3313 | .{ .src = .{ .mem, .none } }, |
| 3314 | .{ .src = .{ .to_ymm, .none } }, |
| 3315 | }, |
| 3316 | .dst_temps = .{.{ .rc = .sse }}, |
| 3317 | .each = .{ .once = &.{ |
| 3318 | .{ ._, .vp_q, .cmpeq, .dst0y, .dst0y, .dst0y, ._ }, |
| 3319 | .{ ._, .vp_, .xor, .dst0y, .dst0y, .src0y, ._ }, |
| 3320 | } }, |
| 3321 | }, .{ |
| 3322 | .required_features = .{ .avx2, null, null, null }, |
| 3323 | .src_constraints = .{ .{ .unsigned_int = .yword }, .any }, |
| 3324 | .patterns = &.{ |
| 3325 | .{ .src = .{ .to_ymm, .none } }, |
| 3326 | }, |
| 3327 | .extra_temps = .{ |
| 3328 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3329 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 3330 | .unused, |
| 3331 | .unused, |
| 3332 | .unused, |
| 3333 | .unused, |
| 3334 | }, |
| 3335 | .dst_temps = .{.{ .rc = .sse }}, |
| 3336 | .each = .{ .once = &.{ |
| 3337 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 3338 | .{ ._, .vp_, .xor, .dst0y, .src0y, .lea(.yword, .tmp0), ._ }, |
| 3339 | } }, |
| 3340 | }, .{ |
| 3341 | .required_features = .{ .avx, null, null, null }, |
| 3342 | .src_constraints = .{ .{ .signed_or_exact_int = .yword }, .any }, |
| 3343 | .patterns = &.{ |
| 3344 | .{ .src = .{ .mem, .none } }, |
| 3345 | .{ .src = .{ .to_ymm, .none } }, |
| 3346 | }, |
| 3347 | .dst_temps = .{.{ .rc = .sse }}, |
| 3348 | .each = .{ .once = &.{ |
| 3349 | .{ ._, .v_pd, .cmp, .dst0y, .dst0y, .dst0y, .si(0b01111) }, |
| 3350 | .{ ._, .v_pd, .xor, .dst0y, .dst0y, .src0y, ._ }, |
| 3351 | } }, |
| 3352 | }, .{ |
| 3353 | .required_features = .{ .avx, null, null, null }, |
| 3354 | .src_constraints = .{ .{ .unsigned_int = .yword }, .any }, |
| 3355 | .patterns = &.{ |
| 3356 | .{ .src = .{ .to_ymm, .none } }, |
| 3357 | }, |
| 3358 | .extra_temps = .{ |
| 3359 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3360 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 3361 | .unused, |
| 3362 | .unused, |
| 3363 | .unused, |
| 3364 | .unused, |
| 3365 | }, |
| 3366 | .dst_temps = .{.{ .rc = .sse }}, |
| 3367 | .each = .{ .once = &.{ |
| 3368 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 3369 | .{ ._, .v_pd, .xor, .dst0y, .src0y, .lea(.yword, .tmp0), ._ }, |
| 3370 | } }, |
| 3371 | }, .{ |
| 3372 | .required_features = .{ .avx2, null, null, null }, |
| 3373 | .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .yword, .is = .xword } }, .any }, |
| 3374 | .patterns = &.{ |
| 3375 | .{ .src = .{ .to_mem, .none } }, |
| 3376 | }, |
| 3377 | .extra_temps = .{ |
| 3378 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3379 | .{ .kind = .{ .rc = .sse } }, |
| 3380 | .{ .kind = .{ .rc = .sse } }, |
| 3381 | .unused, |
| 3382 | .unused, |
| 3383 | .unused, |
| 3384 | }, |
| 3385 | .dst_temps = .{.mem}, |
| 3386 | .clobbers = .{ .eflags = true }, |
| 3387 | .each = .{ .once = &.{ |
| 3388 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3389 | .{ ._, .vp_q, .cmpeq, .tmp1y, .tmp1y, .tmp1y, ._ }, |
| 3390 | .{ .@"0:", .vp_, .xor, .tmp2y, .tmp1y, .memiad(.src0y, .tmp0, .add_size, -16), ._ }, |
| 3391 | .{ ._, .v_dqu, .mov, .memiad(.dst0y, .tmp0, .add_size, -16), .tmp2y, ._, ._ }, |
| 3392 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 3393 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3394 | .{ .@"0:", .vp_, .xor, .tmp2x, .tmp1x, .memad(.src0x, .add_size, -16), ._ }, |
| 3395 | .{ ._, .v_dqa, .mov, .memad(.dst0x, .add_size, -16), .tmp2x, ._, ._ }, |
| 3396 | } }, |
| 3397 | }, .{ |
| 3398 | .required_features = .{ .avx2, null, null, null }, |
| 3399 | .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .yword, .is = .yword } }, .any }, |
| 3400 | .patterns = &.{ |
| 3401 | .{ .src = .{ .to_mem, .none } }, |
| 3402 | }, |
| 3403 | .extra_temps = .{ |
| 3404 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3405 | .{ .kind = .{ .rc = .sse } }, |
| 3406 | .{ .kind = .{ .rc = .sse } }, |
| 3407 | .unused, |
| 3408 | .unused, |
| 3409 | .unused, |
| 3410 | }, |
| 3411 | .dst_temps = .{.mem}, |
| 3412 | .clobbers = .{ .eflags = true }, |
| 3413 | .each = .{ .once = &.{ |
| 3414 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3415 | .{ ._, .vp_q, .cmpeq, .tmp1y, .tmp1y, .tmp1y, ._ }, |
| 3416 | .{ .@"0:", .vp_, .xor, .tmp2y, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._ }, |
| 3417 | .{ ._, .v_dqu, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp2y, ._, ._ }, |
| 3418 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 3419 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3420 | } }, |
| 3421 | }, .{ |
| 3422 | .required_features = .{ .avx, null, null, null }, |
| 3423 | .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .yword, .is = .xword } }, .any }, |
| 3424 | .patterns = &.{ |
| 3425 | .{ .src = .{ .to_mem, .none } }, |
| 3426 | }, |
| 3427 | .extra_temps = .{ |
| 3428 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3429 | .{ .kind = .{ .rc = .sse } }, |
| 3430 | .{ .kind = .{ .rc = .sse } }, |
| 3431 | .unused, |
| 3432 | .unused, |
| 3433 | .unused, |
| 3434 | }, |
| 3435 | .dst_temps = .{.mem}, |
| 3436 | .clobbers = .{ .eflags = true }, |
| 3437 | .each = .{ .once = &.{ |
| 3438 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3439 | .{ ._, .v_pd, .cmp, .tmp1y, .tmp1y, .tmp1y, .si(0b01111) }, |
| 3440 | .{ .@"0:", .v_pd, .xor, .tmp2y, .tmp1y, .memiad(.src0y, .tmp0, .add_size, -16), ._ }, |
| 3441 | .{ ._, .v_pd, .movu, .memiad(.dst0y, .tmp0, .add_size, -16), .tmp2y, ._, ._ }, |
| 3442 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 3443 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3444 | .{ .@"0:", .v_pd, .xor, .tmp2x, .tmp1x, .memad(.src0x, .add_size, -16), ._ }, |
| 3445 | .{ ._, .v_pd, .mova, .memad(.dst0x, .add_size, -16), .tmp2x, ._, ._ }, |
| 3446 | } }, |
| 3447 | }, .{ |
| 3448 | .required_features = .{ .avx, null, null, null }, |
| 3449 | .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .yword, .is = .yword } }, .any }, |
| 3450 | .patterns = &.{ |
| 3451 | .{ .src = .{ .to_mem, .none } }, |
| 3452 | }, |
| 3453 | .extra_temps = .{ |
| 3454 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3455 | .{ .kind = .{ .rc = .sse } }, |
| 3456 | .{ .kind = .{ .rc = .sse } }, |
| 3457 | .unused, |
| 3458 | .unused, |
| 3459 | .unused, |
| 3460 | }, |
| 3461 | .dst_temps = .{.mem}, |
| 3462 | .clobbers = .{ .eflags = true }, |
| 3463 | .each = .{ .once = &.{ |
| 3464 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3465 | .{ ._, .v_pd, .cmp, .tmp1y, .tmp1y, .tmp1y, .si(0b01111) }, |
| 3466 | .{ .@"0:", .v_pd, .xor, .tmp2y, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._ }, |
| 3467 | .{ ._, .v_pd, .movu, .memia(.dst0y, .tmp0, .add_size), .tmp2y, ._, ._ }, |
| 3468 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 3469 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3470 | } }, |
| 3471 | }, .{ |
| 3472 | .required_features = .{ .avx, null, null, null }, |
| 3473 | .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 3474 | .patterns = &.{ |
| 3475 | .{ .src = .{ .to_mem, .none } }, |
| 3476 | }, |
| 3477 | .extra_temps = .{ |
| 3478 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3479 | .{ .kind = .{ .rc = .sse } }, |
| 3480 | .{ .kind = .{ .rc = .sse } }, |
| 3481 | .unused, |
| 3482 | .unused, |
| 3483 | .unused, |
| 3484 | }, |
| 3485 | .dst_temps = .{.mem}, |
| 3486 | .clobbers = .{ .eflags = true }, |
| 3487 | .each = .{ .once = &.{ |
| 3488 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3489 | .{ ._, .vp_q, .cmpeq, .tmp1x, .tmp1x, .tmp1x, ._ }, |
| 3490 | .{ .@"0:", .v_, .xor, .tmp2x, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._ }, |
| 3491 | .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp2x, ._, ._ }, |
| 3492 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3493 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3494 | } }, |
| 3495 | }, .{ |
| 3496 | .required_features = .{ .sse2, null, null, null }, |
| 3497 | .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 3498 | .patterns = &.{ |
| 3499 | .{ .src = .{ .to_mem, .none } }, |
| 3500 | }, |
| 3501 | .extra_temps = .{ |
| 3502 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3503 | .{ .kind = .{ .rc = .sse } }, |
| 3504 | .{ .kind = .{ .rc = .sse } }, |
| 3505 | .unused, |
| 3506 | .unused, |
| 3507 | .unused, |
| 3508 | }, |
| 3509 | .dst_temps = .{.mem}, |
| 3510 | .clobbers = .{ .eflags = true }, |
| 3511 | .each = .{ .once = &.{ |
| 3512 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3513 | .{ ._, .p_d, .cmpeq, .tmp1x, .tmp1x, ._, ._ }, |
| 3514 | .{ .@"0:", ._dqa, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 3515 | .{ ._, .p_, .xor, .tmp2x, .tmp1x, ._, ._ }, |
| 3516 | .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp2x, ._, ._ }, |
| 3517 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3518 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3519 | } }, |
| 3520 | }, .{ |
| 3521 | .required_features = .{ .@"64bit", null, null, null }, |
| 3522 | .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 3523 | .patterns = &.{ |
| 3524 | .{ .src = .{ .mut_mem, .none } }, |
| 3525 | }, |
| 3526 | .extra_temps = .{ |
| 3527 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3528 | .unused, |
| 3529 | .unused, |
| 3530 | .unused, |
| 3531 | .unused, |
| 3532 | .unused, |
| 3533 | }, |
| 3534 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3535 | .clobbers = .{ .eflags = true }, |
| 3536 | .each = .{ .once = &.{ |
| 3537 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3538 | .{ .@"0:", ._, .not, .memia(.dst0q, .tmp0, .add_size), ._, ._, ._ }, |
| 3539 | .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, 8), ._, ._, ._ }, |
| 3540 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3541 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3542 | } }, |
| 3543 | }, .{ |
| 3544 | .required_features = .{ .@"64bit", null, null, null }, |
| 3545 | .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 3546 | .patterns = &.{ |
| 3547 | .{ .src = .{ .to_mem, .none } }, |
| 3548 | }, |
| 3549 | .extra_temps = .{ |
| 3550 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3551 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 3552 | .unused, |
| 3553 | .unused, |
| 3554 | .unused, |
| 3555 | .unused, |
| 3556 | }, |
| 3557 | .dst_temps = .{.mem}, |
| 3558 | .clobbers = .{ .eflags = true }, |
| 3559 | .each = .{ .once = &.{ |
| 3560 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 3561 | .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 3562 | .{ ._, ._, .not, .tmp1q, ._, ._, ._ }, |
| 3563 | .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ }, |
| 3564 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3565 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3566 | } }, |
| 3567 | }, .{ |
| 3568 | .required_features = .{ .@"64bit", null, null, null }, |
| 3569 | .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .xword, .is = .dword } }, .any }, |
| 3570 | .patterns = &.{ |
| 3571 | .{ .src = .{ .mut_mem, .none } }, |
| 3572 | }, |
| 3573 | .extra_temps = .{ |
| 3574 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3575 | .unused, |
| 3576 | .unused, |
| 3577 | .unused, |
| 3578 | .unused, |
| 3579 | .unused, |
| 3580 | }, |
| 3581 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3582 | .clobbers = .{ .eflags = true }, |
| 3583 | .each = .{ .once = &.{ |
| 3584 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3585 | .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16), ._, ._, ._ }, |
| 3586 | .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16 + 8), ._, ._, ._ }, |
| 3587 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3588 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3589 | .{ ._, ._, .not, .memad(.dst0d, .add_size, -16), ._, ._, ._ }, |
| 3590 | } }, |
| 3591 | }, .{ |
| 3592 | .required_features = .{ .@"64bit", null, null, null }, |
| 3593 | .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .xword, .is = .dword } }, .any }, |
| 3594 | .patterns = &.{ |
| 3595 | .{ .src = .{ .to_mem, .none } }, |
| 3596 | }, |
| 3597 | .extra_temps = .{ |
| 3598 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3599 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 3600 | .unused, |
| 3601 | .unused, |
| 3602 | .unused, |
| 3603 | .unused, |
| 3604 | }, |
| 3605 | .dst_temps = .{.mem}, |
| 3606 | .clobbers = .{ .eflags = true }, |
| 3607 | .each = .{ .once = &.{ |
| 3608 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3609 | .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -16), ._, ._ }, |
| 3610 | .{ ._, ._, .not, .tmp1q, ._, ._, ._ }, |
| 3611 | .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -16), .tmp1q, ._, ._ }, |
| 3612 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3613 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3614 | .{ ._, ._, .mov, .tmp0d, .memad(.src0d, .add_size, -16), ._, ._ }, |
| 3615 | .{ ._, ._, .not, .tmp0d, ._, ._, ._ }, |
| 3616 | .{ ._, ._, .mov, .memad(.dst0d, .add_size, -16), .tmp0d, ._, ._ }, |
| 3617 | .{ ._, ._, .mov, .memad(.dst0d, .add_size, -16 + 4), .si(0), ._, ._ }, |
| 3618 | .{ ._, ._, .mov, .memad(.dst0q, .add_size, -16 + 8), .si(0), ._, ._ }, |
| 3619 | } }, |
| 3620 | }, .{ |
| 3621 | .required_features = .{ .@"64bit", null, null, null }, |
| 3622 | .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .qword, .is = .qword } }, .any }, |
| 3623 | .patterns = &.{ |
| 3624 | .{ .src = .{ .mut_mem, .none } }, |
| 3625 | }, |
| 3626 | .extra_temps = .{ |
| 3627 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3628 | .unused, |
| 3629 | .unused, |
| 3630 | .unused, |
| 3631 | .unused, |
| 3632 | .unused, |
| 3633 | }, |
| 3634 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3635 | .clobbers = .{ .eflags = true }, |
| 3636 | .each = .{ .once = &.{ |
| 3637 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3638 | .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16), ._, ._, ._ }, |
| 3639 | .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16 + 8), ._, ._, ._ }, |
| 3640 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3641 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3642 | .{ ._, ._, .not, .memad(.dst0q, .add_size, -16), ._, ._, ._ }, |
| 3643 | } }, |
| 3644 | }, .{ |
| 3645 | .required_features = .{ .@"64bit", null, null, null }, |
| 3646 | .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .qword, .is = .qword } }, .any }, |
| 3647 | .patterns = &.{ |
| 3648 | .{ .src = .{ .to_mem, .none } }, |
| 3649 | }, |
| 3650 | .extra_temps = .{ |
| 3651 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3652 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 3653 | .unused, |
| 3654 | .unused, |
| 3655 | .unused, |
| 3656 | .unused, |
| 3657 | }, |
| 3658 | .dst_temps = .{.mem}, |
| 3659 | .clobbers = .{ .eflags = true }, |
| 3660 | .each = .{ .once = &.{ |
| 3661 | .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ }, |
| 3662 | .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -8), ._, ._ }, |
| 3663 | .{ ._, ._, .not, .tmp1q, ._, ._, ._ }, |
| 3664 | .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -8), .tmp1q, ._, ._ }, |
| 3665 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3666 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3667 | .{ ._, ._, .mov, .memad(.dst0q, .add_size, -8), .si(0), ._, ._ }, |
| 3668 | } }, |
| 3669 | }, .{ |
| 3670 | .required_features = .{ .@"64bit", null, null, null }, |
| 3671 | .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .dword, .is = .dword } }, .any }, |
| 3672 | .patterns = &.{ |
| 3673 | .{ .src = .{ .mut_mem, .none } }, |
| 3674 | }, |
| 3675 | .extra_temps = .{ |
| 3676 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3677 | .unused, |
| 3678 | .unused, |
| 3679 | .unused, |
| 3680 | .unused, |
| 3681 | .unused, |
| 3682 | }, |
| 3683 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3684 | .clobbers = .{ .eflags = true }, |
| 3685 | .each = .{ .once = &.{ |
| 3686 | .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ }, |
| 3687 | .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -8), ._, ._, ._ }, |
| 3688 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3689 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3690 | .{ ._, ._, .not, .memad(.dst0d, .add_size, -8), ._, ._, ._ }, |
| 3691 | } }, |
| 3692 | }, .{ |
| 3693 | .required_features = .{ .@"64bit", null, null, null }, |
| 3694 | .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .dword, .is = .dword } }, .any }, |
| 3695 | .patterns = &.{ |
| 3696 | .{ .src = .{ .to_mem, .none } }, |
| 3697 | }, |
| 3698 | .extra_temps = .{ |
| 3699 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3700 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 3701 | .unused, |
| 3702 | .unused, |
| 3703 | .unused, |
| 3704 | .unused, |
| 3705 | }, |
| 3706 | .dst_temps = .{.mem}, |
| 3707 | .clobbers = .{ .eflags = true }, |
| 3708 | .each = .{ .once = &.{ |
| 3709 | .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ }, |
| 3710 | .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -8), ._, ._ }, |
| 3711 | .{ ._, ._, .not, .tmp1q, ._, ._, ._ }, |
| 3712 | .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -8), .tmp1q, ._, ._ }, |
| 3713 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3714 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3715 | .{ ._, ._, .mov, .tmp0d, .memad(.src0d, .add_size, -8), ._, ._ }, |
| 3716 | .{ ._, ._, .not, .tmp0d, ._, ._, ._ }, |
| 3717 | .{ ._, ._, .mov, .memad(.dst0d, .add_size, -8), .tmp0d, ._, ._ }, |
| 3718 | .{ ._, ._, .mov, .memad(.dst0d, .add_size, -8 + 4), .si(0), ._, ._ }, |
| 3719 | } }, |
| 3720 | }, .{ |
| 3721 | .required_features = .{ .@"64bit", null, null, null }, |
| 3722 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .dword } }, .any }, |
| 3723 | .patterns = &.{ |
| 3724 | .{ .src = .{ .mut_mem, .none } }, |
| 3725 | }, |
| 3726 | .extra_temps = .{ |
| 3727 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3728 | .unused, |
| 3729 | .unused, |
| 3730 | .unused, |
| 3731 | .unused, |
| 3732 | .unused, |
| 3733 | }, |
| 3734 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3735 | .clobbers = .{ .eflags = true }, |
| 3736 | .each = .{ .once = &.{ |
| 3737 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3738 | .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16), ._, ._, ._ }, |
| 3739 | .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16 + 8), ._, ._, ._ }, |
| 3740 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3741 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3742 | .{ ._, ._, .xor, .memad(.dst0d, .add_size, -16), .sa(.src0, .add_umax), ._, ._ }, |
| 3743 | } }, |
| 3744 | }, .{ |
| 3745 | .required_features = .{ .@"64bit", null, null, null }, |
| 3746 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .dword } }, .any }, |
| 3747 | .patterns = &.{ |
| 3748 | .{ .src = .{ .to_mem, .none } }, |
| 3749 | }, |
| 3750 | .extra_temps = .{ |
| 3751 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3752 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 3753 | .unused, |
| 3754 | .unused, |
| 3755 | .unused, |
| 3756 | .unused, |
| 3757 | }, |
| 3758 | .dst_temps = .{.mem}, |
| 3759 | .clobbers = .{ .eflags = true }, |
| 3760 | .each = .{ .once = &.{ |
| 3761 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3762 | .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -16), ._, ._ }, |
| 3763 | .{ ._, ._, .not, .tmp1q, ._, ._, ._ }, |
| 3764 | .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -16), .tmp1q, ._, ._ }, |
| 3765 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3766 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3767 | .{ ._, ._, .mov, .tmp0d, .memad(.src0d, .add_size, -16), ._, ._ }, |
| 3768 | .{ ._, ._, .xor, .tmp0d, .sa(.src0, .add_umax), ._, ._ }, |
| 3769 | .{ ._, ._, .mov, .memad(.dst0d, .add_size, -16), .tmp0d, ._, ._ }, |
| 3770 | .{ ._, ._, .mov, .memad(.dst0d, .add_size, -16 + 4), .si(0), ._, ._ }, |
| 3771 | .{ ._, ._, .mov, .memad(.dst0q, .add_size, -16 + 8), .si(0), ._, ._ }, |
| 3772 | } }, |
| 3773 | }, .{ |
| 3774 | .required_features = .{ .@"64bit", null, null, null }, |
| 3775 | .src_constraints = .{ .{ .remainder_int = .{ .of = .qword, .is = .dword } }, .any }, |
| 3776 | .patterns = &.{ |
| 3777 | .{ .src = .{ .mut_mem, .none } }, |
| 3778 | }, |
| 3779 | .extra_temps = .{ |
| 3780 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3781 | .unused, |
| 3782 | .unused, |
| 3783 | .unused, |
| 3784 | .unused, |
| 3785 | .unused, |
| 3786 | }, |
| 3787 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3788 | .clobbers = .{ .eflags = true }, |
| 3789 | .each = .{ .once = &.{ |
| 3790 | .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ }, |
| 3791 | .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -8), ._, ._, ._ }, |
| 3792 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3793 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3794 | .{ ._, ._, .xor, .memad(.dst0d, .add_size, -8), .sa(.src0, .add_umax), ._, ._ }, |
| 3795 | } }, |
| 3796 | }, .{ |
| 3797 | .required_features = .{ .@"64bit", null, null, null }, |
| 3798 | .src_constraints = .{ .{ .remainder_int = .{ .of = .qword, .is = .dword } }, .any }, |
| 3799 | .patterns = &.{ |
| 3800 | .{ .src = .{ .to_mem, .none } }, |
| 3801 | }, |
| 3802 | .extra_temps = .{ |
| 3803 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3804 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 3805 | .unused, |
| 3806 | .unused, |
| 3807 | .unused, |
| 3808 | .unused, |
| 3809 | }, |
| 3810 | .dst_temps = .{.mem}, |
| 3811 | .clobbers = .{ .eflags = true }, |
| 3812 | .each = .{ .once = &.{ |
| 3813 | .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ }, |
| 3814 | .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -8), ._, ._ }, |
| 3815 | .{ ._, ._, .not, .tmp1q, ._, ._, ._ }, |
| 3816 | .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -8), .tmp1q, ._, ._ }, |
| 3817 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3818 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3819 | .{ ._, ._, .mov, .tmp0d, .memad(.src0d, .add_size, -8), ._, ._ }, |
| 3820 | .{ ._, ._, .xor, .tmp0d, .sa(.src0, .add_umax), ._, ._ }, |
| 3821 | .{ ._, ._, .mov, .memad(.dst0d, .add_size, -8), .tmp0d, ._, ._ }, |
| 3822 | .{ ._, ._, .mov, .memad(.dst0d, .add_size, -8 + 4), .si(0), ._, ._ }, |
| 3823 | } }, |
| 3824 | }, .{ |
| 3825 | .required_features = .{ .@"64bit", null, null, null }, |
| 3826 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 3827 | .patterns = &.{ |
| 3828 | .{ .src = .{ .mut_mem, .none } }, |
| 3829 | }, |
| 3830 | .extra_temps = .{ |
| 3831 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3832 | .unused, |
| 3833 | .unused, |
| 3834 | .unused, |
| 3835 | .unused, |
| 3836 | .unused, |
| 3837 | }, |
| 3838 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3839 | .clobbers = .{ .eflags = true }, |
| 3840 | .each = .{ .once = &.{ |
| 3841 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3842 | .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16), ._, ._, ._ }, |
| 3843 | .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16 + 8), ._, ._, ._ }, |
| 3844 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 3845 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3846 | .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ }, |
| 3847 | .{ ._, ._, .xor, .memad(.dst0q, .add_size, -16), .tmp0q, ._, ._ }, |
| 3848 | } }, |
| 3849 | }, .{ |
| 3850 | .required_features = .{ .@"64bit", null, null, null }, |
| 3851 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 3852 | .patterns = &.{ |
| 3853 | .{ .src = .{ .to_mem, .none } }, |
| 3854 | }, |
| 3855 | .extra_temps = .{ |
| 3856 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3857 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 3858 | .unused, |
| 3859 | .unused, |
| 3860 | .unused, |
| 3861 | .unused, |
| 3862 | }, |
| 3863 | .dst_temps = .{.mem}, |
| 3864 | .clobbers = .{ .eflags = true }, |
| 3865 | .each = .{ .once = &.{ |
| 3866 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 3867 | .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -16), ._, ._ }, |
| 3868 | .{ ._, ._, .not, .tmp1q, ._, ._, ._ }, |
| 3869 | .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -16), .tmp1q, ._, ._ }, |
| 3870 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3871 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3872 | .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ }, |
| 3873 | .{ ._, ._, .xor, .tmp0q, .memad(.src0q, .add_size, -16), ._, ._ }, |
| 3874 | .{ ._, ._, .mov, .memad(.dst0q, .add_size, -16), .tmp0q, ._, ._ }, |
| 3875 | .{ ._, ._, .mov, .memad(.dst0q, .add_size, -8), .si(0), ._, ._ }, |
| 3876 | } }, |
| 3877 | }, .{ |
| 3878 | .required_features = .{ .@"64bit", null, null, null }, |
| 3879 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 3880 | .patterns = &.{ |
| 3881 | .{ .src = .{ .mut_mem, .none } }, |
| 3882 | }, |
| 3883 | .extra_temps = .{ |
| 3884 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3885 | .unused, |
| 3886 | .unused, |
| 3887 | .unused, |
| 3888 | .unused, |
| 3889 | .unused, |
| 3890 | }, |
| 3891 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3892 | .clobbers = .{ .eflags = true }, |
| 3893 | .each = .{ .once = &.{ |
| 3894 | .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ }, |
| 3895 | .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -8), ._, ._, ._ }, |
| 3896 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3897 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3898 | .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ }, |
| 3899 | .{ ._, ._, .xor, .memad(.dst0q, .add_size, -8), .tmp0q, ._, ._ }, |
| 3900 | } }, |
| 3901 | }, .{ |
| 3902 | .required_features = .{ .@"64bit", null, null, null }, |
| 3903 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 3904 | .patterns = &.{ |
| 3905 | .{ .src = .{ .to_mem, .none } }, |
| 3906 | }, |
| 3907 | .extra_temps = .{ |
| 3908 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 3909 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 3910 | .unused, |
| 3911 | .unused, |
| 3912 | .unused, |
| 3913 | .unused, |
| 3914 | }, |
| 3915 | .dst_temps = .{.mem}, |
| 3916 | .clobbers = .{ .eflags = true }, |
| 3917 | .each = .{ .once = &.{ |
| 3918 | .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ }, |
| 3919 | .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -8), ._, ._ }, |
| 3920 | .{ ._, ._, .not, .tmp1q, ._, ._, ._ }, |
| 3921 | .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -8), .tmp1q, ._, ._ }, |
| 3922 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 3923 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 3924 | .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ }, |
| 3925 | .{ ._, ._, .xor, .tmp0q, .memad(.src0q, .add_size, -8), ._, ._ }, |
| 3926 | .{ ._, ._, .mov, .memad(.dst0q, .add_size, -8), .tmp0q, ._, ._ }, |
| 3927 | } }, |
| 3928 | }, .{ |
| 3929 | .required_features = .{ .mmx, null, null, null }, |
| 3930 | .src_constraints = .{ .{ .signed_int_or_full_vec = .qword }, .any }, |
| 3931 | .patterns = &.{ |
| 3932 | .{ .src = .{ .mem, .none } }, |
| 3933 | .{ .src = .{ .to_mm, .none } }, |
| 3934 | }, |
| 3935 | .dst_temps = .{.{ .rc = .mmx }}, |
| 3936 | .each = .{ .once = &.{ |
| 3937 | .{ ._, .p_d, .cmpeq, .dst0q, .dst0q, ._, ._ }, |
| 3938 | .{ ._, .p_, .xor, .dst0q, .src0q, ._, ._ }, |
| 3939 | } }, |
| 3940 | }, .{ |
| 3941 | .required_features = .{ .mmx, null, null, null }, |
| 3942 | .src_constraints = .{ .{ .unsigned_int_vec = .qword }, .any }, |
| 3943 | .patterns = &.{ |
| 3944 | .{ .src = .{ .to_mut_mm, .none } }, |
| 3945 | }, |
| 3946 | .extra_temps = .{ |
| 3947 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3948 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 3949 | .unused, |
| 3950 | .unused, |
| 3951 | .unused, |
| 3952 | .unused, |
| 3953 | }, |
| 3954 | .dst_temps = .{.{ .ref = .src0 }}, |
| 3955 | .each = .{ .once = &.{ |
| 3956 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 3957 | .{ ._, .p_, .xor, .dst0q, .lea(.qword, .tmp0), ._, ._ }, |
| 3958 | } }, |
| 3959 | }, .{ |
| 3960 | .required_features = .{ .avx, null, null, null }, |
| 3961 | .src_constraints = .{ .{ .signed_int_or_full_vec = .xword }, .any }, |
| 3962 | .patterns = &.{ |
| 3963 | .{ .src = .{ .mem, .none } }, |
| 3964 | .{ .src = .{ .to_xmm, .none } }, |
| 3965 | }, |
| 3966 | .dst_temps = .{.{ .rc = .sse }}, |
| 3967 | .each = .{ .once = &.{ |
| 3968 | .{ ._, .vp_q, .cmpeq, .dst0x, .dst0x, .dst0x, ._ }, |
| 3969 | .{ ._, .vp_, .xor, .dst0x, .dst0x, .src0x, ._ }, |
| 3970 | } }, |
| 3971 | }, .{ |
| 3972 | .required_features = .{ .avx, null, null, null }, |
| 3973 | .src_constraints = .{ .{ .unsigned_int_vec = .xword }, .any }, |
| 3974 | .patterns = &.{ |
| 3975 | .{ .src = .{ .to_xmm, .none } }, |
| 3976 | }, |
| 3977 | .extra_temps = .{ |
| 3978 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 3979 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 3980 | .unused, |
| 3981 | .unused, |
| 3982 | .unused, |
| 3983 | .unused, |
| 3984 | }, |
| 3985 | .dst_temps = .{.{ .rc = .sse }}, |
| 3986 | .each = .{ .once = &.{ |
| 3987 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 3988 | .{ ._, .vp_, .xor, .dst0x, .src0x, .lea(.xword, .tmp0), ._ }, |
| 3989 | } }, |
| 3990 | }, .{ |
| 3991 | .required_features = .{ .sse2, null, null, null }, |
| 3992 | .src_constraints = .{ .{ .signed_int_or_full_vec = .xword }, .any }, |
| 3993 | .patterns = &.{ |
| 3994 | .{ .src = .{ .mem, .none } }, |
| 3995 | .{ .src = .{ .to_xmm, .none } }, |
| 3996 | }, |
| 3997 | .dst_temps = .{.{ .rc = .sse }}, |
| 3998 | .each = .{ .once = &.{ |
| 3999 | .{ ._, .p_d, .cmpeq, .dst0x, .dst0x, ._, ._ }, |
| 4000 | .{ ._, .p_, .xor, .dst0x, .src0x, ._, ._ }, |
| 4001 | } }, |
| 4002 | }, .{ |
| 4003 | .required_features = .{ .sse2, null, null, null }, |
| 4004 | .src_constraints = .{ .{ .unsigned_int_vec = .xword }, .any }, |
| 4005 | .patterns = &.{ |
| 4006 | .{ .src = .{ .to_mut_xmm, .none } }, |
| 4007 | }, |
| 4008 | .extra_temps = .{ |
| 4009 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 4010 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 4011 | .unused, |
| 4012 | .unused, |
| 4013 | .unused, |
| 4014 | .unused, |
| 4015 | }, |
| 4016 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4017 | .each = .{ .once = &.{ |
| 4018 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 4019 | .{ ._, .p_, .xor, .dst0x, .lea(.xword, .tmp0), ._, ._ }, |
| 4020 | } }, |
| 4021 | }, .{ |
| 4022 | .required_features = .{ .sse, null, null, null }, |
| 4023 | .src_constraints = .{ .{ .vec = .xword }, .any }, |
| 4024 | .patterns = &.{ |
| 4025 | .{ .src = .{ .to_mut_xmm, .none } }, |
| 4026 | }, |
| 4027 | .extra_temps = .{ |
| 4028 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 4029 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 4030 | .unused, |
| 4031 | .unused, |
| 4032 | .unused, |
| 4033 | .unused, |
| 4034 | }, |
| 4035 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4036 | .each = .{ .once = &.{ |
| 4037 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 4038 | .{ ._, ._ps, .xor, .dst0x, .lea(.xword, .tmp0), ._, ._ }, |
| 4039 | } }, |
| 4040 | }, .{ |
| 4041 | .required_features = .{ .avx2, null, null, null }, |
| 4042 | .src_constraints = .{ .{ .signed_int_or_full_vec = .yword }, .any }, |
| 4043 | .patterns = &.{ |
| 4044 | .{ .src = .{ .mem, .none } }, |
| 4045 | .{ .src = .{ .to_ymm, .none } }, |
| 4046 | }, |
| 4047 | .dst_temps = .{.{ .rc = .sse }}, |
| 4048 | .each = .{ .once = &.{ |
| 4049 | .{ ._, .vp_q, .cmpeq, .dst0y, .dst0y, .dst0y, ._ }, |
| 4050 | .{ ._, .vp_, .xor, .dst0y, .dst0y, .src0y, ._ }, |
| 4051 | } }, |
| 4052 | }, .{ |
| 4053 | .required_features = .{ .avx2, null, null, null }, |
| 4054 | .src_constraints = .{ .{ .unsigned_int_vec = .yword }, .any }, |
| 4055 | .patterns = &.{ |
| 4056 | .{ .src = .{ .to_ymm, .none } }, |
| 4057 | }, |
| 4058 | .extra_temps = .{ |
| 4059 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 4060 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 4061 | .unused, |
| 4062 | .unused, |
| 4063 | .unused, |
| 4064 | .unused, |
| 4065 | }, |
| 4066 | .dst_temps = .{.{ .rc = .sse }}, |
| 4067 | .each = .{ .once = &.{ |
| 4068 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 4069 | .{ ._, .vp_, .xor, .dst0y, .src0y, .lea(.yword, .tmp0), ._ }, |
| 4070 | } }, |
| 4071 | }, .{ |
| 4072 | .required_features = .{ .avx, null, null, null }, |
| 4073 | .src_constraints = .{ .{ .signed_int_or_full_vec = .yword }, .any }, |
| 4074 | .patterns = &.{ |
| 4075 | .{ .src = .{ .mem, .none } }, |
| 4076 | .{ .src = .{ .to_ymm, .none } }, |
| 4077 | }, |
| 4078 | .dst_temps = .{.{ .rc = .sse }}, |
| 4079 | .each = .{ .once = &.{ |
| 4080 | .{ ._, .v_pd, .cmp, .dst0y, .dst0y, .dst0y, .si(0b01111) }, |
| 4081 | .{ ._, .v_pd, .xor, .dst0y, .dst0y, .src0y, ._ }, |
| 4082 | } }, |
| 4083 | }, .{ |
| 4084 | .required_features = .{ .avx, null, null, null }, |
| 4085 | .src_constraints = .{ .{ .unsigned_int_vec = .yword }, .any }, |
| 4086 | .patterns = &.{ |
| 4087 | .{ .src = .{ .to_ymm, .none } }, |
| 4088 | }, |
| 4089 | .extra_temps = .{ |
| 4090 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 4091 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 4092 | .unused, |
| 4093 | .unused, |
| 4094 | .unused, |
| 4095 | .unused, |
| 4096 | }, |
| 4097 | .dst_temps = .{.{ .rc = .sse }}, |
| 4098 | .each = .{ .once = &.{ |
| 4099 | .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ }, |
| 4100 | .{ ._, .v_pd, .xor, .dst0y, .src0y, .lea(.yword, .tmp0), ._ }, |
| 4101 | } }, |
| 4102 | }, .{ |
| 4103 | .required_features = .{ .@"64bit", null, null, null }, |
| 4104 | .patterns = &.{ |
| 4105 | .{ .src = .{ .to_mem, .none } }, |
| 4106 | }, |
| 4107 | .extra_temps = .{ |
| 4108 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 4109 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 4110 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 4111 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 4112 | .unused, |
| 4113 | .unused, |
| 4114 | }, |
| 4115 | .dst_temps = .{.mem}, |
| 4116 | .each = .{ .once = &.{ |
| 4117 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_src0_size), ._, ._ }, |
| 4118 | .{ ._, ._, .lea, .tmp1p, .mem(.tmp3), ._, ._ }, |
| 4119 | .{ .@"0:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_src0_size), ._, ._ }, |
| 4120 | .{ ._, ._, .xor, .tmp2q, .leaia(.qword, .tmp1, .tmp0, .add_src0_size), ._, ._ }, |
| 4121 | .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_src0_size), .tmp2q, ._, ._ }, |
| 4122 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 4123 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 4124 | } }, |
| 4125 | }, .{ |
| 4126 | .patterns = &.{ |
| 4127 | .{ .src = .{ .to_mem, .none } }, |
| 4128 | }, |
| 4129 | .extra_temps = .{ |
| 4130 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 4131 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 4132 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4133 | .{ .kind = .{ .umax_mem = .src0 } }, |
| 4134 | .unused, |
| 4135 | .unused, |
| 4136 | }, |
| 4137 | .dst_temps = .{.mem}, |
| 4138 | .each = .{ .once = &.{ |
| 4139 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_src0_size), ._, ._ }, |
| 4140 | .{ ._, ._, .lea, .tmp1p, .mem(.tmp3), ._, ._ }, |
| 4141 | .{ .@"0:", ._, .mov, .tmp2d, .memia(.src0d, .tmp0, .add_src0_size), ._, ._ }, |
| 4142 | .{ ._, ._, .xor, .tmp2d, .leaia(.dword, .tmp1, .tmp0, .add_src0_size), ._, ._ }, |
| 4143 | .{ ._, ._, .mov, .memia(.dst0d, .tmp0, .add_src0_size), .tmp2d, ._, ._ }, |
| 4144 | .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ }, |
| 4145 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 4146 | } }, |
| 4147 | } }) catch |err| switch (err) { |
| 4148 | error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ |
| 4149 | @tagName(air_tag), |
| 4150 | cg.typeOf(ty_op.operand).fmt(pt), |
| 4151 | ops[0].tracking(cg), |
| 4152 | }), |
| 4153 | else => |e| return e, |
| 4154 | }; |
| 4155 | for (ops) |op| for (res) |r| { |
| 4156 | if (op.index == r.index) break; |
| 4157 | } else try op.die(cg); |
| 4158 | try res[0].moveTo(inst, cg); |
| 4159 | }, |
| 4160 | |
| 4161 | .block => if (use_old) try cg.airBlock(inst) else { |
| 4162 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 4163 | const extra = cg.air.extraData(Air.Block, ty_pl.payload); |
| 4164 | try cg.asmPseudo(.pseudo_dbg_enter_block_none); |
| 4165 | try cg.lowerBlock(inst, @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len])); |
| 4166 | try cg.asmPseudo(.pseudo_dbg_leave_block_none); |
| 4167 | }, |
| 4168 | .loop => if (use_old) try cg.airLoop(inst) else { |
| 4169 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 4170 | const extra = cg.air.extraData(Air.Block, ty_pl.payload); |
| 4171 | cg.scope_generation += 1; |
| 4172 | try cg.loops.putNoClobber(cg.gpa, inst, .{ |
| 4173 | .state = try cg.saveState(), |
| 4174 | .target = @intCast(cg.mir_instructions.len), |
| 4175 | }); |
| 4176 | defer assert(cg.loops.remove(inst)); |
| 4177 | try cg.genBodyBlock(@ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len])); |
| 4178 | }, |
| 4179 | .repeat => if (use_old) try cg.airRepeat(inst) else { |
| 4180 | const repeat = air_datas[@intFromEnum(inst)].repeat; |
| 4181 | const loop = cg.loops.get(repeat.loop_inst).?; |
| 4182 | try cg.restoreState(loop.state, &.{}, .{ |
| 4183 | .emit_instructions = true, |
| 4184 | .update_tracking = false, |
| 4185 | .resurrect = false, |
| 4186 | .close_scope = true, |
| 4187 | }); |
| 4188 | _ = try cg.asmJmpReloc(loop.target); |
| 4189 | }, |
| 4190 | .br => try cg.airBr(inst), |
| 4191 | .trap => try cg.asmOpOnly(.{ ._, .ud2 }), |
| 4192 | .breakpoint => try cg.asmOpOnly(.{ ._, .int3 }), |
| 4193 | .ret_addr => if (use_old) try cg.airRetAddr(inst) else { |
| 4194 | var slot = try cg.tempInit(.usize, .{ .load_frame = .{ |
| 4195 | .index = .ret_addr, |
| 4196 | } }); |
| 4197 | while (try slot.toRegClass(true, .general_purpose, cg)) {} |
| 4198 | try slot.moveTo(inst, cg); |
| 4199 | }, |
| 4200 | .frame_addr => if (use_old) try cg.airFrameAddress(inst) else { |
| 4201 | var slot = try cg.tempInit(.usize, .{ .lea_frame = .{ |
| 4202 | .index = .base_ptr, |
| 4203 | } }); |
| 4204 | try slot.moveTo(inst, cg); |
| 4205 | }, |
| 4206 | .call => try cg.airCall(inst, .auto, .{ .safety = true }), |
| 4207 | .call_always_tail => try cg.airCall(inst, .always_tail, .{ .safety = true }), |
| 4208 | .call_never_tail => try cg.airCall(inst, .never_tail, .{ .safety = true }), |
| 4209 | .call_never_inline => try cg.airCall(inst, .never_inline, .{ .safety = true }), |
| 4210 | |
| 4211 | .clz => |air_tag| if (use_old) try cg.airClz(inst) else { |
| 4212 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 4213 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 4214 | var res: [1]Temp = undefined; |
| 4215 | cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{ |
| 4216 | .required_features = .{ .slow_incdec, null, null, null }, |
| 4217 | .src_constraints = .{ .{ .exact_signed_int = 1 }, .any }, |
| 4218 | .patterns = &.{ |
| 4219 | .{ .src = .{ .mut_mem, .none } }, |
| 4220 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4221 | }, |
| 4222 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4223 | .clobbers = .{ .eflags = true }, |
| 4224 | .each = .{ .once = &.{ |
| 4225 | .{ ._, ._, .add, .dst0b, .si(1), ._, ._ }, |
| 4226 | } }, |
| 4227 | }, .{ |
| 4228 | .src_constraints = .{ .{ .exact_signed_int = 1 }, .any }, |
| 4229 | .patterns = &.{ |
| 4230 | .{ .src = .{ .mut_mem, .none } }, |
| 4231 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4232 | }, |
| 4233 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4234 | .clobbers = .{ .eflags = true }, |
| 4235 | .each = .{ .once = &.{ |
| 4236 | .{ ._, ._, .inc, .dst0b, ._, ._, ._ }, |
| 4237 | } }, |
| 4238 | }, .{ |
| 4239 | .src_constraints = .{ .{ .exact_unsigned_int = 1 }, .any }, |
| 4240 | .patterns = &.{ |
| 4241 | .{ .src = .{ .mut_mem, .none } }, |
| 4242 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4243 | }, |
| 4244 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4245 | .clobbers = .{ .eflags = true }, |
| 4246 | .each = .{ .once = &.{ |
| 4247 | .{ ._, ._, .xor, .dst0b, .si(1), ._, ._ }, |
| 4248 | } }, |
| 4249 | }, .{ |
| 4250 | .required_features = .{ .lzcnt, null, null, null }, |
| 4251 | .src_constraints = .{ .{ .unsigned_or_exact_int = .byte }, .any }, |
| 4252 | .patterns = &.{ |
| 4253 | .{ .src = .{ .mem, .none } }, |
| 4254 | .{ .src = .{ .to_gpr, .none } }, |
| 4255 | }, |
| 4256 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4257 | .clobbers = .{ .eflags = true }, |
| 4258 | .each = .{ .once = &.{ |
| 4259 | .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ }, |
| 4260 | .{ ._, ._, .lzcnt, .dst0d, .dst0d, ._, ._ }, |
| 4261 | .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 4262 | } }, |
| 4263 | }, .{ |
| 4264 | .required_features = .{ .lzcnt, null, null, null }, |
| 4265 | .src_constraints = .{ .{ .signed_int = .byte }, .any }, |
| 4266 | .patterns = &.{ |
| 4267 | .{ .src = .{ .mem, .none } }, |
| 4268 | .{ .src = .{ .to_gpr, .none } }, |
| 4269 | }, |
| 4270 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4271 | .clobbers = .{ .eflags = true }, |
| 4272 | .each = .{ .once = &.{ |
| 4273 | .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ }, |
| 4274 | .{ ._, ._, .@"and", .dst0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4275 | .{ ._, ._, .lzcnt, .dst0d, .dst0d, ._, ._ }, |
| 4276 | .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 4277 | } }, |
| 4278 | }, .{ |
| 4279 | .required_features = .{ .false_deps_lzcnt_tzcnt, .lzcnt, null, null }, |
| 4280 | .src_constraints = .{ .{ .exact_int = 16 }, .any }, |
| 4281 | .patterns = &.{ |
| 4282 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4283 | }, |
| 4284 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4285 | .clobbers = .{ .eflags = true }, |
| 4286 | .each = .{ .once = &.{ |
| 4287 | .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ }, |
| 4288 | } }, |
| 4289 | }, .{ |
| 4290 | .required_features = .{ .lzcnt, null, null, null }, |
| 4291 | .src_constraints = .{ .{ .exact_int = 16 }, .any }, |
| 4292 | .patterns = &.{ |
| 4293 | .{ .src = .{ .mem, .none } }, |
| 4294 | .{ .src = .{ .to_gpr, .none } }, |
| 4295 | }, |
| 4296 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4297 | .clobbers = .{ .eflags = true }, |
| 4298 | .each = .{ .once = &.{ |
| 4299 | .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ }, |
| 4300 | } }, |
| 4301 | }, .{ |
| 4302 | .required_features = .{ .lzcnt, null, null, null }, |
| 4303 | .src_constraints = .{ .{ .signed_int = .word }, .any }, |
| 4304 | .patterns = &.{ |
| 4305 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4306 | }, |
| 4307 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4308 | .clobbers = .{ .eflags = true }, |
| 4309 | .each = .{ .once = &.{ |
| 4310 | .{ ._, ._, .@"and", .src0w, .sa(.src0, .add_umax), ._, ._ }, |
| 4311 | .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ }, |
| 4312 | .{ ._, ._, .sub, .dst0b, .sia(16, .src0, .sub_bit_size), ._, ._ }, |
| 4313 | } }, |
| 4314 | }, .{ |
| 4315 | .required_features = .{ .false_deps_lzcnt_tzcnt, .lzcnt, null, null }, |
| 4316 | .src_constraints = .{ .{ .unsigned_int = .word }, .any }, |
| 4317 | .patterns = &.{ |
| 4318 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4319 | }, |
| 4320 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4321 | .clobbers = .{ .eflags = true }, |
| 4322 | .each = .{ .once = &.{ |
| 4323 | .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ }, |
| 4324 | .{ ._, ._, .sub, .dst0b, .sia(16, .src0, .sub_bit_size), ._, ._ }, |
| 4325 | } }, |
| 4326 | }, .{ |
| 4327 | .required_features = .{ .lzcnt, null, null, null }, |
| 4328 | .src_constraints = .{ .{ .unsigned_int = .word }, .any }, |
| 4329 | .patterns = &.{ |
| 4330 | .{ .src = .{ .mem, .none } }, |
| 4331 | .{ .src = .{ .to_gpr, .none } }, |
| 4332 | }, |
| 4333 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4334 | .clobbers = .{ .eflags = true }, |
| 4335 | .each = .{ .once = &.{ |
| 4336 | .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ }, |
| 4337 | .{ ._, ._, .sub, .dst0b, .sia(16, .src0, .sub_bit_size), ._, ._ }, |
| 4338 | } }, |
| 4339 | }, .{ |
| 4340 | .required_features = .{ .false_deps_lzcnt_tzcnt, .lzcnt, null, null }, |
| 4341 | .src_constraints = .{ .{ .exact_int = 32 }, .any }, |
| 4342 | .patterns = &.{ |
| 4343 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4344 | }, |
| 4345 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4346 | .clobbers = .{ .eflags = true }, |
| 4347 | .each = .{ .once = &.{ |
| 4348 | .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ }, |
| 4349 | } }, |
| 4350 | }, .{ |
| 4351 | .required_features = .{ .lzcnt, null, null, null }, |
| 4352 | .src_constraints = .{ .{ .exact_int = 32 }, .any }, |
| 4353 | .patterns = &.{ |
| 4354 | .{ .src = .{ .mem, .none } }, |
| 4355 | .{ .src = .{ .to_gpr, .none } }, |
| 4356 | }, |
| 4357 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4358 | .clobbers = .{ .eflags = true }, |
| 4359 | .each = .{ .once = &.{ |
| 4360 | .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ }, |
| 4361 | } }, |
| 4362 | }, .{ |
| 4363 | .required_features = .{ .lzcnt, null, null, null }, |
| 4364 | .src_constraints = .{ .{ .signed_int = .dword }, .any }, |
| 4365 | .patterns = &.{ |
| 4366 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4367 | }, |
| 4368 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4369 | .clobbers = .{ .eflags = true }, |
| 4370 | .each = .{ .once = &.{ |
| 4371 | .{ ._, ._, .@"and", .src0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4372 | .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ }, |
| 4373 | .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 4374 | } }, |
| 4375 | }, .{ |
| 4376 | .required_features = .{ .false_deps_lzcnt_tzcnt, .lzcnt, null, null }, |
| 4377 | .src_constraints = .{ .{ .unsigned_int = .dword }, .any }, |
| 4378 | .patterns = &.{ |
| 4379 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4380 | }, |
| 4381 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4382 | .clobbers = .{ .eflags = true }, |
| 4383 | .each = .{ .once = &.{ |
| 4384 | .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ }, |
| 4385 | .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 4386 | } }, |
| 4387 | }, .{ |
| 4388 | .required_features = .{ .lzcnt, null, null, null }, |
| 4389 | .src_constraints = .{ .{ .unsigned_int = .dword }, .any }, |
| 4390 | .patterns = &.{ |
| 4391 | .{ .src = .{ .mem, .none } }, |
| 4392 | .{ .src = .{ .to_gpr, .none } }, |
| 4393 | }, |
| 4394 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4395 | .clobbers = .{ .eflags = true }, |
| 4396 | .each = .{ .once = &.{ |
| 4397 | .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ }, |
| 4398 | .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 4399 | } }, |
| 4400 | }, .{ |
| 4401 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 4402 | .src_constraints = .{ .{ .exact_int = 64 }, .any }, |
| 4403 | .patterns = &.{ |
| 4404 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4405 | }, |
| 4406 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4407 | .clobbers = .{ .eflags = true }, |
| 4408 | .each = .{ .once = &.{ |
| 4409 | .{ ._, ._, .lzcnt, .dst0q, .src0q, ._, ._ }, |
| 4410 | } }, |
| 4411 | }, .{ |
| 4412 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 4413 | .src_constraints = .{ .{ .exact_int = 64 }, .any }, |
| 4414 | .patterns = &.{ |
| 4415 | .{ .src = .{ .mem, .none } }, |
| 4416 | .{ .src = .{ .to_gpr, .none } }, |
| 4417 | }, |
| 4418 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4419 | .clobbers = .{ .eflags = true }, |
| 4420 | .each = .{ .once = &.{ |
| 4421 | .{ ._, ._, .lzcnt, .dst0q, .src0q, ._, ._ }, |
| 4422 | } }, |
| 4423 | }, .{ |
| 4424 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 4425 | .src_constraints = .{ .{ .signed_int = .qword }, .any }, |
| 4426 | .patterns = &.{ |
| 4427 | .{ .src = .{ .mem, .none } }, |
| 4428 | .{ .src = .{ .to_gpr, .none } }, |
| 4429 | }, |
| 4430 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4431 | .clobbers = .{ .eflags = true }, |
| 4432 | .each = .{ .once = &.{ |
| 4433 | .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ }, |
| 4434 | .{ ._, ._, .@"and", .dst0q, .src0q, ._, ._ }, |
| 4435 | .{ ._, ._, .lzcnt, .dst0q, .dst0q, ._, ._ }, |
| 4436 | .{ ._, ._, .sub, .dst0b, .sia(64, .src0, .sub_bit_size), ._, ._ }, |
| 4437 | } }, |
| 4438 | }, .{ |
| 4439 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 4440 | .src_constraints = .{ .{ .unsigned_int = .qword }, .any }, |
| 4441 | .patterns = &.{ |
| 4442 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4443 | }, |
| 4444 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4445 | .clobbers = .{ .eflags = true }, |
| 4446 | .each = .{ .once = &.{ |
| 4447 | .{ ._, ._, .lzcnt, .dst0q, .src0q, ._, ._ }, |
| 4448 | .{ ._, ._, .sub, .dst0b, .sia(64, .src0, .sub_bit_size), ._, ._ }, |
| 4449 | } }, |
| 4450 | }, .{ |
| 4451 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 4452 | .src_constraints = .{ .{ .unsigned_int = .qword }, .any }, |
| 4453 | .patterns = &.{ |
| 4454 | .{ .src = .{ .mem, .none } }, |
| 4455 | .{ .src = .{ .to_gpr, .none } }, |
| 4456 | }, |
| 4457 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4458 | .clobbers = .{ .eflags = true }, |
| 4459 | .each = .{ .once = &.{ |
| 4460 | .{ ._, ._, .lzcnt, .dst0q, .src0q, ._, ._ }, |
| 4461 | .{ ._, ._, .sub, .dst0b, .sia(64, .src0, .sub_bit_size), ._, ._ }, |
| 4462 | } }, |
| 4463 | }, .{ |
| 4464 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4465 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .byte }, .any }, |
| 4466 | .patterns = &.{ |
| 4467 | .{ .src = .{ .mem, .none } }, |
| 4468 | .{ .src = .{ .to_gpr, .none } }, |
| 4469 | }, |
| 4470 | .extra_temps = .{ |
| 4471 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4472 | .unused, |
| 4473 | .unused, |
| 4474 | .unused, |
| 4475 | .unused, |
| 4476 | .unused, |
| 4477 | }, |
| 4478 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4479 | .clobbers = .{ .eflags = true }, |
| 4480 | .each = .{ .once = &.{ |
| 4481 | .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ }, |
| 4482 | .{ ._, ._r, .bs, .dst0d, .dst0d, ._, ._ }, |
| 4483 | .{ ._, ._, .mov, .tmp0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4484 | .{ ._, ._z, .cmov, .dst0d, .tmp0d, ._, ._ }, |
| 4485 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4486 | } }, |
| 4487 | }, .{ |
| 4488 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4489 | .src_constraints = .{ .{ .signed_po2_int = .byte }, .any }, |
| 4490 | .patterns = &.{ |
| 4491 | .{ .src = .{ .mem, .none } }, |
| 4492 | .{ .src = .{ .to_gpr, .none } }, |
| 4493 | }, |
| 4494 | .extra_temps = .{ |
| 4495 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4496 | .unused, |
| 4497 | .unused, |
| 4498 | .unused, |
| 4499 | .unused, |
| 4500 | .unused, |
| 4501 | }, |
| 4502 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4503 | .clobbers = .{ .eflags = true }, |
| 4504 | .each = .{ .once = &.{ |
| 4505 | .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ }, |
| 4506 | .{ ._, ._, .@"and", .dst0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4507 | .{ ._, ._r, .bs, .dst0d, .dst0d, ._, ._ }, |
| 4508 | .{ ._, ._, .mov, .tmp0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4509 | .{ ._, ._z, .cmov, .dst0d, .tmp0d, ._, ._ }, |
| 4510 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4511 | } }, |
| 4512 | }, .{ |
| 4513 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4514 | .src_constraints = .{ .{ .signed_int = .byte }, .any }, |
| 4515 | .patterns = &.{ |
| 4516 | .{ .src = .{ .mem, .none } }, |
| 4517 | .{ .src = .{ .to_gpr, .none } }, |
| 4518 | }, |
| 4519 | .extra_temps = .{ |
| 4520 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4521 | .unused, |
| 4522 | .unused, |
| 4523 | .unused, |
| 4524 | .unused, |
| 4525 | .unused, |
| 4526 | }, |
| 4527 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4528 | .clobbers = .{ .eflags = true }, |
| 4529 | .each = .{ .once = &.{ |
| 4530 | .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ }, |
| 4531 | .{ ._, ._, .@"and", .tmp0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4532 | .{ ._, ._r, .bs, .tmp0d, .tmp0d, ._, ._ }, |
| 4533 | .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ }, |
| 4534 | .{ ._, ._z, .cmov, .tmp0d, .dst0d, ._, ._ }, |
| 4535 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4536 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 4537 | } }, |
| 4538 | }, .{ |
| 4539 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4540 | .src_constraints = .{ .{ .unsigned_int = .byte }, .any }, |
| 4541 | .patterns = &.{ |
| 4542 | .{ .src = .{ .mem, .none } }, |
| 4543 | .{ .src = .{ .to_gpr, .none } }, |
| 4544 | }, |
| 4545 | .extra_temps = .{ |
| 4546 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4547 | .unused, |
| 4548 | .unused, |
| 4549 | .unused, |
| 4550 | .unused, |
| 4551 | .unused, |
| 4552 | }, |
| 4553 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4554 | .clobbers = .{ .eflags = true }, |
| 4555 | .each = .{ .once = &.{ |
| 4556 | .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ }, |
| 4557 | .{ ._, ._r, .bs, .tmp0d, .tmp0d, ._, ._ }, |
| 4558 | .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ }, |
| 4559 | .{ ._, ._z, .cmov, .tmp0d, .dst0d, ._, ._ }, |
| 4560 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4561 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 4562 | } }, |
| 4563 | }, .{ |
| 4564 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4565 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .byte }, .any }, |
| 4566 | .patterns = &.{ |
| 4567 | .{ .src = .{ .mem, .none } }, |
| 4568 | .{ .src = .{ .to_gpr, .none } }, |
| 4569 | }, |
| 4570 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4571 | .clobbers = .{ .eflags = true }, |
| 4572 | .each = .{ .once = &.{ |
| 4573 | .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ }, |
| 4574 | .{ ._, ._r, .bs, .dst0d, .dst0d, ._, ._ }, |
| 4575 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 4576 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4577 | .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4578 | } }, |
| 4579 | }, .{ |
| 4580 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4581 | .src_constraints = .{ .{ .signed_po2_int = .byte }, .any }, |
| 4582 | .patterns = &.{ |
| 4583 | .{ .src = .{ .mem, .none } }, |
| 4584 | .{ .src = .{ .to_gpr, .none } }, |
| 4585 | }, |
| 4586 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4587 | .clobbers = .{ .eflags = true }, |
| 4588 | .each = .{ .once = &.{ |
| 4589 | .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ }, |
| 4590 | .{ ._, ._, .@"and", .dst0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4591 | .{ ._, ._r, .bs, .dst0d, .dst0d, ._, ._ }, |
| 4592 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 4593 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4594 | .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4595 | } }, |
| 4596 | }, .{ |
| 4597 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4598 | .src_constraints = .{ .{ .signed_int = .byte }, .any }, |
| 4599 | .patterns = &.{ |
| 4600 | .{ .src = .{ .mem, .none } }, |
| 4601 | .{ .src = .{ .to_gpr, .none } }, |
| 4602 | }, |
| 4603 | .extra_temps = .{ |
| 4604 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4605 | .unused, |
| 4606 | .unused, |
| 4607 | .unused, |
| 4608 | .unused, |
| 4609 | .unused, |
| 4610 | }, |
| 4611 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4612 | .clobbers = .{ .eflags = true }, |
| 4613 | .each = .{ .once = &.{ |
| 4614 | .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ }, |
| 4615 | .{ ._, ._, .@"and", .tmp0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4616 | .{ ._, ._r, .bs, .tmp0d, .tmp0d, ._, ._ }, |
| 4617 | .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 4618 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 4619 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 4620 | .{ ._, ._, .sbb, .dst0b, .tmp0b, ._, ._ }, |
| 4621 | } }, |
| 4622 | }, .{ |
| 4623 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4624 | .src_constraints = .{ .{ .unsigned_int = .byte }, .any }, |
| 4625 | .patterns = &.{ |
| 4626 | .{ .src = .{ .mem, .none } }, |
| 4627 | .{ .src = .{ .to_gpr, .none } }, |
| 4628 | }, |
| 4629 | .extra_temps = .{ |
| 4630 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4631 | .unused, |
| 4632 | .unused, |
| 4633 | .unused, |
| 4634 | .unused, |
| 4635 | .unused, |
| 4636 | }, |
| 4637 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4638 | .clobbers = .{ .eflags = true }, |
| 4639 | .each = .{ .once = &.{ |
| 4640 | .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ }, |
| 4641 | .{ ._, ._r, .bs, .tmp0d, .tmp0d, ._, ._ }, |
| 4642 | .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 4643 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 4644 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 4645 | .{ ._, ._, .sbb, .dst0b, .tmp0b, ._, ._ }, |
| 4646 | } }, |
| 4647 | }, .{ |
| 4648 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .byte }, .any }, |
| 4649 | .patterns = &.{ |
| 4650 | .{ .src = .{ .mem, .none } }, |
| 4651 | .{ .src = .{ .to_gpr, .none } }, |
| 4652 | }, |
| 4653 | .extra_temps = .{ |
| 4654 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4655 | .unused, |
| 4656 | .unused, |
| 4657 | .unused, |
| 4658 | .unused, |
| 4659 | .unused, |
| 4660 | }, |
| 4661 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4662 | .clobbers = .{ .eflags = true }, |
| 4663 | .each = .{ .once = &.{ |
| 4664 | .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ }, |
| 4665 | .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4666 | .{ ._, ._r, .bs, .dst0d, .tmp0d, ._, ._ }, |
| 4667 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4668 | } }, |
| 4669 | }, .{ |
| 4670 | .src_constraints = .{ .{ .signed_po2_int = .byte }, .any }, |
| 4671 | .patterns = &.{ |
| 4672 | .{ .src = .{ .mem, .none } }, |
| 4673 | .{ .src = .{ .to_gpr, .none } }, |
| 4674 | }, |
| 4675 | .extra_temps = .{ |
| 4676 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4677 | .unused, |
| 4678 | .unused, |
| 4679 | .unused, |
| 4680 | .unused, |
| 4681 | .unused, |
| 4682 | }, |
| 4683 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4684 | .clobbers = .{ .eflags = true }, |
| 4685 | .each = .{ .once = &.{ |
| 4686 | .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ }, |
| 4687 | .{ ._, ._, .@"and", .tmp0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4688 | .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4689 | .{ ._, ._r, .bs, .dst0d, .tmp0d, ._, ._ }, |
| 4690 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4691 | } }, |
| 4692 | }, .{ |
| 4693 | .src_constraints = .{ .{ .signed_int = .byte }, .any }, |
| 4694 | .patterns = &.{ |
| 4695 | .{ .src = .{ .mem, .none } }, |
| 4696 | .{ .src = .{ .to_gpr, .none } }, |
| 4697 | }, |
| 4698 | .extra_temps = .{ |
| 4699 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4700 | .unused, |
| 4701 | .unused, |
| 4702 | .unused, |
| 4703 | .unused, |
| 4704 | .unused, |
| 4705 | }, |
| 4706 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4707 | .clobbers = .{ .eflags = true }, |
| 4708 | .each = .{ .once = &.{ |
| 4709 | .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ }, |
| 4710 | .{ ._, ._, .@"and", .dst0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4711 | .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ }, |
| 4712 | .{ ._, ._r, .bs, .tmp0d, .dst0d, ._, ._ }, |
| 4713 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4714 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 4715 | } }, |
| 4716 | }, .{ |
| 4717 | .src_constraints = .{ .{ .unsigned_int = .byte }, .any }, |
| 4718 | .patterns = &.{ |
| 4719 | .{ .src = .{ .mem, .none } }, |
| 4720 | .{ .src = .{ .to_gpr, .none } }, |
| 4721 | }, |
| 4722 | .extra_temps = .{ |
| 4723 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4724 | .unused, |
| 4725 | .unused, |
| 4726 | .unused, |
| 4727 | .unused, |
| 4728 | .unused, |
| 4729 | }, |
| 4730 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4731 | .clobbers = .{ .eflags = true }, |
| 4732 | .each = .{ .once = &.{ |
| 4733 | .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ }, |
| 4734 | .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ }, |
| 4735 | .{ ._, ._r, .bs, .tmp0d, .dst0d, ._, ._ }, |
| 4736 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4737 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 4738 | } }, |
| 4739 | }, .{ |
| 4740 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4741 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .word }, .any }, |
| 4742 | .patterns = &.{ |
| 4743 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4744 | }, |
| 4745 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4746 | .clobbers = .{ .eflags = true }, |
| 4747 | .each = .{ .once = &.{ |
| 4748 | .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ }, |
| 4749 | .{ ._, ._, .mov, .dst0w, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4750 | .{ ._, ._nz, .cmov, .dst0w, .src0w, ._, ._ }, |
| 4751 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4752 | } }, |
| 4753 | }, .{ |
| 4754 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4755 | .src_constraints = .{ .{ .signed_int = .word }, .any }, |
| 4756 | .patterns = &.{ |
| 4757 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4758 | }, |
| 4759 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4760 | .clobbers = .{ .eflags = true }, |
| 4761 | .each = .{ .once = &.{ |
| 4762 | .{ ._, ._, .@"and", .src0w, .sa(.src0, .add_umax), ._, ._ }, |
| 4763 | .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ }, |
| 4764 | .{ ._, ._, .mov, .dst0w, .si(0xff), ._, ._ }, |
| 4765 | .{ ._, ._z, .cmov, .src0w, .dst0w, ._, ._ }, |
| 4766 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4767 | .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ }, |
| 4768 | } }, |
| 4769 | }, .{ |
| 4770 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4771 | .src_constraints = .{ .{ .unsigned_int = .word }, .any }, |
| 4772 | .patterns = &.{ |
| 4773 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4774 | }, |
| 4775 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4776 | .clobbers = .{ .eflags = true }, |
| 4777 | .each = .{ .once = &.{ |
| 4778 | .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ }, |
| 4779 | .{ ._, ._, .mov, .dst0w, .si(0xff), ._, ._ }, |
| 4780 | .{ ._, ._z, .cmov, .src0w, .dst0w, ._, ._ }, |
| 4781 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4782 | .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ }, |
| 4783 | } }, |
| 4784 | }, .{ |
| 4785 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4786 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .word }, .any }, |
| 4787 | .patterns = &.{ |
| 4788 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4789 | }, |
| 4790 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4791 | .clobbers = .{ .eflags = true }, |
| 4792 | .each = .{ .once = &.{ |
| 4793 | .{ ._, ._r, .bs, .dst0w, .src0w, ._, ._ }, |
| 4794 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 4795 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4796 | .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4797 | } }, |
| 4798 | }, .{ |
| 4799 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4800 | .src_constraints = .{ .{ .signed_int = .word }, .any }, |
| 4801 | .patterns = &.{ |
| 4802 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4803 | }, |
| 4804 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4805 | .clobbers = .{ .eflags = true }, |
| 4806 | .each = .{ .once = &.{ |
| 4807 | .{ ._, ._, .@"and", .src0w, .sa(.src0, .add_umax), ._, ._ }, |
| 4808 | .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ }, |
| 4809 | .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 4810 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 4811 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 4812 | .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ }, |
| 4813 | } }, |
| 4814 | }, .{ |
| 4815 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4816 | .src_constraints = .{ .{ .unsigned_int = .word }, .any }, |
| 4817 | .patterns = &.{ |
| 4818 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4819 | }, |
| 4820 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4821 | .clobbers = .{ .eflags = true }, |
| 4822 | .each = .{ .once = &.{ |
| 4823 | .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ }, |
| 4824 | .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 4825 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 4826 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 4827 | .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ }, |
| 4828 | } }, |
| 4829 | }, .{ |
| 4830 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .word }, .any }, |
| 4831 | .patterns = &.{ |
| 4832 | .{ .src = .{ .mem, .none } }, |
| 4833 | .{ .src = .{ .to_gpr, .none } }, |
| 4834 | }, |
| 4835 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4836 | .clobbers = .{ .eflags = true }, |
| 4837 | .each = .{ .once = &.{ |
| 4838 | .{ ._, ._, .mov, .dst0w, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4839 | .{ ._, ._r, .bs, .dst0w, .src0w, ._, ._ }, |
| 4840 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4841 | } }, |
| 4842 | }, .{ |
| 4843 | .src_constraints = .{ .{ .signed_int = .word }, .any }, |
| 4844 | .patterns = &.{ |
| 4845 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4846 | }, |
| 4847 | .extra_temps = .{ |
| 4848 | .{ .type = .u16, .kind = .{ .rc = .general_purpose } }, |
| 4849 | .unused, |
| 4850 | .unused, |
| 4851 | .unused, |
| 4852 | .unused, |
| 4853 | .unused, |
| 4854 | }, |
| 4855 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4856 | .clobbers = .{ .eflags = true }, |
| 4857 | .each = .{ .once = &.{ |
| 4858 | .{ ._, ._, .@"and", .src0w, .sa(.src0, .add_umax), ._, ._ }, |
| 4859 | .{ ._, ._, .mov, .tmp0w, .si(0xff), ._, ._ }, |
| 4860 | .{ ._, ._r, .bs, .tmp0w, .src0w, ._, ._ }, |
| 4861 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4862 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 4863 | } }, |
| 4864 | }, .{ |
| 4865 | .src_constraints = .{ .{ .unsigned_int = .word }, .any }, |
| 4866 | .patterns = &.{ |
| 4867 | .{ .src = .{ .mem, .none } }, |
| 4868 | .{ .src = .{ .to_gpr, .none } }, |
| 4869 | }, |
| 4870 | .extra_temps = .{ |
| 4871 | .{ .type = .u16, .kind = .{ .rc = .general_purpose } }, |
| 4872 | .unused, |
| 4873 | .unused, |
| 4874 | .unused, |
| 4875 | .unused, |
| 4876 | .unused, |
| 4877 | }, |
| 4878 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4879 | .clobbers = .{ .eflags = true }, |
| 4880 | .each = .{ .once = &.{ |
| 4881 | .{ ._, ._, .mov, .tmp0w, .si(0xff), ._, ._ }, |
| 4882 | .{ ._, ._r, .bs, .tmp0w, .src0w, ._, ._ }, |
| 4883 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4884 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 4885 | } }, |
| 4886 | }, .{ |
| 4887 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4888 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .dword }, .any }, |
| 4889 | .patterns = &.{ |
| 4890 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4891 | }, |
| 4892 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4893 | .clobbers = .{ .eflags = true }, |
| 4894 | .each = .{ .once = &.{ |
| 4895 | .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ }, |
| 4896 | .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4897 | .{ ._, ._nz, .cmov, .dst0d, .src0d, ._, ._ }, |
| 4898 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4899 | } }, |
| 4900 | }, .{ |
| 4901 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4902 | .src_constraints = .{ .{ .signed_int = .dword }, .any }, |
| 4903 | .patterns = &.{ |
| 4904 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4905 | }, |
| 4906 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4907 | .clobbers = .{ .eflags = true }, |
| 4908 | .each = .{ .once = &.{ |
| 4909 | .{ ._, ._, .@"and", .src0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4910 | .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ }, |
| 4911 | .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ }, |
| 4912 | .{ ._, ._z, .cmov, .src0d, .dst0d, ._, ._ }, |
| 4913 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4914 | .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ }, |
| 4915 | } }, |
| 4916 | }, .{ |
| 4917 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 4918 | .src_constraints = .{ .{ .unsigned_int = .dword }, .any }, |
| 4919 | .patterns = &.{ |
| 4920 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4921 | }, |
| 4922 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4923 | .clobbers = .{ .eflags = true }, |
| 4924 | .each = .{ .once = &.{ |
| 4925 | .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ }, |
| 4926 | .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ }, |
| 4927 | .{ ._, ._z, .cmov, .src0d, .dst0d, ._, ._ }, |
| 4928 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4929 | .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ }, |
| 4930 | } }, |
| 4931 | }, .{ |
| 4932 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4933 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .dword }, .any }, |
| 4934 | .patterns = &.{ |
| 4935 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4936 | }, |
| 4937 | .dst_temps = .{.{ .ref = .src0 }}, |
| 4938 | .clobbers = .{ .eflags = true }, |
| 4939 | .each = .{ .once = &.{ |
| 4940 | .{ ._, ._r, .bs, .dst0d, .src0d, ._, ._ }, |
| 4941 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 4942 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4943 | .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4944 | } }, |
| 4945 | }, .{ |
| 4946 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4947 | .src_constraints = .{ .{ .signed_int = .dword }, .any }, |
| 4948 | .patterns = &.{ |
| 4949 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4950 | }, |
| 4951 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4952 | .clobbers = .{ .eflags = true }, |
| 4953 | .each = .{ .once = &.{ |
| 4954 | .{ ._, ._, .@"and", .src0d, .sa(.src0, .add_umax), ._, ._ }, |
| 4955 | .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ }, |
| 4956 | .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 4957 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 4958 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 4959 | .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ }, |
| 4960 | } }, |
| 4961 | }, .{ |
| 4962 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 4963 | .src_constraints = .{ .{ .unsigned_int = .dword }, .any }, |
| 4964 | .patterns = &.{ |
| 4965 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4966 | }, |
| 4967 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4968 | .clobbers = .{ .eflags = true }, |
| 4969 | .each = .{ .once = &.{ |
| 4970 | .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ }, |
| 4971 | .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 4972 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 4973 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 4974 | .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ }, |
| 4975 | } }, |
| 4976 | }, .{ |
| 4977 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .dword }, .any }, |
| 4978 | .patterns = &.{ |
| 4979 | .{ .src = .{ .mem, .none } }, |
| 4980 | .{ .src = .{ .to_gpr, .none } }, |
| 4981 | }, |
| 4982 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 4983 | .clobbers = .{ .eflags = true }, |
| 4984 | .each = .{ .once = &.{ |
| 4985 | .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 4986 | .{ ._, ._r, .bs, .dst0d, .src0d, ._, ._ }, |
| 4987 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 4988 | } }, |
| 4989 | }, .{ |
| 4990 | .src_constraints = .{ .{ .signed_int = .dword }, .any }, |
| 4991 | .patterns = &.{ |
| 4992 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 4993 | }, |
| 4994 | .extra_temps = .{ |
| 4995 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 4996 | .unused, |
| 4997 | .unused, |
| 4998 | .unused, |
| 4999 | .unused, |
| 5000 | .unused, |
| 5001 | }, |
| 5002 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5003 | .clobbers = .{ .eflags = true }, |
| 5004 | .each = .{ .once = &.{ |
| 5005 | .{ ._, ._, .@"and", .src0d, .sa(.src0, .add_umax), ._, ._ }, |
| 5006 | .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ }, |
| 5007 | .{ ._, ._r, .bs, .tmp0d, .src0d, ._, ._ }, |
| 5008 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5009 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 5010 | } }, |
| 5011 | }, .{ |
| 5012 | .src_constraints = .{ .{ .unsigned_int = .dword }, .any }, |
| 5013 | .patterns = &.{ |
| 5014 | .{ .src = .{ .mem, .none } }, |
| 5015 | .{ .src = .{ .to_gpr, .none } }, |
| 5016 | }, |
| 5017 | .extra_temps = .{ |
| 5018 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5019 | .unused, |
| 5020 | .unused, |
| 5021 | .unused, |
| 5022 | .unused, |
| 5023 | .unused, |
| 5024 | }, |
| 5025 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5026 | .clobbers = .{ .eflags = true }, |
| 5027 | .each = .{ .once = &.{ |
| 5028 | .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ }, |
| 5029 | .{ ._, ._r, .bs, .tmp0d, .src0d, ._, ._ }, |
| 5030 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5031 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 5032 | } }, |
| 5033 | }, .{ |
| 5034 | .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, null }, |
| 5035 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .qword }, .any }, |
| 5036 | .patterns = &.{ |
| 5037 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 5038 | }, |
| 5039 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5040 | .clobbers = .{ .eflags = true }, |
| 5041 | .each = .{ .once = &.{ |
| 5042 | .{ ._, ._r, .bs, .src0q, .src0q, ._, ._ }, |
| 5043 | .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 5044 | .{ ._, ._nz, .cmov, .dst0d, .src0d, ._, ._ }, |
| 5045 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5046 | } }, |
| 5047 | }, .{ |
| 5048 | .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, null }, |
| 5049 | .src_constraints = .{ .{ .signed_int = .qword }, .any }, |
| 5050 | .patterns = &.{ |
| 5051 | .{ .src = .{ .mem, .none } }, |
| 5052 | .{ .src = .{ .to_gpr, .none } }, |
| 5053 | }, |
| 5054 | .extra_temps = .{ |
| 5055 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5056 | .unused, |
| 5057 | .unused, |
| 5058 | .unused, |
| 5059 | .unused, |
| 5060 | .unused, |
| 5061 | }, |
| 5062 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5063 | .clobbers = .{ .eflags = true }, |
| 5064 | .each = .{ .once = &.{ |
| 5065 | .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ }, |
| 5066 | .{ ._, ._, .@"and", .tmp0q, .src0q, ._, ._ }, |
| 5067 | .{ ._, ._r, .bs, .tmp0q, .tmp0q, ._, ._ }, |
| 5068 | .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ }, |
| 5069 | .{ ._, ._z, .cmov, .tmp0d, .dst0d, ._, ._ }, |
| 5070 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5071 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 5072 | } }, |
| 5073 | }, .{ |
| 5074 | .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, null }, |
| 5075 | .src_constraints = .{ .{ .unsigned_int = .qword }, .any }, |
| 5076 | .patterns = &.{ |
| 5077 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 5078 | }, |
| 5079 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5080 | .clobbers = .{ .eflags = true }, |
| 5081 | .each = .{ .once = &.{ |
| 5082 | .{ ._, ._r, .bs, .src0q, .src0q, ._, ._ }, |
| 5083 | .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ }, |
| 5084 | .{ ._, ._z, .cmov, .src0d, .dst0d, ._, ._ }, |
| 5085 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5086 | .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ }, |
| 5087 | } }, |
| 5088 | }, .{ |
| 5089 | .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null }, |
| 5090 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .qword }, .any }, |
| 5091 | .patterns = &.{ |
| 5092 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 5093 | }, |
| 5094 | .dst_temps = .{.{ .ref = .src0 }}, |
| 5095 | .clobbers = .{ .eflags = true }, |
| 5096 | .each = .{ .once = &.{ |
| 5097 | .{ ._, ._r, .bs, .dst0q, .src0q, ._, ._ }, |
| 5098 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 5099 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 5100 | .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5101 | } }, |
| 5102 | }, .{ |
| 5103 | .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null }, |
| 5104 | .src_constraints = .{ .{ .signed_int = .qword }, .any }, |
| 5105 | .patterns = &.{ |
| 5106 | .{ .src = .{ .mem, .none } }, |
| 5107 | .{ .src = .{ .to_gpr, .none } }, |
| 5108 | }, |
| 5109 | .extra_temps = .{ |
| 5110 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5111 | .unused, |
| 5112 | .unused, |
| 5113 | .unused, |
| 5114 | .unused, |
| 5115 | .unused, |
| 5116 | }, |
| 5117 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5118 | .clobbers = .{ .eflags = true }, |
| 5119 | .each = .{ .once = &.{ |
| 5120 | .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ }, |
| 5121 | .{ ._, ._, .@"and", .tmp0q, .src0q, ._, ._ }, |
| 5122 | .{ ._, ._r, .bs, .tmp0q, .tmp0q, ._, ._ }, |
| 5123 | .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 5124 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 5125 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 5126 | .{ ._, ._, .sbb, .dst0b, .tmp0b, ._, ._ }, |
| 5127 | } }, |
| 5128 | }, .{ |
| 5129 | .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null }, |
| 5130 | .src_constraints = .{ .{ .unsigned_int = .qword }, .any }, |
| 5131 | .patterns = &.{ |
| 5132 | .{ .src = .{ .to_mut_gpr, .none } }, |
| 5133 | }, |
| 5134 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5135 | .clobbers = .{ .eflags = true }, |
| 5136 | .each = .{ .once = &.{ |
| 5137 | .{ ._, ._r, .bs, .src0q, .src0q, ._, ._ }, |
| 5138 | .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 5139 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 5140 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 5141 | .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ }, |
| 5142 | } }, |
| 5143 | }, .{ |
| 5144 | .required_features = .{ .@"64bit", null, null, null }, |
| 5145 | .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .qword }, .any }, |
| 5146 | .patterns = &.{ |
| 5147 | .{ .src = .{ .mem, .none } }, |
| 5148 | .{ .src = .{ .to_gpr, .none } }, |
| 5149 | }, |
| 5150 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5151 | .clobbers = .{ .eflags = true }, |
| 5152 | .each = .{ .once = &.{ |
| 5153 | .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ }, |
| 5154 | .{ ._, ._r, .bs, .dst0q, .src0q, ._, ._ }, |
| 5155 | .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5156 | } }, |
| 5157 | }, .{ |
| 5158 | .required_features = .{ .@"64bit", null, null, null }, |
| 5159 | .src_constraints = .{ .{ .signed_int = .qword }, .any }, |
| 5160 | .patterns = &.{ |
| 5161 | .{ .src = .{ .mem, .none } }, |
| 5162 | .{ .src = .{ .to_gpr, .none } }, |
| 5163 | }, |
| 5164 | .extra_temps = .{ |
| 5165 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5166 | .unused, |
| 5167 | .unused, |
| 5168 | .unused, |
| 5169 | .unused, |
| 5170 | .unused, |
| 5171 | }, |
| 5172 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5173 | .clobbers = .{ .eflags = true }, |
| 5174 | .each = .{ .once = &.{ |
| 5175 | .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ }, |
| 5176 | .{ ._, ._, .@"and", .dst0q, .src0q, ._, ._ }, |
| 5177 | .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ }, |
| 5178 | .{ ._, ._r, .bs, .tmp0q, .dst0q, ._, ._ }, |
| 5179 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5180 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 5181 | } }, |
| 5182 | }, .{ |
| 5183 | .required_features = .{ .@"64bit", null, null, null }, |
| 5184 | .src_constraints = .{ .{ .unsigned_int = .qword }, .any }, |
| 5185 | .patterns = &.{ |
| 5186 | .{ .src = .{ .mem, .none } }, |
| 5187 | .{ .src = .{ .to_gpr, .none } }, |
| 5188 | }, |
| 5189 | .extra_temps = .{ |
| 5190 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5191 | .unused, |
| 5192 | .unused, |
| 5193 | .unused, |
| 5194 | .unused, |
| 5195 | .unused, |
| 5196 | }, |
| 5197 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5198 | .clobbers = .{ .eflags = true }, |
| 5199 | .each = .{ .once = &.{ |
| 5200 | .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ }, |
| 5201 | .{ ._, ._r, .bs, .tmp0q, .src0q, ._, ._ }, |
| 5202 | .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5203 | .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ }, |
| 5204 | } }, |
| 5205 | }, .{ |
| 5206 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 5207 | .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 5208 | .patterns = &.{ |
| 5209 | .{ .src = .{ .to_mem, .none } }, |
| 5210 | }, |
| 5211 | .extra_temps = .{ |
| 5212 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5213 | .unused, |
| 5214 | .unused, |
| 5215 | .unused, |
| 5216 | .unused, |
| 5217 | .unused, |
| 5218 | }, |
| 5219 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5220 | .clobbers = .{ .eflags = true }, |
| 5221 | .each = .{ .once = &.{ |
| 5222 | .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ }, |
| 5223 | .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 5224 | .{ ._, ._, .lzcnt, .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5225 | .{ ._, ._nc, .j, .@"0f", ._, ._, ._ }, |
| 5226 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5227 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5228 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5229 | .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ }, |
| 5230 | .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ }, |
| 5231 | } }, |
| 5232 | }, .{ |
| 5233 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 5234 | .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 5235 | .patterns = &.{ |
| 5236 | .{ .src = .{ .to_mem, .none } }, |
| 5237 | }, |
| 5238 | .extra_temps = .{ |
| 5239 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5240 | .unused, |
| 5241 | .unused, |
| 5242 | .unused, |
| 5243 | .unused, |
| 5244 | .unused, |
| 5245 | }, |
| 5246 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5247 | .clobbers = .{ .eflags = true }, |
| 5248 | .each = .{ .once = &.{ |
| 5249 | .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ }, |
| 5250 | .{ .@"0:", ._, .lzcnt, .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5251 | .{ ._, ._nc, .j, .@"0f", ._, ._, ._ }, |
| 5252 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5253 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5254 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5255 | .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ }, |
| 5256 | .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ }, |
| 5257 | } }, |
| 5258 | }, .{ |
| 5259 | .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null }, |
| 5260 | .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 5261 | .patterns = &.{ |
| 5262 | .{ .src = .{ .to_mem, .none } }, |
| 5263 | }, |
| 5264 | .extra_temps = .{ |
| 5265 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5266 | .unused, |
| 5267 | .unused, |
| 5268 | .unused, |
| 5269 | .unused, |
| 5270 | .unused, |
| 5271 | }, |
| 5272 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5273 | .clobbers = .{ .eflags = true }, |
| 5274 | .each = .{ .once = &.{ |
| 5275 | .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ }, |
| 5276 | .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 5277 | .{ ._, ._r, .bs, .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5278 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 5279 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5280 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5281 | .{ ._, ._, .mov, .dst0d, .si(-1), ._, ._ }, |
| 5282 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5283 | .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ }, |
| 5284 | .{ ._, ._, .neg, .dst0d, ._, ._, ._ }, |
| 5285 | } }, |
| 5286 | }, .{ |
| 5287 | .required_features = .{ .@"64bit", null, null, null }, |
| 5288 | .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 5289 | .patterns = &.{ |
| 5290 | .{ .src = .{ .to_mem, .none } }, |
| 5291 | }, |
| 5292 | .extra_temps = .{ |
| 5293 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5294 | .unused, |
| 5295 | .unused, |
| 5296 | .unused, |
| 5297 | .unused, |
| 5298 | .unused, |
| 5299 | }, |
| 5300 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5301 | .clobbers = .{ .eflags = true }, |
| 5302 | .each = .{ .once = &.{ |
| 5303 | .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ }, |
| 5304 | .{ .@"0:", ._, .mov, .dst0d, .si(-1), ._, ._ }, |
| 5305 | .{ ._, ._r, .bs, .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5306 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 5307 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5308 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5309 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5310 | .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ }, |
| 5311 | .{ ._, ._, .neg, .dst0d, ._, ._, ._ }, |
| 5312 | } }, |
| 5313 | }, .{ |
| 5314 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 5315 | .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 5316 | .patterns = &.{ |
| 5317 | .{ .src = .{ .to_mem, .none } }, |
| 5318 | }, |
| 5319 | .extra_temps = .{ |
| 5320 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5321 | .unused, |
| 5322 | .unused, |
| 5323 | .unused, |
| 5324 | .unused, |
| 5325 | .unused, |
| 5326 | }, |
| 5327 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5328 | .clobbers = .{ .eflags = true }, |
| 5329 | .each = .{ .once = &.{ |
| 5330 | .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ }, |
| 5331 | .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 5332 | .{ ._, ._, .lzcnt, .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5333 | .{ ._, ._nc, .j, .@"0f", ._, ._, ._ }, |
| 5334 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5335 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5336 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5337 | .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ }, |
| 5338 | .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ }, |
| 5339 | } }, |
| 5340 | }, .{ |
| 5341 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 5342 | .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 5343 | .patterns = &.{ |
| 5344 | .{ .src = .{ .to_mem, .none } }, |
| 5345 | }, |
| 5346 | .extra_temps = .{ |
| 5347 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5348 | .unused, |
| 5349 | .unused, |
| 5350 | .unused, |
| 5351 | .unused, |
| 5352 | .unused, |
| 5353 | }, |
| 5354 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5355 | .clobbers = .{ .eflags = true }, |
| 5356 | .each = .{ .once = &.{ |
| 5357 | .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ }, |
| 5358 | .{ .@"0:", ._, .lzcnt, .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5359 | .{ ._, ._nc, .j, .@"0f", ._, ._, ._ }, |
| 5360 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5361 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5362 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5363 | .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ }, |
| 5364 | .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ }, |
| 5365 | } }, |
| 5366 | }, .{ |
| 5367 | .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null }, |
| 5368 | .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 5369 | .patterns = &.{ |
| 5370 | .{ .src = .{ .to_mem, .none } }, |
| 5371 | }, |
| 5372 | .extra_temps = .{ |
| 5373 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5374 | .unused, |
| 5375 | .unused, |
| 5376 | .unused, |
| 5377 | .unused, |
| 5378 | .unused, |
| 5379 | }, |
| 5380 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5381 | .clobbers = .{ .eflags = true }, |
| 5382 | .each = .{ .once = &.{ |
| 5383 | .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ }, |
| 5384 | .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 5385 | .{ ._, ._r, .bs, .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5386 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 5387 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5388 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5389 | .{ ._, ._, .mov, .dst0d, .si(-1), ._, ._ }, |
| 5390 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5391 | .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ }, |
| 5392 | .{ ._, ._, .neg, .dst0d, ._, ._, ._ }, |
| 5393 | } }, |
| 5394 | }, .{ |
| 5395 | .required_features = .{ .@"64bit", null, null, null }, |
| 5396 | .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 5397 | .patterns = &.{ |
| 5398 | .{ .src = .{ .to_mem, .none } }, |
| 5399 | }, |
| 5400 | .extra_temps = .{ |
| 5401 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5402 | .unused, |
| 5403 | .unused, |
| 5404 | .unused, |
| 5405 | .unused, |
| 5406 | .unused, |
| 5407 | }, |
| 5408 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5409 | .clobbers = .{ .eflags = true }, |
| 5410 | .each = .{ .once = &.{ |
| 5411 | .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ }, |
| 5412 | .{ .@"0:", ._, .mov, .dst0d, .si(-1), ._, ._ }, |
| 5413 | .{ ._, ._r, .bs, .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5414 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 5415 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5416 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5417 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5418 | .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ }, |
| 5419 | .{ ._, ._, .neg, .dst0d, ._, ._, ._ }, |
| 5420 | } }, |
| 5421 | }, .{ |
| 5422 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 5423 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 5424 | .patterns = &.{ |
| 5425 | .{ .src = .{ .to_mem, .none } }, |
| 5426 | }, |
| 5427 | .extra_temps = .{ |
| 5428 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5429 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5430 | .unused, |
| 5431 | .unused, |
| 5432 | .unused, |
| 5433 | .unused, |
| 5434 | }, |
| 5435 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5436 | .clobbers = .{ .eflags = true }, |
| 5437 | .each = .{ .once = &.{ |
| 5438 | .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ }, |
| 5439 | .{ ._, ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 5440 | .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 5441 | .{ ._, ._, .@"and", .tmp1q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5442 | .{ ._, ._, .lzcnt, .dst0q, .tmp1q, ._, ._ }, |
| 5443 | .{ ._, ._nc, .j, .@"0f", ._, ._, ._ }, |
| 5444 | .{ ._, ._, .mov, .tmp1q, .si(-1), ._, ._ }, |
| 5445 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5446 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5447 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5448 | .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ }, |
| 5449 | .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ }, |
| 5450 | } }, |
| 5451 | }, .{ |
| 5452 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 5453 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 5454 | .patterns = &.{ |
| 5455 | .{ .src = .{ .to_mem, .none } }, |
| 5456 | }, |
| 5457 | .extra_temps = .{ |
| 5458 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5459 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5460 | .unused, |
| 5461 | .unused, |
| 5462 | .unused, |
| 5463 | .unused, |
| 5464 | }, |
| 5465 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5466 | .clobbers = .{ .eflags = true }, |
| 5467 | .each = .{ .once = &.{ |
| 5468 | .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ }, |
| 5469 | .{ ._, ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 5470 | .{ .@"0:", ._, .@"and", .tmp1q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5471 | .{ ._, ._, .lzcnt, .dst0q, .tmp1q, ._, ._ }, |
| 5472 | .{ ._, ._nc, .j, .@"0f", ._, ._, ._ }, |
| 5473 | .{ ._, ._, .mov, .tmp1q, .si(-1), ._, ._ }, |
| 5474 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5475 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5476 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5477 | .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ }, |
| 5478 | .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ }, |
| 5479 | } }, |
| 5480 | }, .{ |
| 5481 | .required_features = .{ .@"64bit", null, null, null }, |
| 5482 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 5483 | .patterns = &.{ |
| 5484 | .{ .src = .{ .to_mem, .none } }, |
| 5485 | }, |
| 5486 | .extra_temps = .{ |
| 5487 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5488 | .unused, |
| 5489 | .unused, |
| 5490 | .unused, |
| 5491 | .unused, |
| 5492 | .unused, |
| 5493 | }, |
| 5494 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5495 | .clobbers = .{ .eflags = true }, |
| 5496 | .each = .{ .once = &.{ |
| 5497 | .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ }, |
| 5498 | .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ }, |
| 5499 | .{ .@"0:", ._, .@"and", .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5500 | .{ ._, ._r, .bs, .dst0q, .dst0q, ._, ._ }, |
| 5501 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 5502 | .{ ._, ._, .mov, .dst0q, .si(-1), ._, ._ }, |
| 5503 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5504 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5505 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5506 | .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ }, |
| 5507 | .{ ._, ._, .neg, .dst0d, ._, ._, ._ }, |
| 5508 | } }, |
| 5509 | }, .{ |
| 5510 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 5511 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 5512 | .patterns = &.{ |
| 5513 | .{ .src = .{ .to_mem, .none } }, |
| 5514 | }, |
| 5515 | .extra_temps = .{ |
| 5516 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5517 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5518 | .unused, |
| 5519 | .unused, |
| 5520 | .unused, |
| 5521 | .unused, |
| 5522 | }, |
| 5523 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5524 | .clobbers = .{ .eflags = true }, |
| 5525 | .each = .{ .once = &.{ |
| 5526 | .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ }, |
| 5527 | .{ ._, ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 5528 | .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 5529 | .{ ._, ._, .@"and", .tmp1q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5530 | .{ ._, ._, .lzcnt, .dst0q, .tmp1q, ._, ._ }, |
| 5531 | .{ ._, ._nc, .j, .@"0f", ._, ._, ._ }, |
| 5532 | .{ ._, ._, .mov, .tmp1q, .si(-1), ._, ._ }, |
| 5533 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5534 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5535 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5536 | .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ }, |
| 5537 | .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ }, |
| 5538 | } }, |
| 5539 | }, .{ |
| 5540 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 5541 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 5542 | .patterns = &.{ |
| 5543 | .{ .src = .{ .to_mem, .none } }, |
| 5544 | }, |
| 5545 | .extra_temps = .{ |
| 5546 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5547 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5548 | .unused, |
| 5549 | .unused, |
| 5550 | .unused, |
| 5551 | .unused, |
| 5552 | }, |
| 5553 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5554 | .clobbers = .{ .eflags = true }, |
| 5555 | .each = .{ .once = &.{ |
| 5556 | .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ }, |
| 5557 | .{ ._, ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 5558 | .{ .@"0:", ._, .@"and", .tmp1q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5559 | .{ ._, ._, .lzcnt, .dst0q, .tmp1q, ._, ._ }, |
| 5560 | .{ ._, ._nc, .j, .@"0f", ._, ._, ._ }, |
| 5561 | .{ ._, ._, .mov, .tmp1q, .si(-1), ._, ._ }, |
| 5562 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5563 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5564 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5565 | .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ }, |
| 5566 | .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ }, |
| 5567 | } }, |
| 5568 | }, .{ |
| 5569 | .required_features = .{ .@"64bit", null, null, null }, |
| 5570 | .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 5571 | .patterns = &.{ |
| 5572 | .{ .src = .{ .to_mem, .none } }, |
| 5573 | }, |
| 5574 | .extra_temps = .{ |
| 5575 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5576 | .unused, |
| 5577 | .unused, |
| 5578 | .unused, |
| 5579 | .unused, |
| 5580 | .unused, |
| 5581 | }, |
| 5582 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 5583 | .clobbers = .{ .eflags = true }, |
| 5584 | .each = .{ .once = &.{ |
| 5585 | .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ }, |
| 5586 | .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ }, |
| 5587 | .{ .@"0:", ._, .@"and", .dst0q, .memi(.src0q, .tmp0), ._, ._ }, |
| 5588 | .{ ._, ._r, .bs, .dst0q, .dst0q, ._, ._ }, |
| 5589 | .{ ._, ._nz, .j, .@"0f", ._, ._, ._ }, |
| 5590 | .{ ._, ._, .mov, .dst0q, .si(-1), ._, ._ }, |
| 5591 | .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ }, |
| 5592 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5593 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 5594 | .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ }, |
| 5595 | .{ ._, ._, .neg, .dst0d, ._, ._, ._ }, |
| 5596 | } }, |
| 5597 | }, .{ |
| 5598 | .required_features = .{ .lzcnt, .slow_incdec, null, null }, |
| 5599 | .src_constraints = .{ .{ .scalar_int = .byte }, .any }, |
| 5600 | .patterns = &.{ |
| 5601 | .{ .src = .{ .to_mem, .none } }, |
| 5602 | }, |
| 5603 | .extra_temps = .{ |
| 5604 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5605 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5606 | .unused, |
| 5607 | .unused, |
| 5608 | .unused, |
| 5609 | .unused, |
| 5610 | }, |
| 5611 | .dst_temps = .{.mem}, |
| 5612 | .clobbers = .{ .eflags = true }, |
| 5613 | .each = .{ .once = &.{ |
| 5614 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5615 | .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ }, |
| 5616 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5617 | .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ }, |
| 5618 | .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 5619 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5620 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 5621 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5622 | } }, |
| 5623 | }, .{ |
| 5624 | .required_features = .{ .lzcnt, null, null, null }, |
| 5625 | .src_constraints = .{ .{ .scalar_int = .byte }, .any }, |
| 5626 | .patterns = &.{ |
| 5627 | .{ .src = .{ .to_mem, .none } }, |
| 5628 | }, |
| 5629 | .extra_temps = .{ |
| 5630 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5631 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5632 | .unused, |
| 5633 | .unused, |
| 5634 | .unused, |
| 5635 | .unused, |
| 5636 | }, |
| 5637 | .dst_temps = .{.mem}, |
| 5638 | .clobbers = .{ .eflags = true }, |
| 5639 | .each = .{ .once = &.{ |
| 5640 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5641 | .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ }, |
| 5642 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5643 | .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ }, |
| 5644 | .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 5645 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5646 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 5647 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 5648 | } }, |
| 5649 | }, .{ |
| 5650 | .required_features = .{ .lzcnt, .slow_incdec, null, null }, |
| 5651 | .src_constraints = .{ .{ .scalar_int = .word }, .any }, |
| 5652 | .patterns = &.{ |
| 5653 | .{ .src = .{ .to_mem, .none } }, |
| 5654 | }, |
| 5655 | .extra_temps = .{ |
| 5656 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5657 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5658 | .unused, |
| 5659 | .unused, |
| 5660 | .unused, |
| 5661 | .unused, |
| 5662 | }, |
| 5663 | .dst_temps = .{.mem}, |
| 5664 | .clobbers = .{ .eflags = true }, |
| 5665 | .each = .{ .once = &.{ |
| 5666 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5667 | .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ }, |
| 5668 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5669 | .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ }, |
| 5670 | .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 5671 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5672 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 5673 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5674 | } }, |
| 5675 | }, .{ |
| 5676 | .required_features = .{ .lzcnt, null, null, null }, |
| 5677 | .src_constraints = .{ .{ .scalar_int = .word }, .any }, |
| 5678 | .patterns = &.{ |
| 5679 | .{ .src = .{ .to_mem, .none } }, |
| 5680 | }, |
| 5681 | .extra_temps = .{ |
| 5682 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5683 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5684 | .unused, |
| 5685 | .unused, |
| 5686 | .unused, |
| 5687 | .unused, |
| 5688 | }, |
| 5689 | .dst_temps = .{.mem}, |
| 5690 | .clobbers = .{ .eflags = true }, |
| 5691 | .each = .{ .once = &.{ |
| 5692 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5693 | .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ }, |
| 5694 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5695 | .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ }, |
| 5696 | .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 5697 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5698 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 5699 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 5700 | } }, |
| 5701 | }, .{ |
| 5702 | .required_features = .{ .lzcnt, .slow_incdec, null, null }, |
| 5703 | .src_constraints = .{ .{ .scalar_int = .dword }, .any }, |
| 5704 | .patterns = &.{ |
| 5705 | .{ .src = .{ .to_mem, .none } }, |
| 5706 | }, |
| 5707 | .extra_temps = .{ |
| 5708 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5709 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5710 | .unused, |
| 5711 | .unused, |
| 5712 | .unused, |
| 5713 | .unused, |
| 5714 | }, |
| 5715 | .dst_temps = .{.mem}, |
| 5716 | .clobbers = .{ .eflags = true }, |
| 5717 | .each = .{ .once = &.{ |
| 5718 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5719 | .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ }, |
| 5720 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5721 | .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ }, |
| 5722 | .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 5723 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5724 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 5725 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5726 | } }, |
| 5727 | }, .{ |
| 5728 | .required_features = .{ .lzcnt, null, null, null }, |
| 5729 | .src_constraints = .{ .{ .scalar_int = .dword }, .any }, |
| 5730 | .patterns = &.{ |
| 5731 | .{ .src = .{ .to_mem, .none } }, |
| 5732 | }, |
| 5733 | .extra_temps = .{ |
| 5734 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5735 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5736 | .unused, |
| 5737 | .unused, |
| 5738 | .unused, |
| 5739 | .unused, |
| 5740 | }, |
| 5741 | .dst_temps = .{.mem}, |
| 5742 | .clobbers = .{ .eflags = true }, |
| 5743 | .each = .{ .once = &.{ |
| 5744 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5745 | .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ }, |
| 5746 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5747 | .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ }, |
| 5748 | .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ }, |
| 5749 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5750 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 5751 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 5752 | } }, |
| 5753 | }, .{ |
| 5754 | .required_features = .{ .@"64bit", .lzcnt, .slow_incdec, null }, |
| 5755 | .src_constraints = .{ .{ .scalar_int = .qword }, .any }, |
| 5756 | .patterns = &.{ |
| 5757 | .{ .src = .{ .to_mem, .none } }, |
| 5758 | }, |
| 5759 | .extra_temps = .{ |
| 5760 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5761 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5762 | .unused, |
| 5763 | .unused, |
| 5764 | .unused, |
| 5765 | .unused, |
| 5766 | }, |
| 5767 | .dst_temps = .{.mem}, |
| 5768 | .clobbers = .{ .eflags = true }, |
| 5769 | .each = .{ .once = &.{ |
| 5770 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5771 | .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 5772 | .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ }, |
| 5773 | .{ ._, ._, .lzcnt, .tmp1q, .tmp1q, ._, ._ }, |
| 5774 | .{ ._, ._, .sub, .tmp1b, .sia(64, .src0, .sub_bit_size), ._, ._ }, |
| 5775 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5776 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 5777 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5778 | } }, |
| 5779 | }, .{ |
| 5780 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 5781 | .src_constraints = .{ .{ .scalar_int = .qword }, .any }, |
| 5782 | .patterns = &.{ |
| 5783 | .{ .src = .{ .to_mem, .none } }, |
| 5784 | }, |
| 5785 | .extra_temps = .{ |
| 5786 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5787 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 5788 | .unused, |
| 5789 | .unused, |
| 5790 | .unused, |
| 5791 | .unused, |
| 5792 | }, |
| 5793 | .dst_temps = .{.mem}, |
| 5794 | .clobbers = .{ .eflags = true }, |
| 5795 | .each = .{ .once = &.{ |
| 5796 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5797 | .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 5798 | .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ }, |
| 5799 | .{ ._, ._, .lzcnt, .tmp1q, .tmp1q, ._, ._ }, |
| 5800 | .{ ._, ._, .sub, .tmp1b, .sia(64, .src0, .sub_bit_size), ._, ._ }, |
| 5801 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5802 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 5803 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 5804 | } }, |
| 5805 | }, .{ |
| 5806 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, .slow_incdec, null }, |
| 5807 | .src_constraints = .{ .{ .scalar_int = .byte }, .any }, |
| 5808 | .patterns = &.{ |
| 5809 | .{ .src = .{ .to_mem, .none } }, |
| 5810 | }, |
| 5811 | .extra_temps = .{ |
| 5812 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5813 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5814 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5815 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 5816 | .unused, |
| 5817 | .unused, |
| 5818 | }, |
| 5819 | .dst_temps = .{.mem}, |
| 5820 | .clobbers = .{ .eflags = true }, |
| 5821 | .each = .{ .once = &.{ |
| 5822 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5823 | .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ }, |
| 5824 | .{ .@"0:", ._, .movzx, .tmp2d, .memia(.src0b, .tmp0, .add_len), ._, ._ }, |
| 5825 | .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ }, |
| 5826 | .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ }, |
| 5827 | .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ }, |
| 5828 | .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5829 | .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ }, |
| 5830 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 5831 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 5832 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5833 | } }, |
| 5834 | }, .{ |
| 5835 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 5836 | .src_constraints = .{ .{ .scalar_int = .byte }, .any }, |
| 5837 | .patterns = &.{ |
| 5838 | .{ .src = .{ .to_mem, .none } }, |
| 5839 | }, |
| 5840 | .extra_temps = .{ |
| 5841 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5842 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5843 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5844 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 5845 | .unused, |
| 5846 | .unused, |
| 5847 | }, |
| 5848 | .dst_temps = .{.mem}, |
| 5849 | .clobbers = .{ .eflags = true }, |
| 5850 | .each = .{ .once = &.{ |
| 5851 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5852 | .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ }, |
| 5853 | .{ .@"0:", ._, .movzx, .tmp2d, .memia(.src0b, .tmp0, .add_len), ._, ._ }, |
| 5854 | .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ }, |
| 5855 | .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ }, |
| 5856 | .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ }, |
| 5857 | .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5858 | .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ }, |
| 5859 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 5860 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 5861 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 5862 | } }, |
| 5863 | }, .{ |
| 5864 | .required_features = .{ .bsf_bsr_0_clobbers_result, .slow_incdec, null, null }, |
| 5865 | .src_constraints = .{ .{ .scalar_int = .byte }, .any }, |
| 5866 | .patterns = &.{ |
| 5867 | .{ .src = .{ .to_mem, .none } }, |
| 5868 | }, |
| 5869 | .extra_temps = .{ |
| 5870 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5871 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5872 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5873 | .unused, |
| 5874 | .unused, |
| 5875 | .unused, |
| 5876 | }, |
| 5877 | .dst_temps = .{.mem}, |
| 5878 | .clobbers = .{ .eflags = true }, |
| 5879 | .each = .{ .once = &.{ |
| 5880 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5881 | .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ }, |
| 5882 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5883 | .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ }, |
| 5884 | .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 5885 | .{ ._, ._z, .j, .@"1f", ._, ._, ._ }, |
| 5886 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 5887 | .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ }, |
| 5888 | .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ }, |
| 5889 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 5890 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5891 | } }, |
| 5892 | }, .{ |
| 5893 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 5894 | .src_constraints = .{ .{ .scalar_int = .byte }, .any }, |
| 5895 | .patterns = &.{ |
| 5896 | .{ .src = .{ .to_mem, .none } }, |
| 5897 | }, |
| 5898 | .extra_temps = .{ |
| 5899 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5900 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5901 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5902 | .unused, |
| 5903 | .unused, |
| 5904 | .unused, |
| 5905 | }, |
| 5906 | .dst_temps = .{.mem}, |
| 5907 | .clobbers = .{ .eflags = true }, |
| 5908 | .each = .{ .once = &.{ |
| 5909 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5910 | .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ }, |
| 5911 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5912 | .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ }, |
| 5913 | .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 5914 | .{ ._, ._z, .j, .@"1f", ._, ._, ._ }, |
| 5915 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 5916 | .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ }, |
| 5917 | .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ }, |
| 5918 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 5919 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 5920 | } }, |
| 5921 | }, .{ |
| 5922 | .required_features = .{ .slow_incdec, null, null, null }, |
| 5923 | .src_constraints = .{ .{ .scalar_int = .byte }, .any }, |
| 5924 | .patterns = &.{ |
| 5925 | .{ .src = .{ .to_mem, .none } }, |
| 5926 | }, |
| 5927 | .extra_temps = .{ |
| 5928 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5929 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5930 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5931 | .unused, |
| 5932 | .unused, |
| 5933 | .unused, |
| 5934 | }, |
| 5935 | .dst_temps = .{.mem}, |
| 5936 | .clobbers = .{ .eflags = true }, |
| 5937 | .each = .{ .once = &.{ |
| 5938 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5939 | .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ }, |
| 5940 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5941 | .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ }, |
| 5942 | .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ }, |
| 5943 | .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5944 | .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ }, |
| 5945 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5946 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 5947 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 5948 | } }, |
| 5949 | }, .{ |
| 5950 | .src_constraints = .{ .{ .scalar_int = .byte }, .any }, |
| 5951 | .patterns = &.{ |
| 5952 | .{ .src = .{ .to_mem, .none } }, |
| 5953 | }, |
| 5954 | .extra_temps = .{ |
| 5955 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5956 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5957 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5958 | .unused, |
| 5959 | .unused, |
| 5960 | .unused, |
| 5961 | }, |
| 5962 | .dst_temps = .{.mem}, |
| 5963 | .clobbers = .{ .eflags = true }, |
| 5964 | .each = .{ .once = &.{ |
| 5965 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5966 | .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ }, |
| 5967 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 5968 | .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ }, |
| 5969 | .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ }, |
| 5970 | .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 5971 | .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ }, |
| 5972 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 5973 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 5974 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 5975 | } }, |
| 5976 | }, .{ |
| 5977 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, .slow_incdec, null }, |
| 5978 | .src_constraints = .{ .{ .scalar_int = .word }, .any }, |
| 5979 | .patterns = &.{ |
| 5980 | .{ .src = .{ .to_mem, .none } }, |
| 5981 | }, |
| 5982 | .extra_temps = .{ |
| 5983 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 5984 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5985 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 5986 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 5987 | .unused, |
| 5988 | .unused, |
| 5989 | }, |
| 5990 | .dst_temps = .{.mem}, |
| 5991 | .clobbers = .{ .eflags = true }, |
| 5992 | .each = .{ .once = &.{ |
| 5993 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 5994 | .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ }, |
| 5995 | .{ .@"0:", ._, .movzx, .tmp2d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ }, |
| 5996 | .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ }, |
| 5997 | .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ }, |
| 5998 | .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ }, |
| 5999 | .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6000 | .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ }, |
| 6001 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6002 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6003 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6004 | } }, |
| 6005 | }, .{ |
| 6006 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 6007 | .src_constraints = .{ .{ .scalar_int = .word }, .any }, |
| 6008 | .patterns = &.{ |
| 6009 | .{ .src = .{ .to_mem, .none } }, |
| 6010 | }, |
| 6011 | .extra_temps = .{ |
| 6012 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6013 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6014 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6015 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 6016 | .unused, |
| 6017 | .unused, |
| 6018 | }, |
| 6019 | .dst_temps = .{.mem}, |
| 6020 | .clobbers = .{ .eflags = true }, |
| 6021 | .each = .{ .once = &.{ |
| 6022 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6023 | .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ }, |
| 6024 | .{ .@"0:", ._, .movzx, .tmp2d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ }, |
| 6025 | .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ }, |
| 6026 | .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ }, |
| 6027 | .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ }, |
| 6028 | .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6029 | .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ }, |
| 6030 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6031 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6032 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6033 | } }, |
| 6034 | }, .{ |
| 6035 | .required_features = .{ .bsf_bsr_0_clobbers_result, .slow_incdec, null, null }, |
| 6036 | .src_constraints = .{ .{ .scalar_int = .word }, .any }, |
| 6037 | .patterns = &.{ |
| 6038 | .{ .src = .{ .to_mem, .none } }, |
| 6039 | }, |
| 6040 | .extra_temps = .{ |
| 6041 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6042 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6043 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6044 | .unused, |
| 6045 | .unused, |
| 6046 | .unused, |
| 6047 | }, |
| 6048 | .dst_temps = .{.mem}, |
| 6049 | .clobbers = .{ .eflags = true }, |
| 6050 | .each = .{ .once = &.{ |
| 6051 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6052 | .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ }, |
| 6053 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 6054 | .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ }, |
| 6055 | .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 6056 | .{ ._, ._z, .j, .@"1f", ._, ._, ._ }, |
| 6057 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 6058 | .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ }, |
| 6059 | .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ }, |
| 6060 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6061 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6062 | } }, |
| 6063 | }, .{ |
| 6064 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 6065 | .src_constraints = .{ .{ .scalar_int = .word }, .any }, |
| 6066 | .patterns = &.{ |
| 6067 | .{ .src = .{ .to_mem, .none } }, |
| 6068 | }, |
| 6069 | .extra_temps = .{ |
| 6070 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6071 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6072 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6073 | .unused, |
| 6074 | .unused, |
| 6075 | .unused, |
| 6076 | }, |
| 6077 | .dst_temps = .{.mem}, |
| 6078 | .clobbers = .{ .eflags = true }, |
| 6079 | .each = .{ .once = &.{ |
| 6080 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6081 | .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ }, |
| 6082 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 6083 | .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ }, |
| 6084 | .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 6085 | .{ ._, ._z, .j, .@"1f", ._, ._, ._ }, |
| 6086 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 6087 | .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ }, |
| 6088 | .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ }, |
| 6089 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6090 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6091 | } }, |
| 6092 | }, .{ |
| 6093 | .required_features = .{ .slow_incdec, null, null, null }, |
| 6094 | .src_constraints = .{ .{ .scalar_int = .word }, .any }, |
| 6095 | .patterns = &.{ |
| 6096 | .{ .src = .{ .to_mem, .none } }, |
| 6097 | }, |
| 6098 | .extra_temps = .{ |
| 6099 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6100 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6101 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6102 | .unused, |
| 6103 | .unused, |
| 6104 | .unused, |
| 6105 | }, |
| 6106 | .dst_temps = .{.mem}, |
| 6107 | .clobbers = .{ .eflags = true }, |
| 6108 | .each = .{ .once = &.{ |
| 6109 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6110 | .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ }, |
| 6111 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 6112 | .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ }, |
| 6113 | .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ }, |
| 6114 | .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6115 | .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ }, |
| 6116 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 6117 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6118 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6119 | } }, |
| 6120 | }, .{ |
| 6121 | .src_constraints = .{ .{ .scalar_int = .word }, .any }, |
| 6122 | .patterns = &.{ |
| 6123 | .{ .src = .{ .to_mem, .none } }, |
| 6124 | }, |
| 6125 | .extra_temps = .{ |
| 6126 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6127 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6128 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6129 | .unused, |
| 6130 | .unused, |
| 6131 | .unused, |
| 6132 | }, |
| 6133 | .dst_temps = .{.mem}, |
| 6134 | .clobbers = .{ .eflags = true }, |
| 6135 | .each = .{ .once = &.{ |
| 6136 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6137 | .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ }, |
| 6138 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 6139 | .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ }, |
| 6140 | .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ }, |
| 6141 | .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6142 | .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ }, |
| 6143 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 6144 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6145 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6146 | } }, |
| 6147 | }, .{ |
| 6148 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, .slow_incdec, null }, |
| 6149 | .src_constraints = .{ .{ .scalar_int = .dword }, .any }, |
| 6150 | .patterns = &.{ |
| 6151 | .{ .src = .{ .to_mem, .none } }, |
| 6152 | }, |
| 6153 | .extra_temps = .{ |
| 6154 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6155 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6156 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6157 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 6158 | .unused, |
| 6159 | .unused, |
| 6160 | }, |
| 6161 | .dst_temps = .{.mem}, |
| 6162 | .clobbers = .{ .eflags = true }, |
| 6163 | .each = .{ .once = &.{ |
| 6164 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6165 | .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ }, |
| 6166 | .{ .@"0:", ._, .mov, .tmp2d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ }, |
| 6167 | .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ }, |
| 6168 | .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ }, |
| 6169 | .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ }, |
| 6170 | .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6171 | .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ }, |
| 6172 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6173 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6174 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6175 | } }, |
| 6176 | }, .{ |
| 6177 | .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null }, |
| 6178 | .src_constraints = .{ .{ .scalar_int = .dword }, .any }, |
| 6179 | .patterns = &.{ |
| 6180 | .{ .src = .{ .to_mem, .none } }, |
| 6181 | }, |
| 6182 | .extra_temps = .{ |
| 6183 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6184 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6185 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6186 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 6187 | .unused, |
| 6188 | .unused, |
| 6189 | }, |
| 6190 | .dst_temps = .{.mem}, |
| 6191 | .clobbers = .{ .eflags = true }, |
| 6192 | .each = .{ .once = &.{ |
| 6193 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6194 | .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ }, |
| 6195 | .{ .@"0:", ._, .mov, .tmp2d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ }, |
| 6196 | .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ }, |
| 6197 | .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ }, |
| 6198 | .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ }, |
| 6199 | .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6200 | .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ }, |
| 6201 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6202 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6203 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6204 | } }, |
| 6205 | }, .{ |
| 6206 | .required_features = .{ .bsf_bsr_0_clobbers_result, .slow_incdec, null, null }, |
| 6207 | .src_constraints = .{ .{ .scalar_int = .dword }, .any }, |
| 6208 | .patterns = &.{ |
| 6209 | .{ .src = .{ .to_mem, .none } }, |
| 6210 | }, |
| 6211 | .extra_temps = .{ |
| 6212 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6213 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6214 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6215 | .unused, |
| 6216 | .unused, |
| 6217 | .unused, |
| 6218 | }, |
| 6219 | .dst_temps = .{.mem}, |
| 6220 | .clobbers = .{ .eflags = true }, |
| 6221 | .each = .{ .once = &.{ |
| 6222 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6223 | .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ }, |
| 6224 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 6225 | .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ }, |
| 6226 | .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 6227 | .{ ._, ._z, .j, .@"1f", ._, ._, ._ }, |
| 6228 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 6229 | .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ }, |
| 6230 | .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ }, |
| 6231 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6232 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6233 | } }, |
| 6234 | }, .{ |
| 6235 | .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null }, |
| 6236 | .src_constraints = .{ .{ .scalar_int = .dword }, .any }, |
| 6237 | .patterns = &.{ |
| 6238 | .{ .src = .{ .to_mem, .none } }, |
| 6239 | }, |
| 6240 | .extra_temps = .{ |
| 6241 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6242 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6243 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6244 | .unused, |
| 6245 | .unused, |
| 6246 | .unused, |
| 6247 | }, |
| 6248 | .dst_temps = .{.mem}, |
| 6249 | .clobbers = .{ .eflags = true }, |
| 6250 | .each = .{ .once = &.{ |
| 6251 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6252 | .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ }, |
| 6253 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 6254 | .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ }, |
| 6255 | .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 6256 | .{ ._, ._z, .j, .@"1f", ._, ._, ._ }, |
| 6257 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 6258 | .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ }, |
| 6259 | .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ }, |
| 6260 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6261 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6262 | } }, |
| 6263 | }, .{ |
| 6264 | .required_features = .{ .slow_incdec, null, null, null }, |
| 6265 | .src_constraints = .{ .{ .scalar_int = .dword }, .any }, |
| 6266 | .patterns = &.{ |
| 6267 | .{ .src = .{ .to_mem, .none } }, |
| 6268 | }, |
| 6269 | .extra_temps = .{ |
| 6270 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6271 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6272 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6273 | .unused, |
| 6274 | .unused, |
| 6275 | .unused, |
| 6276 | }, |
| 6277 | .dst_temps = .{.mem}, |
| 6278 | .clobbers = .{ .eflags = true }, |
| 6279 | .each = .{ .once = &.{ |
| 6280 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6281 | .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ }, |
| 6282 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 6283 | .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ }, |
| 6284 | .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ }, |
| 6285 | .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6286 | .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ }, |
| 6287 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 6288 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6289 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6290 | } }, |
| 6291 | }, .{ |
| 6292 | .src_constraints = .{ .{ .scalar_int = .dword }, .any }, |
| 6293 | .patterns = &.{ |
| 6294 | .{ .src = .{ .to_mem, .none } }, |
| 6295 | }, |
| 6296 | .extra_temps = .{ |
| 6297 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6298 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6299 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6300 | .unused, |
| 6301 | .unused, |
| 6302 | .unused, |
| 6303 | }, |
| 6304 | .dst_temps = .{.mem}, |
| 6305 | .clobbers = .{ .eflags = true }, |
| 6306 | .each = .{ .once = &.{ |
| 6307 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6308 | .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ }, |
| 6309 | .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ }, |
| 6310 | .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ }, |
| 6311 | .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ }, |
| 6312 | .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6313 | .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ }, |
| 6314 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 6315 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6316 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6317 | } }, |
| 6318 | }, .{ |
| 6319 | .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, .slow_incdec }, |
| 6320 | .src_constraints = .{ .{ .scalar_int = .qword }, .any }, |
| 6321 | .patterns = &.{ |
| 6322 | .{ .src = .{ .to_mem, .none } }, |
| 6323 | }, |
| 6324 | .extra_temps = .{ |
| 6325 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6326 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6327 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6328 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 6329 | .unused, |
| 6330 | .unused, |
| 6331 | }, |
| 6332 | .dst_temps = .{.mem}, |
| 6333 | .clobbers = .{ .eflags = true }, |
| 6334 | .each = .{ .once = &.{ |
| 6335 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6336 | .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ }, |
| 6337 | .{ .@"0:", ._, .mov, .tmp2q, .ua(.src0, .add_umax), ._, ._ }, |
| 6338 | .{ ._, ._, .@"and", .tmp2q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ }, |
| 6339 | .{ ._, ._r, .bs, .tmp2q, .tmp2q, ._, ._ }, |
| 6340 | .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ }, |
| 6341 | .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6342 | .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ }, |
| 6343 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6344 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6345 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6346 | } }, |
| 6347 | }, .{ |
| 6348 | .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, null }, |
| 6349 | .src_constraints = .{ .{ .scalar_int = .qword }, .any }, |
| 6350 | .patterns = &.{ |
| 6351 | .{ .src = .{ .to_mem, .none } }, |
| 6352 | }, |
| 6353 | .extra_temps = .{ |
| 6354 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6355 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6356 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6357 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 6358 | .unused, |
| 6359 | .unused, |
| 6360 | }, |
| 6361 | .dst_temps = .{.mem}, |
| 6362 | .clobbers = .{ .eflags = true }, |
| 6363 | .each = .{ .once = &.{ |
| 6364 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6365 | .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ }, |
| 6366 | .{ .@"0:", ._, .mov, .tmp2q, .ua(.src0, .add_umax), ._, ._ }, |
| 6367 | .{ ._, ._, .@"and", .tmp2q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ }, |
| 6368 | .{ ._, ._r, .bs, .tmp2q, .tmp2q, ._, ._ }, |
| 6369 | .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ }, |
| 6370 | .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6371 | .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ }, |
| 6372 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6373 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6374 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6375 | } }, |
| 6376 | }, .{ |
| 6377 | .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, .slow_incdec, null }, |
| 6378 | .src_constraints = .{ .{ .scalar_int = .qword }, .any }, |
| 6379 | .patterns = &.{ |
| 6380 | .{ .src = .{ .to_mem, .none } }, |
| 6381 | }, |
| 6382 | .extra_temps = .{ |
| 6383 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6384 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6385 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6386 | .unused, |
| 6387 | .unused, |
| 6388 | .unused, |
| 6389 | }, |
| 6390 | .dst_temps = .{.mem}, |
| 6391 | .clobbers = .{ .eflags = true }, |
| 6392 | .each = .{ .once = &.{ |
| 6393 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6394 | .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 6395 | .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ }, |
| 6396 | .{ ._, ._r, .bs, .tmp1q, .tmp1q, ._, ._ }, |
| 6397 | .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 6398 | .{ ._, ._z, .j, .@"1f", ._, ._, ._ }, |
| 6399 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 6400 | .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ }, |
| 6401 | .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ }, |
| 6402 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6403 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6404 | } }, |
| 6405 | }, .{ |
| 6406 | .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null }, |
| 6407 | .src_constraints = .{ .{ .scalar_int = .qword }, .any }, |
| 6408 | .patterns = &.{ |
| 6409 | .{ .src = .{ .to_mem, .none } }, |
| 6410 | }, |
| 6411 | .extra_temps = .{ |
| 6412 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6413 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6414 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6415 | .unused, |
| 6416 | .unused, |
| 6417 | .unused, |
| 6418 | }, |
| 6419 | .dst_temps = .{.mem}, |
| 6420 | .clobbers = .{ .eflags = true }, |
| 6421 | .each = .{ .once = &.{ |
| 6422 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6423 | .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 6424 | .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ }, |
| 6425 | .{ ._, ._r, .bs, .tmp1q, .tmp1q, ._, ._ }, |
| 6426 | .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ }, |
| 6427 | .{ ._, ._z, .j, .@"1f", ._, ._, ._ }, |
| 6428 | .{ ._, ._c, .st, ._, ._, ._, ._ }, |
| 6429 | .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ }, |
| 6430 | .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ }, |
| 6431 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6432 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6433 | } }, |
| 6434 | }, .{ |
| 6435 | .required_features = .{ .@"64bit", .slow_incdec, null, null }, |
| 6436 | .src_constraints = .{ .{ .scalar_int = .qword }, .any }, |
| 6437 | .patterns = &.{ |
| 6438 | .{ .src = .{ .to_mem, .none } }, |
| 6439 | }, |
| 6440 | .extra_temps = .{ |
| 6441 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6442 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6443 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6444 | .unused, |
| 6445 | .unused, |
| 6446 | .unused, |
| 6447 | }, |
| 6448 | .dst_temps = .{.mem}, |
| 6449 | .clobbers = .{ .eflags = true }, |
| 6450 | .each = .{ .once = &.{ |
| 6451 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6452 | .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 6453 | .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ }, |
| 6454 | .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ }, |
| 6455 | .{ ._, ._r, .bs, .tmp2q, .tmp1q, ._, ._ }, |
| 6456 | .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6457 | .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ }, |
| 6458 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 6459 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6460 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6461 | } }, |
| 6462 | }, .{ |
| 6463 | .required_features = .{ .@"64bit", null, null, null }, |
| 6464 | .src_constraints = .{ .{ .scalar_int = .qword }, .any }, |
| 6465 | .patterns = &.{ |
| 6466 | .{ .src = .{ .to_mem, .none } }, |
| 6467 | }, |
| 6468 | .extra_temps = .{ |
| 6469 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6470 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6471 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6472 | .unused, |
| 6473 | .unused, |
| 6474 | .unused, |
| 6475 | }, |
| 6476 | .dst_temps = .{.mem}, |
| 6477 | .clobbers = .{ .eflags = true }, |
| 6478 | .each = .{ .once = &.{ |
| 6479 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6480 | .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ }, |
| 6481 | .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ }, |
| 6482 | .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ }, |
| 6483 | .{ ._, ._r, .bs, .tmp2q, .tmp1q, ._, ._ }, |
| 6484 | .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ }, |
| 6485 | .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ }, |
| 6486 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ }, |
| 6487 | .{ ._, ._, .inc, .tmp0p, ._, ._, ._ }, |
| 6488 | .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, |
| 6489 | } }, |
| 6490 | }, .{ |
| 6491 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 6492 | .dst_constraints = .{.{ .scalar_int = .byte }}, |
| 6493 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 6494 | .patterns = &.{ |
| 6495 | .{ .src = .{ .to_mem, .none } }, |
| 6496 | }, |
| 6497 | .extra_temps = .{ |
| 6498 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6499 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6500 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6501 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6502 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6503 | .unused, |
| 6504 | }, |
| 6505 | .dst_temps = .{.mem}, |
| 6506 | .clobbers = .{ .eflags = true }, |
| 6507 | .each = .{ .once = &.{ |
| 6508 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6509 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6510 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ }, |
| 6511 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6512 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6513 | .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ }, |
| 6514 | .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ }, |
| 6515 | .{ ._, ._nc, .j, .@"1f", ._, ._, ._ }, |
| 6516 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6517 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6518 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6519 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6520 | .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ }, |
| 6521 | .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ }, |
| 6522 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6523 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6524 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6525 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6526 | } }, |
| 6527 | }, .{ |
| 6528 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 6529 | .dst_constraints = .{.{ .scalar_int = .byte }}, |
| 6530 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 6531 | .patterns = &.{ |
| 6532 | .{ .src = .{ .to_mem, .none } }, |
| 6533 | }, |
| 6534 | .extra_temps = .{ |
| 6535 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6536 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6537 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6538 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6539 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6540 | .unused, |
| 6541 | }, |
| 6542 | .dst_temps = .{.mem}, |
| 6543 | .clobbers = .{ .eflags = true }, |
| 6544 | .each = .{ .once = &.{ |
| 6545 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6546 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6547 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ }, |
| 6548 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6549 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6550 | .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ }, |
| 6551 | .{ ._, ._nc, .j, .@"1f", ._, ._, ._ }, |
| 6552 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6553 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6554 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6555 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6556 | .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ }, |
| 6557 | .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ }, |
| 6558 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6559 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6560 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6561 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6562 | } }, |
| 6563 | }, .{ |
| 6564 | .required_features = .{ .@"64bit", null, null, null }, |
| 6565 | .dst_constraints = .{.{ .scalar_int = .byte }}, |
| 6566 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 6567 | .patterns = &.{ |
| 6568 | .{ .src = .{ .to_mem, .none } }, |
| 6569 | }, |
| 6570 | .extra_temps = .{ |
| 6571 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6572 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6573 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6574 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6575 | .unused, |
| 6576 | .unused, |
| 6577 | }, |
| 6578 | .dst_temps = .{.mem}, |
| 6579 | .clobbers = .{ .eflags = true }, |
| 6580 | .each = .{ .once = &.{ |
| 6581 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6582 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6583 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ }, |
| 6584 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6585 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6586 | .{ ._, ._r, .bs, .tmp3q, .tmp3q, ._, ._ }, |
| 6587 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 6588 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6589 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6590 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6591 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6592 | .{ .@"1:", ._, .lea, .tmp3d, .leasiad(.none, .tmp3, .@"8", .tmp2, .sub_src0_bit_size, 1), ._, ._ }, |
| 6593 | .{ ._, ._, .neg, .tmp3b, ._, ._, ._ }, |
| 6594 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6595 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6596 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6597 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6598 | } }, |
| 6599 | }, .{ |
| 6600 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 6601 | .dst_constraints = .{.{ .scalar_int = .byte }}, |
| 6602 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 6603 | .patterns = &.{ |
| 6604 | .{ .src = .{ .to_mem, .none } }, |
| 6605 | }, |
| 6606 | .extra_temps = .{ |
| 6607 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6608 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6609 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6610 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6611 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6612 | .unused, |
| 6613 | }, |
| 6614 | .dst_temps = .{.mem}, |
| 6615 | .clobbers = .{ .eflags = true }, |
| 6616 | .each = .{ .once = &.{ |
| 6617 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6618 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6619 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ }, |
| 6620 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6621 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6622 | .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ }, |
| 6623 | .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ }, |
| 6624 | .{ ._, ._nc, .j, .@"1f", ._, ._, ._ }, |
| 6625 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6626 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6627 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6628 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6629 | .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ }, |
| 6630 | .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ }, |
| 6631 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6632 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6633 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6634 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6635 | } }, |
| 6636 | }, .{ |
| 6637 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 6638 | .dst_constraints = .{.{ .scalar_int = .byte }}, |
| 6639 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 6640 | .patterns = &.{ |
| 6641 | .{ .src = .{ .to_mem, .none } }, |
| 6642 | }, |
| 6643 | .extra_temps = .{ |
| 6644 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6645 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6646 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6647 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6648 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6649 | .unused, |
| 6650 | }, |
| 6651 | .dst_temps = .{.mem}, |
| 6652 | .clobbers = .{ .eflags = true }, |
| 6653 | .each = .{ .once = &.{ |
| 6654 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6655 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6656 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ }, |
| 6657 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6658 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6659 | .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ }, |
| 6660 | .{ ._, ._nc, .j, .@"1f", ._, ._, ._ }, |
| 6661 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6662 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6663 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6664 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6665 | .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ }, |
| 6666 | .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ }, |
| 6667 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6668 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6669 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6670 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6671 | } }, |
| 6672 | }, .{ |
| 6673 | .required_features = .{ .@"64bit", null, null, null }, |
| 6674 | .dst_constraints = .{.{ .scalar_int = .byte }}, |
| 6675 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 6676 | .patterns = &.{ |
| 6677 | .{ .src = .{ .to_mem, .none } }, |
| 6678 | }, |
| 6679 | .extra_temps = .{ |
| 6680 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6681 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6682 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6683 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6684 | .unused, |
| 6685 | .unused, |
| 6686 | }, |
| 6687 | .dst_temps = .{.mem}, |
| 6688 | .clobbers = .{ .eflags = true }, |
| 6689 | .each = .{ .once = &.{ |
| 6690 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6691 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6692 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ }, |
| 6693 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6694 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6695 | .{ ._, ._r, .bs, .tmp3q, .tmp3q, ._, ._ }, |
| 6696 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 6697 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6698 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6699 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6700 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6701 | .{ .@"1:", ._, .lea, .tmp3d, .leasiad(.none, .tmp3, .@"8", .tmp2, .sub_src0_bit_size, 1), ._, ._ }, |
| 6702 | .{ ._, ._, .neg, .tmp3b, ._, ._, ._ }, |
| 6703 | .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ }, |
| 6704 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6705 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6706 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6707 | } }, |
| 6708 | }, .{ |
| 6709 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 6710 | .dst_constraints = .{.{ .scalar_int = .word }}, |
| 6711 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 6712 | .patterns = &.{ |
| 6713 | .{ .src = .{ .to_mem, .none } }, |
| 6714 | }, |
| 6715 | .extra_temps = .{ |
| 6716 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6717 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6718 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6719 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6720 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6721 | .unused, |
| 6722 | }, |
| 6723 | .dst_temps = .{.mem}, |
| 6724 | .clobbers = .{ .eflags = true }, |
| 6725 | .each = .{ .once = &.{ |
| 6726 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6727 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6728 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ }, |
| 6729 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6730 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6731 | .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ }, |
| 6732 | .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ }, |
| 6733 | .{ ._, ._nc, .j, .@"1f", ._, ._, ._ }, |
| 6734 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6735 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6736 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6737 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6738 | .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ }, |
| 6739 | .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ }, |
| 6740 | .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ }, |
| 6741 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6742 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6743 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6744 | } }, |
| 6745 | }, .{ |
| 6746 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 6747 | .dst_constraints = .{.{ .scalar_int = .word }}, |
| 6748 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 6749 | .patterns = &.{ |
| 6750 | .{ .src = .{ .to_mem, .none } }, |
| 6751 | }, |
| 6752 | .extra_temps = .{ |
| 6753 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6754 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6755 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6756 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6757 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6758 | .unused, |
| 6759 | }, |
| 6760 | .dst_temps = .{.mem}, |
| 6761 | .clobbers = .{ .eflags = true }, |
| 6762 | .each = .{ .once = &.{ |
| 6763 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6764 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6765 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ }, |
| 6766 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6767 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6768 | .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ }, |
| 6769 | .{ ._, ._nc, .j, .@"1f", ._, ._, ._ }, |
| 6770 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6771 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6772 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6773 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6774 | .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ }, |
| 6775 | .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ }, |
| 6776 | .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ }, |
| 6777 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6778 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6779 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6780 | } }, |
| 6781 | }, .{ |
| 6782 | .required_features = .{ .@"64bit", null, null, null }, |
| 6783 | .dst_constraints = .{.{ .scalar_int = .word }}, |
| 6784 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any }, |
| 6785 | .patterns = &.{ |
| 6786 | .{ .src = .{ .to_mem, .none } }, |
| 6787 | }, |
| 6788 | .extra_temps = .{ |
| 6789 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6790 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6791 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6792 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6793 | .unused, |
| 6794 | .unused, |
| 6795 | }, |
| 6796 | .dst_temps = .{.mem}, |
| 6797 | .clobbers = .{ .eflags = true }, |
| 6798 | .each = .{ .once = &.{ |
| 6799 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6800 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6801 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ }, |
| 6802 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6803 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6804 | .{ ._, ._r, .bs, .tmp3q, .tmp3q, ._, ._ }, |
| 6805 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 6806 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6807 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6808 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6809 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6810 | .{ .@"1:", ._, .lea, .tmp3d, .leasiad(.none, .tmp3, .@"8", .tmp2, .sub_src0_bit_size, 1), ._, ._ }, |
| 6811 | .{ ._, ._, .neg, .tmp3d, ._, ._, ._ }, |
| 6812 | .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ }, |
| 6813 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6814 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6815 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6816 | } }, |
| 6817 | }, .{ |
| 6818 | .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null }, |
| 6819 | .dst_constraints = .{.{ .scalar_int = .word }}, |
| 6820 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 6821 | .patterns = &.{ |
| 6822 | .{ .src = .{ .to_mem, .none } }, |
| 6823 | }, |
| 6824 | .extra_temps = .{ |
| 6825 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6826 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6827 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6828 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6829 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6830 | .unused, |
| 6831 | }, |
| 6832 | .dst_temps = .{.mem}, |
| 6833 | .clobbers = .{ .eflags = true }, |
| 6834 | .each = .{ .once = &.{ |
| 6835 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6836 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6837 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ }, |
| 6838 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6839 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6840 | .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ }, |
| 6841 | .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ }, |
| 6842 | .{ ._, ._nc, .j, .@"1f", ._, ._, ._ }, |
| 6843 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6844 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6845 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6846 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6847 | .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ }, |
| 6848 | .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ }, |
| 6849 | .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ }, |
| 6850 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6851 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6852 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6853 | } }, |
| 6854 | }, .{ |
| 6855 | .required_features = .{ .@"64bit", .lzcnt, null, null }, |
| 6856 | .dst_constraints = .{.{ .scalar_int = .word }}, |
| 6857 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 6858 | .patterns = &.{ |
| 6859 | .{ .src = .{ .to_mem, .none } }, |
| 6860 | }, |
| 6861 | .extra_temps = .{ |
| 6862 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6863 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6864 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6865 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6866 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6867 | .unused, |
| 6868 | }, |
| 6869 | .dst_temps = .{.mem}, |
| 6870 | .clobbers = .{ .eflags = true }, |
| 6871 | .each = .{ .once = &.{ |
| 6872 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6873 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6874 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ }, |
| 6875 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6876 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6877 | .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ }, |
| 6878 | .{ ._, ._nc, .j, .@"1f", ._, ._, ._ }, |
| 6879 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6880 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6881 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6882 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6883 | .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ }, |
| 6884 | .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ }, |
| 6885 | .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ }, |
| 6886 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6887 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6888 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6889 | } }, |
| 6890 | }, .{ |
| 6891 | .required_features = .{ .@"64bit", null, null, null }, |
| 6892 | .dst_constraints = .{.{ .scalar_int = .word }}, |
| 6893 | .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any }, |
| 6894 | .patterns = &.{ |
| 6895 | .{ .src = .{ .to_mem, .none } }, |
| 6896 | }, |
| 6897 | .extra_temps = .{ |
| 6898 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 6899 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 6900 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 6901 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 6902 | .unused, |
| 6903 | .unused, |
| 6904 | }, |
| 6905 | .dst_temps = .{.mem}, |
| 6906 | .clobbers = .{ .eflags = true }, |
| 6907 | .each = .{ .once = &.{ |
| 6908 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ }, |
| 6909 | .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ }, |
| 6910 | .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ }, |
| 6911 | .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ }, |
| 6912 | .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ }, |
| 6913 | .{ ._, ._r, .bs, .tmp3q, .tmp3q, ._, ._ }, |
| 6914 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 6915 | .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ }, |
| 6916 | .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ }, |
| 6917 | .{ ._, ._nc, .j, .@"1b", ._, ._, ._ }, |
| 6918 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 6919 | .{ .@"1:", ._, .lea, .tmp3d, .leasiad(.none, .tmp3, .@"8", .tmp2, .sub_src0_bit_size, 1), ._, ._ }, |
| 6920 | .{ ._, ._, .neg, .tmp3d, ._, ._, ._ }, |
| 6921 | .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ }, |
| 6922 | .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ }, |
| 6923 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 6924 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 6925 | } }, |
| 6926 | } }) catch |err| switch (err) { |
| 6927 | error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ |
| 6928 | @tagName(air_tag), |
| 6929 | cg.typeOf(ty_op.operand).fmt(pt), |
| 6930 | ops[0].tracking(cg), |
| 6931 | }), |
| 6932 | else => |e| return e, |
| 6933 | }; |
| 6934 | for (ops) |op| for (res) |r| { |
| 6935 | if (op.index == r.index) break; |
| 6936 | } else try op.die(cg); |
| 6937 | try res[0].moveTo(inst, cg); |
| 6938 | }, |
| 6939 | |
| 6940 | .cmp_vector, .cmp_vector_optimized => |air_tag| if (use_old) try cg.airCmpVector(inst) else fallback: { |
| 6941 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 6942 | const extra = cg.air.extraData(Air.VectorCmp, ty_pl.payload).data; |
| 6943 | switch (extra.compareOperator()) { |
| 6944 | .eq, .neq => if (cg.typeOf(extra.lhs).scalarType(zcu).isRuntimeFloat()) |
| 6945 | break :fallback try cg.airCmpVector(inst), |
| 6946 | else => break :fallback try cg.airCmpVector(inst), |
| 6947 | } |
| 6948 | var ops = try cg.tempsFromOperands(inst, .{ extra.lhs, extra.rhs }); |
| 6949 | var res: [1]Temp = undefined; |
| 6950 | switch (extra.compareOperator()) { |
| 6951 | .lt => unreachable, |
| 6952 | .lte => unreachable, |
| 6953 | .eq, .neq => |cmp_op| cg.select(&res, &.{ty_pl.ty.toType()}, &ops, switch (@as(Condition, switch (cmp_op) { |
| 6954 | else => unreachable, |
| 6955 | .eq => .e, |
| 6956 | .neq => .ne, |
| 6957 | })) { |
| 6958 | else => unreachable, |
| 6959 | inline .e, .ne => |cc| comptime &.{ .{ |
| 6960 | .required_features = .{ .avx2, null, null, null }, |
| 6961 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 6962 | .patterns = &.{ |
| 6963 | .{ .src = .{ .to_ymm, .mem } }, |
| 6964 | .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } }, |
| 6965 | .{ .src = .{ .to_ymm, .to_ymm } }, |
| 6966 | }, |
| 6967 | .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{ |
| 6968 | .kind = .all, |
| 6969 | .inverted = switch (cc) { |
| 6970 | else => unreachable, |
| 6971 | .e => false, |
| 6972 | .ne => true, |
| 6973 | }, |
| 6974 | .scalar = .byte, |
| 6975 | } } }}, |
| 6976 | .each = .{ .once = &.{ |
| 6977 | .{ ._, .vp_b, .cmpeq, .dst0y, .src0y, .src1y, ._ }, |
| 6978 | } }, |
| 6979 | }, .{ |
| 6980 | .required_features = .{ .avx2, null, null, null }, |
| 6981 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 6982 | .patterns = &.{ |
| 6983 | .{ .src = .{ .to_ymm, .mem } }, |
| 6984 | .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } }, |
| 6985 | .{ .src = .{ .to_ymm, .to_ymm } }, |
| 6986 | }, |
| 6987 | .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{ |
| 6988 | .kind = .all, |
| 6989 | .inverted = switch (cc) { |
| 6990 | else => unreachable, |
| 6991 | .e => false, |
| 6992 | .ne => true, |
| 6993 | }, |
| 6994 | .scalar = .word, |
| 6995 | } } }}, |
| 6996 | .each = .{ .once = &.{ |
| 6997 | .{ ._, .vp_w, .cmpeq, .dst0y, .src0y, .src1y, ._ }, |
| 6998 | } }, |
| 6999 | }, .{ |
| 7000 | .required_features = .{ .avx2, null, null, null }, |
| 7001 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 7002 | .patterns = &.{ |
| 7003 | .{ .src = .{ .to_ymm, .mem } }, |
| 7004 | .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } }, |
| 7005 | .{ .src = .{ .to_ymm, .to_ymm } }, |
| 7006 | }, |
| 7007 | .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{ |
| 7008 | .kind = .all, |
| 7009 | .inverted = switch (cc) { |
| 7010 | else => unreachable, |
| 7011 | .e => false, |
| 7012 | .ne => true, |
| 7013 | }, |
| 7014 | .scalar = .dword, |
| 7015 | } } }}, |
| 7016 | .each = .{ .once = &.{ |
| 7017 | .{ ._, .vp_d, .cmpeq, .dst0y, .src0y, .src1y, ._ }, |
| 7018 | } }, |
| 7019 | }, .{ |
| 7020 | .required_features = .{ .avx2, null, null, null }, |
| 7021 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 7022 | .patterns = &.{ |
| 7023 | .{ .src = .{ .to_ymm, .mem } }, |
| 7024 | .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } }, |
| 7025 | .{ .src = .{ .to_ymm, .to_ymm } }, |
| 7026 | }, |
| 7027 | .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{ |
| 7028 | .kind = .all, |
| 7029 | .inverted = switch (cc) { |
| 7030 | else => unreachable, |
| 7031 | .e => false, |
| 7032 | .ne => true, |
| 7033 | }, |
| 7034 | .scalar = .qword, |
| 7035 | } } }}, |
| 7036 | .each = .{ .once = &.{ |
| 7037 | .{ ._, .vp_q, .cmpeq, .dst0y, .src0y, .src1y, ._ }, |
| 7038 | } }, |
| 7039 | }, .{ |
| 7040 | .required_features = .{ .avx, null, null, null }, |
| 7041 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 7042 | .patterns = &.{ |
| 7043 | .{ .src = .{ .to_xmm, .mem } }, |
| 7044 | .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } }, |
| 7045 | .{ .src = .{ .to_xmm, .to_xmm } }, |
| 7046 | }, |
| 7047 | .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{ |
| 7048 | .kind = .all, |
| 7049 | .inverted = switch (cc) { |
| 7050 | else => unreachable, |
| 7051 | .e => false, |
| 7052 | .ne => true, |
| 7053 | }, |
| 7054 | .scalar = .byte, |
| 7055 | } } }}, |
| 7056 | .each = .{ .once = &.{ |
| 7057 | .{ ._, .vp_b, .cmpeq, .dst0x, .src0x, .src1x, ._ }, |
| 7058 | } }, |
| 7059 | }, .{ |
| 7060 | .required_features = .{ .avx, null, null, null }, |
| 7061 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 7062 | .patterns = &.{ |
| 7063 | .{ .src = .{ .to_xmm, .mem } }, |
| 7064 | .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } }, |
| 7065 | .{ .src = .{ .to_xmm, .to_xmm } }, |
| 7066 | }, |
| 7067 | .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{ |
| 7068 | .kind = .all, |
| 7069 | .inverted = switch (cc) { |
| 7070 | else => unreachable, |
| 7071 | .e => false, |
| 7072 | .ne => true, |
| 7073 | }, |
| 7074 | .scalar = .word, |
| 7075 | } } }}, |
| 7076 | .each = .{ .once = &.{ |
| 7077 | .{ ._, .vp_w, .cmpeq, .dst0x, .src0x, .src1x, ._ }, |
| 7078 | } }, |
| 7079 | }, .{ |
| 7080 | .required_features = .{ .avx, null, null, null }, |
| 7081 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 7082 | .patterns = &.{ |
| 7083 | .{ .src = .{ .to_xmm, .mem } }, |
| 7084 | .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } }, |
| 7085 | .{ .src = .{ .to_xmm, .to_xmm } }, |
| 7086 | }, |
| 7087 | .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{ |
| 7088 | .kind = .all, |
| 7089 | .inverted = switch (cc) { |
| 7090 | else => unreachable, |
| 7091 | .e => false, |
| 7092 | .ne => true, |
| 7093 | }, |
| 7094 | .scalar = .dword, |
| 7095 | } } }}, |
| 7096 | .each = .{ .once = &.{ |
| 7097 | .{ ._, .vp_d, .cmpeq, .dst0x, .src0x, .src1x, ._ }, |
| 7098 | } }, |
| 7099 | }, .{ |
| 7100 | .required_features = .{ .avx, null, null, null }, |
| 7101 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 7102 | .patterns = &.{ |
| 7103 | .{ .src = .{ .to_xmm, .mem } }, |
| 7104 | .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } }, |
| 7105 | .{ .src = .{ .to_xmm, .to_xmm } }, |
| 7106 | }, |
| 7107 | .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{ |
| 7108 | .kind = .all, |
| 7109 | .inverted = switch (cc) { |
| 7110 | else => unreachable, |
| 7111 | .e => false, |
| 7112 | .ne => true, |
| 7113 | }, |
| 7114 | .scalar = .qword, |
| 7115 | } } }}, |
| 7116 | .each = .{ .once = &.{ |
| 7117 | .{ ._, .vp_q, .cmpeq, .dst0x, .src0x, .src1x, ._ }, |
| 7118 | } }, |
| 7119 | }, .{ |
| 7120 | .required_features = .{ .sse2, null, null, null }, |
| 7121 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 7122 | .patterns = &.{ |
| 7123 | .{ .src = .{ .to_mut_xmm, .mem } }, |
| 7124 | .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } }, |
| 7125 | .{ .src = .{ .to_mut_xmm, .to_xmm } }, |
| 7126 | }, |
| 7127 | .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{ |
| 7128 | .kind = .all, |
| 7129 | .inverted = switch (cc) { |
| 7130 | else => unreachable, |
| 7131 | .e => false, |
| 7132 | .ne => true, |
| 7133 | }, |
| 7134 | .scalar = .byte, |
| 7135 | } } }}, |
| 7136 | .each = .{ .once = &.{ |
| 7137 | .{ ._, .p_b, .cmpeq, .dst0x, .src1x, ._, ._ }, |
| 7138 | } }, |
| 7139 | }, .{ |
| 7140 | .required_features = .{ .sse2, null, null, null }, |
| 7141 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 7142 | .patterns = &.{ |
| 7143 | .{ .src = .{ .to_mut_xmm, .mem } }, |
| 7144 | .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } }, |
| 7145 | .{ .src = .{ .to_mut_xmm, .to_xmm } }, |
| 7146 | }, |
| 7147 | .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{ |
| 7148 | .kind = .all, |
| 7149 | .inverted = switch (cc) { |
| 7150 | else => unreachable, |
| 7151 | .e => false, |
| 7152 | .ne => true, |
| 7153 | }, |
| 7154 | .scalar = .word, |
| 7155 | } } }}, |
| 7156 | .each = .{ .once = &.{ |
| 7157 | .{ ._, .p_w, .cmpeq, .dst0x, .src1x, ._, ._ }, |
| 7158 | } }, |
| 7159 | }, .{ |
| 7160 | .required_features = .{ .sse2, null, null, null }, |
| 7161 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 7162 | .patterns = &.{ |
| 7163 | .{ .src = .{ .to_mut_xmm, .mem } }, |
| 7164 | .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } }, |
| 7165 | .{ .src = .{ .to_mut_xmm, .to_xmm } }, |
| 7166 | }, |
| 7167 | .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{ |
| 7168 | .kind = .all, |
| 7169 | .inverted = switch (cc) { |
| 7170 | else => unreachable, |
| 7171 | .e => false, |
| 7172 | .ne => true, |
| 7173 | }, |
| 7174 | .scalar = .dword, |
| 7175 | } } }}, |
| 7176 | .each = .{ .once = &.{ |
| 7177 | .{ ._, .p_d, .cmpeq, .dst0x, .src1x, ._, ._ }, |
| 7178 | } }, |
| 7179 | }, .{ |
| 7180 | .required_features = .{ .sse4_1, null, null, null }, |
| 7181 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 7182 | .patterns = &.{ |
| 7183 | .{ .src = .{ .to_mut_xmm, .mem } }, |
| 7184 | .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } }, |
| 7185 | .{ .src = .{ .to_mut_xmm, .to_xmm } }, |
| 7186 | }, |
| 7187 | .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{ |
| 7188 | .kind = .all, |
| 7189 | .inverted = switch (cc) { |
| 7190 | else => unreachable, |
| 7191 | .e => false, |
| 7192 | .ne => true, |
| 7193 | }, |
| 7194 | .scalar = .qword, |
| 7195 | } } }}, |
| 7196 | .each = .{ .once = &.{ |
| 7197 | .{ ._, .p_q, .cmpeq, .dst0x, .src1x, ._, ._ }, |
| 7198 | } }, |
| 7199 | }, .{ |
| 7200 | .required_features = .{ .mmx, null, null, null }, |
| 7201 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 7202 | .patterns = &.{ |
| 7203 | .{ .src = .{ .to_mut_mm, .mem } }, |
| 7204 | .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } }, |
| 7205 | .{ .src = .{ .to_mut_mm, .to_mm } }, |
| 7206 | }, |
| 7207 | .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{ |
| 7208 | .kind = .all, |
| 7209 | .inverted = switch (cc) { |
| 7210 | else => unreachable, |
| 7211 | .e => false, |
| 7212 | .ne => true, |
| 7213 | }, |
| 7214 | .scalar = .byte, |
| 7215 | } } }}, |
| 7216 | .each = .{ .once = &.{ |
| 7217 | .{ ._, .p_b, .cmpeq, .dst0q, .src1q, ._, ._ }, |
| 7218 | } }, |
| 7219 | }, .{ |
| 7220 | .required_features = .{ .mmx, null, null, null }, |
| 7221 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 7222 | .patterns = &.{ |
| 7223 | .{ .src = .{ .to_mut_mm, .mem } }, |
| 7224 | .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } }, |
| 7225 | .{ .src = .{ .to_mut_mm, .to_mm } }, |
| 7226 | }, |
| 7227 | .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{ |
| 7228 | .kind = .all, |
| 7229 | .inverted = switch (cc) { |
| 7230 | else => unreachable, |
| 7231 | .e => false, |
| 7232 | .ne => true, |
| 7233 | }, |
| 7234 | .scalar = .word, |
| 7235 | } } }}, |
| 7236 | .each = .{ .once = &.{ |
| 7237 | .{ ._, .p_w, .cmpeq, .dst0q, .src1q, ._, ._ }, |
| 7238 | } }, |
| 7239 | }, .{ |
| 7240 | .required_features = .{ .mmx, null, null, null }, |
| 7241 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 7242 | .patterns = &.{ |
| 7243 | .{ .src = .{ .to_mut_mm, .mem } }, |
| 7244 | .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } }, |
| 7245 | .{ .src = .{ .to_mut_mm, .to_mm } }, |
| 7246 | }, |
| 7247 | .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{ |
| 7248 | .kind = .all, |
| 7249 | .inverted = switch (cc) { |
| 7250 | else => unreachable, |
| 7251 | .e => false, |
| 7252 | .ne => true, |
| 7253 | }, |
| 7254 | .scalar = .dword, |
| 7255 | } } }}, |
| 7256 | .each = .{ .once = &.{ |
| 7257 | .{ ._, .p_d, .cmpeq, .dst0q, .src1q, ._, ._ }, |
| 7258 | } }, |
| 7259 | }, .{ |
| 7260 | .src_constraints = .{ .{ .bool_vec = .byte }, .{ .bool_vec = .byte } }, |
| 7261 | .patterns = &.{ |
| 7262 | .{ .src = .{ .mut_mem, .imm8 } }, |
| 7263 | .{ .src = .{ .imm8, .mut_mem }, .commute = .{ 0, 1 } }, |
| 7264 | .{ .src = .{ .to_mut_gpr, .imm8 } }, |
| 7265 | .{ .src = .{ .imm8, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 7266 | .{ .src = .{ .mut_mem, .to_gpr } }, |
| 7267 | .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } }, |
| 7268 | .{ .src = .{ .to_mut_gpr, .mem } }, |
| 7269 | .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 7270 | .{ .src = .{ .to_mut_gpr, .to_gpr } }, |
| 7271 | }, |
| 7272 | .dst_temps = .{.{ .ref = .src0 }}, |
| 7273 | .clobbers = .{ .eflags = true }, |
| 7274 | .each = .{ .once = switch (cc) { |
| 7275 | else => unreachable, |
| 7276 | .e => &.{ |
| 7277 | .{ ._, ._, .xor, .dst0b, .src1b, ._, ._ }, |
| 7278 | .{ ._, ._, .not, .dst0b, ._, ._, ._ }, |
| 7279 | }, |
| 7280 | .ne => &.{ |
| 7281 | .{ ._, ._, .xor, .dst0b, .src1b, ._, ._ }, |
| 7282 | }, |
| 7283 | } }, |
| 7284 | }, .{ |
| 7285 | .src_constraints = .{ .{ .bool_vec = .word }, .{ .bool_vec = .word } }, |
| 7286 | .patterns = &.{ |
| 7287 | .{ .src = .{ .mut_mem, .imm16 } }, |
| 7288 | .{ .src = .{ .imm16, .mut_mem }, .commute = .{ 0, 1 } }, |
| 7289 | .{ .src = .{ .to_mut_gpr, .imm16 } }, |
| 7290 | .{ .src = .{ .imm16, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 7291 | .{ .src = .{ .mut_mem, .to_gpr } }, |
| 7292 | .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } }, |
| 7293 | .{ .src = .{ .to_mut_gpr, .mem } }, |
| 7294 | .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 7295 | .{ .src = .{ .to_mut_gpr, .to_gpr } }, |
| 7296 | }, |
| 7297 | .dst_temps = .{.{ .ref = .src0 }}, |
| 7298 | .clobbers = .{ .eflags = true }, |
| 7299 | .each = .{ .once = switch (cc) { |
| 7300 | else => unreachable, |
| 7301 | .e => &.{ |
| 7302 | .{ ._, ._, .xor, .dst0w, .src1w, ._, ._ }, |
| 7303 | .{ ._, ._, .not, .dst0w, ._, ._, ._ }, |
| 7304 | }, |
| 7305 | .ne => &.{ |
| 7306 | .{ ._, ._, .xor, .dst0w, .src1w, ._, ._ }, |
| 7307 | }, |
| 7308 | } }, |
| 7309 | }, .{ |
| 7310 | .src_constraints = .{ .{ .bool_vec = .dword }, .{ .bool_vec = .dword } }, |
| 7311 | .patterns = &.{ |
| 7312 | .{ .src = .{ .mut_mem, .imm32 } }, |
| 7313 | .{ .src = .{ .imm32, .mut_mem }, .commute = .{ 0, 1 } }, |
| 7314 | .{ .src = .{ .to_mut_gpr, .imm32 } }, |
| 7315 | .{ .src = .{ .imm32, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 7316 | .{ .src = .{ .mut_mem, .to_gpr } }, |
| 7317 | .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } }, |
| 7318 | .{ .src = .{ .to_mut_gpr, .mem } }, |
| 7319 | .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 7320 | .{ .src = .{ .to_mut_gpr, .to_gpr } }, |
| 7321 | }, |
| 7322 | .dst_temps = .{.{ .ref = .src0 }}, |
| 7323 | .clobbers = .{ .eflags = true }, |
| 7324 | .each = .{ .once = switch (cc) { |
| 7325 | else => unreachable, |
| 7326 | .e => &.{ |
| 7327 | .{ ._, ._, .xor, .dst0d, .src1d, ._, ._ }, |
| 7328 | .{ ._, ._, .not, .dst0d, ._, ._, ._ }, |
| 7329 | }, |
| 7330 | .ne => &.{ |
| 7331 | .{ ._, ._, .xor, .dst0d, .src1d, ._, ._ }, |
| 7332 | }, |
| 7333 | } }, |
| 7334 | }, .{ |
| 7335 | .required_features = .{ .@"64bit", null, null, null }, |
| 7336 | .src_constraints = .{ .{ .bool_vec = .qword }, .{ .bool_vec = .qword } }, |
| 7337 | .patterns = &.{ |
| 7338 | .{ .src = .{ .mut_mem, .simm32 } }, |
| 7339 | .{ .src = .{ .simm32, .mut_mem }, .commute = .{ 0, 1 } }, |
| 7340 | .{ .src = .{ .to_mut_gpr, .simm32 } }, |
| 7341 | .{ .src = .{ .simm32, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 7342 | .{ .src = .{ .mut_mem, .to_gpr } }, |
| 7343 | .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } }, |
| 7344 | .{ .src = .{ .to_mut_gpr, .mem } }, |
| 7345 | .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } }, |
| 7346 | .{ .src = .{ .to_mut_gpr, .to_gpr } }, |
| 7347 | }, |
| 7348 | .dst_temps = .{.{ .ref = .src0 }}, |
| 7349 | .clobbers = .{ .eflags = true }, |
| 7350 | .each = .{ .once = switch (cc) { |
| 7351 | else => unreachable, |
| 7352 | .e => &.{ |
| 7353 | .{ ._, ._, .xor, .dst0q, .src1q, ._, ._ }, |
| 7354 | .{ ._, ._, .not, .dst0q, ._, ._, ._ }, |
| 7355 | }, |
| 7356 | .ne => &.{ |
| 7357 | .{ ._, ._, .xor, .dst0q, .src1q, ._, ._ }, |
| 7358 | }, |
| 7359 | } }, |
| 7360 | }, .{ |
| 7361 | .src_constraints = .{ .any_bool_vec, .any_bool_vec }, |
| 7362 | .patterns = &.{ |
| 7363 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7364 | }, |
| 7365 | .extra_temps = .{ |
| 7366 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7367 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 7368 | .unused, |
| 7369 | .unused, |
| 7370 | .unused, |
| 7371 | .unused, |
| 7372 | }, |
| 7373 | .dst_temps = .{.mem}, |
| 7374 | .clobbers = .{ .eflags = true }, |
| 7375 | .each = .{ .once = switch (cc) { |
| 7376 | else => unreachable, |
| 7377 | .e => &.{ |
| 7378 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7379 | .{ .@"0:", ._, .mov, .tmp1p, .memia(.src0p, .tmp0, .add_size), ._, ._ }, |
| 7380 | .{ ._, ._, .xor, .tmp1p, .memia(.src1p, .tmp0, .add_size), ._, ._ }, |
| 7381 | .{ ._, ._, .not, .tmp1p, ._, ._, ._ }, |
| 7382 | .{ ._, ._, .mov, .memia(.dst0p, .tmp0, .add_size), .tmp1p, ._, ._ }, |
| 7383 | .{ ._, ._, .add, .tmp0p, .sa(.tmp1, .add_size), ._, ._ }, |
| 7384 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7385 | }, |
| 7386 | .ne => &.{ |
| 7387 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7388 | .{ .@"0:", ._, .mov, .tmp1p, .memia(.src0p, .tmp0, .add_size), ._, ._ }, |
| 7389 | .{ ._, ._, .xor, .tmp1p, .memia(.src1p, .tmp0, .add_size), ._, ._ }, |
| 7390 | .{ ._, ._, .mov, .memia(.dst0p, .tmp0, .add_size), .tmp1p, ._, ._ }, |
| 7391 | .{ ._, ._, .add, .tmp0p, .sa(.tmp1, .add_size), ._, ._ }, |
| 7392 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7393 | }, |
| 7394 | } }, |
| 7395 | }, .{ |
| 7396 | .required_features = .{ .avx2, null, null, null }, |
| 7397 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 7398 | .patterns = &.{ |
| 7399 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7400 | }, |
| 7401 | .extra_temps = .{ |
| 7402 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7403 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 7404 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 7405 | .{ .kind = .{ .rc = .sse } }, |
| 7406 | .unused, |
| 7407 | .unused, |
| 7408 | }, |
| 7409 | .dst_temps = .{.mem}, |
| 7410 | .clobbers = .{ .eflags = true }, |
| 7411 | .each = .{ .once = switch (cc) { |
| 7412 | else => unreachable, |
| 7413 | .e => &.{ |
| 7414 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7415 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7416 | .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 7417 | .{ ._, .vp_b, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 7418 | .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3y, ._, ._ }, |
| 7419 | .{ ._, ._, .mov, .memi(.dst0d, .tmp1), .tmp2d, ._, ._ }, |
| 7420 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 7421 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 7422 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7423 | }, |
| 7424 | .ne => &.{ |
| 7425 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7426 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7427 | .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 7428 | .{ ._, .vp_b, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 7429 | .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3y, ._, ._ }, |
| 7430 | .{ ._, ._, .not, .tmp2d, ._, ._, ._ }, |
| 7431 | .{ ._, ._, .mov, .memi(.dst0d, .tmp1), .tmp2d, ._, ._ }, |
| 7432 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 7433 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 7434 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7435 | }, |
| 7436 | } }, |
| 7437 | }, .{ |
| 7438 | .required_features = .{ .avx2, null, null, null }, |
| 7439 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 7440 | .patterns = &.{ |
| 7441 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7442 | }, |
| 7443 | .extra_temps = .{ |
| 7444 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7445 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 7446 | .{ .type = .u16, .kind = .{ .rc = .general_purpose } }, |
| 7447 | .{ .kind = .{ .rc = .sse } }, |
| 7448 | .unused, |
| 7449 | .unused, |
| 7450 | }, |
| 7451 | .dst_temps = .{.mem}, |
| 7452 | .clobbers = .{ .eflags = true }, |
| 7453 | .each = .{ .once = switch (cc) { |
| 7454 | else => unreachable, |
| 7455 | .e => &.{ |
| 7456 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7457 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7458 | .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 7459 | .{ ._, .vp_w, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 7460 | .{ ._, .vp_b, .ackssw, .tmp3y, .tmp3y, .tmp3y, ._ }, |
| 7461 | .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3y, ._, ._ }, |
| 7462 | .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ }, |
| 7463 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7464 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 7465 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7466 | }, |
| 7467 | .ne => &.{ |
| 7468 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7469 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7470 | .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 7471 | .{ ._, .vp_w, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 7472 | .{ ._, .vp_b, .ackssw, .tmp3y, .tmp3y, .tmp3y, ._ }, |
| 7473 | .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3y, ._, ._ }, |
| 7474 | .{ ._, ._, .not, .tmp2d, ._, ._, ._ }, |
| 7475 | .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ }, |
| 7476 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7477 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 7478 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7479 | }, |
| 7480 | } }, |
| 7481 | }, .{ |
| 7482 | .required_features = .{ .avx2, null, null, null }, |
| 7483 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 7484 | .patterns = &.{ |
| 7485 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7486 | }, |
| 7487 | .extra_temps = .{ |
| 7488 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7489 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 7490 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7491 | .{ .kind = .{ .rc = .sse } }, |
| 7492 | .unused, |
| 7493 | .unused, |
| 7494 | }, |
| 7495 | .dst_temps = .{.mem}, |
| 7496 | .clobbers = .{ .eflags = true }, |
| 7497 | .each = .{ .once = switch (cc) { |
| 7498 | else => unreachable, |
| 7499 | .e => &.{ |
| 7500 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7501 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7502 | .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 7503 | .{ ._, .vp_d, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 7504 | .{ ._, .v_ps, .movmsk, .tmp2d, .tmp3y, ._, ._ }, |
| 7505 | .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ }, |
| 7506 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ }, |
| 7507 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 7508 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7509 | }, |
| 7510 | .ne => &.{ |
| 7511 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7512 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7513 | .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 7514 | .{ ._, .vp_d, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 7515 | .{ ._, .v_ps, .movmsk, .tmp2d, .tmp3y, ._, ._ }, |
| 7516 | .{ ._, ._, .not, .tmp2b, ._, ._, ._ }, |
| 7517 | .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ }, |
| 7518 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ }, |
| 7519 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 7520 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7521 | }, |
| 7522 | } }, |
| 7523 | }, .{ |
| 7524 | .required_features = .{ .avx2, null, null, null }, |
| 7525 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 7526 | .patterns = &.{ |
| 7527 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7528 | }, |
| 7529 | .extra_temps = .{ |
| 7530 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7531 | .{ .type = .u32, .kind = .{ .reg = .rcx } }, |
| 7532 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7533 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7534 | .{ .kind = .{ .rc = .sse } }, |
| 7535 | .unused, |
| 7536 | }, |
| 7537 | .dst_temps = .{.mem}, |
| 7538 | .clobbers = .{ .eflags = true }, |
| 7539 | .each = .{ .once = switch (cc) { |
| 7540 | else => unreachable, |
| 7541 | .e => &.{ |
| 7542 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7543 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7544 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7545 | .{ .@"0:", .v_dqu, .mov, .tmp4y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 7546 | .{ ._, .vp_q, .cmpeq, .tmp4y, .tmp4y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 7547 | .{ ._, .v_pd, .movmsk, .tmp3d, .tmp4y, ._, ._ }, |
| 7548 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7549 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7550 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 7551 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7552 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7553 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7554 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7555 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 7556 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7557 | .{ .@"1:", ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 7558 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7559 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7560 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 7561 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7562 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7563 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 7564 | }, |
| 7565 | .ne => &.{ |
| 7566 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7567 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7568 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7569 | .{ .@"0:", .v_dqu, .mov, .tmp4y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 7570 | .{ ._, .vp_q, .cmpeq, .tmp4y, .tmp4y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 7571 | .{ ._, .v_pd, .movmsk, .tmp3d, .tmp4y, ._, ._ }, |
| 7572 | .{ ._, ._, .xor, .tmp3b, .si(0b1111), ._, ._ }, |
| 7573 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7574 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7575 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 7576 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7577 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7578 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7579 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7580 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 7581 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7582 | .{ .@"1:", ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 7583 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7584 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7585 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 7586 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7587 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7588 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 7589 | }, |
| 7590 | } }, |
| 7591 | }, .{ |
| 7592 | .required_features = .{ .avx, null, null, null }, |
| 7593 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 7594 | .patterns = &.{ |
| 7595 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7596 | }, |
| 7597 | .extra_temps = .{ |
| 7598 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7599 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 7600 | .{ .type = .u16, .kind = .{ .rc = .general_purpose } }, |
| 7601 | .{ .kind = .{ .rc = .sse } }, |
| 7602 | .unused, |
| 7603 | .unused, |
| 7604 | }, |
| 7605 | .dst_temps = .{.mem}, |
| 7606 | .clobbers = .{ .eflags = true }, |
| 7607 | .each = .{ .once = switch (cc) { |
| 7608 | else => unreachable, |
| 7609 | .e => &.{ |
| 7610 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7611 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7612 | .{ .@"0:", .v_dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7613 | .{ ._, .vp_b, .cmpeq, .tmp3x, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 7614 | .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3x, ._, ._ }, |
| 7615 | .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ }, |
| 7616 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7617 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7618 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7619 | }, |
| 7620 | .ne => &.{ |
| 7621 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7622 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7623 | .{ .@"0:", .v_dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7624 | .{ ._, .vp_b, .cmpeq, .tmp3x, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 7625 | .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3x, ._, ._ }, |
| 7626 | .{ ._, ._, .not, .tmp2d, ._, ._, ._ }, |
| 7627 | .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ }, |
| 7628 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7629 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7630 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7631 | }, |
| 7632 | } }, |
| 7633 | }, .{ |
| 7634 | .required_features = .{ .avx, null, null, null }, |
| 7635 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 7636 | .patterns = &.{ |
| 7637 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7638 | }, |
| 7639 | .extra_temps = .{ |
| 7640 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7641 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 7642 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7643 | .{ .kind = .{ .rc = .sse } }, |
| 7644 | .unused, |
| 7645 | .unused, |
| 7646 | }, |
| 7647 | .dst_temps = .{.mem}, |
| 7648 | .clobbers = .{ .eflags = true }, |
| 7649 | .each = .{ .once = switch (cc) { |
| 7650 | else => unreachable, |
| 7651 | .e => &.{ |
| 7652 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7653 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7654 | .{ .@"0:", .v_dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7655 | .{ ._, .vp_w, .cmpeq, .tmp3x, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 7656 | .{ ._, .vp_b, .ackssw, .tmp3x, .tmp3x, .tmp3x, ._ }, |
| 7657 | .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3x, ._, ._ }, |
| 7658 | .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ }, |
| 7659 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ }, |
| 7660 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7661 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7662 | }, |
| 7663 | .ne => &.{ |
| 7664 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7665 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7666 | .{ .@"0:", .v_dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7667 | .{ ._, .vp_w, .cmpeq, .tmp3x, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 7668 | .{ ._, .vp_b, .ackssw, .tmp3x, .tmp3x, .tmp3x, ._ }, |
| 7669 | .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3x, ._, ._ }, |
| 7670 | .{ ._, ._, .not, .tmp2b, ._, ._, ._ }, |
| 7671 | .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ }, |
| 7672 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ }, |
| 7673 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7674 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7675 | }, |
| 7676 | } }, |
| 7677 | }, .{ |
| 7678 | .required_features = .{ .avx, null, null, null }, |
| 7679 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 7680 | .patterns = &.{ |
| 7681 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7682 | }, |
| 7683 | .extra_temps = .{ |
| 7684 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7685 | .{ .type = .u32, .kind = .{ .reg = .rcx } }, |
| 7686 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7687 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7688 | .{ .kind = .{ .rc = .sse } }, |
| 7689 | .unused, |
| 7690 | }, |
| 7691 | .dst_temps = .{.mem}, |
| 7692 | .clobbers = .{ .eflags = true }, |
| 7693 | .each = .{ .once = switch (cc) { |
| 7694 | else => unreachable, |
| 7695 | .e => &.{ |
| 7696 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7697 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7698 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7699 | .{ .@"0:", .v_dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7700 | .{ ._, .vp_d, .cmpeq, .tmp4x, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 7701 | .{ ._, .v_ps, .movmsk, .tmp3d, .tmp4x, ._, ._ }, |
| 7702 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7703 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7704 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 7705 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7706 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7707 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7708 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7709 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 7710 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7711 | .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7712 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7713 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7714 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 7715 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7716 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7717 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 7718 | }, |
| 7719 | .ne => &.{ |
| 7720 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7721 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7722 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7723 | .{ .@"0:", .v_dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7724 | .{ ._, .vp_d, .cmpeq, .tmp4x, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 7725 | .{ ._, .v_ps, .movmsk, .tmp3d, .tmp4x, ._, ._ }, |
| 7726 | .{ ._, ._, .xor, .tmp3b, .si(0b1111), ._, ._ }, |
| 7727 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7728 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7729 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 7730 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7731 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7732 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7733 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7734 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 7735 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7736 | .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7737 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7738 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7739 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 7740 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7741 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7742 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 7743 | }, |
| 7744 | } }, |
| 7745 | }, .{ |
| 7746 | .required_features = .{ .avx, null, null, null }, |
| 7747 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 7748 | .patterns = &.{ |
| 7749 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7750 | }, |
| 7751 | .extra_temps = .{ |
| 7752 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7753 | .{ .type = .u32, .kind = .{ .reg = .rcx } }, |
| 7754 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7755 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7756 | .{ .kind = .{ .rc = .sse } }, |
| 7757 | .unused, |
| 7758 | }, |
| 7759 | .dst_temps = .{.mem}, |
| 7760 | .clobbers = .{ .eflags = true }, |
| 7761 | .each = .{ .once = switch (cc) { |
| 7762 | else => unreachable, |
| 7763 | .e => &.{ |
| 7764 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7765 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7766 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7767 | .{ .@"0:", .v_dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7768 | .{ ._, .vp_q, .cmpeq, .tmp4x, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 7769 | .{ ._, .v_pd, .movmsk, .tmp3d, .tmp4x, ._, ._ }, |
| 7770 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7771 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7772 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7773 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7774 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7775 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7776 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7777 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 7778 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7779 | .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7780 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7781 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7782 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 7783 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7784 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7785 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 7786 | }, |
| 7787 | .ne => &.{ |
| 7788 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7789 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7790 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7791 | .{ .@"0:", .v_dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7792 | .{ ._, .vp_q, .cmpeq, .tmp4x, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 7793 | .{ ._, .v_pd, .movmsk, .tmp3d, .tmp4x, ._, ._ }, |
| 7794 | .{ ._, ._, .xor, .tmp3b, .si(0b11), ._, ._ }, |
| 7795 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7796 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7797 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7798 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7799 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7800 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7801 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7802 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 7803 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7804 | .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7805 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7806 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7807 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 7808 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7809 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7810 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 7811 | }, |
| 7812 | } }, |
| 7813 | }, .{ |
| 7814 | .required_features = .{ .sse2, null, null, null }, |
| 7815 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 7816 | .patterns = &.{ |
| 7817 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7818 | }, |
| 7819 | .extra_temps = .{ |
| 7820 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7821 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 7822 | .{ .type = .u16, .kind = .{ .rc = .general_purpose } }, |
| 7823 | .{ .kind = .{ .rc = .sse } }, |
| 7824 | .unused, |
| 7825 | .unused, |
| 7826 | }, |
| 7827 | .dst_temps = .{.mem}, |
| 7828 | .clobbers = .{ .eflags = true }, |
| 7829 | .each = .{ .once = switch (cc) { |
| 7830 | else => unreachable, |
| 7831 | .e => &.{ |
| 7832 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7833 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7834 | .{ .@"0:", ._dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7835 | .{ ._, .p_b, .cmpeq, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 7836 | .{ ._, .p_b, .movmsk, .tmp2d, .tmp3x, ._, ._ }, |
| 7837 | .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ }, |
| 7838 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7839 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7840 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7841 | }, |
| 7842 | .ne => &.{ |
| 7843 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7844 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7845 | .{ .@"0:", ._dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7846 | .{ ._, .p_b, .cmpeq, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 7847 | .{ ._, .p_b, .movmsk, .tmp2d, .tmp3x, ._, ._ }, |
| 7848 | .{ ._, ._, .not, .tmp2d, ._, ._, ._ }, |
| 7849 | .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ }, |
| 7850 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7851 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7852 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7853 | }, |
| 7854 | } }, |
| 7855 | }, .{ |
| 7856 | .required_features = .{ .sse2, null, null, null }, |
| 7857 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 7858 | .patterns = &.{ |
| 7859 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7860 | }, |
| 7861 | .extra_temps = .{ |
| 7862 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7863 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 7864 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7865 | .{ .kind = .{ .rc = .sse } }, |
| 7866 | .unused, |
| 7867 | .unused, |
| 7868 | }, |
| 7869 | .dst_temps = .{.mem}, |
| 7870 | .clobbers = .{ .eflags = true }, |
| 7871 | .each = .{ .once = switch (cc) { |
| 7872 | else => unreachable, |
| 7873 | .e => &.{ |
| 7874 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7875 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7876 | .{ .@"0:", ._dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7877 | .{ ._, .p_w, .cmpeq, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 7878 | .{ ._, .p_b, .ackssw, .tmp3x, .tmp3x, ._, ._ }, |
| 7879 | .{ ._, .p_b, .movmsk, .tmp2d, .tmp3x, ._, ._ }, |
| 7880 | .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ }, |
| 7881 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ }, |
| 7882 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7883 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7884 | }, |
| 7885 | .ne => &.{ |
| 7886 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7887 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7888 | .{ .@"0:", ._dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7889 | .{ ._, .p_w, .cmpeq, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 7890 | .{ ._, .p_b, .ackssw, .tmp3x, .tmp3x, ._, ._ }, |
| 7891 | .{ ._, .p_b, .movmsk, .tmp2d, .tmp3x, ._, ._ }, |
| 7892 | .{ ._, ._, .not, .tmp2b, ._, ._, ._ }, |
| 7893 | .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ }, |
| 7894 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ }, |
| 7895 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7896 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7897 | }, |
| 7898 | } }, |
| 7899 | }, .{ |
| 7900 | .required_features = .{ .sse2, null, null, null }, |
| 7901 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 7902 | .patterns = &.{ |
| 7903 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7904 | }, |
| 7905 | .extra_temps = .{ |
| 7906 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7907 | .{ .type = .u32, .kind = .{ .reg = .rcx } }, |
| 7908 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7909 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7910 | .{ .kind = .{ .rc = .sse } }, |
| 7911 | .unused, |
| 7912 | }, |
| 7913 | .dst_temps = .{.mem}, |
| 7914 | .clobbers = .{ .eflags = true }, |
| 7915 | .each = .{ .once = switch (cc) { |
| 7916 | else => unreachable, |
| 7917 | .e => &.{ |
| 7918 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7919 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7920 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7921 | .{ .@"0:", ._dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7922 | .{ ._, .p_d, .cmpeq, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 7923 | .{ ._, ._ps, .movmsk, .tmp3d, .tmp4x, ._, ._ }, |
| 7924 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7925 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7926 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 7927 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7928 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7929 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7930 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7931 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 7932 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7933 | .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7934 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7935 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7936 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 7937 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7938 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7939 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 7940 | }, |
| 7941 | .ne => &.{ |
| 7942 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7943 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7944 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7945 | .{ .@"0:", ._dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7946 | .{ ._, .p_d, .cmpeq, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 7947 | .{ ._, ._ps, .movmsk, .tmp3d, .tmp4x, ._, ._ }, |
| 7948 | .{ ._, ._, .xor, .tmp3b, .si(0b1111), ._, ._ }, |
| 7949 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7950 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7951 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 7952 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7953 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7954 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7955 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7956 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 7957 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7958 | .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 7959 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 7960 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7961 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 7962 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7963 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7964 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 7965 | }, |
| 7966 | } }, |
| 7967 | }, .{ |
| 7968 | .required_features = .{ .sse4_1, null, null, null }, |
| 7969 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 7970 | .patterns = &.{ |
| 7971 | .{ .src = .{ .to_mem, .to_mem } }, |
| 7972 | }, |
| 7973 | .extra_temps = .{ |
| 7974 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 7975 | .{ .type = .u32, .kind = .{ .reg = .rcx } }, |
| 7976 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7977 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 7978 | .{ .kind = .{ .rc = .sse } }, |
| 7979 | .unused, |
| 7980 | }, |
| 7981 | .dst_temps = .{.mem}, |
| 7982 | .clobbers = .{ .eflags = true }, |
| 7983 | .each = .{ .once = switch (cc) { |
| 7984 | else => unreachable, |
| 7985 | .e => &.{ |
| 7986 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 7987 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 7988 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 7989 | .{ .@"0:", ._dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 7990 | .{ ._, .p_q, .cmpeq, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 7991 | .{ ._, ._pd, .movmsk, .tmp3d, .tmp4x, ._, ._ }, |
| 7992 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 7993 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 7994 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 7995 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 7996 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 7997 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 7998 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 7999 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 8000 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8001 | .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 8002 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8003 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8004 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 8005 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 8006 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 8007 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 8008 | }, |
| 8009 | .ne => &.{ |
| 8010 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8011 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 8012 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8013 | .{ .@"0:", ._dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 8014 | .{ ._, .p_q, .cmpeq, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 8015 | .{ ._, ._pd, .movmsk, .tmp3d, .tmp4x, ._, ._ }, |
| 8016 | .{ ._, ._, .xor, .tmp3b, .si(0b11), ._, ._ }, |
| 8017 | .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ }, |
| 8018 | .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ }, |
| 8019 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 8020 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8021 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 8022 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 8023 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 8024 | .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ }, |
| 8025 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8026 | .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 8027 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8028 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8029 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 8030 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 8031 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 8032 | .{ ._, ._, .mov, .memi(.dst0b, .tmp3), .tmp2b, ._, ._ }, |
| 8033 | }, |
| 8034 | } }, |
| 8035 | }, .{ |
| 8036 | .required_features = .{ .sse, .mmx, null, null }, |
| 8037 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 8038 | .patterns = &.{ |
| 8039 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8040 | }, |
| 8041 | .extra_temps = .{ |
| 8042 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8043 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8044 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8045 | .{ .kind = .{ .rc = .mmx } }, |
| 8046 | .unused, |
| 8047 | .unused, |
| 8048 | }, |
| 8049 | .dst_temps = .{.mem}, |
| 8050 | .clobbers = .{ .eflags = true }, |
| 8051 | .each = .{ .once = switch (cc) { |
| 8052 | else => unreachable, |
| 8053 | .e => &.{ |
| 8054 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8055 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 8056 | .{ .@"0:", ._q, .mov, .tmp3q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8057 | .{ ._, .p_b, .cmpeq, .tmp3q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8058 | .{ ._, .p_b, .movmsk, .tmp2d, .tmp3q, ._, ._ }, |
| 8059 | .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ }, |
| 8060 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ }, |
| 8061 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 8062 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8063 | }, |
| 8064 | .ne => &.{ |
| 8065 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8066 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 8067 | .{ .@"0:", ._q, .mov, .tmp3q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8068 | .{ ._, .p_b, .cmpeq, .tmp3q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8069 | .{ ._, .p_b, .movmsk, .tmp2d, .tmp3q, ._, ._ }, |
| 8070 | .{ ._, ._, .not, .tmp2b, ._, ._, ._ }, |
| 8071 | .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ }, |
| 8072 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ }, |
| 8073 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 8074 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8075 | }, |
| 8076 | } }, |
| 8077 | }, .{ |
| 8078 | .required_features = .{ .sse, .mmx, null, null }, |
| 8079 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 8080 | .patterns = &.{ |
| 8081 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8082 | }, |
| 8083 | .extra_temps = .{ |
| 8084 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8085 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8086 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8087 | .{ .kind = .{ .rc = .mmx } }, |
| 8088 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8089 | .{ .kind = .{ .rc = .mmx } }, |
| 8090 | }, |
| 8091 | .dst_temps = .{.mem}, |
| 8092 | .clobbers = .{ .eflags = true }, |
| 8093 | .each = .{ .once = switch (cc) { |
| 8094 | else => unreachable, |
| 8095 | .e => &.{ |
| 8096 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8097 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 8098 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8099 | .{ ._, .p_, .xor, .tmp3q, .tmp3q, ._, ._ }, |
| 8100 | .{ .@"0:", ._q, .mov, .tmp5q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8101 | .{ ._, .p_w, .cmpeq, .tmp5q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8102 | .{ ._, .p_b, .ackssw, .tmp5q, .tmp3q, ._, ._ }, |
| 8103 | .{ ._, .p_b, .movmsk, .tmp4d, .tmp5q, ._, ._ }, |
| 8104 | .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ }, |
| 8105 | .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ }, |
| 8106 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 8107 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8108 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 8109 | .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ }, |
| 8110 | .{ ._, ._r, .sh, .tmp4d, .si(3), ._, ._ }, |
| 8111 | .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ }, |
| 8112 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8113 | .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 8114 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8115 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8116 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 8117 | .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ }, |
| 8118 | .{ ._, ._r, .sh, .tmp4d, .si(3), ._, ._ }, |
| 8119 | .{ ._, ._, .mov, .memi(.dst0b, .tmp4), .tmp2b, ._, ._ }, |
| 8120 | }, |
| 8121 | .ne => &.{ |
| 8122 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8123 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 8124 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8125 | .{ ._, .p_, .xor, .tmp3q, .tmp3q, ._, ._ }, |
| 8126 | .{ .@"0:", ._q, .mov, .tmp5q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8127 | .{ ._, .p_w, .cmpeq, .tmp5q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8128 | .{ ._, .p_b, .ackssw, .tmp5q, .tmp3q, ._, ._ }, |
| 8129 | .{ ._, .p_b, .movmsk, .tmp4d, .tmp5q, ._, ._ }, |
| 8130 | .{ ._, ._, .xor, .tmp4b, .si(0b1111), ._, ._ }, |
| 8131 | .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ }, |
| 8132 | .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ }, |
| 8133 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ }, |
| 8134 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8135 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 8136 | .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ }, |
| 8137 | .{ ._, ._r, .sh, .tmp4d, .si(3), ._, ._ }, |
| 8138 | .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ }, |
| 8139 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8140 | .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 8141 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8142 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8143 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 8144 | .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ }, |
| 8145 | .{ ._, ._r, .sh, .tmp4d, .si(3), ._, ._ }, |
| 8146 | .{ ._, ._, .mov, .memi(.dst0b, .tmp4), .tmp2b, ._, ._ }, |
| 8147 | }, |
| 8148 | } }, |
| 8149 | }, .{ |
| 8150 | .required_features = .{ .sse, .mmx, null, null }, |
| 8151 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 8152 | .patterns = &.{ |
| 8153 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8154 | }, |
| 8155 | .extra_temps = .{ |
| 8156 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8157 | .{ .type = .u32, .kind = .{ .reg = .rcx } }, |
| 8158 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8159 | .{ .kind = .{ .rc = .mmx } }, |
| 8160 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8161 | .{ .kind = .{ .rc = .mmx } }, |
| 8162 | }, |
| 8163 | .dst_temps = .{.mem}, |
| 8164 | .clobbers = .{ .eflags = true }, |
| 8165 | .each = .{ .once = switch (cc) { |
| 8166 | else => unreachable, |
| 8167 | .e => &.{ |
| 8168 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8169 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 8170 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8171 | .{ ._, .p_, .xor, .tmp3q, .tmp3q, ._, ._ }, |
| 8172 | .{ .@"0:", ._q, .mov, .tmp5q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8173 | .{ ._, .p_d, .cmpeq, .tmp5q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8174 | .{ ._, .p_w, .ackssd, .tmp5q, .tmp3q, ._, ._ }, |
| 8175 | .{ ._, .p_b, .ackssw, .tmp5q, .tmp3q, ._, ._ }, |
| 8176 | .{ ._, .p_b, .movmsk, .tmp4d, .tmp5q, ._, ._ }, |
| 8177 | .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ }, |
| 8178 | .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ }, |
| 8179 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 8180 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8181 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 8182 | .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ }, |
| 8183 | .{ ._, ._r, .sh, .tmp4d, .si(3), ._, ._ }, |
| 8184 | .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ }, |
| 8185 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8186 | .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 8187 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8188 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8189 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 8190 | .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ }, |
| 8191 | .{ ._, ._r, .sh, .tmp4d, .si(3), ._, ._ }, |
| 8192 | .{ ._, ._, .mov, .memi(.dst0b, .tmp4), .tmp2b, ._, ._ }, |
| 8193 | }, |
| 8194 | .ne => &.{ |
| 8195 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8196 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 8197 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8198 | .{ ._, .p_, .xor, .tmp3q, .tmp3q, ._, ._ }, |
| 8199 | .{ .@"0:", ._q, .mov, .tmp5q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8200 | .{ ._, .p_d, .cmpeq, .tmp5q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8201 | .{ ._, .p_w, .ackssd, .tmp5q, .tmp3q, ._, ._ }, |
| 8202 | .{ ._, .p_b, .ackssw, .tmp5q, .tmp3q, ._, ._ }, |
| 8203 | .{ ._, .p_b, .movmsk, .tmp4d, .tmp5q, ._, ._ }, |
| 8204 | .{ ._, ._, .xor, .tmp4b, .si(0b11), ._, ._ }, |
| 8205 | .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ }, |
| 8206 | .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ }, |
| 8207 | .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ }, |
| 8208 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8209 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 8210 | .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ }, |
| 8211 | .{ ._, ._r, .sh, .tmp4d, .si(3), ._, ._ }, |
| 8212 | .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ }, |
| 8213 | .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ }, |
| 8214 | .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 8215 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8216 | .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ }, |
| 8217 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 8218 | .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ }, |
| 8219 | .{ ._, ._r, .sh, .tmp4d, .si(3), ._, ._ }, |
| 8220 | .{ ._, ._, .mov, .memi(.dst0b, .tmp4), .tmp2b, ._, ._ }, |
| 8221 | }, |
| 8222 | } }, |
| 8223 | }, .{ |
| 8224 | .dst_constraints = .{.{ .bool_vec = .byte }}, |
| 8225 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 8226 | .patterns = &.{ |
| 8227 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8228 | }, |
| 8229 | .extra_temps = .{ |
| 8230 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8231 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8232 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8233 | .unused, |
| 8234 | .unused, |
| 8235 | .unused, |
| 8236 | }, |
| 8237 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8238 | .clobbers = .{ .eflags = true }, |
| 8239 | .each = .{ .once = &.{ |
| 8240 | .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ }, |
| 8241 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8242 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8243 | .{ .@"0:", ._, .mov, .tmp2b, .memia(.src0b, .tmp0, .add_size), ._, ._ }, |
| 8244 | .{ ._, ._, .cmp, .tmp2b, .memia(.src1b, .tmp0, .add_size), ._, ._ }, |
| 8245 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8246 | .{ ._, ._l, .sh, .tmp2b, .tmp1b, ._, ._ }, |
| 8247 | .{ ._, ._, .@"or", .dst0b, .tmp2b, ._, ._ }, |
| 8248 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8249 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 8250 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8251 | } }, |
| 8252 | }, .{ |
| 8253 | .dst_constraints = .{.{ .bool_vec = .byte }}, |
| 8254 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 8255 | .patterns = &.{ |
| 8256 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8257 | }, |
| 8258 | .extra_temps = .{ |
| 8259 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8260 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8261 | .{ .type = .u16, .kind = .{ .rc = .general_purpose } }, |
| 8262 | .unused, |
| 8263 | .unused, |
| 8264 | .unused, |
| 8265 | }, |
| 8266 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8267 | .clobbers = .{ .eflags = true }, |
| 8268 | .each = .{ .once = &.{ |
| 8269 | .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ }, |
| 8270 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8271 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8272 | .{ .@"0:", ._, .mov, .tmp2w, .memia(.src0w, .tmp0, .add_size), ._, ._ }, |
| 8273 | .{ ._, ._, .cmp, .tmp2w, .memia(.src1w, .tmp0, .add_size), ._, ._ }, |
| 8274 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8275 | .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ }, |
| 8276 | .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ }, |
| 8277 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8278 | .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ }, |
| 8279 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8280 | } }, |
| 8281 | }, .{ |
| 8282 | .dst_constraints = .{.{ .bool_vec = .byte }}, |
| 8283 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 8284 | .patterns = &.{ |
| 8285 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8286 | }, |
| 8287 | .extra_temps = .{ |
| 8288 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8289 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8290 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8291 | .unused, |
| 8292 | .unused, |
| 8293 | .unused, |
| 8294 | }, |
| 8295 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8296 | .clobbers = .{ .eflags = true }, |
| 8297 | .each = .{ .once = &.{ |
| 8298 | .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ }, |
| 8299 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8300 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8301 | .{ .@"0:", ._, .mov, .tmp2d, .memia(.src0d, .tmp0, .add_size), ._, ._ }, |
| 8302 | .{ ._, ._, .cmp, .tmp2d, .memia(.src1d, .tmp0, .add_size), ._, ._ }, |
| 8303 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8304 | .{ ._, ._l, .sh, .tmp2b, .tmp1b, ._, ._ }, |
| 8305 | .{ ._, ._, .@"or", .dst0b, .tmp2b, ._, ._ }, |
| 8306 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8307 | .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ }, |
| 8308 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8309 | } }, |
| 8310 | }, .{ |
| 8311 | .required_features = .{ .@"64bit", null, null, null }, |
| 8312 | .dst_constraints = .{.{ .bool_vec = .byte }}, |
| 8313 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 8314 | .patterns = &.{ |
| 8315 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8316 | }, |
| 8317 | .extra_temps = .{ |
| 8318 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8319 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8320 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 8321 | .unused, |
| 8322 | .unused, |
| 8323 | .unused, |
| 8324 | }, |
| 8325 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8326 | .clobbers = .{ .eflags = true }, |
| 8327 | .each = .{ .once = &.{ |
| 8328 | .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ }, |
| 8329 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8330 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8331 | .{ .@"0:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8332 | .{ ._, ._, .cmp, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8333 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8334 | .{ ._, ._l, .sh, .tmp2b, .tmp1b, ._, ._ }, |
| 8335 | .{ ._, ._, .@"or", .dst0b, .tmp2b, ._, ._ }, |
| 8336 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8337 | .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ }, |
| 8338 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8339 | } }, |
| 8340 | }, .{ |
| 8341 | .dst_constraints = .{.{ .bool_vec = .byte }}, |
| 8342 | .patterns = &.{ |
| 8343 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8344 | }, |
| 8345 | .extra_temps = .{ |
| 8346 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8347 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8348 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8349 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8350 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8351 | .unused, |
| 8352 | }, |
| 8353 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8354 | .clobbers = .{ .eflags = true }, |
| 8355 | .each = .{ .once = &.{ |
| 8356 | .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ }, |
| 8357 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 8358 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8359 | .{ .@"0:", ._, .mov, .tmp2d, .sa(.src0p, .add_elem_limbs), ._, ._ }, |
| 8360 | .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ }, |
| 8361 | .{ .@"1:", ._, .mov, .tmp4p, .memi(.src0p, .tmp0), ._, ._ }, |
| 8362 | .{ ._, ._, .xor, .tmp4p, .memi(.src1p, .tmp0), ._, ._ }, |
| 8363 | .{ ._, ._, .@"or", .tmp3p, .tmp4p, ._, ._ }, |
| 8364 | .{ ._, ._, .add, .tmp0p, .sa(.tmp4, .add_size), ._, ._ }, |
| 8365 | .{ ._, ._, .sub, .tmp2d, .si(1), ._, ._ }, |
| 8366 | .{ ._, ._b, .j, .@"1b", ._, ._, ._ }, |
| 8367 | .{ ._, ._, .@"test", .tmp3p, .tmp3p, ._, ._ }, |
| 8368 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8369 | .{ ._, ._l, .sh, .tmp2b, .tmp1b, ._, ._ }, |
| 8370 | .{ ._, ._, .@"or", .dst0b, .tmp2b, ._, ._ }, |
| 8371 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8372 | .{ ._, ._, .cmp, .tmp1b, .sa(.dst0, .add_len), ._, ._ }, |
| 8373 | .{ ._, ._b, .j, .@"0b", ._, ._, ._ }, |
| 8374 | } }, |
| 8375 | }, .{ |
| 8376 | .dst_constraints = .{.{ .bool_vec = .dword }}, |
| 8377 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 8378 | .patterns = &.{ |
| 8379 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8380 | }, |
| 8381 | .extra_temps = .{ |
| 8382 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8383 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8384 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8385 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8386 | .unused, |
| 8387 | .unused, |
| 8388 | }, |
| 8389 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8390 | .clobbers = .{ .eflags = true }, |
| 8391 | .each = .{ .once = &.{ |
| 8392 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8393 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8394 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8395 | .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8396 | .{ ._, ._, .mov, .tmp3b, .memia(.src0b, .tmp0, .add_size), ._, ._ }, |
| 8397 | .{ ._, ._, .cmp, .tmp3b, .memia(.src1b, .tmp0, .add_size), ._, ._ }, |
| 8398 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8399 | .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ }, |
| 8400 | .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ }, |
| 8401 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8402 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 8403 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8404 | } }, |
| 8405 | }, .{ |
| 8406 | .dst_constraints = .{.{ .bool_vec = .dword }}, |
| 8407 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 8408 | .patterns = &.{ |
| 8409 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8410 | }, |
| 8411 | .extra_temps = .{ |
| 8412 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8413 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8414 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8415 | .{ .type = .u16, .kind = .{ .rc = .general_purpose } }, |
| 8416 | .unused, |
| 8417 | .unused, |
| 8418 | }, |
| 8419 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8420 | .clobbers = .{ .eflags = true }, |
| 8421 | .each = .{ .once = &.{ |
| 8422 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8423 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8424 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8425 | .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8426 | .{ ._, ._, .mov, .tmp3w, .memia(.src0w, .tmp0, .add_size), ._, ._ }, |
| 8427 | .{ ._, ._, .cmp, .tmp3w, .memia(.src1w, .tmp0, .add_size), ._, ._ }, |
| 8428 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8429 | .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ }, |
| 8430 | .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ }, |
| 8431 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8432 | .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ }, |
| 8433 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8434 | } }, |
| 8435 | }, .{ |
| 8436 | .dst_constraints = .{.{ .bool_vec = .dword }}, |
| 8437 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 8438 | .patterns = &.{ |
| 8439 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8440 | }, |
| 8441 | .extra_temps = .{ |
| 8442 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8443 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8444 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8445 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8446 | .unused, |
| 8447 | .unused, |
| 8448 | }, |
| 8449 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8450 | .clobbers = .{ .eflags = true }, |
| 8451 | .each = .{ .once = &.{ |
| 8452 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8453 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8454 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8455 | .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8456 | .{ ._, ._, .mov, .tmp3d, .memia(.src0d, .tmp0, .add_size), ._, ._ }, |
| 8457 | .{ ._, ._, .cmp, .tmp3d, .memia(.src1d, .tmp0, .add_size), ._, ._ }, |
| 8458 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8459 | .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ }, |
| 8460 | .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ }, |
| 8461 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8462 | .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ }, |
| 8463 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8464 | } }, |
| 8465 | }, .{ |
| 8466 | .required_features = .{ .@"64bit", null, null, null }, |
| 8467 | .dst_constraints = .{.{ .bool_vec = .dword }}, |
| 8468 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 8469 | .patterns = &.{ |
| 8470 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8471 | }, |
| 8472 | .extra_temps = .{ |
| 8473 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8474 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8475 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8476 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 8477 | .unused, |
| 8478 | .unused, |
| 8479 | }, |
| 8480 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8481 | .clobbers = .{ .eflags = true }, |
| 8482 | .each = .{ .once = &.{ |
| 8483 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8484 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8485 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8486 | .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8487 | .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8488 | .{ ._, ._, .cmp, .tmp3q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8489 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8490 | .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ }, |
| 8491 | .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ }, |
| 8492 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8493 | .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ }, |
| 8494 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8495 | } }, |
| 8496 | }, .{ |
| 8497 | .dst_constraints = .{.{ .bool_vec = .dword }}, |
| 8498 | .patterns = &.{ |
| 8499 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8500 | }, |
| 8501 | .extra_temps = .{ |
| 8502 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8503 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8504 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8505 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8506 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8507 | .unused, |
| 8508 | }, |
| 8509 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8510 | .clobbers = .{ .eflags = true }, |
| 8511 | .each = .{ .once = &.{ |
| 8512 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8513 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 8514 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8515 | .{ .@"0:", ._, .mov, .tmp2d, .sa(.src0p, .add_elem_limbs), ._, ._ }, |
| 8516 | .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ }, |
| 8517 | .{ .@"1:", ._, .mov, .tmp4p, .memi(.src0p, .tmp0), ._, ._ }, |
| 8518 | .{ ._, ._, .xor, .tmp4p, .memi(.src1p, .tmp0), ._, ._ }, |
| 8519 | .{ ._, ._, .@"or", .tmp3p, .tmp4p, ._, ._ }, |
| 8520 | .{ ._, ._, .add, .tmp0p, .sa(.tmp4, .add_size), ._, ._ }, |
| 8521 | .{ ._, ._, .sub, .tmp2d, .si(1), ._, ._ }, |
| 8522 | .{ ._, ._b, .j, .@"1b", ._, ._, ._ }, |
| 8523 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8524 | .{ ._, ._, .@"test", .tmp3p, .tmp3p, ._, ._ }, |
| 8525 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8526 | .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ }, |
| 8527 | .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ }, |
| 8528 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8529 | .{ ._, ._, .cmp, .tmp1b, .sa(.dst0, .add_len), ._, ._ }, |
| 8530 | .{ ._, ._b, .j, .@"0b", ._, ._, ._ }, |
| 8531 | } }, |
| 8532 | }, .{ |
| 8533 | .required_features = .{ .@"64bit", null, null, null }, |
| 8534 | .dst_constraints = .{.{ .bool_vec = .qword }}, |
| 8535 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 8536 | .patterns = &.{ |
| 8537 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8538 | }, |
| 8539 | .extra_temps = .{ |
| 8540 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8541 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8542 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 8543 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8544 | .unused, |
| 8545 | .unused, |
| 8546 | }, |
| 8547 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8548 | .clobbers = .{ .eflags = true }, |
| 8549 | .each = .{ .once = &.{ |
| 8550 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8551 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8552 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8553 | .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8554 | .{ ._, ._, .mov, .tmp3b, .memia(.src0b, .tmp0, .add_size), ._, ._ }, |
| 8555 | .{ ._, ._, .cmp, .tmp3b, .memia(.src1b, .tmp0, .add_size), ._, ._ }, |
| 8556 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8557 | .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ }, |
| 8558 | .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ }, |
| 8559 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8560 | .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 8561 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8562 | } }, |
| 8563 | }, .{ |
| 8564 | .required_features = .{ .@"64bit", null, null, null }, |
| 8565 | .dst_constraints = .{.{ .bool_vec = .qword }}, |
| 8566 | .src_constraints = .{ .{ .scalar_int = .word }, .{ .scalar_int = .word } }, |
| 8567 | .patterns = &.{ |
| 8568 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8569 | }, |
| 8570 | .extra_temps = .{ |
| 8571 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8572 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8573 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 8574 | .{ .type = .u16, .kind = .{ .rc = .general_purpose } }, |
| 8575 | .unused, |
| 8576 | .unused, |
| 8577 | }, |
| 8578 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8579 | .clobbers = .{ .eflags = true }, |
| 8580 | .each = .{ .once = &.{ |
| 8581 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8582 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8583 | .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8584 | .{ ._, ._, .mov, .tmp3w, .memia(.src0w, .tmp0, .add_size), ._, ._ }, |
| 8585 | .{ ._, ._, .cmp, .tmp3w, .memia(.src1w, .tmp0, .add_size), ._, ._ }, |
| 8586 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8587 | .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ }, |
| 8588 | .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ }, |
| 8589 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8590 | .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ }, |
| 8591 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8592 | } }, |
| 8593 | }, .{ |
| 8594 | .required_features = .{ .@"64bit", null, null, null }, |
| 8595 | .dst_constraints = .{.{ .bool_vec = .qword }}, |
| 8596 | .src_constraints = .{ .{ .scalar_int = .dword }, .{ .scalar_int = .dword } }, |
| 8597 | .patterns = &.{ |
| 8598 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8599 | }, |
| 8600 | .extra_temps = .{ |
| 8601 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8602 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8603 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 8604 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 8605 | .unused, |
| 8606 | .unused, |
| 8607 | }, |
| 8608 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8609 | .clobbers = .{ .eflags = true }, |
| 8610 | .each = .{ .once = &.{ |
| 8611 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8612 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8613 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8614 | .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8615 | .{ ._, ._, .mov, .tmp3d, .memia(.src0d, .tmp0, .add_size), ._, ._ }, |
| 8616 | .{ ._, ._, .cmp, .tmp3d, .memia(.src1d, .tmp0, .add_size), ._, ._ }, |
| 8617 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8618 | .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ }, |
| 8619 | .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ }, |
| 8620 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8621 | .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ }, |
| 8622 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8623 | } }, |
| 8624 | }, .{ |
| 8625 | .required_features = .{ .@"64bit", null, null, null }, |
| 8626 | .dst_constraints = .{.{ .bool_vec = .qword }}, |
| 8627 | .src_constraints = .{ .{ .scalar_int = .qword }, .{ .scalar_int = .qword } }, |
| 8628 | .patterns = &.{ |
| 8629 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8630 | }, |
| 8631 | .extra_temps = .{ |
| 8632 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8633 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8634 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 8635 | .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, |
| 8636 | .unused, |
| 8637 | .unused, |
| 8638 | }, |
| 8639 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8640 | .clobbers = .{ .eflags = true }, |
| 8641 | .each = .{ .once = &.{ |
| 8642 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8643 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8644 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8645 | .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8646 | .{ ._, ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 8647 | .{ ._, ._, .cmp, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 8648 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8649 | .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ }, |
| 8650 | .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ }, |
| 8651 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8652 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 8653 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8654 | } }, |
| 8655 | }, .{ |
| 8656 | .required_features = .{ .@"64bit", null, null, null }, |
| 8657 | .dst_constraints = .{.{ .bool_vec = .qword }}, |
| 8658 | .patterns = &.{ |
| 8659 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8660 | }, |
| 8661 | .extra_temps = .{ |
| 8662 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8663 | .{ .type = .u8, .kind = .{ .reg = .cl } }, |
| 8664 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8665 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8666 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8667 | .unused, |
| 8668 | }, |
| 8669 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8670 | .clobbers = .{ .eflags = true }, |
| 8671 | .each = .{ .once = &.{ |
| 8672 | .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ }, |
| 8673 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 8674 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8675 | .{ .@"0:", ._, .mov, .tmp2d, .sa(.src0p, .add_elem_limbs), ._, ._ }, |
| 8676 | .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ }, |
| 8677 | .{ .@"1:", ._, .mov, .tmp4p, .memi(.src0p, .tmp0), ._, ._ }, |
| 8678 | .{ ._, ._, .xor, .tmp4p, .memi(.src1p, .tmp0), ._, ._ }, |
| 8679 | .{ ._, ._, .@"or", .tmp3p, .tmp4p, ._, ._ }, |
| 8680 | .{ ._, ._, .add, .tmp0p, .sa(.tmp4, .add_size), ._, ._ }, |
| 8681 | .{ ._, ._, .sub, .tmp2d, .si(1), ._, ._ }, |
| 8682 | .{ ._, ._b, .j, .@"1b", ._, ._, ._ }, |
| 8683 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8684 | .{ ._, ._, .@"test", .tmp3p, .tmp3p, ._, ._ }, |
| 8685 | .{ ._, .fromCondition(cc), .set, .tmp2b, ._, ._, ._ }, |
| 8686 | .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ }, |
| 8687 | .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ }, |
| 8688 | .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ }, |
| 8689 | .{ ._, ._, .cmp, .tmp1b, .sa(.dst0, .add_len), ._, ._ }, |
| 8690 | .{ ._, ._b, .j, .@"0b", ._, ._, ._ }, |
| 8691 | } }, |
| 8692 | }, .{ |
| 8693 | .src_constraints = .{ .{ .scalar_int = .byte }, .{ .scalar_int = .byte } }, |
| 8694 | .patterns = &.{ |
| 8695 | .{ .src = .{ .to_mem, .to_mem } }, |
| 8696 | }, |
| 8697 | .extra_temps = .{ |
| 8698 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8699 | .{ .type = .u32, .kind = .{ .reg = .ecx } }, |
| 8700 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8701 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8702 | .{ .type = .u8, .kind = .{ .rc = .general_purpose } }, |
| 8703 | .unused, |
| 8704 | }, |
| 8705 | .dst_temps = .{.mem}, |
| 8706 | .clobbers = .{ .eflags = true }, |
| 8707 | .each = .{ .once = &.{ |
| 8708 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8709 | .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ }, |
| 8710 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8711 | .{ .@"0:", ._, .xor, .tmp3d, .tmp3d, ._, ._ }, |
| 8712 | .{ ._, ._, .mov, .tmp4b, .memia(.src0b, .tmp0, .add_size), ._, ._ }, |
| 8713 | .{ ._, ._, .cmp, .tmp4b, .memia(.src1b, .tmp0, .add_size), ._, ._ }, |
| 8714 | .{ ._, .fromCondition(cc), .set, .tmp3b, ._, ._, ._ }, |
| 8715 | .{ ._, ._l, .sh, .tmp3p, .tmp1b, ._, ._ }, |
| 8716 | .{ ._, ._, .@"or", .tmp2p, .tmp3p, ._, ._ }, |
| 8717 | .{ ._, ._, .add, .tmp1d, .si(1), ._, ._ }, |
| 8718 | .{ ._, ._, .@"test", .tmp1d, .sia(-1, .none, .add_ptr_bit_size), ._, ._ }, |
| 8719 | .{ ._, ._nz, .j, .@"1f", ._, ._, ._ }, |
| 8720 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 8721 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 8722 | .{ ._, ._, .mov, .memia(.dst0p, .tmp3, .sub_ptr_size), .tmp2p, ._, ._ }, |
| 8723 | .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ }, |
| 8724 | .{ .@"1:", ._, .add, .tmp0p, .si(1), ._, ._ }, |
| 8725 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8726 | .{ ._, ._, .@"test", .tmp1d, .sia(-1, .none, .add_ptr_bit_size), ._, ._ }, |
| 8727 | .{ ._, ._z, .j, .@"0f", ._, ._, ._ }, |
| 8728 | .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ }, |
| 8729 | .{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ }, |
| 8730 | .{ ._, ._, .mov, .memi(.dst0p, .tmp3), .tmp2p, ._, ._ }, |
| 8731 | } }, |
| 8732 | } }, |
| 8733 | }) catch |err| switch (err) { |
| 8734 | error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ |
| 8735 | @tagName(air_tag), |
| 8736 | cg.typeOf(extra.lhs).fmt(pt), |
| 8737 | ops[0].tracking(cg), |
| 8738 | ops[1].tracking(cg), |
| 8739 | }), |
| 8740 | else => |e| return e, |
| 8741 | }, |
| 8742 | .gte => unreachable, |
| 8743 | .gt => unreachable, |
| 8744 | } |
| 8745 | for (ops) |op| for (res) |r| { |
| 8746 | if (op.index == r.index) break; |
| 8747 | } else try op.die(cg); |
| 8748 | try res[0].moveTo(inst, cg); |
| 8749 | }, |
| 8750 | |
| 8751 | .cmp_lt, |
| 8752 | .cmp_lt_optimized, |
| 8753 | .cmp_lte, |
| 8754 | .cmp_lte_optimized, |
| 8755 | .cmp_gte, |
| 8756 | .cmp_gte_optimized, |
| 8757 | .cmp_gt, |
| 8758 | .cmp_gt_optimized, |
| 8759 | => |air_tag| if (use_old) try cg.airCmp(inst, switch (air_tag) { |
| 8760 | else => unreachable, |
| 8761 | .cmp_lt, .cmp_lt_optimized => .lt, |
| 8762 | .cmp_lte, .cmp_lte_optimized => .lte, |
| 8763 | .cmp_gte, .cmp_gte_optimized => .gte, |
| 8764 | .cmp_gt, .cmp_gt_optimized => .gt, |
| 8765 | }) else fallback: { |
| 8766 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 8767 | const scalar_ty = cg.typeOf(bin_op.lhs).scalarType(zcu); |
| 8768 | if (scalar_ty.isRuntimeFloat()) break :fallback try cg.airCmp(inst, switch (air_tag) { |
| 8769 | else => unreachable, |
| 8770 | .cmp_lt, .cmp_lt_optimized => .lt, |
| 8771 | .cmp_lte, .cmp_lte_optimized => .lte, |
| 8772 | .cmp_gte, .cmp_gte_optimized => .gte, |
| 8773 | .cmp_gt, .cmp_gt_optimized => .gt, |
| 8774 | }); |
| 8775 | const signedness = if (scalar_ty.isAbiInt(zcu)) |
| 8776 | scalar_ty.intInfo(zcu).signedness |
| 8777 | else |
| 8778 | .unsigned; |
| 8779 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 8780 | var res: [1]Temp = undefined; |
| 8781 | cg.select(&res, &.{.bool}, &ops, switch (@as(Condition, switch (signedness) { |
| 8782 | .signed => switch (air_tag) { |
| 8783 | else => unreachable, |
| 8784 | .cmp_lt, .cmp_lt_optimized => .l, |
| 8785 | .cmp_lte, .cmp_lte_optimized => .le, |
| 8786 | .cmp_gte, .cmp_gte_optimized => .ge, |
| 8787 | .cmp_gt, .cmp_gt_optimized => .g, |
| 8788 | }, |
| 8789 | .unsigned => switch (air_tag) { |
| 8790 | else => unreachable, |
| 8791 | .cmp_lt, .cmp_lt_optimized => .b, |
| 8792 | .cmp_lte, .cmp_lte_optimized => .be, |
| 8793 | .cmp_gte, .cmp_gte_optimized => .ae, |
| 8794 | .cmp_gt, .cmp_gt_optimized => .a, |
| 8795 | }, |
| 8796 | })) { |
| 8797 | else => unreachable, |
| 8798 | inline .l, .le, .ge, .g, .b, .be, .ae, .a => |cc| comptime &.{ .{ |
| 8799 | .src_constraints = .{ .{ .int = .byte }, .{ .int = .byte } }, |
| 8800 | .patterns = &.{ |
| 8801 | .{ .src = .{ .imm8, .mem }, .commute = .{ 0, 1 } }, |
| 8802 | .{ .src = .{ .imm8, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8803 | .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8804 | }, |
| 8805 | .dst_temps = .{.{ .cc = cc.commute() }}, |
| 8806 | .clobbers = .{ .eflags = true }, |
| 8807 | .each = .{ .once = &.{ |
| 8808 | .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ }, |
| 8809 | } }, |
| 8810 | }, .{ |
| 8811 | .src_constraints = .{ .{ .int = .byte }, .{ .int = .byte } }, |
| 8812 | .patterns = &.{ |
| 8813 | .{ .src = .{ .mem, .imm8 } }, |
| 8814 | .{ .src = .{ .to_gpr, .imm8 } }, |
| 8815 | .{ .src = .{ .to_gpr, .mem } }, |
| 8816 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 8817 | }, |
| 8818 | .dst_temps = .{.{ .cc = cc }}, |
| 8819 | .clobbers = .{ .eflags = true }, |
| 8820 | .each = .{ .once = &.{ |
| 8821 | .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ }, |
| 8822 | } }, |
| 8823 | }, .{ |
| 8824 | .src_constraints = .{ .{ .int = .word }, .{ .int = .word } }, |
| 8825 | .patterns = &.{ |
| 8826 | .{ .src = .{ .imm16, .mem }, .commute = .{ 0, 1 } }, |
| 8827 | .{ .src = .{ .imm16, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8828 | .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8829 | }, |
| 8830 | .dst_temps = .{.{ .cc = cc.commute() }}, |
| 8831 | .clobbers = .{ .eflags = true }, |
| 8832 | .each = .{ .once = &.{ |
| 8833 | .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ }, |
| 8834 | } }, |
| 8835 | }, .{ |
| 8836 | .src_constraints = .{ .{ .int = .word }, .{ .int = .word } }, |
| 8837 | .patterns = &.{ |
| 8838 | .{ .src = .{ .mem, .imm16 } }, |
| 8839 | .{ .src = .{ .to_gpr, .imm16 } }, |
| 8840 | .{ .src = .{ .to_gpr, .mem } }, |
| 8841 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 8842 | }, |
| 8843 | .dst_temps = .{.{ .cc = cc }}, |
| 8844 | .clobbers = .{ .eflags = true }, |
| 8845 | .each = .{ .once = &.{ |
| 8846 | .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ }, |
| 8847 | } }, |
| 8848 | }, .{ |
| 8849 | .src_constraints = .{ .{ .int = .dword }, .{ .int = .dword } }, |
| 8850 | .patterns = &.{ |
| 8851 | .{ .src = .{ .imm32, .mem }, .commute = .{ 0, 1 } }, |
| 8852 | .{ .src = .{ .imm32, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8853 | .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8854 | }, |
| 8855 | .dst_temps = .{.{ .cc = cc.commute() }}, |
| 8856 | .clobbers = .{ .eflags = true }, |
| 8857 | .each = .{ .once = &.{ |
| 8858 | .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ }, |
| 8859 | } }, |
| 8860 | }, .{ |
| 8861 | .src_constraints = .{ .{ .int = .dword }, .{ .int = .dword } }, |
| 8862 | .patterns = &.{ |
| 8863 | .{ .src = .{ .mem, .imm32 } }, |
| 8864 | .{ .src = .{ .to_gpr, .imm32 } }, |
| 8865 | .{ .src = .{ .to_gpr, .mem } }, |
| 8866 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 8867 | }, |
| 8868 | .dst_temps = .{.{ .cc = cc }}, |
| 8869 | .clobbers = .{ .eflags = true }, |
| 8870 | .each = .{ .once = &.{ |
| 8871 | .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ }, |
| 8872 | } }, |
| 8873 | }, .{ |
| 8874 | .required_features = .{ .@"64bit", null, null, null }, |
| 8875 | .src_constraints = .{ .{ .int = .qword }, .{ .int = .qword } }, |
| 8876 | .patterns = &.{ |
| 8877 | .{ .src = .{ .simm32, .mem }, .commute = .{ 0, 1 } }, |
| 8878 | .{ .src = .{ .simm32, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8879 | .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8880 | }, |
| 8881 | .dst_temps = .{.{ .cc = cc.commute() }}, |
| 8882 | .clobbers = .{ .eflags = true }, |
| 8883 | .each = .{ .once = &.{ |
| 8884 | .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ }, |
| 8885 | } }, |
| 8886 | }, .{ |
| 8887 | .required_features = .{ .@"64bit", null, null, null }, |
| 8888 | .src_constraints = .{ .{ .int = .qword }, .{ .int = .qword } }, |
| 8889 | .patterns = &.{ |
| 8890 | .{ .src = .{ .mem, .simm32 } }, |
| 8891 | .{ .src = .{ .to_gpr, .simm32 } }, |
| 8892 | .{ .src = .{ .to_gpr, .mem } }, |
| 8893 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 8894 | }, |
| 8895 | .dst_temps = .{.{ .cc = cc }}, |
| 8896 | .clobbers = .{ .eflags = true }, |
| 8897 | .each = .{ .once = &.{ |
| 8898 | .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ }, |
| 8899 | } }, |
| 8900 | }, .{ |
| 8901 | .src_constraints = .{ .any_int, .any_int }, |
| 8902 | .patterns = &.{ |
| 8903 | .{ .src = .{ .to_mem, .to_mem }, .commute = switch (cc) { |
| 8904 | else => unreachable, |
| 8905 | .l, .ge, .b, .ae => .{ 0, 0 }, |
| 8906 | .le, .g, .be, .a => .{ 0, 1 }, |
| 8907 | } }, |
| 8908 | }, |
| 8909 | .extra_temps = .{ |
| 8910 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 8911 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 8912 | .unused, |
| 8913 | .unused, |
| 8914 | .unused, |
| 8915 | .unused, |
| 8916 | }, |
| 8917 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 8918 | .clobbers = .{ .eflags = true }, |
| 8919 | .each = .{ .once = &.{ |
| 8920 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 8921 | .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, |
| 8922 | .{ .@"0:", ._r, .sh, .tmp1b, .si(1), ._, ._ }, |
| 8923 | .{ ._, ._, .mov, .tmp1p, .memia(.src0p, .tmp0, .add_size), ._, ._ }, |
| 8924 | .{ ._, ._, .sbb, .tmp1p, .memia(.src1p, .tmp0, .add_size), ._, ._ }, |
| 8925 | .{ ._, ._c, .set, .tmp1b, ._, ._, ._ }, |
| 8926 | .{ ._, .fromCondition(switch (cc) { |
| 8927 | else => unreachable, |
| 8928 | .l, .ge, .b, .ae => cc, |
| 8929 | .le, .g, .be, .a => cc.commute(), |
| 8930 | }), .set, .dst0b, ._, ._, ._ }, |
| 8931 | .{ ._, ._, .add, .tmp0p, .sa(.tmp1, .add_size), ._, ._ }, |
| 8932 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 8933 | } }, |
| 8934 | } }, |
| 8935 | }) catch |err| switch (err) { |
| 8936 | error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ |
| 8937 | @tagName(air_tag), |
| 8938 | cg.typeOf(bin_op.lhs).fmt(pt), |
| 8939 | ops[0].tracking(cg), |
| 8940 | ops[1].tracking(cg), |
| 8941 | }), |
| 8942 | else => |e| return e, |
| 8943 | }; |
| 8944 | for (ops) |op| for (res) |r| { |
| 8945 | if (op.index == r.index) break; |
| 8946 | } else try op.die(cg); |
| 8947 | try res[0].moveTo(inst, cg); |
| 8948 | }, |
| 8949 | .cmp_eq, |
| 8950 | .cmp_eq_optimized, |
| 8951 | .cmp_neq, |
| 8952 | .cmp_neq_optimized, |
| 8953 | => |air_tag| if (use_old) try cg.airCmp(inst, switch (air_tag) { |
| 8954 | else => unreachable, |
| 8955 | .cmp_eq, .cmp_eq_optimized => .eq, |
| 8956 | .cmp_neq, .cmp_neq_optimized => .neq, |
| 8957 | }) else fallback: { |
| 8958 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 8959 | const scalar_ty = cg.typeOf(bin_op.lhs).scalarType(zcu); |
| 8960 | if (intInfo(scalar_ty, cg) == null) break :fallback try cg.airCmp(inst, switch (air_tag) { |
| 8961 | else => unreachable, |
| 8962 | .cmp_eq, .cmp_eq_optimized => .eq, |
| 8963 | .cmp_neq, .cmp_neq_optimized => .neq, |
| 8964 | }); |
| 8965 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 8966 | var res: [1]Temp = undefined; |
| 8967 | cg.select(&res, &.{.bool}, &ops, switch (@as(Condition, switch (air_tag) { |
| 8968 | else => unreachable, |
| 8969 | .cmp_eq, .cmp_eq_optimized => .e, |
| 8970 | .cmp_neq, .cmp_neq_optimized => .ne, |
| 8971 | })) { |
| 8972 | else => unreachable, |
| 8973 | inline .e, .ne => |cc| comptime &.{ .{ |
| 8974 | .src_constraints = .{ .{ .int = .byte }, .{ .int = .byte } }, |
| 8975 | .patterns = &.{ |
| 8976 | .{ .src = .{ .mem, .imm8 } }, |
| 8977 | .{ .src = .{ .imm8, .mem }, .commute = .{ 0, 1 } }, |
| 8978 | .{ .src = .{ .to_gpr, .imm8 } }, |
| 8979 | .{ .src = .{ .imm8, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8980 | .{ .src = .{ .to_gpr, .mem } }, |
| 8981 | .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8982 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 8983 | }, |
| 8984 | .dst_temps = .{.{ .cc = cc }}, |
| 8985 | .clobbers = .{ .eflags = true }, |
| 8986 | .each = .{ .once = &.{ |
| 8987 | .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ }, |
| 8988 | } }, |
| 8989 | }, .{ |
| 8990 | .src_constraints = .{ .{ .int = .word }, .{ .int = .word } }, |
| 8991 | .patterns = &.{ |
| 8992 | .{ .src = .{ .mem, .imm16 } }, |
| 8993 | .{ .src = .{ .imm16, .mem }, .commute = .{ 0, 1 } }, |
| 8994 | .{ .src = .{ .to_gpr, .imm16 } }, |
| 8995 | .{ .src = .{ .imm16, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8996 | .{ .src = .{ .to_gpr, .mem } }, |
| 8997 | .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } }, |
| 8998 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 8999 | }, |
| 9000 | .dst_temps = .{.{ .cc = cc }}, |
| 9001 | .clobbers = .{ .eflags = true }, |
| 9002 | .each = .{ .once = &.{ |
| 9003 | .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ }, |
| 9004 | } }, |
| 9005 | }, .{ |
| 9006 | .src_constraints = .{ .{ .int = .dword }, .{ .int = .dword } }, |
| 9007 | .patterns = &.{ |
| 9008 | .{ .src = .{ .mem, .imm32 } }, |
| 9009 | .{ .src = .{ .imm32, .mem }, .commute = .{ 0, 1 } }, |
| 9010 | .{ .src = .{ .to_gpr, .imm32 } }, |
| 9011 | .{ .src = .{ .imm32, .to_gpr }, .commute = .{ 0, 1 } }, |
| 9012 | .{ .src = .{ .to_gpr, .mem } }, |
| 9013 | .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } }, |
| 9014 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 9015 | }, |
| 9016 | .dst_temps = .{.{ .cc = cc }}, |
| 9017 | .clobbers = .{ .eflags = true }, |
| 9018 | .each = .{ .once = &.{ |
| 9019 | .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ }, |
| 9020 | } }, |
| 9021 | }, .{ |
| 9022 | .required_features = .{ .@"64bit", null, null, null }, |
| 9023 | .src_constraints = .{ .{ .int = .qword }, .{ .int = .qword } }, |
| 9024 | .patterns = &.{ |
| 9025 | .{ .src = .{ .mem, .simm32 } }, |
| 9026 | .{ .src = .{ .simm32, .mem }, .commute = .{ 0, 1 } }, |
| 9027 | .{ .src = .{ .to_gpr, .simm32 } }, |
| 9028 | .{ .src = .{ .simm32, .to_gpr }, .commute = .{ 0, 1 } }, |
| 9029 | .{ .src = .{ .to_gpr, .mem } }, |
| 9030 | .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } }, |
| 9031 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 9032 | }, |
| 9033 | .dst_temps = .{.{ .cc = cc }}, |
| 9034 | .clobbers = .{ .eflags = true }, |
| 9035 | .each = .{ .once = &.{ |
| 9036 | .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ }, |
| 9037 | } }, |
| 9038 | }, .{ |
| 9039 | .required_features = .{ .sse, .mmx, null, null }, |
| 9040 | .src_constraints = .{ .{ .int = .qword }, .{ .int = .qword } }, |
| 9041 | .patterns = &.{ |
| 9042 | .{ .src = .{ .to_mut_mm, .mem } }, |
| 9043 | .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } }, |
| 9044 | .{ .src = .{ .to_mut_mm, .to_mm } }, |
| 9045 | }, |
| 9046 | .extra_temps = .{ |
| 9047 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 9048 | .{ .kind = .{ .rc = .mmx } }, |
| 9049 | .unused, |
| 9050 | .unused, |
| 9051 | .unused, |
| 9052 | .unused, |
| 9053 | }, |
| 9054 | .dst_temps = .{.{ .cc = cc }}, |
| 9055 | .clobbers = .{ .eflags = true }, |
| 9056 | .each = .{ .once = &.{ |
| 9057 | .{ ._, .p_, .xor, .tmp1q, .tmp1q, ._, ._ }, |
| 9058 | .{ ._, .p_, .xor, .src0q, .src1q, ._, ._ }, |
| 9059 | .{ ._, .p_b, .cmpeq, .tmp1q, .src0q, ._, ._ }, |
| 9060 | .{ ._, .p_b, .movmsk, .tmp0d, .tmp1q, ._, ._ }, |
| 9061 | .{ ._, ._, .xor, .tmp0d, .si(0xff), ._, ._ }, |
| 9062 | } }, |
| 9063 | }, .{ |
| 9064 | .required_features = .{ .avx, null, null, null }, |
| 9065 | .src_constraints = .{ .{ .int = .xword }, .{ .int = .xword } }, |
| 9066 | .patterns = &.{ |
| 9067 | .{ .src = .{ .to_xmm, .mem } }, |
| 9068 | .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } }, |
| 9069 | .{ .src = .{ .to_xmm, .to_xmm } }, |
| 9070 | }, |
| 9071 | .extra_temps = .{ |
| 9072 | .{ .kind = .{ .rc = .sse } }, |
| 9073 | .unused, |
| 9074 | .unused, |
| 9075 | .unused, |
| 9076 | .unused, |
| 9077 | .unused, |
| 9078 | }, |
| 9079 | .dst_temps = .{.{ .cc = cc }}, |
| 9080 | .clobbers = .{ .eflags = true }, |
| 9081 | .each = .{ .once = &.{ |
| 9082 | .{ ._, .vp_, .xor, .tmp0x, .src0x, .src1x, ._ }, |
| 9083 | .{ ._, .vp_, .@"test", .tmp0x, .tmp0x, ._, ._ }, |
| 9084 | } }, |
| 9085 | }, .{ |
| 9086 | .required_features = .{ .sse4_1, null, null, null }, |
| 9087 | .src_constraints = .{ .{ .int = .xword }, .{ .int = .xword } }, |
| 9088 | .patterns = &.{ |
| 9089 | .{ .src = .{ .to_mut_xmm, .mem } }, |
| 9090 | .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } }, |
| 9091 | .{ .src = .{ .to_mut_xmm, .to_xmm } }, |
| 9092 | }, |
| 9093 | .dst_temps = .{.{ .cc = cc }}, |
| 9094 | .clobbers = .{ .eflags = true }, |
| 9095 | .each = .{ .once = &.{ |
| 9096 | .{ ._, .p_, .xor, .src0x, .src1x, ._, ._ }, |
| 9097 | .{ ._, .p_, .@"test", .src0x, .src0x, ._, ._ }, |
| 9098 | } }, |
| 9099 | }, .{ |
| 9100 | .required_features = .{ .sse2, null, null, null }, |
| 9101 | .src_constraints = .{ .{ .int = .xword }, .{ .int = .xword } }, |
| 9102 | .patterns = &.{ |
| 9103 | .{ .src = .{ .to_mut_xmm, .mem } }, |
| 9104 | .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } }, |
| 9105 | .{ .src = .{ .to_mut_xmm, .to_xmm } }, |
| 9106 | }, |
| 9107 | .extra_temps = .{ |
| 9108 | .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, |
| 9109 | .{ .kind = .{ .rc = .sse } }, |
| 9110 | .unused, |
| 9111 | .unused, |
| 9112 | .unused, |
| 9113 | .unused, |
| 9114 | }, |
| 9115 | .dst_temps = .{.{ .cc = cc }}, |
| 9116 | .clobbers = .{ .eflags = true }, |
| 9117 | .each = .{ .once = &.{ |
| 9118 | .{ ._, .p_, .xor, .tmp1x, .tmp1x, ._, ._ }, |
| 9119 | .{ ._, .p_, .xor, .src0x, .src1x, ._, ._ }, |
| 9120 | .{ ._, .p_b, .cmpeq, .tmp1x, .src0x, ._, ._ }, |
| 9121 | .{ ._, .p_b, .movmsk, .tmp0d, .tmp1x, ._, ._ }, |
| 9122 | .{ ._, ._, .xor, .tmp0d, .si(0xffff), ._, ._ }, |
| 9123 | } }, |
| 9124 | }, .{ |
| 9125 | .required_features = .{ .avx2, null, null, null }, |
| 9126 | .src_constraints = .{ .{ .int = .yword }, .{ .int = .yword } }, |
| 9127 | .patterns = &.{ |
| 9128 | .{ .src = .{ .to_ymm, .mem } }, |
| 9129 | .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } }, |
| 9130 | .{ .src = .{ .to_ymm, .to_ymm } }, |
| 9131 | }, |
| 9132 | .extra_temps = .{ |
| 9133 | .{ .kind = .{ .rc = .sse } }, |
| 9134 | .unused, |
| 9135 | .unused, |
| 9136 | .unused, |
| 9137 | .unused, |
| 9138 | .unused, |
| 9139 | }, |
| 9140 | .dst_temps = .{.{ .cc = cc }}, |
| 9141 | .clobbers = .{ .eflags = true }, |
| 9142 | .each = .{ .once = &.{ |
| 9143 | .{ ._, .vp_, .xor, .tmp0y, .src0y, .src1y, ._ }, |
| 9144 | .{ ._, .vp_, .@"test", .tmp0y, .tmp0y, ._, ._ }, |
| 9145 | } }, |
| 9146 | }, .{ |
| 9147 | .required_features = .{ .avx, null, null, null }, |
| 9148 | .src_constraints = .{ .{ .int = .yword }, .{ .int = .yword } }, |
| 9149 | .patterns = &.{ |
| 9150 | .{ .src = .{ .to_ymm, .mem } }, |
| 9151 | .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } }, |
| 9152 | .{ .src = .{ .to_ymm, .to_ymm } }, |
| 9153 | }, |
| 9154 | .extra_temps = .{ |
| 9155 | .{ .kind = .{ .rc = .sse } }, |
| 9156 | .unused, |
| 9157 | .unused, |
| 9158 | .unused, |
| 9159 | .unused, |
| 9160 | .unused, |
| 9161 | }, |
| 9162 | .dst_temps = .{.{ .cc = cc }}, |
| 9163 | .clobbers = .{ .eflags = true }, |
| 9164 | .each = .{ .once = &.{ |
| 9165 | .{ ._, .v_pd, .xor, .tmp0y, .src0y, .src1y, ._ }, |
| 9166 | .{ ._, .vp_, .@"test", .tmp0y, .tmp0y, ._, ._ }, |
| 9167 | } }, |
| 9168 | }, .{ |
| 9169 | .required_features = .{ .avx2, null, null, null }, |
| 9170 | .src_constraints = .{ |
| 9171 | .{ .remainder_int = .{ .of = .yword, .is = .xword } }, |
| 9172 | .{ .remainder_int = .{ .of = .yword, .is = .xword } }, |
| 9173 | }, |
| 9174 | .patterns = &.{ |
| 9175 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9176 | }, |
| 9177 | .extra_temps = .{ |
| 9178 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9179 | .{ .kind = .{ .rc = .sse } }, |
| 9180 | .{ .kind = .{ .rc = .sse } }, |
| 9181 | .unused, |
| 9182 | .unused, |
| 9183 | .unused, |
| 9184 | }, |
| 9185 | .dst_temps = .{.{ .cc = cc }}, |
| 9186 | .clobbers = .{ .eflags = true }, |
| 9187 | .each = .{ .once = &.{ |
| 9188 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 9189 | .{ ._, .vp_, .xor, .tmp1y, .tmp1y, .tmp1y, ._ }, |
| 9190 | .{ .@"0:", .v_dqu, .mov, .tmp2y, .memiad(.src0y, .tmp0, .add_size, -16), ._, ._ }, |
| 9191 | .{ ._, .vp_, .xor, .tmp2y, .tmp2y, .memiad(.src1y, .tmp0, .add_size, -16), ._ }, |
| 9192 | .{ ._, .vp_, .@"or", .tmp1y, .tmp1y, .tmp2y, ._ }, |
| 9193 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 9194 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9195 | .{ ._, .v_dqa, .mov, .tmp2x, .memad(.src0x, .add_size, -16), ._, ._ }, |
| 9196 | .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .memad(.src1x, .add_size, -16), ._ }, |
| 9197 | .{ ._, .vp_, .@"or", .tmp1y, .tmp1y, .tmp2y, ._ }, |
| 9198 | .{ ._, .vp_, .@"test", .tmp1y, .tmp1y, ._, ._ }, |
| 9199 | } }, |
| 9200 | }, .{ |
| 9201 | .required_features = .{ .avx2, null, null, null }, |
| 9202 | .patterns = &.{ |
| 9203 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9204 | }, |
| 9205 | .extra_temps = .{ |
| 9206 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9207 | .{ .kind = .{ .rc = .sse } }, |
| 9208 | .{ .kind = .{ .rc = .sse } }, |
| 9209 | .unused, |
| 9210 | .unused, |
| 9211 | .unused, |
| 9212 | }, |
| 9213 | .dst_temps = .{.{ .cc = cc }}, |
| 9214 | .clobbers = .{ .eflags = true }, |
| 9215 | .each = .{ .once = &.{ |
| 9216 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 9217 | .{ ._, .vp_, .xor, .tmp1y, .tmp1y, .tmp1y, ._ }, |
| 9218 | .{ .@"0:", .v_dqu, .mov, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 9219 | .{ ._, .vp_, .xor, .tmp2y, .tmp2y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 9220 | .{ ._, .vp_, .@"or", .tmp1y, .tmp1y, .tmp2y, ._ }, |
| 9221 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 9222 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9223 | .{ ._, .vp_, .@"test", .tmp1y, .tmp1y, ._, ._ }, |
| 9224 | } }, |
| 9225 | }, .{ |
| 9226 | .required_features = .{ .avx, null, null, null }, |
| 9227 | .src_constraints = .{ |
| 9228 | .{ .remainder_int = .{ .of = .yword, .is = .xword } }, |
| 9229 | .{ .remainder_int = .{ .of = .yword, .is = .xword } }, |
| 9230 | }, |
| 9231 | .patterns = &.{ |
| 9232 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9233 | }, |
| 9234 | .extra_temps = .{ |
| 9235 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9236 | .{ .kind = .{ .rc = .sse } }, |
| 9237 | .{ .kind = .{ .rc = .sse } }, |
| 9238 | .unused, |
| 9239 | .unused, |
| 9240 | .unused, |
| 9241 | }, |
| 9242 | .dst_temps = .{.{ .cc = cc }}, |
| 9243 | .clobbers = .{ .eflags = true }, |
| 9244 | .each = .{ .once = &.{ |
| 9245 | .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ }, |
| 9246 | .{ ._, .v_pd, .xor, .tmp1y, .tmp1y, .tmp1y, ._ }, |
| 9247 | .{ .@"0:", .v_pd, .movu, .tmp2y, .memiad(.src0y, .tmp0, .add_size, -16), ._, ._ }, |
| 9248 | .{ ._, .v_pd, .xor, .tmp2y, .tmp2y, .memiad(.src1y, .tmp0, .add_size, -16), ._ }, |
| 9249 | .{ ._, .v_pd, .@"or", .tmp1y, .tmp1y, .tmp2y, ._ }, |
| 9250 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 9251 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9252 | .{ ._, .v_pd, .mova, .tmp2x, .memad(.src0x, .add_size, -16), ._, ._ }, |
| 9253 | .{ ._, .v_pd, .xor, .tmp2x, .tmp2x, .memad(.src1x, .add_size, -16), ._ }, |
| 9254 | .{ ._, .v_pd, .@"or", .tmp1y, .tmp1y, .tmp2y, ._ }, |
| 9255 | .{ ._, .vp_, .@"test", .tmp1y, .tmp1y, ._, ._ }, |
| 9256 | } }, |
| 9257 | }, .{ |
| 9258 | .required_features = .{ .avx, null, null, null }, |
| 9259 | .patterns = &.{ |
| 9260 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9261 | }, |
| 9262 | .extra_temps = .{ |
| 9263 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9264 | .{ .kind = .{ .rc = .sse } }, |
| 9265 | .{ .kind = .{ .rc = .sse } }, |
| 9266 | .unused, |
| 9267 | .unused, |
| 9268 | .unused, |
| 9269 | }, |
| 9270 | .dst_temps = .{.{ .cc = cc }}, |
| 9271 | .clobbers = .{ .eflags = true }, |
| 9272 | .each = .{ .once = &.{ |
| 9273 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 9274 | .{ ._, .v_pd, .xor, .tmp1y, .tmp1y, .tmp1y, ._ }, |
| 9275 | .{ .@"0:", .v_pd, .movu, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._, ._ }, |
| 9276 | .{ ._, .v_pd, .xor, .tmp2y, .tmp2y, .memia(.src1y, .tmp0, .add_size), ._ }, |
| 9277 | .{ ._, .v_pd, .@"or", .tmp1y, .tmp1y, .tmp2y, ._ }, |
| 9278 | .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ }, |
| 9279 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9280 | .{ ._, .vp_, .@"test", .tmp1y, .tmp1y, ._, ._ }, |
| 9281 | } }, |
| 9282 | }, .{ |
| 9283 | .required_features = .{ .avx, null, null, null }, |
| 9284 | .patterns = &.{ |
| 9285 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9286 | }, |
| 9287 | .extra_temps = .{ |
| 9288 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9289 | .{ .kind = .{ .rc = .sse } }, |
| 9290 | .{ .kind = .{ .rc = .sse } }, |
| 9291 | .unused, |
| 9292 | .unused, |
| 9293 | .unused, |
| 9294 | }, |
| 9295 | .dst_temps = .{.{ .cc = cc }}, |
| 9296 | .clobbers = .{ .eflags = true }, |
| 9297 | .each = .{ .once = &.{ |
| 9298 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 9299 | .{ ._, .vp_, .xor, .tmp1x, .tmp1x, .tmp1x, ._ }, |
| 9300 | .{ .@"0:", .v_dqu, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 9301 | .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._ }, |
| 9302 | .{ ._, .vp_, .@"or", .tmp1x, .tmp1x, .tmp2x, ._ }, |
| 9303 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 9304 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9305 | .{ ._, .vp_, .@"test", .tmp1x, .tmp1x, ._, ._ }, |
| 9306 | } }, |
| 9307 | }, .{ |
| 9308 | .required_features = .{ .sse4_1, null, null, null }, |
| 9309 | .patterns = &.{ |
| 9310 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9311 | }, |
| 9312 | .extra_temps = .{ |
| 9313 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9314 | .{ .kind = .{ .rc = .sse } }, |
| 9315 | .{ .kind = .{ .rc = .sse } }, |
| 9316 | .unused, |
| 9317 | .unused, |
| 9318 | .unused, |
| 9319 | }, |
| 9320 | .dst_temps = .{.{ .cc = cc }}, |
| 9321 | .clobbers = .{ .eflags = true }, |
| 9322 | .each = .{ .once = &.{ |
| 9323 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 9324 | .{ ._, .p_, .xor, .tmp1x, .tmp1x, ._, ._ }, |
| 9325 | .{ .@"0:", ._dqu, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 9326 | .{ ._, .p_, .xor, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 9327 | .{ ._, .p_, .@"or", .tmp1x, .tmp2x, ._, ._ }, |
| 9328 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 9329 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9330 | .{ ._, .p_, .@"test", .tmp1x, .tmp1x, ._, ._ }, |
| 9331 | } }, |
| 9332 | }, .{ |
| 9333 | .required_features = .{ .sse2, null, null, null }, |
| 9334 | .patterns = &.{ |
| 9335 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9336 | }, |
| 9337 | .extra_temps = .{ |
| 9338 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9339 | .{ .kind = .{ .rc = .sse } }, |
| 9340 | .{ .kind = .{ .rc = .sse } }, |
| 9341 | .unused, |
| 9342 | .unused, |
| 9343 | .unused, |
| 9344 | }, |
| 9345 | .dst_temps = .{.{ .cc = cc }}, |
| 9346 | .clobbers = .{ .eflags = true }, |
| 9347 | .each = .{ .once = &.{ |
| 9348 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 9349 | .{ ._, .p_, .xor, .tmp1x, .tmp1x, ._, ._ }, |
| 9350 | .{ .@"0:", ._dqu, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ }, |
| 9351 | .{ ._, .p_, .xor, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ }, |
| 9352 | .{ ._, .p_, .@"or", .tmp1x, .tmp2x, ._, ._ }, |
| 9353 | .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ }, |
| 9354 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9355 | .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ }, |
| 9356 | .{ ._, .p_b, .cmpeq, .tmp1x, .tmp2x, ._, ._ }, |
| 9357 | .{ ._, .p_b, .movmsk, .tmp0d, .tmp1x, ._, ._ }, |
| 9358 | .{ ._, ._, .cmp, .tmp0d, .si(0xffff), ._, ._ }, |
| 9359 | } }, |
| 9360 | }, .{ |
| 9361 | .required_features = .{ .sse, .mmx, null, null }, |
| 9362 | .patterns = &.{ |
| 9363 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9364 | }, |
| 9365 | .extra_temps = .{ |
| 9366 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9367 | .{ .kind = .{ .rc = .mmx } }, |
| 9368 | .{ .kind = .{ .rc = .mmx } }, |
| 9369 | .unused, |
| 9370 | .unused, |
| 9371 | .unused, |
| 9372 | }, |
| 9373 | .dst_temps = .{.{ .cc = cc }}, |
| 9374 | .clobbers = .{ .eflags = true }, |
| 9375 | .each = .{ .once = &.{ |
| 9376 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 9377 | .{ ._, .p_, .xor, .tmp1q, .tmp1q, ._, ._ }, |
| 9378 | .{ .@"0:", ._q, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ }, |
| 9379 | .{ ._, .p_, .xor, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ }, |
| 9380 | .{ ._, .p_, .@"or", .tmp1q, .tmp2q, ._, ._ }, |
| 9381 | .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ }, |
| 9382 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9383 | .{ ._, .p_, .xor, .tmp2q, .tmp2q, ._, ._ }, |
| 9384 | .{ ._, .p_b, .cmpeq, .tmp1q, .tmp2q, ._, ._ }, |
| 9385 | .{ ._, .p_b, .movmsk, .tmp0d, .tmp1q, ._, ._ }, |
| 9386 | .{ ._, ._, .cmp, .tmp0d, .si(0xff), ._, ._ }, |
| 9387 | } }, |
| 9388 | }, .{ |
| 9389 | .patterns = &.{ |
| 9390 | .{ .src = .{ .to_mem, .to_mem } }, |
| 9391 | }, |
| 9392 | .extra_temps = .{ |
| 9393 | .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, |
| 9394 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 9395 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 9396 | .unused, |
| 9397 | .unused, |
| 9398 | .unused, |
| 9399 | }, |
| 9400 | .dst_temps = .{.{ .cc = cc }}, |
| 9401 | .clobbers = .{ .eflags = true }, |
| 9402 | .each = .{ .once = &.{ |
| 9403 | .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ }, |
| 9404 | .{ ._, ._, .xor, .tmp1p, .tmp1p, ._, ._ }, |
| 9405 | .{ .@"0:", ._, .mov, .tmp2p, .memia(.src0p, .tmp0, .add_size), ._, ._ }, |
| 9406 | .{ ._, ._, .xor, .tmp2p, .memia(.src1p, .tmp0, .add_size), ._, ._ }, |
| 9407 | .{ ._, ._, .@"or", .tmp1p, .tmp2p, ._, ._ }, |
| 9408 | .{ ._, ._, .add, .tmp0p, .sa(.tmp2, .add_size), ._, ._ }, |
| 9409 | .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, |
| 9410 | .{ ._, ._, .@"test", .tmp1p, .tmp1p, ._, ._ }, |
| 9411 | } }, |
| 9412 | } }, |
| 9413 | }) catch |err| switch (err) { |
| 9414 | error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ |
| 9415 | @tagName(air_tag), |
| 9416 | cg.typeOf(bin_op.lhs).fmt(pt), |
| 9417 | ops[0].tracking(cg), |
| 9418 | ops[1].tracking(cg), |
| 9419 | }), |
| 9420 | else => |e| return e, |
| 9421 | }; |
| 9422 | for (ops) |op| for (res) |r| { |
| 9423 | if (op.index == r.index) break; |
| 9424 | } else try op.die(cg); |
| 9425 | try res[0].moveTo(inst, cg); |
| 9426 | }, |
| 9427 | |
| 9428 | .cond_br => try cg.airCondBr(inst), |
| 9429 | .switch_br => try cg.airSwitchBr(inst), |
| 9430 | .loop_switch_br => try cg.airLoopSwitchBr(inst), |
| 9431 | .switch_dispatch => try cg.airSwitchDispatch(inst), |
| 9432 | .@"try", .try_cold => try cg.airTry(inst), |
| 9433 | .try_ptr, .try_ptr_cold => try cg.airTryPtr(inst), |
| 9434 | .dbg_stmt => if (use_old) try cg.airDbgStmt(inst) else { |
| 9435 | const dbg_stmt = air_datas[@intFromEnum(inst)].dbg_stmt; |
| 9436 | _ = try cg.addInst(.{ |
| 9437 | .tag = .pseudo, |
| 9438 | .ops = .pseudo_dbg_line_line_column, |
| 9439 | .data = .{ .line_column = .{ |
| 9440 | .line = dbg_stmt.line, |
| 9441 | .column = dbg_stmt.column, |
| 9442 | } }, |
| 9443 | }); |
| 9444 | }, |
| 9445 | .dbg_empty_stmt => if (use_old) try cg.airDbgEmptyStmt() else { |
| 9446 | if (cg.mir_instructions.len > 0) { |
| 9447 | const prev_mir_op = &cg.mir_instructions.items(.ops)[cg.mir_instructions.len - 1]; |
| 9448 | if (prev_mir_op.* == .pseudo_dbg_line_stmt_line_column) |
| 9449 | prev_mir_op.* = .pseudo_dbg_line_line_column; |
| 9450 | } |
| 9451 | try cg.asmOpOnly(.{ ._, .nop }); |
| 9452 | }, |
| 9453 | .dbg_inline_block => if (use_old) try cg.airDbgInlineBlock(inst) else { |
| 9454 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 9455 | const extra = cg.air.extraData(Air.DbgInlineBlock, ty_pl.payload); |
| 9456 | const old_inline_func = cg.inline_func; |
| 9457 | defer cg.inline_func = old_inline_func; |
| 9458 | cg.inline_func = extra.data.func; |
| 9459 | _ = try cg.addInst(.{ |
| 9460 | .tag = .pseudo, |
| 9461 | .ops = .pseudo_dbg_enter_inline_func, |
| 9462 | .data = .{ .func = extra.data.func }, |
| 9463 | }); |
| 9464 | try cg.lowerBlock(inst, @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len])); |
| 9465 | _ = try cg.addInst(.{ |
| 9466 | .tag = .pseudo, |
| 9467 | .ops = .pseudo_dbg_leave_inline_func, |
| 9468 | .data = .{ .func = old_inline_func }, |
| 9469 | }); |
| 9470 | }, |
| 9471 | .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => if (use_old) try cg.airDbgVar(inst) else { |
| 9472 | const pl_op = air_datas[@intFromEnum(inst)].pl_op; |
| 9473 | var ops = try cg.tempsFromOperands(inst, .{pl_op.operand}); |
| 9474 | try cg.genLocalDebugInfo(inst, ops[0].tracking(cg).short); |
| 9475 | try ops[0].die(cg); |
| 9476 | }, |
| 9477 | .is_null_ptr => if (use_old) try cg.airIsNullPtr(inst) else { |
| 9478 | const un_op = air_datas[@intFromEnum(inst)].un_op; |
| 9479 | const opt_ty = cg.typeOf(un_op).childType(zcu); |
| 9480 | const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu); |
| 9481 | const opt_child_ty = opt_ty.optionalChild(zcu); |
| 9482 | const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu)); |
| 9483 | var ops = try cg.tempsFromOperands(inst, .{un_op}); |
| 9484 | if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, cg); |
| 9485 | while (try ops[0].toLea(cg)) {} |
| 9486 | try cg.asmMemoryImmediate( |
| 9487 | .{ ._, .cmp }, |
| 9488 | try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = if (!opt_repr_is_pl) |
| 9489 | .byte |
| 9490 | else if (opt_child_ty.isSlice(zcu)) |
| 9491 | .qword |
| 9492 | else |
| 9493 | .fromSize(opt_child_abi_size) }), |
| 9494 | .u(0), |
| 9495 | ); |
| 9496 | var is_null = try cg.tempInit(.bool, .{ .eflags = .e }); |
| 9497 | try ops[0].die(cg); |
| 9498 | try is_null.moveTo(inst, cg); |
| 9499 | }, |
| 9500 | .is_non_null_ptr => if (use_old) try cg.airIsNonNullPtr(inst) else { |
| 9501 | const un_op = air_datas[@intFromEnum(inst)].un_op; |
| 9502 | const opt_ty = cg.typeOf(un_op).childType(zcu); |
| 9503 | const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu); |
| 9504 | const opt_child_ty = opt_ty.optionalChild(zcu); |
| 9505 | const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu)); |
| 9506 | var ops = try cg.tempsFromOperands(inst, .{un_op}); |
| 9507 | if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, cg); |
| 9508 | while (try ops[0].toLea(cg)) {} |
| 9509 | try cg.asmMemoryImmediate( |
| 9510 | .{ ._, .cmp }, |
| 9511 | try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = if (!opt_repr_is_pl) |
| 9512 | .byte |
| 9513 | else if (opt_child_ty.isSlice(zcu)) |
| 9514 | .qword |
| 9515 | else |
| 9516 | .fromSize(opt_child_abi_size) }), |
| 9517 | .u(0), |
| 9518 | ); |
| 9519 | var is_non_null = try cg.tempInit(.bool, .{ .eflags = .ne }); |
| 9520 | try ops[0].die(cg); |
| 9521 | try is_non_null.moveTo(inst, cg); |
| 9522 | }, |
| 9523 | .is_err_ptr => if (use_old) try cg.airIsErrPtr(inst) else { |
| 9524 | const un_op = air_datas[@intFromEnum(inst)].un_op; |
| 9525 | const eu_ty = cg.typeOf(un_op).childType(zcu); |
| 9526 | const eu_err_ty = eu_ty.errorUnionSet(zcu); |
| 9527 | const eu_pl_ty = eu_ty.errorUnionPayload(zcu); |
| 9528 | const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu)); |
| 9529 | var ops = try cg.tempsFromOperands(inst, .{un_op}); |
| 9530 | try ops[0].toOffset(eu_err_off, cg); |
| 9531 | while (try ops[0].toLea(cg)) {} |
| 9532 | try cg.asmMemoryImmediate( |
| 9533 | .{ ._, .cmp }, |
| 9534 | try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }), |
| 9535 | .u(0), |
| 9536 | ); |
| 9537 | var is_err = try cg.tempInit(.bool, .{ .eflags = .ne }); |
| 9538 | try ops[0].die(cg); |
| 9539 | try is_err.moveTo(inst, cg); |
| 9540 | }, |
| 9541 | .is_non_err_ptr => if (use_old) try cg.airIsNonErrPtr(inst) else { |
| 9542 | const un_op = air_datas[@intFromEnum(inst)].un_op; |
| 9543 | const eu_ty = cg.typeOf(un_op).childType(zcu); |
| 9544 | const eu_err_ty = eu_ty.errorUnionSet(zcu); |
| 9545 | const eu_pl_ty = eu_ty.errorUnionPayload(zcu); |
| 9546 | const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu)); |
| 9547 | var ops = try cg.tempsFromOperands(inst, .{un_op}); |
| 9548 | try ops[0].toOffset(eu_err_off, cg); |
| 9549 | while (try ops[0].toLea(cg)) {} |
| 9550 | try cg.asmMemoryImmediate( |
| 9551 | .{ ._, .cmp }, |
| 9552 | try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }), |
| 9553 | .u(0), |
| 9554 | ); |
| 9555 | var is_non_err = try cg.tempInit(.bool, .{ .eflags = .e }); |
| 9556 | try ops[0].die(cg); |
| 9557 | try is_non_err.moveTo(inst, cg); |
| 9558 | }, |
| 9559 | .load => if (use_old) try cg.airLoad(inst) else fallback: { |
| 9560 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9561 | const val_ty = ty_op.ty.toType(); |
| 9562 | const ptr_ty = cg.typeOf(ty_op.operand); |
| 9563 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 9564 | if (ptr_info.packed_offset.host_size > 0 and |
| 9565 | (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type)) |
| 9566 | break :fallback try cg.airLoad(inst); |
| 9567 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9568 | var res = try ops[0].load(val_ty, .{ |
| 9569 | .disp = switch (ptr_info.flags.vector_index) { |
| 9570 | .none => 0, |
| 9571 | .runtime => unreachable, |
| 9572 | else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)), |
| 9573 | }, |
| 9574 | }, cg); |
| 9575 | for (ops) |op| if (op.index != res.index) try op.die(cg); |
| 9576 | try res.moveTo(inst, cg); |
| 9577 | }, |
| 9578 | .int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else { |
| 9579 | const un_op = air_datas[@intFromEnum(inst)].un_op; |
| 9580 | var ops = try cg.tempsFromOperands(inst, .{un_op}); |
| 9581 | try ops[0].toSlicePtr(cg); |
| 9582 | try ops[0].moveTo(inst, cg); |
| 9583 | }, |
| 9584 | .int_from_bool => if (use_old) try cg.airIntFromBool(inst) else { |
| 9585 | const un_op = air_datas[@intFromEnum(inst)].un_op; |
| 9586 | var ops = try cg.tempsFromOperands(inst, .{un_op}); |
| 9587 | try ops[0].moveTo(inst, cg); |
| 9588 | }, |
| 9589 | .ret => try cg.airRet(inst, false), |
| 9590 | .ret_safe => try cg.airRet(inst, true), |
| 9591 | .ret_load => try cg.airRetLoad(inst), |
| 9592 | .store, .store_safe => |air_tag| if (use_old) try cg.airStore(inst, switch (air_tag) { |
| 9593 | else => unreachable, |
| 9594 | .store => false, |
| 9595 | .store_safe => true, |
| 9596 | }) else fallback: { |
| 9597 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 9598 | const ptr_ty = cg.typeOf(bin_op.lhs); |
| 9599 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 9600 | const val_ty = cg.typeOf(bin_op.rhs); |
| 9601 | if (ptr_info.packed_offset.host_size > 0 and |
| 9602 | (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type)) |
| 9603 | break :fallback try cg.airStore(inst, switch (air_tag) { |
| 9604 | else => unreachable, |
| 9605 | .store => false, |
| 9606 | .store_safe => true, |
| 9607 | }); |
| 9608 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 9609 | try ops[0].store(&ops[1], .{ |
| 9610 | .disp = switch (ptr_info.flags.vector_index) { |
| 9611 | .none => 0, |
| 9612 | .runtime => unreachable, |
| 9613 | else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)), |
| 9614 | }, |
| 9615 | .safe = switch (air_tag) { |
| 9616 | else => unreachable, |
| 9617 | .store => false, |
| 9618 | .store_safe => true, |
| 9619 | }, |
| 9620 | }, cg); |
| 9621 | for (ops) |op| try op.die(cg); |
| 9622 | }, |
| 9623 | .unreach => {}, |
| 9624 | .optional_payload_ptr => if (use_old) try cg.airOptionalPayloadPtr(inst) else { |
| 9625 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9626 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9627 | try ops[0].moveTo(inst, cg); |
| 9628 | }, |
| 9629 | .optional_payload_ptr_set => if (use_old) try cg.airOptionalPayloadPtrSet(inst) else { |
| 9630 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9631 | const opt_ty = cg.typeOf(ty_op.operand).childType(zcu); |
| 9632 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9633 | if (!opt_ty.optionalReprIsPayload(zcu)) { |
| 9634 | const opt_child_ty = opt_ty.optionalChild(zcu); |
| 9635 | const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu)); |
| 9636 | try ops[0].toOffset(opt_child_abi_size, cg); |
| 9637 | var has_value = try cg.tempInit(.bool, .{ .immediate = 1 }); |
| 9638 | try ops[0].store(&has_value, .{}, cg); |
| 9639 | try has_value.die(cg); |
| 9640 | try ops[0].toOffset(-opt_child_abi_size, cg); |
| 9641 | } |
| 9642 | try ops[0].moveTo(inst, cg); |
| 9643 | }, |
| 9644 | .unwrap_errunion_payload_ptr => if (use_old) try cg.airUnwrapErrUnionPayloadPtr(inst) else { |
| 9645 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9646 | const eu_ty = cg.typeOf(ty_op.operand).childType(zcu); |
| 9647 | const eu_pl_ty = eu_ty.errorUnionPayload(zcu); |
| 9648 | const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu)); |
| 9649 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9650 | try ops[0].toOffset(eu_pl_off, cg); |
| 9651 | try ops[0].moveTo(inst, cg); |
| 9652 | }, |
| 9653 | .unwrap_errunion_err_ptr => if (use_old) try cg.airUnwrapErrUnionErrPtr(inst) else { |
| 9654 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9655 | const eu_ty = cg.typeOf(ty_op.operand).childType(zcu); |
| 9656 | const eu_pl_ty = eu_ty.errorUnionPayload(zcu); |
| 9657 | const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu)); |
| 9658 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9659 | try ops[0].toOffset(eu_err_off, cg); |
| 9660 | var err = try ops[0].load(eu_ty.errorUnionSet(zcu), .{}, cg); |
| 9661 | try ops[0].die(cg); |
| 9662 | try err.moveTo(inst, cg); |
| 9663 | }, |
| 9664 | .errunion_payload_ptr_set => if (use_old) try cg.airErrUnionPayloadPtrSet(inst) else { |
| 9665 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9666 | const eu_ty = cg.typeOf(ty_op.operand).childType(zcu); |
| 9667 | const eu_err_ty = eu_ty.errorUnionSet(zcu); |
| 9668 | const eu_pl_ty = eu_ty.errorUnionPayload(zcu); |
| 9669 | const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu)); |
| 9670 | const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu)); |
| 9671 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9672 | try ops[0].toOffset(eu_err_off, cg); |
| 9673 | var no_err = try cg.tempInit(eu_err_ty, .{ .immediate = 0 }); |
| 9674 | try ops[0].store(&no_err, .{}, cg); |
| 9675 | try no_err.die(cg); |
| 9676 | try ops[0].toOffset(eu_pl_off - eu_err_off, cg); |
| 9677 | try ops[0].moveTo(inst, cg); |
| 9678 | }, |
| 9679 | .struct_field_ptr => if (use_old) try cg.airStructFieldPtr(inst) else { |
| 9680 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 9681 | const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data; |
| 9682 | var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand}); |
| 9683 | try ops[0].toOffset(cg.fieldOffset( |
| 9684 | cg.typeOf(extra.struct_operand), |
| 9685 | ty_pl.ty.toType(), |
| 9686 | extra.field_index, |
| 9687 | ), cg); |
| 9688 | try ops[0].moveTo(inst, cg); |
| 9689 | }, |
| 9690 | .struct_field_ptr_index_0, |
| 9691 | .struct_field_ptr_index_1, |
| 9692 | .struct_field_ptr_index_2, |
| 9693 | .struct_field_ptr_index_3, |
| 9694 | => |air_tag| if (use_old) try cg.airStructFieldPtrIndex(inst, switch (air_tag) { |
| 9695 | else => unreachable, |
| 9696 | .struct_field_ptr_index_0 => 0, |
| 9697 | .struct_field_ptr_index_1 => 1, |
| 9698 | .struct_field_ptr_index_2 => 2, |
| 9699 | .struct_field_ptr_index_3 => 3, |
| 9700 | }) else { |
| 9701 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9702 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9703 | try ops[0].toOffset(cg.fieldOffset( |
| 9704 | cg.typeOf(ty_op.operand), |
| 9705 | ty_op.ty.toType(), |
| 9706 | switch (air_tag) { |
| 9707 | else => unreachable, |
| 9708 | .struct_field_ptr_index_0 => 0, |
| 9709 | .struct_field_ptr_index_1 => 1, |
| 9710 | .struct_field_ptr_index_2 => 2, |
| 9711 | .struct_field_ptr_index_3 => 3, |
| 9712 | }, |
| 9713 | ), cg); |
| 9714 | try ops[0].moveTo(inst, cg); |
| 9715 | }, |
| 9716 | .struct_field_val => if (use_old) try cg.airStructFieldVal(inst) else fallback: { |
| 9717 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 9718 | const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data; |
| 9719 | const agg_ty = cg.typeOf(extra.struct_operand); |
| 9720 | const field_ty = ty_pl.ty.toType(); |
| 9721 | const field_off: u31 = switch (agg_ty.containerLayout(zcu)) { |
| 9722 | .auto, .@"extern" => @intCast(agg_ty.structFieldOffset(extra.field_index, zcu)), |
| 9723 | .@"packed" => break :fallback try cg.airStructFieldVal(inst), |
| 9724 | }; |
| 9725 | var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand}); |
| 9726 | // hack around Sema OPV bugs |
| 9727 | var res = if (field_ty.hasRuntimeBitsIgnoreComptime(zcu)) |
| 9728 | try ops[0].read(field_ty, .{ .disp = field_off }, cg) |
| 9729 | else |
| 9730 | try cg.tempInit(field_ty, .none); |
| 9731 | for (ops) |op| if (op.index != res.index) try op.die(cg); |
| 9732 | try res.moveTo(inst, cg); |
| 9733 | }, |
| 9734 | .set_union_tag => if (use_old) try cg.airSetUnionTag(inst) else { |
| 9735 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 9736 | const union_ty = cg.typeOf(bin_op.lhs).childType(zcu); |
| 9737 | const union_layout = union_ty.unionGetLayout(zcu); |
| 9738 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 9739 | // hack around Sema OPV bugs |
| 9740 | if (union_layout.tag_size > 0) try ops[0].store(&ops[1], .{ |
| 9741 | .disp = @intCast(union_layout.tagOffset()), |
| 9742 | }, cg); |
| 9743 | for (ops) |op| try op.die(cg); |
| 9744 | }, |
| 9745 | .get_union_tag => if (use_old) try cg.airGetUnionTag(inst) else { |
| 9746 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9747 | const union_ty = cg.typeOf(ty_op.operand); |
| 9748 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9749 | const union_layout = union_ty.unionGetLayout(zcu); |
| 9750 | assert(union_layout.tag_size > 0); |
| 9751 | var res = try ops[0].read(ty_op.ty.toType(), .{ |
| 9752 | .disp = @intCast(union_layout.tagOffset()), |
| 9753 | }, cg); |
| 9754 | for (ops) |op| if (op.index != res.index) try op.die(cg); |
| 9755 | try res.moveTo(inst, cg); |
| 9756 | }, |
| 9757 | .slice => if (use_old) try cg.airSlice(inst) else { |
| 9758 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 9759 | const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 9760 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 9761 | try ops[0].toPair(&ops[1], cg); |
| 9762 | try ops[0].moveTo(inst, cg); |
| 9763 | }, |
| 9764 | .slice_len => if (use_old) try cg.airSliceLen(inst) else { |
| 9765 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9766 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9767 | try ops[0].toSliceLen(cg); |
| 9768 | try ops[0].moveTo(inst, cg); |
| 9769 | }, |
| 9770 | .slice_ptr => if (use_old) try cg.airSlicePtr(inst) else { |
| 9771 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9772 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9773 | try ops[0].toSlicePtr(cg); |
| 9774 | try ops[0].moveTo(inst, cg); |
| 9775 | }, |
| 9776 | .ptr_slice_len_ptr => if (use_old) try cg.airPtrSliceLenPtr(inst) else { |
| 9777 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9778 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9779 | try ops[0].toOffset(8, cg); |
| 9780 | try ops[0].moveTo(inst, cg); |
| 9781 | }, |
| 9782 | .ptr_slice_ptr_ptr => if (use_old) try cg.airPtrSlicePtrPtr(inst) else { |
| 9783 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9784 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9785 | try ops[0].toOffset(0, cg); |
| 9786 | try ops[0].moveTo(inst, cg); |
| 9787 | }, |
| 9788 | .slice_elem_val, .ptr_elem_val => |air_tag| if (use_old) switch (air_tag) { |
| 9789 | else => unreachable, |
| 9790 | .slice_elem_val => try cg.airSliceElemVal(inst), |
| 9791 | .ptr_elem_val => try cg.airPtrElemVal(inst), |
| 9792 | } else { |
| 9793 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 9794 | const res_ty = cg.typeOf(bin_op.lhs).elemType2(zcu); |
| 9795 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 9796 | try ops[0].toSlicePtr(cg); |
| 9797 | var res: [1]Temp = undefined; |
| 9798 | if (res_ty.hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{ |
| 9799 | .dst_constraints = .{.{ .int = .byte }}, |
| 9800 | .patterns = &.{ |
| 9801 | .{ .src = .{ .to_gpr, .simm32 } }, |
| 9802 | }, |
| 9803 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 9804 | .each = .{ .once = &.{ |
| 9805 | .{ ._, ._, .movzx, .dst0d, .leaa(.byte, .src0, .add_src0_elem_size_times_src1), ._, ._ }, |
| 9806 | } }, |
| 9807 | }, .{ |
| 9808 | .dst_constraints = .{.{ .int = .byte }}, |
| 9809 | .patterns = &.{ |
| 9810 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 9811 | }, |
| 9812 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 9813 | .each = .{ .once = &.{ |
| 9814 | .{ ._, ._, .movzx, .dst0d, .leai(.byte, .src0, .src1), ._, ._ }, |
| 9815 | } }, |
| 9816 | }, .{ |
| 9817 | .dst_constraints = .{.{ .int = .word }}, |
| 9818 | .patterns = &.{ |
| 9819 | .{ .src = .{ .to_gpr, .simm32 } }, |
| 9820 | }, |
| 9821 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 9822 | .each = .{ .once = &.{ |
| 9823 | .{ ._, ._, .movzx, .dst0d, .leaa(.word, .src0, .add_src0_elem_size_times_src1), ._, ._ }, |
| 9824 | } }, |
| 9825 | }, .{ |
| 9826 | .dst_constraints = .{.{ .int = .word }}, |
| 9827 | .patterns = &.{ |
| 9828 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 9829 | }, |
| 9830 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 9831 | .each = .{ .once = &.{ |
| 9832 | .{ ._, ._, .movzx, .dst0d, .leasi(.word, .src0, .@"2", .src1), ._, ._ }, |
| 9833 | } }, |
| 9834 | }, .{ |
| 9835 | .dst_constraints = .{.{ .int = .dword }}, |
| 9836 | .patterns = &.{ |
| 9837 | .{ .src = .{ .to_gpr, .simm32 } }, |
| 9838 | }, |
| 9839 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 9840 | .each = .{ .once = &.{ |
| 9841 | .{ ._, ._, .mov, .dst0d, .leaa(.dword, .src0, .add_src0_elem_size_times_src1), ._, ._ }, |
| 9842 | } }, |
| 9843 | }, .{ |
| 9844 | .dst_constraints = .{.{ .int = .dword }}, |
| 9845 | .patterns = &.{ |
| 9846 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 9847 | }, |
| 9848 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 9849 | .each = .{ .once = &.{ |
| 9850 | .{ ._, ._, .mov, .dst0d, .leasi(.dword, .src0, .@"4", .src1), ._, ._ }, |
| 9851 | } }, |
| 9852 | }, .{ |
| 9853 | .dst_constraints = .{.{ .int = .qword }}, |
| 9854 | .patterns = &.{ |
| 9855 | .{ .src = .{ .to_gpr, .simm32 } }, |
| 9856 | }, |
| 9857 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 9858 | .each = .{ .once = &.{ |
| 9859 | .{ ._, ._, .mov, .dst0q, .leaa(.qword, .src0, .add_src0_elem_size_times_src1), ._, ._ }, |
| 9860 | } }, |
| 9861 | }, .{ |
| 9862 | .required_features = .{ .@"64bit", null, null, null }, |
| 9863 | .dst_constraints = .{.{ .int = .qword }}, |
| 9864 | .patterns = &.{ |
| 9865 | .{ .src = .{ .to_gpr, .to_gpr } }, |
| 9866 | }, |
| 9867 | .dst_temps = .{.{ .rc = .general_purpose }}, |
| 9868 | .each = .{ .once = &.{ |
| 9869 | .{ ._, ._, .mov, .dst0q, .leasi(.qword, .src0, .@"8", .src1), ._, ._ }, |
| 9870 | } }, |
| 9871 | } }) catch |err| switch (err) { |
| 9872 | error.SelectFailed => { |
| 9873 | const elem_size = res_ty.abiSize(zcu); |
| 9874 | while (true) for (&ops) |*op| { |
| 9875 | if (try op.toRegClass(true, .general_purpose, cg)) break; |
| 9876 | } else break; |
| 9877 | const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64(); |
| 9878 | const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64(); |
| 9879 | if (!std.math.isPowerOfTwo(elem_size)) { |
| 9880 | try cg.spillEflagsIfOccupied(); |
| 9881 | try cg.asmRegisterRegisterImmediate( |
| 9882 | .{ .i_, .mul }, |
| 9883 | rhs_reg, |
| 9884 | rhs_reg, |
| 9885 | .u(elem_size), |
| 9886 | ); |
| 9887 | try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{ |
| 9888 | .base = .{ .reg = lhs_reg }, |
| 9889 | .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } }, |
| 9890 | }); |
| 9891 | } else if (elem_size > 8) { |
| 9892 | try cg.spillEflagsIfOccupied(); |
| 9893 | try cg.asmRegisterImmediate( |
| 9894 | .{ ._l, .sh }, |
| 9895 | rhs_reg, |
| 9896 | .u(std.math.log2_int(u64, elem_size)), |
| 9897 | ); |
| 9898 | try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{ |
| 9899 | .base = .{ .reg = lhs_reg }, |
| 9900 | .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } }, |
| 9901 | }); |
| 9902 | } else try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{ |
| 9903 | .base = .{ .reg = lhs_reg }, |
| 9904 | .mod = .{ .rm = .{ |
| 9905 | .size = .qword, |
| 9906 | .index = rhs_reg, |
| 9907 | .scale = .fromFactor(@intCast(elem_size)), |
| 9908 | } }, |
| 9909 | }); |
| 9910 | res[0] = try ops[0].load(res_ty, .{}, cg); |
| 9911 | }, |
| 9912 | else => |e| return e, |
| 9913 | } else { |
| 9914 | // hack around Sema OPV bugs |
| 9915 | res[0] = try cg.tempInit(res_ty, .none); |
| 9916 | } |
| 9917 | for (ops) |op| for (res) |r| { |
| 9918 | if (op.index == r.index) break; |
| 9919 | } else try op.die(cg); |
| 9920 | try res[0].moveTo(inst, cg); |
| 9921 | }, |
| 9922 | .slice_elem_ptr, .ptr_elem_ptr => |air_tag| if (use_old) switch (air_tag) { |
| 9923 | else => unreachable, |
| 9924 | .slice_elem_ptr => try cg.airSliceElemPtr(inst), |
| 9925 | .ptr_elem_ptr => try cg.airPtrElemPtr(inst), |
| 9926 | } else { |
| 9927 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 9928 | const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 9929 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 9930 | try ops[0].toSlicePtr(cg); |
| 9931 | const dst_ty = ty_pl.ty.toType(); |
| 9932 | if (dst_ty.ptrInfo(zcu).flags.vector_index == .none) zero_offset: { |
| 9933 | const elem_size = dst_ty.childType(zcu).abiSize(zcu); |
| 9934 | // hack around Sema OPV bugs |
| 9935 | if (elem_size == 0) break :zero_offset; |
| 9936 | while (true) for (&ops) |*op| { |
| 9937 | if (try op.toRegClass(true, .general_purpose, cg)) break; |
| 9938 | } else break; |
| 9939 | const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64(); |
| 9940 | const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64(); |
| 9941 | if (!std.math.isPowerOfTwo(elem_size)) { |
| 9942 | try cg.spillEflagsIfOccupied(); |
| 9943 | try cg.asmRegisterRegisterImmediate( |
| 9944 | .{ .i_, .mul }, |
| 9945 | rhs_reg, |
| 9946 | rhs_reg, |
| 9947 | .u(elem_size), |
| 9948 | ); |
| 9949 | try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{ |
| 9950 | .base = .{ .reg = lhs_reg }, |
| 9951 | .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } }, |
| 9952 | }); |
| 9953 | } else if (elem_size > 8) { |
| 9954 | try cg.spillEflagsIfOccupied(); |
| 9955 | try cg.asmRegisterImmediate( |
| 9956 | .{ ._l, .sh }, |
| 9957 | rhs_reg, |
| 9958 | .u(std.math.log2_int(u64, elem_size)), |
| 9959 | ); |
| 9960 | try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{ |
| 9961 | .base = .{ .reg = lhs_reg }, |
| 9962 | .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } }, |
| 9963 | }); |
| 9964 | } else try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{ |
| 9965 | .base = .{ .reg = lhs_reg }, |
| 9966 | .mod = .{ .rm = .{ |
| 9967 | .size = .qword, |
| 9968 | .index = rhs_reg, |
| 9969 | .scale = .fromFactor(@intCast(elem_size)), |
| 9970 | } }, |
| 9971 | }); |
| 9972 | } |
| 9973 | try ops[1].die(cg); |
| 9974 | try ops[0].moveTo(inst, cg); |
| 9975 | }, |
| 9976 | .array_to_slice => if (use_old) try cg.airArrayToSlice(inst) else { |
| 9977 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9978 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9979 | var len = try cg.tempInit(.usize, .{ |
| 9980 | .immediate = cg.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu), |
| 9981 | }); |
| 9982 | try ops[0].toPair(&len, cg); |
| 9983 | try ops[0].moveTo(inst, cg); |
| 9984 | }, |
| 9985 | .error_set_has_value => return cg.fail("TODO implement error_set_has_value", .{}), |
| 9986 | .union_init => if (use_old) try cg.airUnionInit(inst) else { |
| 9987 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 9988 | const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 9989 | const union_ty = ty_pl.ty.toType(); |
| 9990 | var ops = try cg.tempsFromOperands(inst, .{extra.init}); |
| 9991 | var res = try cg.tempAllocMem(union_ty); |
| 9992 | const union_layout = union_ty.unionGetLayout(zcu); |
| 9993 | if (union_layout.tag_size > 0) { |
| 9994 | var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex( |
| 9995 | union_ty.unionTagTypeSafety(zcu).?, |
| 9996 | extra.field_index, |
| 9997 | )); |
| 9998 | try res.write(&tag_temp, .{ |
| 9999 | .disp = @intCast(union_layout.tagOffset()), |
| 10000 | }, cg); |
| 10001 | try tag_temp.die(cg); |
| 10002 | } |
| 10003 | try res.write(&ops[0], .{ |
| 10004 | .disp = @intCast(union_layout.payloadOffset()), |
| 10005 | }, cg); |
| 10006 | try ops[0].die(cg); |
| 10007 | try res.moveTo(inst, cg); |
| 10008 | }, |
| 10009 | .field_parent_ptr => if (use_old) try cg.airFieldParentPtr(inst) else { |
| 10010 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 10011 | const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 10012 | var ops = try cg.tempsFromOperands(inst, .{extra.field_ptr}); |
| 10013 | try ops[0].toOffset(-cg.fieldOffset( |
| 10014 | ty_pl.ty.toType(), |
| 10015 | cg.typeOf(extra.field_ptr), |
| 10016 | extra.field_index, |
| 10017 | ), cg); |
| 10018 | try ops[0].moveTo(inst, cg); |
| 10019 | }, |
| 10020 | |
| 10021 | .is_named_enum_value => return cg.fail("TODO implement is_named_enum_value", .{}), |
| 10022 | |
| 10023 | .wasm_memory_size => unreachable, |
| 10024 | .wasm_memory_grow => unreachable, |
| 10025 | |
| 10026 | .addrspace_cast => { |
| 10027 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 10028 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 10029 | try ops[0].moveTo(inst, cg); |
| 10030 | }, |
| 10031 | |
| 10032 | .vector_store_elem => return cg.fail("TODO implement vector_store_elem", .{}), |
| 10033 | |
| 10034 | .c_va_arg => try cg.airVaArg(inst), |
| 10035 | .c_va_copy => try cg.airVaCopy(inst), |
| 10036 | .c_va_end => try cg.airVaEnd(inst), |
| 10037 | .c_va_start => try cg.airVaStart(inst), |
| 10038 | |
| 10039 | .work_item_id => unreachable, |
| 10040 | .work_group_size => unreachable, |
| 10041 | .work_group_id => unreachable, |
| 10042 | } |
| 10043 | cg.resetTemps(); |
| 10044 | cg.checkInvariantsAfterAirInst(); |
| 10045 | } |
| 10046 | verbose_tracking_log.debug("{}", .{cg.fmtTracking()}); |
| 2573 | 10047 | } |
| 2574 | 10048 | |
| 2575 | | /// Asserts there is already capacity to insert into top branch inst_table. |
| 2576 | | fn processDeath(self: *Self, inst: Air.Inst.Index) !void { |
| 2577 | | try self.inst_tracking.getPtr(inst).?.die(self, inst); |
| 10049 | fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 10050 | const pt = self.pt; |
| 10051 | const zcu = pt.zcu; |
| 10052 | const ip = &zcu.intern_pool; |
| 10053 | switch (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu)) { |
| 10054 | .@"enum" => { |
| 10055 | const enum_ty: Type = .fromInterned(lazy_sym.ty); |
| 10056 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)}); |
| 10057 | |
| 10058 | const param_regs = abi.getCAbiIntParamRegs(.auto); |
| 10059 | const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); |
| 10060 | defer for (param_locks) |lock| self.register_manager.unlockReg(lock); |
| 10061 | |
| 10062 | const ret_reg = param_regs[0]; |
| 10063 | const enum_mcv = MCValue{ .register = param_regs[1] }; |
| 10064 | |
| 10065 | const epilogue_relocs = try self.gpa.alloc(Mir.Inst.Index, enum_ty.enumFieldCount(zcu)); |
| 10066 | defer self.gpa.free(epilogue_relocs); |
| 10067 | |
| 10068 | const data_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 10069 | const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); |
| 10070 | defer self.register_manager.unlockReg(data_lock); |
| 10071 | try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty.toIntern() }); |
| 10072 | |
| 10073 | var data_off: i32 = 0; |
| 10074 | const tag_names = enum_ty.enumFields(zcu); |
| 10075 | for (epilogue_relocs, 0..) |*epilogue_reloc, tag_index| { |
| 10076 | const tag_name_len = tag_names.get(ip)[tag_index].length(ip); |
| 10077 | const tag_val = try pt.enumValueFieldIndex(enum_ty, @intCast(tag_index)); |
| 10078 | const tag_mcv = try self.genTypedValue(tag_val); |
| 10079 | try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv); |
| 10080 | const skip_reloc = try self.asmJccReloc(.ne, undefined); |
| 10081 | |
| 10082 | try self.genSetMem( |
| 10083 | .{ .reg = ret_reg }, |
| 10084 | 0, |
| 10085 | .usize, |
| 10086 | .{ .register_offset = .{ .reg = data_reg, .off = data_off } }, |
| 10087 | .{}, |
| 10088 | ); |
| 10089 | try self.genSetMem(.{ .reg = ret_reg }, 8, .usize, .{ .immediate = tag_name_len }, .{}); |
| 10090 | |
| 10091 | epilogue_reloc.* = try self.asmJmpReloc(undefined); |
| 10092 | self.performReloc(skip_reloc); |
| 10093 | |
| 10094 | data_off += @intCast(tag_name_len + 1); |
| 10095 | } |
| 10096 | |
| 10097 | try self.asmOpOnly(.{ ._, .ud2 }); |
| 10098 | |
| 10099 | for (epilogue_relocs) |reloc| self.performReloc(reloc); |
| 10100 | try self.asmOpOnly(.{ ._, .ret }); |
| 10101 | }, |
| 10102 | else => return self.fail( |
| 10103 | "TODO implement {s} for {}", |
| 10104 | .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) }, |
| 10105 | ), |
| 10106 | } |
| 2578 | 10107 | } |
| 2579 | 10108 | |
| 2580 | | /// Called when there are no operands, and the instruction is always unreferenced. |
| 2581 | | fn finishAirBookkeeping(self: *Self) void { |
| 2582 | | if (std.debug.runtime_safety) { |
| 2583 | | self.air_bookkeeping += 1; |
| 10109 | fn getValue(self: *CodeGen, value: MCValue, inst: ?Air.Inst.Index) !void { |
| 10110 | for (value.getRegs()) |reg| try self.register_manager.getReg(reg, inst); |
| 10111 | switch (value) { |
| 10112 | else => {}, |
| 10113 | .eflags, .register_overflow => self.eflags_inst = inst, |
| 10114 | } |
| 10115 | } |
| 10116 | |
| 10117 | fn getValueIfFree(self: *CodeGen, value: MCValue, inst: ?Air.Inst.Index) void { |
| 10118 | for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg)) |
| 10119 | self.register_manager.getRegAssumeFree(reg, inst); |
| 10120 | } |
| 10121 | |
| 10122 | fn freeReg(self: *CodeGen, reg: Register) !void { |
| 10123 | self.register_manager.freeReg(reg); |
| 10124 | if (reg.class() == .x87) try self.asmRegister(.{ .f_, .free }, reg); |
| 10125 | } |
| 10126 | |
| 10127 | fn freeValue(self: *CodeGen, value: MCValue) !void { |
| 10128 | switch (value) { |
| 10129 | .register => |reg| try self.freeReg(reg), |
| 10130 | inline .register_pair, |
| 10131 | .register_triple, |
| 10132 | .register_quadruple, |
| 10133 | => |regs| for (regs) |reg| try self.freeReg(reg), |
| 10134 | .register_offset, .indirect => |reg_off| try self.freeReg(reg_off.reg), |
| 10135 | .register_overflow => |reg_ov| { |
| 10136 | try self.freeReg(reg_ov.reg); |
| 10137 | self.eflags_inst = null; |
| 10138 | }, |
| 10139 | .register_mask => |reg_mask| try self.freeReg(reg_mask.reg), |
| 10140 | .eflags => self.eflags_inst = null, |
| 10141 | else => {}, // TODO process stack allocation death |
| 2584 | 10142 | } |
| 2585 | 10143 | } |
| 2586 | 10144 | |
| 2587 | | fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void { |
| 10145 | fn feed(self: *CodeGen, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) !void { |
| 10146 | if (bt.feed()) if (operand.toIndex()) |inst| try self.processDeath(inst); |
| 10147 | } |
| 10148 | |
| 10149 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 10150 | fn processDeath(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 10151 | try self.inst_tracking.getPtr(inst).?.die(self, inst); |
| 10152 | } |
| 10153 | |
| 10154 | fn finishAirResult(self: *CodeGen, inst: Air.Inst.Index, result: MCValue) void { |
| 2588 | 10155 | if (self.liveness.isUnused(inst) and self.air.instructions.items(.tag)[@intFromEnum(inst)] != .arg) switch (result) { |
| 2589 | 10156 | .none, .dead, .unreach => {}, |
| 2590 | 10157 | else => unreachable, // Why didn't the result die? |
| 2591 | 10158 | } else { |
| 2592 | | tracking_log.debug("%{d} => {} (birth)", .{ inst, result }); |
| 2593 | | self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(result)); |
| 10159 | tracking_log.debug("{} => {} (birth)", .{ inst, result }); |
| 10160 | self.inst_tracking.putAssumeCapacityNoClobber(inst, .init(result)); |
| 2594 | 10161 | // In some cases, an operand may be reused as the result. |
| 2595 | 10162 | // If that operand died and was a register, it was freed by |
| 2596 | 10163 | // processDeath, so we have to "re-allocate" the register. |
| 2597 | 10164 | self.getValueIfFree(result, inst); |
| 2598 | 10165 | } |
| 2599 | | self.finishAirBookkeeping(); |
| 2600 | 10166 | } |
| 2601 | 10167 | |
| 2602 | 10168 | fn finishAir( |
| 2603 | | self: *Self, |
| 10169 | self: *CodeGen, |
| 2604 | 10170 | inst: Air.Inst.Index, |
| 2605 | 10171 | result: MCValue, |
| 2606 | 10172 | operands: [Liveness.bpi - 1]Air.Inst.Ref, |
| 2607 | 10173 | ) !void { |
| 2608 | | var tomb_bits = self.liveness.getTombBits(inst); |
| 2609 | | for (operands) |op| { |
| 2610 | | const dies = @as(u1, @truncate(tomb_bits)) != 0; |
| 2611 | | tomb_bits >>= 1; |
| 2612 | | if (!dies) continue; |
| 10174 | const tomb_bits = self.liveness.getTombBits(inst); |
| 10175 | for (0.., operands) |op_index, op| { |
| 10176 | if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue; |
| 10177 | if (self.reused_operands.isSet(op_index)) continue; |
| 2613 | 10178 | try self.processDeath(op.toIndexAllowNone() orelse continue); |
| 2614 | 10179 | } |
| 2615 | 10180 | self.finishAirResult(inst, result); |
| ... | ... | @@ -2622,7 +10187,7 @@ const FrameLayout = struct { |
| 2622 | 10187 | }; |
| 2623 | 10188 | |
| 2624 | 10189 | fn setFrameLoc( |
| 2625 | | self: *Self, |
| 10190 | self: *CodeGen, |
| 2626 | 10191 | frame_index: FrameIndex, |
| 2627 | 10192 | base: Register, |
| 2628 | 10193 | offset: *i32, |
| ... | ... | @@ -2637,7 +10202,7 @@ fn setFrameLoc( |
| 2637 | 10202 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; |
| 2638 | 10203 | } |
| 2639 | 10204 | |
| 2640 | | fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayout { |
| 10205 | fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention.Tag) !FrameLayout { |
| 2641 | 10206 | const frame_allocs_len = self.frame_allocs.len; |
| 2642 | 10207 | try self.frame_locs.resize(self.gpa, frame_allocs_len); |
| 2643 | 10208 | const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count); |
| ... | ... | @@ -2657,7 +10222,7 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo |
| 2657 | 10222 | } |
| 2658 | 10223 | }; |
| 2659 | 10224 | const sort_context = SortContext{ .frame_align = frame_align }; |
| 2660 | | mem.sort(FrameIndex, stack_frame_order, sort_context, SortContext.lessThan); |
| 10225 | std.mem.sort(FrameIndex, stack_frame_order, sort_context, SortContext.lessThan); |
| 2661 | 10226 | } |
| 2662 | 10227 | |
| 2663 | 10228 | const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)]; |
| ... | ... | @@ -2668,9 +10233,8 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo |
| 2668 | 10233 | |
| 2669 | 10234 | // Create list of registers to save in the prologue. |
| 2670 | 10235 | // TODO handle register classes |
| 2671 | | var save_reg_list = Mir.RegisterList{}; |
| 2672 | | const callee_preserved_regs = |
| 2673 | | abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*)); |
| 10236 | var save_reg_list: Mir.RegisterList = .empty; |
| 10237 | const callee_preserved_regs = abi.getCalleePreservedRegs(cc); |
| 2674 | 10238 | for (callee_preserved_regs) |reg| { |
| 2675 | 10239 | if (self.register_manager.isRegAllocated(reg)) { |
| 2676 | 10240 | save_reg_list.push(callee_preserved_regs, reg); |
| ... | ... | @@ -2684,7 +10248,7 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo |
| 2684 | 10248 | const stack_frame_align_offset = if (need_align_stack) |
| 2685 | 10249 | 0 |
| 2686 | 10250 | else |
| 2687 | | save_reg_list.size() + frame_offset[@intFromEnum(FrameIndex.args_frame)]; |
| 10251 | save_reg_list.size(self.target) + frame_offset[@intFromEnum(FrameIndex.args_frame)]; |
| 2688 | 10252 | |
| 2689 | 10253 | var rsp_offset: i32 = 0; |
| 2690 | 10254 | self.setFrameLoc(.call_frame, .rsp, &rsp_offset, true); |
| ... | ... | @@ -2697,22 +10261,22 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo |
| 2697 | 10261 | @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]); |
| 2698 | 10262 | |
| 2699 | 10263 | return .{ |
| 2700 | | .stack_mask = @as(u32, math.maxInt(u32)) << @intCast(if (need_align_stack) @intFromEnum(needed_align) else 0), |
| 10264 | .stack_mask = @as(u32, std.math.maxInt(u32)) << @intCast(if (need_align_stack) @intFromEnum(needed_align) else 0), |
| 2701 | 10265 | .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]), |
| 2702 | 10266 | .save_reg_list = save_reg_list, |
| 2703 | 10267 | }; |
| 2704 | 10268 | } |
| 2705 | 10269 | |
| 2706 | | fn getFrameAddrAlignment(self: *Self, frame_addr: bits.FrameAddr) Alignment { |
| 10270 | fn getFrameAddrAlignment(self: *CodeGen, frame_addr: bits.FrameAddr) InternPool.Alignment { |
| 2707 | 10271 | const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; |
| 2708 | 10272 | return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off))); |
| 2709 | 10273 | } |
| 2710 | 10274 | |
| 2711 | | fn getFrameAddrSize(self: *Self, frame_addr: bits.FrameAddr) u32 { |
| 10275 | fn getFrameAddrSize(self: *CodeGen, frame_addr: bits.FrameAddr) u32 { |
| 2712 | 10276 | return self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_size - @as(u31, @intCast(frame_addr.off)); |
| 2713 | 10277 | } |
| 2714 | 10278 | |
| 2715 | | fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 10279 | fn allocFrameIndex(self: *CodeGen, alloc: FrameAlloc) !FrameIndex { |
| 2716 | 10280 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 2717 | 10281 | const frame_size = frame_allocs_slice.items(.abi_size); |
| 2718 | 10282 | const frame_align = frame_allocs_slice.items(.abi_align); |
| ... | ... | @@ -2735,36 +10299,36 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 2735 | 10299 | } |
| 2736 | 10300 | |
| 2737 | 10301 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 2738 | | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { |
| 10302 | fn allocMemPtr(self: *CodeGen, inst: Air.Inst.Index) !FrameIndex { |
| 2739 | 10303 | const pt = self.pt; |
| 2740 | 10304 | const zcu = pt.zcu; |
| 2741 | 10305 | const ptr_ty = self.typeOfIndex(inst); |
| 2742 | 10306 | const val_ty = ptr_ty.childType(zcu); |
| 2743 | | return self.allocFrameIndex(FrameAlloc.init(.{ |
| 2744 | | .size = math.cast(u32, val_ty.abiSize(zcu)) orelse { |
| 10307 | return self.allocFrameIndex(.init(.{ |
| 10308 | .size = std.math.cast(u32, val_ty.abiSize(zcu)) orelse { |
| 2745 | 10309 | return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(pt)}); |
| 2746 | 10310 | }, |
| 2747 | 10311 | .alignment = ptr_ty.ptrAlignment(zcu).max(.@"1"), |
| 2748 | 10312 | })); |
| 2749 | 10313 | } |
| 2750 | 10314 | |
| 2751 | | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 10315 | fn allocRegOrMem(self: *CodeGen, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2752 | 10316 | return self.allocRegOrMemAdvanced(self.typeOfIndex(inst), inst, reg_ok); |
| 2753 | 10317 | } |
| 2754 | 10318 | |
| 2755 | | fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue { |
| 10319 | fn allocTempRegOrMem(self: *CodeGen, elem_ty: Type, reg_ok: bool) !MCValue { |
| 2756 | 10320 | return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok); |
| 2757 | 10321 | } |
| 2758 | 10322 | |
| 2759 | | fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { |
| 10323 | fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2760 | 10324 | const pt = self.pt; |
| 2761 | 10325 | const zcu = pt.zcu; |
| 2762 | | const abi_size = math.cast(u32, ty.abiSize(zcu)) orelse { |
| 10326 | const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse { |
| 2763 | 10327 | return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(pt)}); |
| 2764 | 10328 | }; |
| 2765 | 10329 | |
| 2766 | 10330 | if (reg_ok) need_mem: { |
| 2767 | | if (abi_size <= @as(u32, switch (ty.zigTypeTag(zcu)) { |
| 10331 | if (std.math.isPowerOfTwo(abi_size) and abi_size <= @as(u32, switch (ty.zigTypeTag(zcu)) { |
| 2768 | 10332 | .float => switch (ty.floatBits(self.target.*)) { |
| 2769 | 10333 | 16, 32, 64, 128 => 16, |
| 2770 | 10334 | 80 => break :need_mem, |
| ... | ... | @@ -2772,43 +10336,76 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b |
| 2772 | 10336 | }, |
| 2773 | 10337 | .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| 2774 | 10338 | .float => switch (ty.childType(zcu).floatBits(self.target.*)) { |
| 2775 | | 16, 32, 64, 128 => if (self.hasFeature(.avx)) 32 else 16, |
| 10339 | 16, 32, 64, 128 => self.vectorSize(.float), |
| 2776 | 10340 | 80 => break :need_mem, |
| 2777 | 10341 | else => unreachable, |
| 2778 | 10342 | }, |
| 2779 | | else => if (self.hasFeature(.avx)) 32 else 16, |
| 10343 | else => self.vectorSize(.int), |
| 2780 | 10344 | }, |
| 2781 | 10345 | else => 8, |
| 2782 | 10346 | })) { |
| 2783 | | if (self.register_manager.tryAllocReg(inst, self.regClassForType(ty))) |reg| { |
| 10347 | if (self.register_manager.tryAllocReg(inst, self.regSetForType(ty))) |reg| { |
| 2784 | 10348 | return MCValue{ .register = registerAlias(reg, abi_size) }; |
| 2785 | 10349 | } |
| 2786 | 10350 | } |
| 2787 | 10351 | } |
| 2788 | 10352 | |
| 2789 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ty, zcu)); |
| 10353 | const frame_index = try self.allocFrameIndex(.initSpill(ty, zcu)); |
| 2790 | 10354 | return .{ .load_frame = .{ .index = frame_index } }; |
| 2791 | 10355 | } |
| 2792 | 10356 | |
| 2793 | | fn regClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet { |
| 10357 | fn regClassForType(self: *CodeGen, ty: Type) Register.Class { |
| 2794 | 10358 | const pt = self.pt; |
| 2795 | 10359 | const zcu = pt.zcu; |
| 2796 | 10360 | return switch (ty.zigTypeTag(zcu)) { |
| 2797 | 10361 | .float => switch (ty.floatBits(self.target.*)) { |
| 2798 | | 80 => abi.RegisterClass.x87, |
| 2799 | | else => abi.RegisterClass.sse, |
| 10362 | 80 => .x87, |
| 10363 | else => .sse, |
| 2800 | 10364 | }, |
| 2801 | 10365 | .vector => switch (ty.childType(zcu).toIntern()) { |
| 2802 | | .bool_type, .u1_type => abi.RegisterClass.gp, |
| 2803 | | else => if (ty.isAbiInt(zcu) and ty.intInfo(zcu).bits == 1) |
| 2804 | | abi.RegisterClass.gp |
| 2805 | | else |
| 2806 | | abi.RegisterClass.sse, |
| 10366 | .bool_type => .general_purpose, |
| 10367 | else => .sse, |
| 2807 | 10368 | }, |
| 2808 | | else => abi.RegisterClass.gp, |
| 10369 | else => .general_purpose, |
| 2809 | 10370 | }; |
| 2810 | 10371 | } |
| 2811 | 10372 | |
| 10373 | fn regSetForRegClass(rc: Register.Class) RegisterManager.RegisterBitSet { |
| 10374 | return switch (rc) { |
| 10375 | .general_purpose => abi.RegisterClass.gp, |
| 10376 | .segment, .ip => unreachable, |
| 10377 | .x87 => abi.RegisterClass.x87, |
| 10378 | .mmx => @panic("TODO"), |
| 10379 | .sse => abi.RegisterClass.sse, |
| 10380 | }; |
| 10381 | } |
| 10382 | |
| 10383 | fn regSetForType(self: *CodeGen, ty: Type) RegisterManager.RegisterBitSet { |
| 10384 | return regSetForRegClass(self.regClassForType(ty)); |
| 10385 | } |
| 10386 | |
| 10387 | fn vectorSize(cg: *CodeGen, kind: enum { int, float }) u6 { |
| 10388 | return if (cg.hasFeature(switch (kind) { |
| 10389 | .int => .avx2, |
| 10390 | .float => .avx, |
| 10391 | })) 32 else if (cg.hasFeature(.sse)) 16 else 8; |
| 10392 | } |
| 10393 | |
| 10394 | fn limbType(cg: *CodeGen, ty: Type) Type { |
| 10395 | const pt = cg.pt; |
| 10396 | const zcu = pt.zcu; |
| 10397 | const vector_size = cg.vectorSize(if (ty.isRuntimeFloat()) .float else .int); |
| 10398 | const scalar_ty, const scalar_size = scalar: { |
| 10399 | const scalar_ty = ty.scalarType(zcu); |
| 10400 | const scalar_size = scalar_ty.abiSize(zcu); |
| 10401 | if (scalar_size <= vector_size) break :scalar .{ scalar_ty, scalar_size }; |
| 10402 | }; |
| 10403 | pt.vectorType(.{ |
| 10404 | .len = @divExact(vector_size, scalar_size), |
| 10405 | .child = scalar_ty.toIntern(), |
| 10406 | }); |
| 10407 | } |
| 10408 | |
| 2812 | 10409 | const State = struct { |
| 2813 | 10410 | registers: RegisterManager.TrackedRegisters, |
| 2814 | 10411 | reg_tracking: [RegisterManager.RegisterBitSet.bit_length]InstTracking, |
| ... | ... | @@ -2817,14 +10414,14 @@ const State = struct { |
| 2817 | 10414 | scope_generation: u32, |
| 2818 | 10415 | }; |
| 2819 | 10416 | |
| 2820 | | fn initRetroactiveState(self: *Self) State { |
| 10417 | fn initRetroactiveState(self: *CodeGen) State { |
| 2821 | 10418 | var state: State = undefined; |
| 2822 | 10419 | state.inst_tracking_len = @intCast(self.inst_tracking.count()); |
| 2823 | 10420 | state.scope_generation = self.scope_generation; |
| 2824 | 10421 | return state; |
| 2825 | 10422 | } |
| 2826 | 10423 | |
| 2827 | | fn saveRetroactiveState(self: *Self, state: *State) !void { |
| 10424 | fn saveRetroactiveState(self: *CodeGen, state: *State) !void { |
| 2828 | 10425 | try self.spillEflagsIfOccupied(); |
| 2829 | 10426 | const free_registers = self.register_manager.free_registers; |
| 2830 | 10427 | var it = free_registers.iterator(.{ .kind = .unset }); |
| ... | ... | @@ -2836,13 +10433,13 @@ fn saveRetroactiveState(self: *Self, state: *State) !void { |
| 2836 | 10433 | state.free_registers = free_registers; |
| 2837 | 10434 | } |
| 2838 | 10435 | |
| 2839 | | fn saveState(self: *Self) !State { |
| 10436 | fn saveState(self: *CodeGen) !State { |
| 2840 | 10437 | var state = self.initRetroactiveState(); |
| 2841 | 10438 | try self.saveRetroactiveState(&state); |
| 2842 | 10439 | return state; |
| 2843 | 10440 | } |
| 2844 | 10441 | |
| 2845 | | fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, comptime opts: struct { |
| 10442 | fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, comptime opts: struct { |
| 2846 | 10443 | emit_instructions: bool, |
| 2847 | 10444 | update_tracking: bool, |
| 2848 | 10445 | resurrect: bool, |
| ... | ... | @@ -2857,9 +10454,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2857 | 10454 | } |
| 2858 | 10455 | |
| 2859 | 10456 | if (opts.resurrect) for ( |
| 2860 | | self.inst_tracking.keys()[0..state.inst_tracking_len], |
| 2861 | | self.inst_tracking.values()[0..state.inst_tracking_len], |
| 2862 | | ) |inst, *tracking| tracking.resurrect(inst, state.scope_generation); |
| 10457 | self.inst_tracking.keys()[Temp.Index.max..state.inst_tracking_len], |
| 10458 | self.inst_tracking.values()[Temp.Index.max..state.inst_tracking_len], |
| 10459 | ) |inst, *tracking| try tracking.resurrect(self, inst, state.scope_generation); |
| 2863 | 10460 | for (deaths) |death| try self.processDeath(death); |
| 2864 | 10461 | |
| 2865 | 10462 | const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).array.len]RegisterLock; |
| ... | ... | @@ -2876,43 +10473,34 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2876 | 10473 | reg_locks.deinit(); |
| 2877 | 10474 | }; |
| 2878 | 10475 | |
| 2879 | | for (0..state.registers.len) |index| { |
| 2880 | | const current_maybe_inst = if (self.register_manager.free_registers.isSet(index)) |
| 2881 | | null |
| 2882 | | else |
| 2883 | | self.register_manager.registers[index]; |
| 2884 | | const target_maybe_inst = if (state.free_registers.isSet(index)) |
| 2885 | | null |
| 2886 | | else |
| 2887 | | state.registers[index]; |
| 10476 | for ( |
| 10477 | 0.., |
| 10478 | self.register_manager.registers, |
| 10479 | state.registers, |
| 10480 | state.reg_tracking, |
| 10481 | ) |reg_i, current_slot, target_slot, reg_tracking| { |
| 10482 | const reg_index: RegisterManager.TrackedIndex = @intCast(reg_i); |
| 10483 | const current_maybe_inst = if (self.register_manager.isRegIndexFree(reg_index)) null else current_slot; |
| 10484 | const target_maybe_inst = if (state.free_registers.isSet(reg_index)) null else target_slot; |
| 2888 | 10485 | if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst| |
| 2889 | 10486 | assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len); |
| 2890 | 10487 | if (opts.emit_instructions) { |
| 2891 | | if (current_maybe_inst) |current_inst| { |
| 10488 | if (current_maybe_inst) |current_inst| |
| 2892 | 10489 | try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst); |
| 2893 | | } |
| 2894 | | if (target_maybe_inst) |target_inst| { |
| 2895 | | const target_tracking = self.inst_tracking.getPtr(target_inst).?; |
| 2896 | | try target_tracking.materialize(self, target_inst, state.reg_tracking[index]); |
| 2897 | | } |
| 10490 | if (target_maybe_inst) |target_inst| |
| 10491 | try self.inst_tracking.getPtr(target_inst).?.materialize(self, target_inst, reg_tracking); |
| 2898 | 10492 | } |
| 2899 | 10493 | if (opts.update_tracking) { |
| 2900 | 10494 | if (current_maybe_inst) |current_inst| { |
| 2901 | 10495 | try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst); |
| 2902 | | } |
| 2903 | | { |
| 2904 | | const reg = RegisterManager.regAtTrackedIndex(@intCast(index)); |
| 2905 | | self.register_manager.freeReg(reg); |
| 2906 | | self.register_manager.getRegAssumeFree(reg, target_maybe_inst); |
| 10496 | self.register_manager.freeRegIndex(reg_index); |
| 2907 | 10497 | } |
| 2908 | 10498 | if (target_maybe_inst) |target_inst| { |
| 2909 | | self.inst_tracking.getPtr(target_inst).?.trackMaterialize( |
| 2910 | | target_inst, |
| 2911 | | state.reg_tracking[index], |
| 2912 | | ); |
| 10499 | self.register_manager.getRegIndexAssumeFree(reg_index, target_maybe_inst); |
| 10500 | self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking); |
| 2913 | 10501 | } |
| 2914 | 10502 | } else if (target_maybe_inst) |_| |
| 2915 | | try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(@intCast(index))); |
| 10503 | try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(reg_index)); |
| 2916 | 10504 | } |
| 2917 | 10505 | if (opts.emit_instructions) if (self.eflags_inst) |inst| |
| 2918 | 10506 | try self.inst_tracking.getPtr(inst).?.spill(self, inst); |
| ... | ... | @@ -2930,7 +10518,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2930 | 10518 | } |
| 2931 | 10519 | } |
| 2932 | 10520 | |
| 2933 | | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 10521 | pub fn spillInstruction(self: *CodeGen, reg: Register, inst: Air.Inst.Index) !void { |
| 2934 | 10522 | const tracking = self.inst_tracking.getPtr(inst) orelse return; |
| 2935 | 10523 | for (tracking.getRegs()) |tracked_reg| { |
| 2936 | 10524 | if (tracked_reg.id() == reg.id()) break; |
| ... | ... | @@ -2939,7 +10527,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 2939 | 10527 | try tracking.trackSpill(self, inst); |
| 2940 | 10528 | } |
| 2941 | 10529 | |
| 2942 | | pub fn spillEflagsIfOccupied(self: *Self) !void { |
| 10530 | pub fn spillEflagsIfOccupied(self: *CodeGen) !void { |
| 2943 | 10531 | if (self.eflags_inst) |inst| { |
| 2944 | 10532 | self.eflags_inst = null; |
| 2945 | 10533 | const tracking = self.inst_tracking.getPtr(inst).?; |
| ... | ... | @@ -2949,23 +10537,22 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { |
| 2949 | 10537 | } |
| 2950 | 10538 | } |
| 2951 | 10539 | |
| 2952 | | pub fn spillCallerPreservedRegs(self: *Self, cc: std.builtin.CallingConvention) !void { |
| 10540 | pub fn spillCallerPreservedRegs(self: *CodeGen, cc: std.builtin.CallingConvention.Tag) !void { |
| 2953 | 10541 | switch (cc) { |
| 2954 | | .x86_64_sysv => try self.spillRegisters(abi.getCallerPreservedRegs(.{ .x86_64_sysv = .{} })), |
| 2955 | | .x86_64_win => try self.spillRegisters(abi.getCallerPreservedRegs(.{ .x86_64_win = .{} })), |
| 10542 | inline .auto, .x86_64_sysv, .x86_64_win => |tag| try self.spillRegisters(abi.getCallerPreservedRegs(tag)), |
| 2956 | 10543 | else => unreachable, |
| 2957 | 10544 | } |
| 2958 | 10545 | } |
| 2959 | 10546 | |
| 2960 | | pub fn spillRegisters(self: *Self, comptime registers: []const Register) !void { |
| 10547 | pub fn spillRegisters(self: *CodeGen, comptime registers: []const Register) !void { |
| 2961 | 10548 | inline for (registers) |reg| try self.register_manager.getKnownReg(reg, null); |
| 2962 | 10549 | } |
| 2963 | 10550 | |
| 2964 | 10551 | /// Copies a value to a register without tracking the register. The register is not considered |
| 2965 | 10552 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 2966 | 10553 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 2967 | | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 2968 | | const reg = try self.register_manager.allocReg(null, self.regClassForType(ty)); |
| 10554 | fn copyToTmpRegister(self: *CodeGen, ty: Type, mcv: MCValue) !Register { |
| 10555 | const reg = try self.register_manager.allocReg(null, self.regSetForType(ty)); |
| 2969 | 10556 | try self.genSetReg(reg, ty, mcv, .{}); |
| 2970 | 10557 | return reg; |
| 2971 | 10558 | } |
| ... | ... | @@ -2975,22 +10562,22 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 2975 | 10562 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 2976 | 10563 | /// WARNING make sure that the allocated register matches the returned MCValue from an instruction! |
| 2977 | 10564 | fn copyToRegisterWithInstTracking( |
| 2978 | | self: *Self, |
| 10565 | self: *CodeGen, |
| 2979 | 10566 | reg_owner: Air.Inst.Index, |
| 2980 | 10567 | ty: Type, |
| 2981 | 10568 | mcv: MCValue, |
| 2982 | 10569 | ) !MCValue { |
| 2983 | | const reg: Register = try self.register_manager.allocReg(reg_owner, self.regClassForType(ty)); |
| 10570 | const reg: Register = try self.register_manager.allocReg(reg_owner, self.regSetForType(ty)); |
| 2984 | 10571 | try self.genSetReg(reg, ty, mcv, .{}); |
| 2985 | 10572 | return MCValue{ .register = reg }; |
| 2986 | 10573 | } |
| 2987 | 10574 | |
| 2988 | | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 10575 | fn airAlloc(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 2989 | 10576 | const result = MCValue{ .lea_frame = .{ .index = try self.allocMemPtr(inst) } }; |
| 2990 | 10577 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 2991 | 10578 | } |
| 2992 | 10579 | |
| 2993 | | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 10580 | fn airRetPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 2994 | 10581 | const result: MCValue = switch (self.ret_mcv.long) { |
| 2995 | 10582 | else => unreachable, |
| 2996 | 10583 | .none => .{ .lea_frame = .{ .index = try self.allocMemPtr(inst) } }, |
| ... | ... | @@ -3006,7 +10593,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3006 | 10593 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 3007 | 10594 | } |
| 3008 | 10595 | |
| 3009 | | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 10596 | fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 3010 | 10597 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3011 | 10598 | const dst_ty = self.typeOfIndex(inst); |
| 3012 | 10599 | const dst_bits = dst_ty.floatBits(self.target.*); |
| ... | ... | @@ -3043,7 +10630,7 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3043 | 10630 | floatCompilerRtAbiName(src_bits), |
| 3044 | 10631 | floatCompilerRtAbiName(dst_bits), |
| 3045 | 10632 | }) catch unreachable, |
| 3046 | | } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}); |
| 10633 | } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}, .{}); |
| 3047 | 10634 | } |
| 3048 | 10635 | |
| 3049 | 10636 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -3067,18 +10654,18 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3067 | 10654 | .{ .v_, .cvtps2ph }, |
| 3068 | 10655 | dst_reg, |
| 3069 | 10656 | mat_src_reg.to128(), |
| 3070 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 10657 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 3071 | 10658 | ); |
| 3072 | 10659 | }, |
| 3073 | 10660 | else => unreachable, |
| 3074 | 10661 | } |
| 3075 | 10662 | } else { |
| 3076 | 10663 | assert(src_bits == 64 and dst_bits == 32); |
| 3077 | | if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 10664 | if (self.hasFeature(.avx)) if (src_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 3078 | 10665 | .{ .v_ss, .cvtsd2 }, |
| 3079 | 10666 | dst_reg, |
| 3080 | 10667 | dst_reg, |
| 3081 | | try src_mcv.mem(self, .qword), |
| 10668 | try src_mcv.mem(self, .{ .size = .qword }), |
| 3082 | 10669 | ) else try self.asmRegisterRegisterRegister( |
| 3083 | 10670 | .{ .v_ss, .cvtsd2 }, |
| 3084 | 10671 | dst_reg, |
| ... | ... | @@ -3087,10 +10674,10 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3087 | 10674 | src_mcv.getReg().? |
| 3088 | 10675 | else |
| 3089 | 10676 | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 3090 | | ) else if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 10677 | ) else if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 3091 | 10678 | .{ ._ss, .cvtsd2 }, |
| 3092 | 10679 | dst_reg, |
| 3093 | | try src_mcv.mem(self, .qword), |
| 10680 | try src_mcv.mem(self, .{ .size = .qword }), |
| 3094 | 10681 | ) else try self.asmRegisterRegister( |
| 3095 | 10682 | .{ ._ss, .cvtsd2 }, |
| 3096 | 10683 | dst_reg, |
| ... | ... | @@ -3105,7 +10692,7 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3105 | 10692 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3106 | 10693 | } |
| 3107 | 10694 | |
| 3108 | | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 10695 | fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 3109 | 10696 | const pt = self.pt; |
| 3110 | 10697 | const zcu = pt.zcu; |
| 3111 | 10698 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -3147,7 +10734,7 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 3147 | 10734 | floatCompilerRtAbiName(src_bits), |
| 3148 | 10735 | floatCompilerRtAbiName(dst_bits), |
| 3149 | 10736 | }) catch unreachable, |
| 3150 | | } }, &.{src_scalar_ty}, &.{.{ .air_ref = ty_op.operand }}); |
| 10737 | } }, &.{src_scalar_ty}, &.{.{ .air_ref = ty_op.operand }}, .{}); |
| 3151 | 10738 | } |
| 3152 | 10739 | |
| 3153 | 10740 | const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu)); |
| ... | ... | @@ -3186,11 +10773,11 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 3186 | 10773 | } else { |
| 3187 | 10774 | assert(src_bits == 32 and dst_bits == 64); |
| 3188 | 10775 | if (self.hasFeature(.avx)) switch (vec_len) { |
| 3189 | | 1 => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 10776 | 1 => if (src_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 3190 | 10777 | .{ .v_sd, .cvtss2 }, |
| 3191 | 10778 | dst_alias, |
| 3192 | 10779 | dst_alias, |
| 3193 | | try src_mcv.mem(self, self.memSize(src_ty)), |
| 10780 | try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }), |
| 3194 | 10781 | ) else try self.asmRegisterRegisterRegister( |
| 3195 | 10782 | .{ .v_sd, .cvtss2 }, |
| 3196 | 10783 | dst_alias, |
| ... | ... | @@ -3200,10 +10787,10 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 3200 | 10787 | else |
| 3201 | 10788 | try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size), |
| 3202 | 10789 | ), |
| 3203 | | 2...4 => if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 10790 | 2...4 => if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 3204 | 10791 | .{ .v_pd, .cvtps2 }, |
| 3205 | 10792 | dst_alias, |
| 3206 | | try src_mcv.mem(self, self.memSize(src_ty)), |
| 10793 | try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }), |
| 3207 | 10794 | ) else try self.asmRegisterRegister( |
| 3208 | 10795 | .{ .v_pd, .cvtps2 }, |
| 3209 | 10796 | dst_alias, |
| ... | ... | @@ -3213,14 +10800,14 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 3213 | 10800 | try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size), |
| 3214 | 10801 | ), |
| 3215 | 10802 | else => break :result null, |
| 3216 | | } else if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 10803 | } else if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 3217 | 10804 | switch (vec_len) { |
| 3218 | 10805 | 1 => .{ ._sd, .cvtss2 }, |
| 3219 | 10806 | 2 => .{ ._pd, .cvtps2 }, |
| 3220 | 10807 | else => break :result null, |
| 3221 | 10808 | }, |
| 3222 | 10809 | dst_alias, |
| 3223 | | try src_mcv.mem(self, self.memSize(src_ty)), |
| 10810 | try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }), |
| 3224 | 10811 | ) else try self.asmRegisterRegister( |
| 3225 | 10812 | switch (vec_len) { |
| 3226 | 10813 | 1 => .{ ._sd, .cvtss2 }, |
| ... | ... | @@ -3241,7 +10828,7 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 3241 | 10828 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3242 | 10829 | } |
| 3243 | 10830 | |
| 3244 | | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 10831 | fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 3245 | 10832 | const pt = self.pt; |
| 3246 | 10833 | const zcu = pt.zcu; |
| 3247 | 10834 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -3249,7 +10836,8 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3249 | 10836 | const dst_ty = self.typeOfIndex(inst); |
| 3250 | 10837 | |
| 3251 | 10838 | const result = @as(?MCValue, result: { |
| 3252 | | const dst_abi_size: u32 = @intCast(dst_ty.abiSize(zcu)); |
| 10839 | const src_abi_size: u31 = @intCast(src_ty.abiSize(zcu)); |
| 10840 | const dst_abi_size: u31 = @intCast(dst_ty.abiSize(zcu)); |
| 3253 | 10841 | |
| 3254 | 10842 | const src_int_info = src_ty.intInfo(zcu); |
| 3255 | 10843 | const dst_int_info = dst_ty.intInfo(zcu); |
| ... | ... | @@ -3260,14 +10848,13 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3260 | 10848 | |
| 3261 | 10849 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3262 | 10850 | if (dst_ty.isVector(zcu)) { |
| 3263 | | const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu)); |
| 3264 | 10851 | const max_abi_size = @max(dst_abi_size, src_abi_size); |
| 3265 | | if (max_abi_size > @as(u32, if (self.hasFeature(.avx2)) 32 else 16)) break :result null; |
| 10852 | if (max_abi_size > self.vectorSize(.int)) break :result null; |
| 3266 | 10853 | const has_avx = self.hasFeature(.avx); |
| 3267 | 10854 | |
| 3268 | 10855 | const dst_elem_abi_size = dst_ty.childType(zcu).abiSize(zcu); |
| 3269 | 10856 | const src_elem_abi_size = src_ty.childType(zcu).abiSize(zcu); |
| 3270 | | switch (math.order(dst_elem_abi_size, src_elem_abi_size)) { |
| 10857 | switch (std.math.order(dst_elem_abi_size, src_elem_abi_size)) { |
| 3271 | 10858 | .lt => { |
| 3272 | 10859 | const mir_tag: Mir.Inst.FixedTag = switch (dst_elem_abi_size) { |
| 3273 | 10860 | else => break :result null, |
| ... | ... | @@ -3354,10 +10941,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3354 | 10941 | const dst_reg = dst_mcv.getReg().?; |
| 3355 | 10942 | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 3356 | 10943 | |
| 3357 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 10944 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 3358 | 10945 | mir_tag, |
| 3359 | 10946 | dst_alias, |
| 3360 | | try src_mcv.mem(self, self.memSize(src_ty)), |
| 10947 | try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }), |
| 3361 | 10948 | ) else try self.asmRegisterRegister( |
| 3362 | 10949 | mir_tag, |
| 3363 | 10950 | dst_alias, |
| ... | ... | @@ -3430,9 +11017,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3430 | 11017 | else => src_int_info.bits, |
| 3431 | 11018 | }; |
| 3432 | 11019 | |
| 3433 | | const dst_mcv = if (dst_int_info.bits <= src_storage_bits and |
| 3434 | | math.divCeil(u16, dst_int_info.bits, 64) catch unreachable == |
| 3435 | | math.divCeil(u32, src_storage_bits, 64) catch unreachable and |
| 11020 | const dst_mcv = if ((if (src_mcv.getReg()) |src_reg| src_reg.class() == .general_purpose else src_abi_size > 8) and |
| 11021 | dst_int_info.bits <= src_storage_bits and |
| 11022 | std.math.divCeil(u16, dst_int_info.bits, 64) catch unreachable == |
| 11023 | std.math.divCeil(u32, src_storage_bits, 64) catch unreachable and |
| 3436 | 11024 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { |
| 3437 | 11025 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 3438 | 11026 | try self.genCopy(min_ty, dst_mcv, src_mcv, .{}); |
| ... | ... | @@ -3449,10 +11037,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3449 | 11037 | break :result .{ .register = registerAlias(dst_mcv.getReg().?, dst_abi_size) }; |
| 3450 | 11038 | } |
| 3451 | 11039 | |
| 3452 | | const src_limbs_len = math.divCeil(u16, src_int_info.bits, 64) catch unreachable; |
| 3453 | | const dst_limbs_len = math.divCeil(u16, dst_int_info.bits, 64) catch unreachable; |
| 11040 | const src_limbs_len = std.math.divCeil(u31, src_abi_size, 8) catch unreachable; |
| 11041 | const dst_limbs_len = @divExact(dst_abi_size, 8); |
| 3454 | 11042 | |
| 3455 | | const high_mcv: MCValue = if (dst_mcv.isMemory()) |
| 11043 | const high_mcv: MCValue = if (dst_mcv.isBase()) |
| 3456 | 11044 | dst_mcv.address().offset((src_limbs_len - 1) * 8).deref() |
| 3457 | 11045 | else |
| 3458 | 11046 | .{ .register = dst_mcv.register_pair[1] }; |
| ... | ... | @@ -3460,8 +11048,8 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3460 | 11048 | high_mcv.getReg().? |
| 3461 | 11049 | else |
| 3462 | 11050 | try self.copyToTmpRegister(switch (src_int_info.signedness) { |
| 3463 | | .signed => Type.isize, |
| 3464 | | .unsigned => Type.usize, |
| 11051 | .signed => .isize, |
| 11052 | .unsigned => .usize, |
| 3465 | 11053 | }, high_mcv); |
| 3466 | 11054 | const high_lock = self.register_manager.lockRegAssumeUnused(high_reg); |
| 3467 | 11055 | defer self.register_manager.unlockReg(high_lock); |
| ... | ... | @@ -3469,7 +11057,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3469 | 11057 | const high_bits = src_int_info.bits % 64; |
| 3470 | 11058 | if (high_bits > 0) { |
| 3471 | 11059 | try self.truncateRegister(src_ty, high_reg); |
| 3472 | | const high_ty = if (dst_int_info.bits >= 64) Type.usize else dst_ty; |
| 11060 | const high_ty: Type = if (dst_int_info.bits >= 64) .usize else dst_ty; |
| 3473 | 11061 | try self.genCopy(high_ty, high_mcv, .{ .register = high_reg }, .{}); |
| 3474 | 11062 | } |
| 3475 | 11063 | |
| ... | ... | @@ -3478,13 +11066,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3478 | 11066 | switch (extend) { |
| 3479 | 11067 | .signed => extend: { |
| 3480 | 11068 | const extend_mcv = MCValue{ .register = high_reg }; |
| 3481 | | try self.genShiftBinOpMir( |
| 3482 | | .{ ._r, .sa }, |
| 3483 | | Type.isize, |
| 3484 | | extend_mcv, |
| 3485 | | Type.u8, |
| 3486 | | .{ .immediate = 63 }, |
| 3487 | | ); |
| 11069 | try self.genShiftBinOpMir(.{ ._r, .sa }, .isize, extend_mcv, .u8, .{ .immediate = 63 }); |
| 3488 | 11070 | break :extend extend_mcv; |
| 3489 | 11071 | }, |
| 3490 | 11072 | .unsigned => .{ .immediate = 0 }, |
| ... | ... | @@ -3500,7 +11082,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 3500 | 11082 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3501 | 11083 | } |
| 3502 | 11084 | |
| 3503 | | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 11085 | fn airTrunc(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 3504 | 11086 | const pt = self.pt; |
| 3505 | 11087 | const zcu = pt.zcu; |
| 3506 | 11088 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -3516,7 +11098,8 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3516 | 11098 | if (src_mcv.getReg()) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; |
| 3517 | 11099 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 3518 | 11100 | |
| 3519 | | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 11101 | const dst_mcv = if (src_mcv.isRegister() and src_mcv.getReg().?.class() == self.regClassForType(dst_ty) and |
| 11102 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3520 | 11103 | src_mcv |
| 3521 | 11104 | else if (dst_abi_size <= 8) |
| 3522 | 11105 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv) |
| ... | ... | @@ -3570,7 +11153,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3570 | 11153 | const dst_info = dst_elem_ty.intInfo(zcu); |
| 3571 | 11154 | const src_info = src_elem_ty.intInfo(zcu); |
| 3572 | 11155 | |
| 3573 | | const mask_val = try pt.intValue(src_elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(64 - dst_info.bits)); |
| 11156 | const mask_val = try pt.intValue(src_elem_ty, @as(u64, std.math.maxInt(u64)) >> @intCast(64 - dst_info.bits)); |
| 3574 | 11157 | |
| 3575 | 11158 | const splat_ty = try pt.vectorType(.{ |
| 3576 | 11159 | .len = @intCast(@divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits)), |
| ... | ... | @@ -3583,10 +11166,10 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3583 | 11166 | .storage = .{ .repeated_elem = mask_val.ip_index }, |
| 3584 | 11167 | } }); |
| 3585 | 11168 | |
| 3586 | | const splat_mcv = try self.genTypedValue(Value.fromInterned(splat_val)); |
| 11169 | const splat_mcv = try self.genTypedValue(.fromInterned(splat_val)); |
| 3587 | 11170 | const splat_addr_mcv: MCValue = switch (splat_mcv) { |
| 3588 | 11171 | .memory, .indirect, .load_frame => splat_mcv.address(), |
| 3589 | | else => .{ .register = try self.copyToTmpRegister(Type.usize, splat_mcv.address()) }, |
| 11172 | else => .{ .register = try self.copyToTmpRegister(.usize, splat_mcv.address()) }, |
| 3590 | 11173 | }; |
| 3591 | 11174 | |
| 3592 | 11175 | const dst_reg = dst_mcv.getReg().?; |
| ... | ... | @@ -3596,7 +11179,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3596 | 11179 | .{ .vp_, .@"and" }, |
| 3597 | 11180 | dst_alias, |
| 3598 | 11181 | dst_alias, |
| 3599 | | try splat_addr_mcv.deref().mem(self, Memory.Size.fromSize(splat_abi_size)), |
| 11182 | try splat_addr_mcv.deref().mem(self, .{ .size = .fromSize(splat_abi_size) }), |
| 3600 | 11183 | ); |
| 3601 | 11184 | if (src_abi_size > 16) { |
| 3602 | 11185 | const temp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse); |
| ... | ... | @@ -3607,7 +11190,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3607 | 11190 | .{ if (self.hasFeature(.avx2)) .v_i128 else .v_f128, .extract }, |
| 3608 | 11191 | registerAlias(temp_reg, dst_abi_size), |
| 3609 | 11192 | dst_alias, |
| 3610 | | Immediate.u(1), |
| 11193 | .u(1), |
| 3611 | 11194 | ); |
| 3612 | 11195 | try self.asmRegisterRegisterRegister( |
| 3613 | 11196 | mir_tag, |
| ... | ... | @@ -3620,7 +11203,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3620 | 11203 | try self.asmRegisterMemory( |
| 3621 | 11204 | .{ .p_, .@"and" }, |
| 3622 | 11205 | dst_alias, |
| 3623 | | try splat_addr_mcv.deref().mem(self, Memory.Size.fromSize(splat_abi_size)), |
| 11206 | try splat_addr_mcv.deref().mem(self, .{ .size = .fromSize(splat_abi_size) }), |
| 3624 | 11207 | ); |
| 3625 | 11208 | try self.asmRegisterRegister(mir_tag, dst_alias, dst_alias); |
| 3626 | 11209 | } |
| ... | ... | @@ -3646,7 +11229,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3646 | 11229 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3647 | 11230 | } |
| 3648 | 11231 | |
| 3649 | | fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void { |
| 11232 | fn airIntFromBool(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 3650 | 11233 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 3651 | 11234 | const ty = self.typeOfIndex(inst); |
| 3652 | 11235 | |
| ... | ... | @@ -3659,13 +11242,13 @@ fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void { |
| 3659 | 11242 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 3660 | 11243 | } |
| 3661 | 11244 | |
| 3662 | | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 11245 | fn airSlice(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 3663 | 11246 | const zcu = self.pt.zcu; |
| 3664 | 11247 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3665 | 11248 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3666 | 11249 | |
| 3667 | 11250 | const slice_ty = self.typeOfIndex(inst); |
| 3668 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(slice_ty, zcu)); |
| 11251 | const frame_index = try self.allocFrameIndex(.initSpill(slice_ty, zcu)); |
| 3669 | 11252 | |
| 3670 | 11253 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 3671 | 11254 | try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, .{ .air_ref = bin_op.lhs }, .{}); |
| ... | ... | @@ -3683,13 +11266,13 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 3683 | 11266 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3684 | 11267 | } |
| 3685 | 11268 | |
| 3686 | | fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 11269 | fn airUnOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 3687 | 11270 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3688 | 11271 | const dst_mcv = try self.genUnOp(inst, tag, ty_op.operand); |
| 3689 | 11272 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 3690 | 11273 | } |
| 3691 | 11274 | |
| 3692 | | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 11275 | fn airBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 3693 | 11276 | const pt = self.pt; |
| 3694 | 11277 | const zcu = pt.zcu; |
| 3695 | 11278 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -3724,14 +11307,14 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 3724 | 11307 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3725 | 11308 | } |
| 3726 | 11309 | |
| 3727 | | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 11310 | fn airPtrArithmetic(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 3728 | 11311 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3729 | 11312 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3730 | 11313 | const dst_mcv = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 3731 | 11314 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3732 | 11315 | } |
| 3733 | 11316 | |
| 3734 | | fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| 11317 | fn activeIntBits(self: *CodeGen, dst_air: Air.Inst.Ref) u16 { |
| 3735 | 11318 | const pt = self.pt; |
| 3736 | 11319 | const zcu = pt.zcu; |
| 3737 | 11320 | const air_tag = self.air.instructions.items(.tag); |
| ... | ... | @@ -3766,7 +11349,7 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| 3766 | 11349 | return dst_info.bits; |
| 3767 | 11350 | } |
| 3768 | 11351 | |
| 3769 | | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 11352 | fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 3770 | 11353 | const pt = self.pt; |
| 3771 | 11354 | const zcu = pt.zcu; |
| 3772 | 11355 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -3802,11 +11385,11 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3802 | 11385 | state: State, |
| 3803 | 11386 | reloc: Mir.Inst.Index, |
| 3804 | 11387 | } = if (signed and tag == .div_floor) state: { |
| 3805 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(Type.usize, zcu)); |
| 11388 | const frame_index = try self.allocFrameIndex(.initType(.usize, zcu)); |
| 3806 | 11389 | try self.asmMemoryImmediate( |
| 3807 | 11390 | .{ ._, .mov }, |
| 3808 | 11391 | .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .qword } } }, |
| 3809 | | Immediate.u(0), |
| 11392 | .u(0), |
| 3810 | 11393 | ); |
| 3811 | 11394 | |
| 3812 | 11395 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| ... | ... | @@ -3817,7 +11400,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3817 | 11400 | const mat_lhs_mcv = switch (lhs_mcv) { |
| 3818 | 11401 | .load_symbol => mat_lhs_mcv: { |
| 3819 | 11402 | // TODO clean this up! |
| 3820 | | const addr_reg = try self.copyToTmpRegister(Type.usize, lhs_mcv.address()); |
| 11403 | const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address()); |
| 3821 | 11404 | break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 3822 | 11405 | }, |
| 3823 | 11406 | else => lhs_mcv, |
| ... | ... | @@ -3827,10 +11410,10 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3827 | 11410 | else => null, |
| 3828 | 11411 | }; |
| 3829 | 11412 | defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3830 | | if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 11413 | if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory( |
| 3831 | 11414 | .{ ._, .mov }, |
| 3832 | 11415 | tmp_reg, |
| 3833 | | try mat_lhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 11416 | try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 3834 | 11417 | ) else try self.asmRegisterRegister( |
| 3835 | 11418 | .{ ._, .mov }, |
| 3836 | 11419 | tmp_reg, |
| ... | ... | @@ -3841,7 +11424,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3841 | 11424 | const mat_rhs_mcv = switch (rhs_mcv) { |
| 3842 | 11425 | .load_symbol => mat_rhs_mcv: { |
| 3843 | 11426 | // TODO clean this up! |
| 3844 | | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 11427 | const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); |
| 3845 | 11428 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 3846 | 11429 | }, |
| 3847 | 11430 | else => rhs_mcv, |
| ... | ... | @@ -3851,10 +11434,10 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3851 | 11434 | else => null, |
| 3852 | 11435 | }; |
| 3853 | 11436 | defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3854 | | if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 11437 | if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory( |
| 3855 | 11438 | .{ ._, .xor }, |
| 3856 | 11439 | tmp_reg, |
| 3857 | | try mat_rhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 11440 | try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 3858 | 11441 | ) else try self.asmRegisterRegister( |
| 3859 | 11442 | .{ ._, .xor }, |
| 3860 | 11443 | tmp_reg, |
| ... | ... | @@ -3882,6 +11465,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3882 | 11465 | } }, |
| 3883 | 11466 | &.{ src_ty, src_ty }, |
| 3884 | 11467 | &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } }, |
| 11468 | .{}, |
| 3885 | 11469 | ); |
| 3886 | 11470 | break :result if (signed) switch (tag) { |
| 3887 | 11471 | .div_floor => { |
| ... | ... | @@ -3911,6 +11495,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3911 | 11495 | } }, |
| 3912 | 11496 | &.{ src_ty, src_ty }, |
| 3913 | 11497 | &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } }, |
| 11498 | .{}, |
| 3914 | 11499 | ); |
| 3915 | 11500 | try self.asmRegisterMemory( |
| 3916 | 11501 | .{ ._, .sub }, |
| ... | ... | @@ -3920,11 +11505,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3920 | 11505 | .mod = .{ .rm = .{ .size = .qword } }, |
| 3921 | 11506 | }, |
| 3922 | 11507 | ); |
| 3923 | | try self.asmRegisterImmediate( |
| 3924 | | .{ ._, .sbb }, |
| 3925 | | dst_mcv.register_pair[1], |
| 3926 | | Immediate.u(0), |
| 3927 | | ); |
| 11508 | try self.asmRegisterImmediate(.{ ._, .sbb }, dst_mcv.register_pair[1], .u(0)); |
| 3928 | 11509 | try self.freeValue( |
| 3929 | 11510 | .{ .load_frame = .{ .index = signed_div_floor_state.frame_index } }, |
| 3930 | 11511 | ); |
| ... | ... | @@ -3936,7 +11517,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3936 | 11517 | defer for (dst_locks) |lock| self.register_manager.unlockReg(lock); |
| 3937 | 11518 | |
| 3938 | 11519 | const tmp_regs = |
| 3939 | | try self.register_manager.allocRegs(2, .{null} ** 2, abi.RegisterClass.gp); |
| 11520 | try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp); |
| 3940 | 11521 | const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs); |
| 3941 | 11522 | defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); |
| 3942 | 11523 | |
| ... | ... | @@ -3944,7 +11525,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3944 | 11525 | const mat_rhs_mcv = switch (rhs_mcv) { |
| 3945 | 11526 | .load_symbol => mat_rhs_mcv: { |
| 3946 | 11527 | // TODO clean this up! |
| 3947 | | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 11528 | const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); |
| 3948 | 11529 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 3949 | 11530 | }, |
| 3950 | 11531 | else => rhs_mcv, |
| ... | ... | @@ -3957,16 +11538,16 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3957 | 11538 | |
| 3958 | 11539 | for (tmp_regs, dst_regs) |tmp_reg, dst_reg| |
| 3959 | 11540 | try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_reg); |
| 3960 | | if (mat_rhs_mcv.isMemory()) { |
| 11541 | if (mat_rhs_mcv.isBase()) { |
| 3961 | 11542 | try self.asmRegisterMemory( |
| 3962 | 11543 | .{ ._, .add }, |
| 3963 | 11544 | tmp_regs[0], |
| 3964 | | try mat_rhs_mcv.mem(self, .qword), |
| 11545 | try mat_rhs_mcv.mem(self, .{ .size = .qword }), |
| 3965 | 11546 | ); |
| 3966 | 11547 | try self.asmRegisterMemory( |
| 3967 | 11548 | .{ ._, .adc }, |
| 3968 | 11549 | tmp_regs[1], |
| 3969 | | try mat_rhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 11550 | try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 3970 | 11551 | ); |
| 3971 | 11552 | } else for ( |
| 3972 | 11553 | [_]Mir.Inst.Tag{ .add, .adc }, |
| ... | ... | @@ -3996,7 +11577,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3996 | 11577 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3997 | 11578 | } |
| 3998 | 11579 | |
| 3999 | | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 11580 | fn airAddSat(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 4000 | 11581 | const pt = self.pt; |
| 4001 | 11582 | const zcu = pt.zcu; |
| 4002 | 11583 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -4031,22 +11612,10 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4031 | 11612 | const reg_extra_bits = self.regExtraBits(ty); |
| 4032 | 11613 | const cc: Condition = if (ty.isSignedInt(zcu)) cc: { |
| 4033 | 11614 | if (reg_extra_bits > 0) { |
| 4034 | | try self.genShiftBinOpMir( |
| 4035 | | .{ ._l, .sa }, |
| 4036 | | ty, |
| 4037 | | dst_mcv, |
| 4038 | | Type.u8, |
| 4039 | | .{ .immediate = reg_extra_bits }, |
| 4040 | | ); |
| 11615 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .u8, .{ .immediate = reg_extra_bits }); |
| 4041 | 11616 | } |
| 4042 | 11617 | try self.genSetReg(limit_reg, ty, dst_mcv, .{}); |
| 4043 | | try self.genShiftBinOpMir( |
| 4044 | | .{ ._r, .sa }, |
| 4045 | | ty, |
| 4046 | | limit_mcv, |
| 4047 | | Type.u8, |
| 4048 | | .{ .immediate = reg_bits - 1 }, |
| 4049 | | ); |
| 11618 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .u8, .{ .immediate = reg_bits - 1 }); |
| 4050 | 11619 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ |
| 4051 | 11620 | .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1, |
| 4052 | 11621 | }); |
| ... | ... | @@ -4056,19 +11625,13 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4056 | 11625 | const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg); |
| 4057 | 11626 | defer self.register_manager.unlockReg(shifted_rhs_lock); |
| 4058 | 11627 | |
| 4059 | | try self.genShiftBinOpMir( |
| 4060 | | .{ ._l, .sa }, |
| 4061 | | ty, |
| 4062 | | shifted_rhs_mcv, |
| 4063 | | Type.u8, |
| 4064 | | .{ .immediate = reg_extra_bits }, |
| 4065 | | ); |
| 11628 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, shifted_rhs_mcv, .u8, .{ .immediate = reg_extra_bits }); |
| 4066 | 11629 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv); |
| 4067 | 11630 | } else try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv); |
| 4068 | 11631 | break :cc .o; |
| 4069 | 11632 | } else cc: { |
| 4070 | 11633 | try self.genSetReg(limit_reg, ty, .{ |
| 4071 | | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(64 - ty.bitSize(zcu)), |
| 11634 | .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - ty.bitSize(zcu)), |
| 4072 | 11635 | }, .{}); |
| 4073 | 11636 | |
| 4074 | 11637 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv); |
| ... | ... | @@ -4086,18 +11649,13 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4086 | 11649 | registerAlias(limit_reg, cmov_abi_size), |
| 4087 | 11650 | ); |
| 4088 | 11651 | |
| 4089 | | if (reg_extra_bits > 0 and ty.isSignedInt(zcu)) try self.genShiftBinOpMir( |
| 4090 | | .{ ._r, .sa }, |
| 4091 | | ty, |
| 4092 | | dst_mcv, |
| 4093 | | Type.u8, |
| 4094 | | .{ .immediate = reg_extra_bits }, |
| 4095 | | ); |
| 11652 | if (reg_extra_bits > 0 and ty.isSignedInt(zcu)) |
| 11653 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .u8, .{ .immediate = reg_extra_bits }); |
| 4096 | 11654 | |
| 4097 | 11655 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 4098 | 11656 | } |
| 4099 | 11657 | |
| 4100 | | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 11658 | fn airSubSat(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 4101 | 11659 | const pt = self.pt; |
| 4102 | 11660 | const zcu = pt.zcu; |
| 4103 | 11661 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -4132,22 +11690,10 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4132 | 11690 | const reg_extra_bits = self.regExtraBits(ty); |
| 4133 | 11691 | const cc: Condition = if (ty.isSignedInt(zcu)) cc: { |
| 4134 | 11692 | if (reg_extra_bits > 0) { |
| 4135 | | try self.genShiftBinOpMir( |
| 4136 | | .{ ._l, .sa }, |
| 4137 | | ty, |
| 4138 | | dst_mcv, |
| 4139 | | Type.u8, |
| 4140 | | .{ .immediate = reg_extra_bits }, |
| 4141 | | ); |
| 11693 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .u8, .{ .immediate = reg_extra_bits }); |
| 4142 | 11694 | } |
| 4143 | 11695 | try self.genSetReg(limit_reg, ty, dst_mcv, .{}); |
| 4144 | | try self.genShiftBinOpMir( |
| 4145 | | .{ ._r, .sa }, |
| 4146 | | ty, |
| 4147 | | limit_mcv, |
| 4148 | | Type.u8, |
| 4149 | | .{ .immediate = reg_bits - 1 }, |
| 4150 | | ); |
| 11696 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .u8, .{ .immediate = reg_bits - 1 }); |
| 4151 | 11697 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ |
| 4152 | 11698 | .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1, |
| 4153 | 11699 | }); |
| ... | ... | @@ -4157,13 +11703,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4157 | 11703 | const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg); |
| 4158 | 11704 | defer self.register_manager.unlockReg(shifted_rhs_lock); |
| 4159 | 11705 | |
| 4160 | | try self.genShiftBinOpMir( |
| 4161 | | .{ ._l, .sa }, |
| 4162 | | ty, |
| 4163 | | shifted_rhs_mcv, |
| 4164 | | Type.u8, |
| 4165 | | .{ .immediate = reg_extra_bits }, |
| 4166 | | ); |
| 11706 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, shifted_rhs_mcv, .u8, .{ .immediate = reg_extra_bits }); |
| 4167 | 11707 | try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv); |
| 4168 | 11708 | } else try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv); |
| 4169 | 11709 | break :cc .o; |
| ... | ... | @@ -4180,18 +11720,13 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4180 | 11720 | registerAlias(limit_reg, cmov_abi_size), |
| 4181 | 11721 | ); |
| 4182 | 11722 | |
| 4183 | | if (reg_extra_bits > 0 and ty.isSignedInt(zcu)) try self.genShiftBinOpMir( |
| 4184 | | .{ ._r, .sa }, |
| 4185 | | ty, |
| 4186 | | dst_mcv, |
| 4187 | | Type.u8, |
| 4188 | | .{ .immediate = reg_extra_bits }, |
| 4189 | | ); |
| 11723 | if (reg_extra_bits > 0 and ty.isSignedInt(zcu)) |
| 11724 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .u8, .{ .immediate = reg_extra_bits }); |
| 4190 | 11725 | |
| 4191 | 11726 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 4192 | 11727 | } |
| 4193 | 11728 | |
| 4194 | | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 11729 | fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 4195 | 11730 | const pt = self.pt; |
| 4196 | 11731 | const zcu = pt.zcu; |
| 4197 | 11732 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -4199,18 +11734,18 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4199 | 11734 | |
| 4200 | 11735 | const result = result: { |
| 4201 | 11736 | if (ty.toIntern() == .i128_type) { |
| 4202 | | const ptr_c_int = try pt.singleMutPtrType(Type.c_int); |
| 4203 | | const overflow = try self.allocTempRegOrMem(Type.c_int, false); |
| 11737 | const ptr_c_int = try pt.singleMutPtrType(.c_int); |
| 11738 | const overflow = try self.allocTempRegOrMem(.c_int, false); |
| 4204 | 11739 | |
| 4205 | 11740 | const dst_mcv = try self.genCall(.{ .lib = .{ |
| 4206 | 11741 | .return_type = .i128_type, |
| 4207 | 11742 | .param_types = &.{ .i128_type, .i128_type, ptr_c_int.toIntern() }, |
| 4208 | 11743 | .callee = "__muloti4", |
| 4209 | | } }, &.{ Type.i128, Type.i128, ptr_c_int }, &.{ |
| 11744 | } }, &.{ .i128, .i128, ptr_c_int }, &.{ |
| 4210 | 11745 | .{ .air_ref = bin_op.lhs }, |
| 4211 | 11746 | .{ .air_ref = bin_op.rhs }, |
| 4212 | 11747 | overflow.address(), |
| 4213 | | }); |
| 11748 | }, .{}); |
| 4214 | 11749 | const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_mcv.register_pair); |
| 4215 | 11750 | defer for (dst_locks) |lock| self.register_manager.unlockReg(lock); |
| 4216 | 11751 | |
| ... | ... | @@ -4222,7 +11757,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4222 | 11757 | const mat_lhs_mcv = switch (lhs_mcv) { |
| 4223 | 11758 | .load_symbol => mat_lhs_mcv: { |
| 4224 | 11759 | // TODO clean this up! |
| 4225 | | const addr_reg = try self.copyToTmpRegister(Type.usize, lhs_mcv.address()); |
| 11760 | const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address()); |
| 4226 | 11761 | break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 4227 | 11762 | }, |
| 4228 | 11763 | else => lhs_mcv, |
| ... | ... | @@ -4232,10 +11767,10 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4232 | 11767 | else => null, |
| 4233 | 11768 | }; |
| 4234 | 11769 | defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4235 | | if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 11770 | if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory( |
| 4236 | 11771 | .{ ._, .mov }, |
| 4237 | 11772 | tmp_reg, |
| 4238 | | try mat_lhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 11773 | try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 4239 | 11774 | ) else try self.asmRegisterRegister( |
| 4240 | 11775 | .{ ._, .mov }, |
| 4241 | 11776 | tmp_reg, |
| ... | ... | @@ -4246,7 +11781,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4246 | 11781 | const mat_rhs_mcv = switch (rhs_mcv) { |
| 4247 | 11782 | .load_symbol => mat_rhs_mcv: { |
| 4248 | 11783 | // TODO clean this up! |
| 4249 | | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 11784 | const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); |
| 4250 | 11785 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 4251 | 11786 | }, |
| 4252 | 11787 | else => rhs_mcv, |
| ... | ... | @@ -4256,22 +11791,22 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4256 | 11791 | else => null, |
| 4257 | 11792 | }; |
| 4258 | 11793 | defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4259 | | if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 11794 | if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory( |
| 4260 | 11795 | .{ ._, .xor }, |
| 4261 | 11796 | tmp_reg, |
| 4262 | | try mat_rhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 11797 | try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 4263 | 11798 | ) else try self.asmRegisterRegister( |
| 4264 | 11799 | .{ ._, .xor }, |
| 4265 | 11800 | tmp_reg, |
| 4266 | 11801 | mat_rhs_mcv.register_pair[1], |
| 4267 | 11802 | ); |
| 4268 | 11803 | |
| 4269 | | try self.asmRegisterImmediate(.{ ._r, .sa }, tmp_reg, Immediate.u(63)); |
| 11804 | try self.asmRegisterImmediate(.{ ._r, .sa }, tmp_reg, .u(63)); |
| 4270 | 11805 | try self.asmRegister(.{ ._, .not }, tmp_reg); |
| 4271 | | try self.asmMemoryImmediate(.{ ._, .cmp }, try overflow.mem(self, .dword), Immediate.s(0)); |
| 11806 | try self.asmMemoryImmediate(.{ ._, .cmp }, try overflow.mem(self, .{ .size = .dword }), .s(0)); |
| 4272 | 11807 | try self.freeValue(overflow); |
| 4273 | 11808 | try self.asmCmovccRegisterRegister(.ne, dst_mcv.register_pair[0], tmp_reg); |
| 4274 | | try self.asmRegisterImmediate(.{ ._c, .bt }, tmp_reg, Immediate.u(63)); |
| 11809 | try self.asmRegisterImmediate(.{ ._c, .bt }, tmp_reg, .u(63)); |
| 4275 | 11810 | try self.asmCmovccRegisterRegister(.ne, dst_mcv.register_pair[1], tmp_reg); |
| 4276 | 11811 | break :result dst_mcv; |
| 4277 | 11812 | } |
| ... | ... | @@ -4308,20 +11843,14 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4308 | 11843 | const cc: Condition = if (ty.isSignedInt(zcu)) cc: { |
| 4309 | 11844 | try self.genSetReg(limit_reg, ty, lhs_mcv, .{}); |
| 4310 | 11845 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv); |
| 4311 | | try self.genShiftBinOpMir( |
| 4312 | | .{ ._r, .sa }, |
| 4313 | | ty, |
| 4314 | | limit_mcv, |
| 4315 | | Type.u8, |
| 4316 | | .{ .immediate = reg_bits - 1 }, |
| 4317 | | ); |
| 11846 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .u8, .{ .immediate = reg_bits - 1 }); |
| 4318 | 11847 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ |
| 4319 | 11848 | .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1, |
| 4320 | 11849 | }); |
| 4321 | 11850 | break :cc .o; |
| 4322 | 11851 | } else cc: { |
| 4323 | 11852 | try self.genSetReg(limit_reg, ty, .{ |
| 4324 | | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(64 - reg_bits), |
| 11853 | .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - reg_bits), |
| 4325 | 11854 | }, .{}); |
| 4326 | 11855 | break :cc .c; |
| 4327 | 11856 | }; |
| ... | ... | @@ -4338,7 +11867,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 4338 | 11867 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 4339 | 11868 | } |
| 4340 | 11869 | |
| 4341 | | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 11870 | fn airAddSubWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 4342 | 11871 | const pt = self.pt; |
| 4343 | 11872 | const zcu = pt.zcu; |
| 4344 | 11873 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -4366,7 +11895,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4366 | 11895 | }; |
| 4367 | 11896 | |
| 4368 | 11897 | const tuple_ty = self.typeOfIndex(inst); |
| 4369 | | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 11898 | if (int_info.bits >= 8 and std.math.isPowerOfTwo(int_info.bits)) { |
| 4370 | 11899 | switch (partial_mcv) { |
| 4371 | 11900 | .register => |reg| { |
| 4372 | 11901 | self.eflags_inst = inst; |
| ... | ... | @@ -4375,12 +11904,11 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4375 | 11904 | else => {}, |
| 4376 | 11905 | } |
| 4377 | 11906 | |
| 4378 | | const frame_index = |
| 4379 | | try self.allocFrameIndex(FrameAlloc.initSpill(tuple_ty, zcu)); |
| 11907 | const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu)); |
| 4380 | 11908 | try self.genSetMem( |
| 4381 | 11909 | .{ .frame = frame_index }, |
| 4382 | 11910 | @intCast(tuple_ty.structFieldOffset(1, zcu)), |
| 4383 | | Type.u1, |
| 11911 | .u1, |
| 4384 | 11912 | .{ .eflags = cc }, |
| 4385 | 11913 | .{}, |
| 4386 | 11914 | ); |
| ... | ... | @@ -4394,8 +11922,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4394 | 11922 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 4395 | 11923 | } |
| 4396 | 11924 | |
| 4397 | | const frame_index = |
| 4398 | | try self.allocFrameIndex(FrameAlloc.initSpill(tuple_ty, zcu)); |
| 11925 | const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu)); |
| 4399 | 11926 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 4400 | 11927 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 4401 | 11928 | }, |
| ... | ... | @@ -4405,7 +11932,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4405 | 11932 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 4406 | 11933 | } |
| 4407 | 11934 | |
| 4408 | | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 11935 | fn airShlWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 4409 | 11936 | const pt = self.pt; |
| 4410 | 11937 | const zcu = pt.zcu; |
| 4411 | 11938 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -4444,7 +11971,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4444 | 11971 | const cc = Condition.ne; |
| 4445 | 11972 | |
| 4446 | 11973 | const tuple_ty = self.typeOfIndex(inst); |
| 4447 | | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 11974 | if (int_info.bits >= 8 and std.math.isPowerOfTwo(int_info.bits)) { |
| 4448 | 11975 | switch (partial_mcv) { |
| 4449 | 11976 | .register => |reg| { |
| 4450 | 11977 | self.eflags_inst = inst; |
| ... | ... | @@ -4453,8 +11980,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4453 | 11980 | else => {}, |
| 4454 | 11981 | } |
| 4455 | 11982 | |
| 4456 | | const frame_index = |
| 4457 | | try self.allocFrameIndex(FrameAlloc.initSpill(tuple_ty, zcu)); |
| 11983 | const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu)); |
| 4458 | 11984 | try self.genSetMem( |
| 4459 | 11985 | .{ .frame = frame_index }, |
| 4460 | 11986 | @intCast(tuple_ty.structFieldOffset(1, zcu)), |
| ... | ... | @@ -4473,7 +11999,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4473 | 11999 | } |
| 4474 | 12000 | |
| 4475 | 12001 | const frame_index = |
| 4476 | | try self.allocFrameIndex(FrameAlloc.initSpill(tuple_ty, zcu)); |
| 12002 | try self.allocFrameIndex(.initSpill(tuple_ty, zcu)); |
| 4477 | 12003 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 4478 | 12004 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 4479 | 12005 | }, |
| ... | ... | @@ -4484,7 +12010,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4484 | 12010 | } |
| 4485 | 12011 | |
| 4486 | 12012 | fn genSetFrameTruncatedOverflowCompare( |
| 4487 | | self: *Self, |
| 12013 | self: *CodeGen, |
| 4488 | 12014 | tuple_ty: Type, |
| 4489 | 12015 | frame_index: FrameIndex, |
| 4490 | 12016 | src_mcv: MCValue, |
| ... | ... | @@ -4499,6 +12025,7 @@ fn genSetFrameTruncatedOverflowCompare( |
| 4499 | 12025 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 4500 | 12026 | |
| 4501 | 12027 | const ty = tuple_ty.fieldType(0, zcu); |
| 12028 | const ty_size = ty.abiSize(zcu); |
| 4502 | 12029 | const int_info = ty.intInfo(zcu); |
| 4503 | 12030 | |
| 4504 | 12031 | const hi_bits = (int_info.bits - 1) % 64 + 1; |
| ... | ... | @@ -4510,7 +12037,7 @@ fn genSetFrameTruncatedOverflowCompare( |
| 4510 | 12037 | const rest_ty = try pt.intType(.unsigned, int_info.bits - hi_bits); |
| 4511 | 12038 | |
| 4512 | 12039 | const temp_regs = |
| 4513 | | try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp); |
| 12040 | try self.register_manager.allocRegs(3, @splat(null), abi.RegisterClass.gp); |
| 4514 | 12041 | const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); |
| 4515 | 12042 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 4516 | 12043 | |
| ... | ... | @@ -4530,13 +12057,15 @@ fn genSetFrameTruncatedOverflowCompare( |
| 4530 | 12057 | const eq_reg = temp_regs[2]; |
| 4531 | 12058 | if (overflow_cc) |_| { |
| 4532 | 12059 | try self.asmSetccRegister(.ne, eq_reg.to8()); |
| 4533 | | try self.genBinOpMir( |
| 4534 | | .{ ._, .@"or" }, |
| 4535 | | Type.u8, |
| 4536 | | .{ .register = overflow_reg }, |
| 4537 | | .{ .register = eq_reg }, |
| 4538 | | ); |
| 12060 | try self.genBinOpMir(.{ ._, .@"or" }, .u8, .{ .register = overflow_reg }, .{ .register = eq_reg }); |
| 4539 | 12061 | } |
| 12062 | try self.genSetMem( |
| 12063 | .{ .frame = frame_index }, |
| 12064 | @intCast(tuple_ty.structFieldOffset(1, zcu)), |
| 12065 | tuple_ty.fieldType(1, zcu), |
| 12066 | if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne }, |
| 12067 | .{}, |
| 12068 | ); |
| 4540 | 12069 | |
| 4541 | 12070 | const payload_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu)); |
| 4542 | 12071 | if (hi_limb_off > 0) try self.genSetMem( |
| ... | ... | @@ -4546,23 +12075,30 @@ fn genSetFrameTruncatedOverflowCompare( |
| 4546 | 12075 | src_mcv, |
| 4547 | 12076 | .{}, |
| 4548 | 12077 | ); |
| 4549 | | try self.genSetMem( |
| 4550 | | .{ .frame = frame_index }, |
| 4551 | | payload_off + hi_limb_off, |
| 4552 | | limb_ty, |
| 4553 | | .{ .register = scratch_reg }, |
| 4554 | | .{}, |
| 4555 | | ); |
| 4556 | | try self.genSetMem( |
| 4557 | | .{ .frame = frame_index }, |
| 4558 | | @intCast(tuple_ty.structFieldOffset(1, zcu)), |
| 4559 | | tuple_ty.fieldType(1, zcu), |
| 4560 | | if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne }, |
| 12078 | try self.genSetMem( |
| 12079 | .{ .frame = frame_index }, |
| 12080 | payload_off + hi_limb_off, |
| 12081 | limb_ty, |
| 12082 | .{ .register = scratch_reg }, |
| 4561 | 12083 | .{}, |
| 4562 | 12084 | ); |
| 12085 | var ext_off: i32 = hi_limb_off + 8; |
| 12086 | if (ext_off < ty_size) { |
| 12087 | switch (int_info.signedness) { |
| 12088 | .signed => try self.asmRegisterImmediate(.{ ._r, .sa }, scratch_reg.to64(), .s(63)), |
| 12089 | .unsigned => try self.asmRegisterRegister(.{ ._, .xor }, scratch_reg.to32(), scratch_reg.to32()), |
| 12090 | } |
| 12091 | while (ext_off < ty_size) : (ext_off += 8) try self.genSetMem( |
| 12092 | .{ .frame = frame_index }, |
| 12093 | payload_off + ext_off, |
| 12094 | limb_ty, |
| 12095 | .{ .register = scratch_reg }, |
| 12096 | .{}, |
| 12097 | ); |
| 12098 | } |
| 4563 | 12099 | } |
| 4564 | 12100 | |
| 4565 | | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 12101 | fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 4566 | 12102 | const pt = self.pt; |
| 4567 | 12103 | const zcu = pt.zcu; |
| 4568 | 12104 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -4576,7 +12112,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4576 | 12112 | if (dst_info.bits > 128 and dst_info.signedness == .unsigned) { |
| 4577 | 12113 | const slow_inc = self.hasFeature(.slow_incdec); |
| 4578 | 12114 | const abi_size: u32 = @intCast(dst_ty.abiSize(zcu)); |
| 4579 | | const limb_len = math.divCeil(u32, abi_size, 8) catch unreachable; |
| 12115 | const limb_len = std.math.divCeil(u32, abi_size, 8) catch unreachable; |
| 4580 | 12116 | |
| 4581 | 12117 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| 4582 | 12118 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx }); |
| ... | ... | @@ -4593,7 +12129,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4593 | 12129 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 4594 | 12130 | |
| 4595 | 12131 | const temp_regs = |
| 4596 | | try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp); |
| 12132 | try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp); |
| 4597 | 12133 | const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs); |
| 4598 | 12134 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 4599 | 12135 | |
| ... | ... | @@ -4618,7 +12154,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4618 | 12154 | try self.asmRegisterRegister(.{ ._, .xor }, .edx, .edx); |
| 4619 | 12155 | |
| 4620 | 12156 | const inner_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 4621 | | try self.asmRegisterImmediate(.{ ._r, .sh }, .cl, Immediate.u(1)); |
| 12157 | try self.asmRegisterImmediate(.{ ._r, .sh }, .cl, .u(1)); |
| 4622 | 12158 | try self.asmMemoryRegister(.{ ._, .adc }, .{ |
| 4623 | 12159 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| 4624 | 12160 | .mod = .{ .rm = .{ |
| ... | ... | @@ -4642,7 +12178,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4642 | 12178 | }); |
| 4643 | 12179 | try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64()); |
| 4644 | 12180 | |
| 4645 | | try self.asmRegisterImmediate(.{ ._r, .sh }, .ch, Immediate.u(1)); |
| 12181 | try self.asmRegisterImmediate(.{ ._r, .sh }, .ch, .u(1)); |
| 4646 | 12182 | try self.asmMemoryRegister(.{ ._, .adc }, .{ |
| 4647 | 12183 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| 4648 | 12184 | .mod = .{ .rm = .{ |
| ... | ... | @@ -4656,30 +12192,22 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4656 | 12192 | try self.asmSetccRegister(.c, .ch); |
| 4657 | 12193 | |
| 4658 | 12194 | if (slow_inc) { |
| 4659 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), Immediate.u(1)); |
| 4660 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), Immediate.u(1)); |
| 12195 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1)); |
| 12196 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), .u(1)); |
| 4661 | 12197 | } else { |
| 4662 | 12198 | try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32()); |
| 4663 | 12199 | try self.asmRegister(.{ ._, .inc }, temp_regs[3].to32()); |
| 4664 | 12200 | } |
| 4665 | | try self.asmRegisterImmediate( |
| 4666 | | .{ ._, .cmp }, |
| 4667 | | temp_regs[3].to32(), |
| 4668 | | Immediate.u(limb_len), |
| 4669 | | ); |
| 12201 | try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[3].to32(), .u(limb_len)); |
| 4670 | 12202 | _ = try self.asmJccReloc(.b, inner_loop); |
| 4671 | 12203 | |
| 4672 | 12204 | try self.asmRegisterRegister(.{ ._, .@"or" }, .rdx, .rcx); |
| 4673 | 12205 | const overflow = try self.asmJccReloc(.nz, undefined); |
| 4674 | 12206 | const overflow_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 4675 | | try self.asmRegisterImmediate( |
| 4676 | | .{ ._, .cmp }, |
| 4677 | | temp_regs[2].to32(), |
| 4678 | | Immediate.u(limb_len), |
| 4679 | | ); |
| 12207 | try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[2].to32(), .u(limb_len)); |
| 4680 | 12208 | const no_overflow = try self.asmJccReloc(.nb, undefined); |
| 4681 | 12209 | if (slow_inc) { |
| 4682 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), Immediate.u(1)); |
| 12210 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1)); |
| 4683 | 12211 | } else { |
| 4684 | 12212 | try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32()); |
| 4685 | 12213 | } |
| ... | ... | @@ -4691,7 +12219,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4691 | 12219 | .scale = .@"8", |
| 4692 | 12220 | .disp = lhs_mcv.load_frame.off - 8, |
| 4693 | 12221 | } }, |
| 4694 | | }, Immediate.u(0)); |
| 12222 | }, .u(0)); |
| 4695 | 12223 | _ = try self.asmJccReloc(.z, overflow_loop); |
| 4696 | 12224 | self.performReloc(overflow); |
| 4697 | 12225 | try self.asmMemoryImmediate(.{ ._, .mov }, .{ |
| ... | ... | @@ -4701,20 +12229,16 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4701 | 12229 | .disp = dst_mcv.load_frame.off + |
| 4702 | 12230 | @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), |
| 4703 | 12231 | } }, |
| 4704 | | }, Immediate.u(1)); |
| 12232 | }, .u(1)); |
| 4705 | 12233 | self.performReloc(no_overflow); |
| 4706 | 12234 | |
| 4707 | 12235 | self.performReloc(skip_inner); |
| 4708 | 12236 | if (slow_inc) { |
| 4709 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), Immediate.u(1)); |
| 12237 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1)); |
| 4710 | 12238 | } else { |
| 4711 | 12239 | try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32()); |
| 4712 | 12240 | } |
| 4713 | | try self.asmRegisterImmediate( |
| 4714 | | .{ ._, .cmp }, |
| 4715 | | temp_regs[0].to32(), |
| 4716 | | Immediate.u(limb_len), |
| 4717 | | ); |
| 12241 | try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[0].to32(), .u(limb_len)); |
| 4718 | 12242 | _ = try self.asmJccReloc(.b, outer_loop); |
| 4719 | 12243 | |
| 4720 | 12244 | break :result dst_mcv; |
| ... | ... | @@ -4727,17 +12251,17 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4727 | 12251 | if (src_bits > 64 and src_bits <= 128 and |
| 4728 | 12252 | dst_info.bits > 64 and dst_info.bits <= 128) switch (dst_info.signedness) { |
| 4729 | 12253 | .signed => { |
| 4730 | | const ptr_c_int = try pt.singleMutPtrType(Type.c_int); |
| 4731 | | const overflow = try self.allocTempRegOrMem(Type.c_int, false); |
| 12254 | const ptr_c_int = try pt.singleMutPtrType(.c_int); |
| 12255 | const overflow = try self.allocTempRegOrMem(.c_int, false); |
| 4732 | 12256 | const result = try self.genCall(.{ .lib = .{ |
| 4733 | 12257 | .return_type = .i128_type, |
| 4734 | 12258 | .param_types = &.{ .i128_type, .i128_type, ptr_c_int.toIntern() }, |
| 4735 | 12259 | .callee = "__muloti4", |
| 4736 | | } }, &.{ Type.i128, Type.i128, ptr_c_int }, &.{ |
| 12260 | } }, &.{ .i128, .i128, ptr_c_int }, &.{ |
| 4737 | 12261 | .{ .air_ref = bin_op.lhs }, |
| 4738 | 12262 | .{ .air_ref = bin_op.rhs }, |
| 4739 | 12263 | overflow.address(), |
| 4740 | | }); |
| 12264 | }, .{}); |
| 4741 | 12265 | |
| 4742 | 12266 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 4743 | 12267 | try self.genSetMem( |
| ... | ... | @@ -4749,8 +12273,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4749 | 12273 | ); |
| 4750 | 12274 | try self.asmMemoryImmediate( |
| 4751 | 12275 | .{ ._, .cmp }, |
| 4752 | | try overflow.mem(self, self.memSize(Type.c_int)), |
| 4753 | | Immediate.s(0), |
| 12276 | try overflow.mem(self, .{ .size = self.memSize(.c_int) }), |
| 12277 | .s(0), |
| 4754 | 12278 | ); |
| 4755 | 12279 | try self.genSetMem( |
| 4756 | 12280 | .{ .frame = dst_mcv.load_frame.index }, |
| ... | ... | @@ -4769,52 +12293,74 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4769 | 12293 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 4770 | 12294 | |
| 4771 | 12295 | const tmp_regs = |
| 4772 | | try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp); |
| 12296 | try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp); |
| 4773 | 12297 | const tmp_locks = self.register_manager.lockRegsAssumeUnused(4, tmp_regs); |
| 4774 | 12298 | defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); |
| 4775 | 12299 | |
| 4776 | 12300 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 4777 | 12301 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 4778 | | const mat_lhs_mcv = switch (lhs_mcv) { |
| 4779 | | .load_symbol => mat_lhs_mcv: { |
| 12302 | const mat_lhs_mcv = mat_lhs_mcv: switch (lhs_mcv) { |
| 12303 | .register => |lhs_reg| switch (lhs_reg.class()) { |
| 12304 | else => lhs_mcv, |
| 12305 | .sse => { |
| 12306 | const mat_lhs_mcv: MCValue = .{ |
| 12307 | .register_pair = try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp), |
| 12308 | }; |
| 12309 | try self.genCopy(dst_ty, mat_lhs_mcv, lhs_mcv, .{}); |
| 12310 | break :mat_lhs_mcv mat_lhs_mcv; |
| 12311 | }, |
| 12312 | }, |
| 12313 | .load_symbol => { |
| 4780 | 12314 | // TODO clean this up! |
| 4781 | | const addr_reg = try self.copyToTmpRegister(Type.usize, lhs_mcv.address()); |
| 12315 | const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address()); |
| 4782 | 12316 | break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 4783 | 12317 | }, |
| 4784 | 12318 | else => lhs_mcv, |
| 4785 | 12319 | }; |
| 4786 | | const mat_lhs_lock = switch (mat_lhs_mcv) { |
| 4787 | | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 4788 | | else => null, |
| 12320 | const mat_lhs_locks: [2]?RegisterLock = switch (mat_lhs_mcv) { |
| 12321 | .register_pair => |mat_lhs_regs| self.register_manager.lockRegs(2, mat_lhs_regs), |
| 12322 | .indirect => |reg_off| .{ self.register_manager.lockReg(reg_off.reg), null }, |
| 12323 | else => @splat(null), |
| 4789 | 12324 | }; |
| 4790 | | defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4791 | | const mat_rhs_mcv = switch (rhs_mcv) { |
| 4792 | | .load_symbol => mat_rhs_mcv: { |
| 12325 | defer for (mat_lhs_locks) |mat_lhs_lock| if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 12326 | const mat_rhs_mcv = mat_rhs_mcv: switch (rhs_mcv) { |
| 12327 | .register => |rhs_reg| switch (rhs_reg.class()) { |
| 12328 | else => rhs_mcv, |
| 12329 | .sse => { |
| 12330 | const mat_rhs_mcv: MCValue = .{ |
| 12331 | .register_pair = try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp), |
| 12332 | }; |
| 12333 | try self.genCopy(dst_ty, mat_rhs_mcv, rhs_mcv, .{}); |
| 12334 | break :mat_rhs_mcv mat_rhs_mcv; |
| 12335 | }, |
| 12336 | }, |
| 12337 | .load_symbol => { |
| 4793 | 12338 | // TODO clean this up! |
| 4794 | | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 12339 | const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); |
| 4795 | 12340 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 4796 | 12341 | }, |
| 4797 | 12342 | else => rhs_mcv, |
| 4798 | 12343 | }; |
| 4799 | | const mat_rhs_lock = switch (mat_rhs_mcv) { |
| 4800 | | .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg), |
| 4801 | | else => null, |
| 12344 | const mat_rhs_locks: [2]?RegisterLock = switch (mat_rhs_mcv) { |
| 12345 | .register_pair => |mat_rhs_regs| self.register_manager.lockRegs(2, mat_rhs_regs), |
| 12346 | .indirect => |reg_off| .{ self.register_manager.lockReg(reg_off.reg), null }, |
| 12347 | else => @splat(null), |
| 4802 | 12348 | }; |
| 4803 | | defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 12349 | defer for (mat_rhs_locks) |mat_rhs_lock| if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4804 | 12350 | |
| 4805 | | if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 12351 | if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory( |
| 4806 | 12352 | .{ ._, .mov }, |
| 4807 | 12353 | .rax, |
| 4808 | | try mat_lhs_mcv.mem(self, .qword), |
| 12354 | try mat_lhs_mcv.mem(self, .{ .size = .qword }), |
| 4809 | 12355 | ) else try self.asmRegisterRegister( |
| 4810 | 12356 | .{ ._, .mov }, |
| 4811 | 12357 | .rax, |
| 4812 | 12358 | mat_lhs_mcv.register_pair[0], |
| 4813 | 12359 | ); |
| 4814 | | if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 12360 | if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory( |
| 4815 | 12361 | .{ ._, .mov }, |
| 4816 | 12362 | tmp_regs[0], |
| 4817 | | try mat_rhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 12363 | try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 4818 | 12364 | ) else try self.asmRegisterRegister( |
| 4819 | 12365 | .{ ._, .mov }, |
| 4820 | 12366 | tmp_regs[0], |
| ... | ... | @@ -4824,17 +12370,17 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4824 | 12370 | try self.asmSetccRegister(.nz, tmp_regs[1].to8()); |
| 4825 | 12371 | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_regs[0], .rax); |
| 4826 | 12372 | try self.asmSetccRegister(.o, tmp_regs[2].to8()); |
| 4827 | | if (mat_rhs_mcv.isMemory()) |
| 4828 | | try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .qword)) |
| 12373 | if (mat_rhs_mcv.isBase()) |
| 12374 | try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword })) |
| 4829 | 12375 | else |
| 4830 | 12376 | try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]); |
| 4831 | 12377 | try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_regs[0]); |
| 4832 | 12378 | try self.asmSetccRegister(.c, tmp_regs[3].to8()); |
| 4833 | 12379 | try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[2].to8(), tmp_regs[3].to8()); |
| 4834 | | if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 12380 | if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory( |
| 4835 | 12381 | .{ ._, .mov }, |
| 4836 | 12382 | tmp_regs[0], |
| 4837 | | try mat_lhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 12383 | try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 4838 | 12384 | ) else try self.asmRegisterRegister( |
| 4839 | 12385 | .{ ._, .mov }, |
| 4840 | 12386 | tmp_regs[0], |
| ... | ... | @@ -4848,10 +12394,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4848 | 12394 | tmp_regs[3].to8(), |
| 4849 | 12395 | ); |
| 4850 | 12396 | try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[1].to8(), tmp_regs[2].to8()); |
| 4851 | | if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 12397 | if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory( |
| 4852 | 12398 | .{ .i_, .mul }, |
| 4853 | 12399 | tmp_regs[0], |
| 4854 | | try mat_rhs_mcv.mem(self, .qword), |
| 12400 | try mat_rhs_mcv.mem(self, .{ .size = .qword }), |
| 4855 | 12401 | ) else try self.asmRegisterRegister( |
| 4856 | 12402 | .{ .i_, .mul }, |
| 4857 | 12403 | tmp_regs[0], |
| ... | ... | @@ -4906,7 +12452,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4906 | 12452 | self.eflags_inst = inst; |
| 4907 | 12453 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; |
| 4908 | 12454 | } else { |
| 4909 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(tuple_ty, zcu)); |
| 12455 | const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu)); |
| 4910 | 12456 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 4911 | 12457 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 4912 | 12458 | }, |
| ... | ... | @@ -4917,7 +12463,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4917 | 12463 | src_ty.fmt(pt), dst_ty.fmt(pt), |
| 4918 | 12464 | }); |
| 4919 | 12465 | |
| 4920 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(tuple_ty, zcu)); |
| 12466 | const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu)); |
| 4921 | 12467 | if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { |
| 4922 | 12468 | try self.genSetMem( |
| 4923 | 12469 | .{ .frame = frame_index }, |
| ... | ... | @@ -4951,7 +12497,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4951 | 12497 | /// Generates signed or unsigned integer multiplication/division. |
| 4952 | 12498 | /// Clobbers .rax and .rdx registers. |
| 4953 | 12499 | /// Quotient is saved in .rax and remainder in .rdx. |
| 4954 | | fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue, rhs: MCValue) !void { |
| 12500 | fn genIntMulDivOpMir(self: *CodeGen, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue, rhs: MCValue) !void { |
| 4955 | 12501 | const pt = self.pt; |
| 4956 | 12502 | const abi_size: u32 = @intCast(ty.abiSize(pt.zcu)); |
| 4957 | 12503 | const bit_size: u32 = @intCast(self.regBitSize(ty)); |
| ... | ... | @@ -4992,7 +12538,7 @@ fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue |
| 4992 | 12538 | .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)), |
| 4993 | 12539 | .memory, .indirect, .load_frame => try self.asmMemory( |
| 4994 | 12540 | tag, |
| 4995 | | try mat_rhs.mem(self, Memory.Size.fromSize(abi_size)), |
| 12541 | try mat_rhs.mem(self, .{ .size = .fromSize(abi_size) }), |
| 4996 | 12542 | ), |
| 4997 | 12543 | else => unreachable, |
| 4998 | 12544 | } |
| ... | ... | @@ -5001,7 +12547,7 @@ fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue |
| 5001 | 12547 | |
| 5002 | 12548 | /// Always returns a register. |
| 5003 | 12549 | /// Clobbers .rax and .rdx registers. |
| 5004 | | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 12550 | fn genInlineIntDivFloor(self: *CodeGen, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 5005 | 12551 | const pt = self.pt; |
| 5006 | 12552 | const zcu = pt.zcu; |
| 5007 | 12553 | const abi_size: u32 = @intCast(ty.abiSize(zcu)); |
| ... | ... | @@ -5038,7 +12584,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 5038 | 12584 | try self.asmRegisterImmediate( |
| 5039 | 12585 | .{ ._r, .sa }, |
| 5040 | 12586 | registerAlias(divisor, abi_size), |
| 5041 | | Immediate.u(int_info.bits - 1), |
| 12587 | .u(int_info.bits - 1), |
| 5042 | 12588 | ); |
| 5043 | 12589 | try self.asmRegisterRegister( |
| 5044 | 12590 | .{ ._, .@"test" }, |
| ... | ... | @@ -5054,7 +12600,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 5054 | 12600 | return MCValue{ .register = divisor }; |
| 5055 | 12601 | } |
| 5056 | 12602 | |
| 5057 | | fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 12603 | fn airShlShrBinOp(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5058 | 12604 | const pt = self.pt; |
| 5059 | 12605 | const zcu = pt.zcu; |
| 5060 | 12606 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -5084,7 +12630,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 5084 | 12630 | defer self.register_manager.unlockReg(tmp_lock); |
| 5085 | 12631 | |
| 5086 | 12632 | const lhs_bits: u31 = @intCast(lhs_ty.bitSize(zcu)); |
| 5087 | | const tmp_ty = if (lhs_bits > 64) Type.usize else lhs_ty; |
| 12633 | const tmp_ty: Type = if (lhs_bits > 64) .usize else lhs_ty; |
| 5088 | 12634 | const off = frame_addr.off + (lhs_bits - 1) / 64 * 8; |
| 5089 | 12635 | try self.genSetReg( |
| 5090 | 12636 | tmp_reg, |
| ... | ... | @@ -5217,8 +12763,8 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 5217 | 12763 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| |
| 5218 | 12764 | self.register_manager.unlockReg(lock); |
| 5219 | 12765 | |
| 5220 | | const shift_imm = |
| 5221 | | Immediate.u(@intCast(Value.fromInterned(rhs_elem).toUnsignedInt(zcu))); |
| 12766 | const shift_imm: Immediate = |
| 12767 | .u(@intCast(Value.fromInterned(rhs_elem).toUnsignedInt(zcu))); |
| 5222 | 12768 | if (self.hasFeature(.avx)) try self.asmRegisterRegisterImmediate( |
| 5223 | 12769 | mir_tag, |
| 5224 | 12770 | registerAlias(dst_reg, abi_size), |
| ... | ... | @@ -5264,16 +12810,15 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 5264 | 12810 | defer self.register_manager.unlockReg(shift_lock); |
| 5265 | 12811 | |
| 5266 | 12812 | const mask_ty = try pt.vectorType(.{ .len = 16, .child = .u8_type }); |
| 5267 | | const mask_mcv = try self.genTypedValue(Value.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 12813 | const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 5268 | 12814 | .ty = mask_ty.toIntern(), |
| 5269 | 12815 | .storage = .{ .elems = &([1]InternPool.Index{ |
| 5270 | | (try rhs_ty.childType(zcu).maxIntScalar(pt, Type.u8)).toIntern(), |
| 12816 | (try rhs_ty.childType(zcu).maxIntScalar(pt, .u8)).toIntern(), |
| 5271 | 12817 | } ++ [1]InternPool.Index{ |
| 5272 | | (try pt.intValue(Type.u8, 0)).toIntern(), |
| 12818 | (try pt.intValue(.u8, 0)).toIntern(), |
| 5273 | 12819 | } ** 15) }, |
| 5274 | 12820 | } }))); |
| 5275 | | const mask_addr_reg = |
| 5276 | | try self.copyToTmpRegister(Type.usize, mask_mcv.address()); |
| 12821 | const mask_addr_reg = try self.copyToTmpRegister(.usize, mask_mcv.address()); |
| 5277 | 12822 | const mask_addr_lock = self.register_manager.lockRegAssumeUnused(mask_addr_reg); |
| 5278 | 12823 | defer self.register_manager.unlockReg(mask_addr_lock); |
| 5279 | 12824 | |
| ... | ... | @@ -5322,14 +12867,14 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 5322 | 12867 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5323 | 12868 | } |
| 5324 | 12869 | |
| 5325 | | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 12870 | fn airShlSat(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5326 | 12871 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 5327 | 12872 | _ = bin_op; |
| 5328 | 12873 | return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); |
| 5329 | 12874 | //return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5330 | 12875 | } |
| 5331 | 12876 | |
| 5332 | | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 12877 | fn airOptionalPayload(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5333 | 12878 | const zcu = self.pt.zcu; |
| 5334 | 12879 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5335 | 12880 | const result: MCValue = result: { |
| ... | ... | @@ -5362,7 +12907,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 5362 | 12907 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5363 | 12908 | } |
| 5364 | 12909 | |
| 5365 | | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 12910 | fn airOptionalPayloadPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5366 | 12911 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5367 | 12912 | |
| 5368 | 12913 | const dst_ty = self.typeOfIndex(inst); |
| ... | ... | @@ -5375,7 +12920,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5375 | 12920 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 5376 | 12921 | } |
| 5377 | 12922 | |
| 5378 | | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 12923 | fn airOptionalPayloadPtrSet(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5379 | 12924 | const pt = self.pt; |
| 5380 | 12925 | const zcu = pt.zcu; |
| 5381 | 12926 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -5407,7 +12952,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 5407 | 12952 | try self.genSetMem( |
| 5408 | 12953 | .{ .reg = dst_mcv.getReg().? }, |
| 5409 | 12954 | pl_abi_size, |
| 5410 | | Type.bool, |
| 12955 | .bool, |
| 5411 | 12956 | .{ .immediate = 1 }, |
| 5412 | 12957 | .{}, |
| 5413 | 12958 | ); |
| ... | ... | @@ -5416,7 +12961,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 5416 | 12961 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5417 | 12962 | } |
| 5418 | 12963 | |
| 5419 | | fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 12964 | fn airUnwrapErrUnionErr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5420 | 12965 | const pt = self.pt; |
| 5421 | 12966 | const zcu = pt.zcu; |
| 5422 | 12967 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -5434,7 +12979,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 5434 | 12979 | break :result operand; |
| 5435 | 12980 | } |
| 5436 | 12981 | |
| 5437 | | const err_off = errUnionErrorOffset(payload_ty, zcu); |
| 12982 | const err_off = codegen.errUnionErrorOffset(payload_ty, zcu); |
| 5438 | 12983 | switch (operand) { |
| 5439 | 12984 | .register => |reg| { |
| 5440 | 12985 | // TODO reuse operand |
| ... | ... | @@ -5446,9 +12991,9 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 5446 | 12991 | .{ ._r, .sh }, |
| 5447 | 12992 | err_union_ty, |
| 5448 | 12993 | result, |
| 5449 | | Type.u8, |
| 12994 | .u8, |
| 5450 | 12995 | .{ .immediate = @as(u6, @intCast(err_off * 8)) }, |
| 5451 | | ) else try self.truncateRegister(Type.anyerror, result.register); |
| 12996 | ) else try self.truncateRegister(.anyerror, result.register); |
| 5452 | 12997 | break :result result; |
| 5453 | 12998 | }, |
| 5454 | 12999 | .load_frame => |frame_addr| break :result .{ .load_frame = .{ |
| ... | ... | @@ -5461,7 +13006,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 5461 | 13006 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5462 | 13007 | } |
| 5463 | 13008 | |
| 5464 | | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 13009 | fn airUnwrapErrUnionPayload(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5465 | 13010 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5466 | 13011 | const operand_ty = self.typeOf(ty_op.operand); |
| 5467 | 13012 | const operand = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -5470,7 +13015,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 5470 | 13015 | } |
| 5471 | 13016 | |
| 5472 | 13017 | // *(E!T) -> E |
| 5473 | | fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13018 | fn airUnwrapErrUnionErrPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5474 | 13019 | const pt = self.pt; |
| 5475 | 13020 | const zcu = pt.zcu; |
| 5476 | 13021 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -5492,7 +13037,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5492 | 13037 | const eu_ty = src_ty.childType(zcu); |
| 5493 | 13038 | const pl_ty = eu_ty.errorUnionPayload(zcu); |
| 5494 | 13039 | const err_ty = eu_ty.errorUnionSet(zcu); |
| 5495 | | const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); |
| 13040 | const err_off: i32 = @intCast(codegen.errUnionErrorOffset(pl_ty, zcu)); |
| 5496 | 13041 | const err_abi_size: u32 = @intCast(err_ty.abiSize(zcu)); |
| 5497 | 13042 | try self.asmRegisterMemory( |
| 5498 | 13043 | .{ ._, .mov }, |
| ... | ... | @@ -5500,7 +13045,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5500 | 13045 | .{ |
| 5501 | 13046 | .base = .{ .reg = src_reg }, |
| 5502 | 13047 | .mod = .{ .rm = .{ |
| 5503 | | .size = Memory.Size.fromSize(err_abi_size), |
| 13048 | .size = .fromSize(err_abi_size), |
| 5504 | 13049 | .disp = err_off, |
| 5505 | 13050 | } }, |
| 5506 | 13051 | }, |
| ... | ... | @@ -5510,7 +13055,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5510 | 13055 | } |
| 5511 | 13056 | |
| 5512 | 13057 | // *(E!T) -> *T |
| 5513 | | fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13058 | fn airUnwrapErrUnionPayloadPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5514 | 13059 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5515 | 13060 | const operand_ty = self.typeOf(ty_op.operand); |
| 5516 | 13061 | const operand = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -5518,7 +13063,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5518 | 13063 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5519 | 13064 | } |
| 5520 | 13065 | |
| 5521 | | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 13066 | fn airErrUnionPayloadPtrSet(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5522 | 13067 | const pt = self.pt; |
| 5523 | 13068 | const zcu = pt.zcu; |
| 5524 | 13069 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -5535,18 +13080,18 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 5535 | 13080 | const eu_ty = src_ty.childType(zcu); |
| 5536 | 13081 | const pl_ty = eu_ty.errorUnionPayload(zcu); |
| 5537 | 13082 | const err_ty = eu_ty.errorUnionSet(zcu); |
| 5538 | | const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); |
| 13083 | const err_off: i32 = @intCast(codegen.errUnionErrorOffset(pl_ty, zcu)); |
| 5539 | 13084 | const err_abi_size: u32 = @intCast(err_ty.abiSize(zcu)); |
| 5540 | 13085 | try self.asmMemoryImmediate( |
| 5541 | 13086 | .{ ._, .mov }, |
| 5542 | 13087 | .{ |
| 5543 | 13088 | .base = .{ .reg = src_reg }, |
| 5544 | 13089 | .mod = .{ .rm = .{ |
| 5545 | | .size = Memory.Size.fromSize(err_abi_size), |
| 13090 | .size = .fromSize(err_abi_size), |
| 5546 | 13091 | .disp = err_off, |
| 5547 | 13092 | } }, |
| 5548 | 13093 | }, |
| 5549 | | Immediate.u(0), |
| 13094 | .u(0), |
| 5550 | 13095 | ); |
| 5551 | 13096 | |
| 5552 | 13097 | if (self.liveness.isUnused(inst)) break :result .unreach; |
| ... | ... | @@ -5559,7 +13104,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 5559 | 13104 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 5560 | 13105 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5561 | 13106 | |
| 5562 | | const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu)); |
| 13107 | const pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(pl_ty, zcu)); |
| 5563 | 13108 | const dst_abi_size: u32 = @intCast(dst_ty.abiSize(zcu)); |
| 5564 | 13109 | try self.asmRegisterMemory( |
| 5565 | 13110 | .{ ._, .lea }, |
| ... | ... | @@ -5575,7 +13120,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 5575 | 13120 | } |
| 5576 | 13121 | |
| 5577 | 13122 | fn genUnwrapErrUnionPayloadMir( |
| 5578 | | self: *Self, |
| 13123 | self: *CodeGen, |
| 5579 | 13124 | maybe_inst: ?Air.Inst.Index, |
| 5580 | 13125 | err_union_ty: Type, |
| 5581 | 13126 | err_union: MCValue, |
| ... | ... | @@ -5587,7 +13132,7 @@ fn genUnwrapErrUnionPayloadMir( |
| 5587 | 13132 | const result: MCValue = result: { |
| 5588 | 13133 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none; |
| 5589 | 13134 | |
| 5590 | | const payload_off: u31 = @intCast(errUnionPayloadOffset(payload_ty, zcu)); |
| 13135 | const payload_off: u31 = @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu)); |
| 5591 | 13136 | switch (err_union) { |
| 5592 | 13137 | .load_frame => |frame_addr| break :result .{ .load_frame = .{ |
| 5593 | 13138 | .index = frame_addr.index, |
| ... | ... | @@ -5598,7 +13143,7 @@ fn genUnwrapErrUnionPayloadMir( |
| 5598 | 13143 | const eu_lock = self.register_manager.lockReg(reg); |
| 5599 | 13144 | defer if (eu_lock) |lock| self.register_manager.unlockReg(lock); |
| 5600 | 13145 | |
| 5601 | | const payload_in_gp = self.regClassForType(payload_ty).supersetOf(abi.RegisterClass.gp); |
| 13146 | const payload_in_gp = self.regSetForType(payload_ty).supersetOf(abi.RegisterClass.gp); |
| 5602 | 13147 | const result_mcv: MCValue = if (payload_in_gp and maybe_inst != null) |
| 5603 | 13148 | try self.copyToRegisterWithInstTracking(maybe_inst.?, err_union_ty, err_union) |
| 5604 | 13149 | else |
| ... | ... | @@ -5607,7 +13152,7 @@ fn genUnwrapErrUnionPayloadMir( |
| 5607 | 13152 | .{ ._r, .sh }, |
| 5608 | 13153 | err_union_ty, |
| 5609 | 13154 | result_mcv, |
| 5610 | | Type.u8, |
| 13155 | .u8, |
| 5611 | 13156 | .{ .immediate = @as(u6, @intCast(payload_off * 8)) }, |
| 5612 | 13157 | ) else try self.truncateRegister(payload_ty, result_mcv.register); |
| 5613 | 13158 | break :result if (payload_in_gp) |
| ... | ... | @@ -5625,7 +13170,7 @@ fn genUnwrapErrUnionPayloadMir( |
| 5625 | 13170 | } |
| 5626 | 13171 | |
| 5627 | 13172 | fn genUnwrapErrUnionPayloadPtrMir( |
| 5628 | | self: *Self, |
| 13173 | self: *CodeGen, |
| 5629 | 13174 | maybe_inst: ?Air.Inst.Index, |
| 5630 | 13175 | ptr_ty: Type, |
| 5631 | 13176 | ptr_mcv: MCValue, |
| ... | ... | @@ -5636,7 +13181,7 @@ fn genUnwrapErrUnionPayloadPtrMir( |
| 5636 | 13181 | const payload_ty = err_union_ty.errorUnionPayload(zcu); |
| 5637 | 13182 | |
| 5638 | 13183 | const result: MCValue = result: { |
| 5639 | | const payload_off = errUnionPayloadOffset(payload_ty, zcu); |
| 13184 | const payload_off = codegen.errUnionPayloadOffset(payload_ty, zcu); |
| 5640 | 13185 | const result_mcv: MCValue = if (maybe_inst) |inst| |
| 5641 | 13186 | try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr_mcv) |
| 5642 | 13187 | else |
| ... | ... | @@ -5648,23 +13193,23 @@ fn genUnwrapErrUnionPayloadPtrMir( |
| 5648 | 13193 | return result; |
| 5649 | 13194 | } |
| 5650 | 13195 | |
| 5651 | | fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| 13196 | fn airErrReturnTrace(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5652 | 13197 | _ = inst; |
| 5653 | 13198 | return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 5654 | 13199 | //return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 5655 | 13200 | } |
| 5656 | 13201 | |
| 5657 | | fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { |
| 13202 | fn airSetErrReturnTrace(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5658 | 13203 | _ = inst; |
| 5659 | 13204 | return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch}); |
| 5660 | 13205 | } |
| 5661 | 13206 | |
| 5662 | | fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 13207 | fn airSaveErrReturnTraceIndex(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5663 | 13208 | _ = inst; |
| 5664 | 13209 | return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch}); |
| 5665 | 13210 | } |
| 5666 | 13211 | |
| 5667 | | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 13212 | fn airWrapOptional(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5668 | 13213 | const pt = self.pt; |
| 5669 | 13214 | const zcu = pt.zcu; |
| 5670 | 13215 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -5696,7 +13241,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 5696 | 13241 | try self.asmRegisterImmediate( |
| 5697 | 13242 | .{ ._s, .bt }, |
| 5698 | 13243 | opt_reg, |
| 5699 | | Immediate.u(@as(u6, @intCast(pl_abi_size * 8))), |
| 13244 | .u(@as(u6, @intCast(pl_abi_size * 8))), |
| 5700 | 13245 | ); |
| 5701 | 13246 | }, |
| 5702 | 13247 | |
| ... | ... | @@ -5709,7 +13254,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 5709 | 13254 | .disp = frame_addr.off + pl_abi_size, |
| 5710 | 13255 | } }, |
| 5711 | 13256 | }, |
| 5712 | | Immediate.u(1), |
| 13257 | .u(1), |
| 5713 | 13258 | ), |
| 5714 | 13259 | } |
| 5715 | 13260 | } |
| ... | ... | @@ -5719,7 +13264,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 5719 | 13264 | } |
| 5720 | 13265 | |
| 5721 | 13266 | /// T to E!T |
| 5722 | | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 13267 | fn airWrapErrUnionPayload(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5723 | 13268 | const pt = self.pt; |
| 5724 | 13269 | const zcu = pt.zcu; |
| 5725 | 13270 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -5732,9 +13277,9 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 5732 | 13277 | const result: MCValue = result: { |
| 5733 | 13278 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .{ .immediate = 0 }; |
| 5734 | 13279 | |
| 5735 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu)); |
| 5736 | | const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu)); |
| 5737 | | const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); |
| 13280 | const frame_index = try self.allocFrameIndex(.initSpill(eu_ty, zcu)); |
| 13281 | const pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(pl_ty, zcu)); |
| 13282 | const err_off: i32 = @intCast(codegen.errUnionErrorOffset(pl_ty, zcu)); |
| 5738 | 13283 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, operand, .{}); |
| 5739 | 13284 | try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, .{ .immediate = 0 }, .{}); |
| 5740 | 13285 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| ... | ... | @@ -5743,7 +13288,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 5743 | 13288 | } |
| 5744 | 13289 | |
| 5745 | 13290 | /// E to E!T |
| 5746 | | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 13291 | fn airWrapErrUnionErr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5747 | 13292 | const pt = self.pt; |
| 5748 | 13293 | const zcu = pt.zcu; |
| 5749 | 13294 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -5755,9 +13300,9 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 5755 | 13300 | const result: MCValue = result: { |
| 5756 | 13301 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result try self.resolveInst(ty_op.operand); |
| 5757 | 13302 | |
| 5758 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu)); |
| 5759 | | const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu)); |
| 5760 | | const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); |
| 13303 | const frame_index = try self.allocFrameIndex(.initSpill(eu_ty, zcu)); |
| 13304 | const pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(pl_ty, zcu)); |
| 13305 | const err_off: i32 = @intCast(codegen.errUnionErrorOffset(pl_ty, zcu)); |
| 5761 | 13306 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef, .{}); |
| 5762 | 13307 | const operand = try self.resolveInst(ty_op.operand); |
| 5763 | 13308 | try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand, .{}); |
| ... | ... | @@ -5766,44 +13311,58 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 5766 | 13311 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5767 | 13312 | } |
| 5768 | 13313 | |
| 5769 | | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13314 | fn airSlicePtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5770 | 13315 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5771 | 13316 | const result = result: { |
| 5772 | 13317 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 5773 | | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 13318 | const ptr_mcv: MCValue = switch (src_mcv) { |
| 13319 | .register_pair => |regs| .{ .register = regs[0] }, |
| 13320 | else => src_mcv, |
| 13321 | }; |
| 13322 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) { |
| 13323 | switch (src_mcv) { |
| 13324 | .register_pair => |regs| try self.freeValue(.{ .register = regs[1] }), |
| 13325 | else => {}, |
| 13326 | } |
| 13327 | break :result ptr_mcv; |
| 13328 | } |
| 5774 | 13329 | |
| 5775 | 13330 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 5776 | | const dst_ty = self.typeOfIndex(inst); |
| 5777 | | try self.genCopy(dst_ty, dst_mcv, src_mcv, .{}); |
| 13331 | try self.genCopy(self.typeOfIndex(inst), dst_mcv, ptr_mcv, .{}); |
| 5778 | 13332 | break :result dst_mcv; |
| 5779 | 13333 | }; |
| 5780 | 13334 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5781 | 13335 | } |
| 5782 | 13336 | |
| 5783 | | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 13337 | fn airSliceLen(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5784 | 13338 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5785 | | |
| 5786 | | const result: MCValue = result: { |
| 13339 | const result = result: { |
| 5787 | 13340 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 5788 | | switch (src_mcv) { |
| 5789 | | .load_frame => |frame_addr| { |
| 5790 | | const len_mcv: MCValue = .{ .load_frame = .{ |
| 5791 | | .index = frame_addr.index, |
| 5792 | | .off = frame_addr.off + 8, |
| 5793 | | } }; |
| 5794 | | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv; |
| 5795 | | |
| 5796 | | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 5797 | | try self.genCopy(Type.usize, dst_mcv, len_mcv, .{}); |
| 5798 | | break :result dst_mcv; |
| 5799 | | }, |
| 13341 | const len_mcv: MCValue = switch (src_mcv) { |
| 13342 | .register_pair => |regs| .{ .register = regs[1] }, |
| 13343 | .load_frame => |frame_addr| .{ .load_frame = .{ |
| 13344 | .index = frame_addr.index, |
| 13345 | .off = frame_addr.off + 8, |
| 13346 | } }, |
| 5800 | 13347 | else => return self.fail("TODO implement slice_len for {}", .{src_mcv}), |
| 13348 | }; |
| 13349 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) { |
| 13350 | switch (src_mcv) { |
| 13351 | .register_pair => |regs| try self.freeValue(.{ .register = regs[0] }), |
| 13352 | .load_frame => {}, |
| 13353 | else => unreachable, |
| 13354 | } |
| 13355 | break :result len_mcv; |
| 5801 | 13356 | } |
| 13357 | |
| 13358 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 13359 | try self.genCopy(self.typeOfIndex(inst), dst_mcv, len_mcv, .{}); |
| 13360 | break :result dst_mcv; |
| 5802 | 13361 | }; |
| 5803 | 13362 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 5804 | 13363 | } |
| 5805 | 13364 | |
| 5806 | | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13365 | fn airPtrSliceLenPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5807 | 13366 | const pt = self.pt; |
| 5808 | 13367 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5809 | 13368 | |
| ... | ... | @@ -5838,7 +13397,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5838 | 13397 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 5839 | 13398 | } |
| 5840 | 13399 | |
| 5841 | | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13400 | fn airPtrSlicePtrPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5842 | 13401 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5843 | 13402 | |
| 5844 | 13403 | const dst_ty = self.typeOfIndex(inst); |
| ... | ... | @@ -5851,7 +13410,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5851 | 13410 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 5852 | 13411 | } |
| 5853 | 13412 | |
| 5854 | | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 13413 | fn elemOffset(self: *CodeGen, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 5855 | 13414 | const reg: Register = blk: { |
| 5856 | 13415 | switch (index) { |
| 5857 | 13416 | .immediate => |imm| { |
| ... | ... | @@ -5871,7 +13430,7 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi |
| 5871 | 13430 | return reg; |
| 5872 | 13431 | } |
| 5873 | 13432 | |
| 5874 | | fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 13433 | fn genSliceElemPtr(self: *CodeGen, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 5875 | 13434 | const pt = self.pt; |
| 5876 | 13435 | const zcu = pt.zcu; |
| 5877 | 13436 | const slice_ty = self.typeOf(lhs); |
| ... | ... | @@ -5899,7 +13458,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 5899 | 13458 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 5900 | 13459 | |
| 5901 | 13460 | const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 5902 | | try self.genSetReg(addr_reg, Type.usize, slice_mcv, .{}); |
| 13461 | try self.genSetReg(addr_reg, .usize, slice_mcv, .{}); |
| 5903 | 13462 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 5904 | 13463 | // offset register. |
| 5905 | 13464 | try self.genBinOpMir(.{ ._, .add }, slice_ptr_field_type, .{ .register = addr_reg }, .{ |
| ... | ... | @@ -5908,7 +13467,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 5908 | 13467 | return MCValue{ .register = addr_reg.to64() }; |
| 5909 | 13468 | } |
| 5910 | 13469 | |
| 5911 | | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 13470 | fn airSliceElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5912 | 13471 | const pt = self.pt; |
| 5913 | 13472 | const zcu = pt.zcu; |
| 5914 | 13473 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -5927,14 +13486,14 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5927 | 13486 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5928 | 13487 | } |
| 5929 | 13488 | |
| 5930 | | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13489 | fn airSliceElemPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5931 | 13490 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 5932 | 13491 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5933 | 13492 | const dst_mcv = try self.genSliceElemPtr(extra.lhs, extra.rhs); |
| 5934 | 13493 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 5935 | 13494 | } |
| 5936 | 13495 | |
| 5937 | | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 13496 | fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 5938 | 13497 | const pt = self.pt; |
| 5939 | 13498 | const zcu = pt.zcu; |
| 5940 | 13499 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -5952,7 +13511,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5952 | 13511 | |
| 5953 | 13512 | const index_ty = self.typeOf(bin_op.rhs); |
| 5954 | 13513 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 5955 | | const index_lock: ?RegisterLock = switch (index_mcv) { |
| 13514 | const index_lock = switch (index_mcv) { |
| 5956 | 13515 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5957 | 13516 | else => null, |
| 5958 | 13517 | }; |
| ... | ... | @@ -5960,48 +13519,111 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5960 | 13519 | |
| 5961 | 13520 | try self.spillEflagsIfOccupied(); |
| 5962 | 13521 | if (array_ty.isVector(zcu) and elem_ty.bitSize(zcu) == 1) { |
| 5963 | | const index_reg = switch (index_mcv) { |
| 5964 | | .register => |reg| reg, |
| 5965 | | else => try self.copyToTmpRegister(index_ty, index_mcv), |
| 13522 | const array_mat_mcv: MCValue = switch (array_mcv) { |
| 13523 | else => array_mcv, |
| 13524 | .register_mask => .{ .register = try self.copyToTmpRegister(array_ty, array_mcv) }, |
| 13525 | }; |
| 13526 | const array_mat_lock = switch (array_mat_mcv) { |
| 13527 | .register => |reg| self.register_manager.lockReg(reg), |
| 13528 | else => null, |
| 5966 | 13529 | }; |
| 5967 | | switch (array_mcv) { |
| 13530 | defer if (array_mat_lock) |lock| self.register_manager.unlockReg(lock); |
| 13531 | |
| 13532 | switch (array_mat_mcv) { |
| 5968 | 13533 | .register => |array_reg| switch (array_reg.class()) { |
| 5969 | | .general_purpose => try self.asmRegisterRegister( |
| 5970 | | .{ ._, .bt }, |
| 5971 | | array_reg.to64(), |
| 5972 | | index_reg.to64(), |
| 5973 | | ), |
| 5974 | | .sse => { |
| 5975 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, zcu)); |
| 5976 | | try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mcv, .{}); |
| 5977 | | try self.asmMemoryRegister( |
| 13534 | .general_purpose => switch (index_mcv) { |
| 13535 | .immediate => |index_imm| try self.asmRegisterImmediate( |
| 5978 | 13536 | .{ ._, .bt }, |
| 5979 | | .{ |
| 5980 | | .base = .{ .frame = frame_index }, |
| 5981 | | .mod = .{ .rm = .{ .size = .qword } }, |
| 5982 | | }, |
| 5983 | | index_reg.to64(), |
| 5984 | | ); |
| 13537 | array_reg.to64(), |
| 13538 | .u(index_imm), |
| 13539 | ), |
| 13540 | else => try self.asmRegisterRegister( |
| 13541 | .{ ._, .bt }, |
| 13542 | array_reg.to64(), |
| 13543 | switch (index_mcv) { |
| 13544 | .register => |index_reg| index_reg, |
| 13545 | else => try self.copyToTmpRegister(index_ty, index_mcv), |
| 13546 | }.to64(), |
| 13547 | ), |
| 13548 | }, |
| 13549 | .sse => { |
| 13550 | const frame_index = try self.allocFrameIndex(.initType(array_ty, zcu)); |
| 13551 | try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mat_mcv, .{}); |
| 13552 | switch (index_mcv) { |
| 13553 | .immediate => |index_imm| try self.asmMemoryImmediate( |
| 13554 | .{ ._, .bt }, |
| 13555 | .{ |
| 13556 | .base = .{ .frame = frame_index }, |
| 13557 | .mod = .{ .rm = .{ |
| 13558 | .size = .qword, |
| 13559 | .disp = @intCast(index_imm / 64 * 8), |
| 13560 | } }, |
| 13561 | }, |
| 13562 | .u(index_imm % 64), |
| 13563 | ), |
| 13564 | else => try self.asmMemoryRegister( |
| 13565 | .{ ._, .bt }, |
| 13566 | .{ |
| 13567 | .base = .{ .frame = frame_index }, |
| 13568 | .mod = .{ .rm = .{ .size = .qword } }, |
| 13569 | }, |
| 13570 | switch (index_mcv) { |
| 13571 | .register => |index_reg| index_reg, |
| 13572 | else => try self.copyToTmpRegister(index_ty, index_mcv), |
| 13573 | }.to64(), |
| 13574 | ), |
| 13575 | } |
| 5985 | 13576 | }, |
| 5986 | 13577 | else => unreachable, |
| 5987 | 13578 | }, |
| 5988 | | .load_frame => try self.asmMemoryRegister( |
| 5989 | | .{ ._, .bt }, |
| 5990 | | try array_mcv.mem(self, .qword), |
| 5991 | | index_reg.to64(), |
| 5992 | | ), |
| 5993 | | .memory, .load_symbol, .load_direct, .load_got, .load_tlv => try self.asmMemoryRegister( |
| 5994 | | .{ ._, .bt }, |
| 5995 | | .{ |
| 5996 | | .base = .{ |
| 5997 | | .reg = try self.copyToTmpRegister(Type.usize, array_mcv.address()), |
| 13579 | .load_frame => switch (index_mcv) { |
| 13580 | .immediate => |index_imm| try self.asmMemoryImmediate( |
| 13581 | .{ ._, .bt }, |
| 13582 | try array_mat_mcv.mem(self, .{ |
| 13583 | .size = .qword, |
| 13584 | .disp = @intCast(index_imm / 64 * 8), |
| 13585 | }), |
| 13586 | .u(index_imm % 64), |
| 13587 | ), |
| 13588 | else => try self.asmMemoryRegister( |
| 13589 | .{ ._, .bt }, |
| 13590 | try array_mat_mcv.mem(self, .{ .size = .qword }), |
| 13591 | switch (index_mcv) { |
| 13592 | .register => |index_reg| index_reg, |
| 13593 | else => try self.copyToTmpRegister(index_ty, index_mcv), |
| 13594 | }.to64(), |
| 13595 | ), |
| 13596 | }, |
| 13597 | .memory, .load_symbol, .load_direct, .load_got, .load_tlv => switch (index_mcv) { |
| 13598 | .immediate => |index_imm| try self.asmMemoryImmediate( |
| 13599 | .{ ._, .bt }, |
| 13600 | .{ |
| 13601 | .base = .{ |
| 13602 | .reg = try self.copyToTmpRegister(.usize, array_mat_mcv.address()), |
| 13603 | }, |
| 13604 | .mod = .{ .rm = .{ |
| 13605 | .size = .qword, |
| 13606 | .disp = @intCast(index_imm / 64 * 8), |
| 13607 | } }, |
| 5998 | 13608 | }, |
| 5999 | | .mod = .{ .rm = .{ .size = .qword } }, |
| 6000 | | }, |
| 6001 | | index_reg.to64(), |
| 6002 | | ), |
| 13609 | .u(index_imm % 64), |
| 13610 | ), |
| 13611 | else => try self.asmMemoryRegister( |
| 13612 | .{ ._, .bt }, |
| 13613 | .{ |
| 13614 | .base = .{ |
| 13615 | .reg = try self.copyToTmpRegister(.usize, array_mat_mcv.address()), |
| 13616 | }, |
| 13617 | .mod = .{ .rm = .{ .size = .qword } }, |
| 13618 | }, |
| 13619 | switch (index_mcv) { |
| 13620 | .register => |index_reg| index_reg, |
| 13621 | else => try self.copyToTmpRegister(index_ty, index_mcv), |
| 13622 | }.to64(), |
| 13623 | ), |
| 13624 | }, |
| 6003 | 13625 | else => return self.fail("TODO airArrayElemVal for {s} of {}", .{ |
| 6004 | | @tagName(array_mcv), array_ty.fmt(pt), |
| 13626 | @tagName(array_mat_mcv), array_ty.fmt(pt), |
| 6005 | 13627 | }), |
| 6006 | 13628 | } |
| 6007 | 13629 | |
| ... | ... | @@ -6017,7 +13639,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 6017 | 13639 | |
| 6018 | 13640 | switch (array_mcv) { |
| 6019 | 13641 | .register => { |
| 6020 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, zcu)); |
| 13642 | const frame_index = try self.allocFrameIndex(.initType(array_ty, zcu)); |
| 6021 | 13643 | try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mcv, .{}); |
| 6022 | 13644 | try self.asmRegisterMemory( |
| 6023 | 13645 | .{ ._, .lea }, |
| ... | ... | @@ -6038,7 +13660,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 6038 | 13660 | .load_direct, |
| 6039 | 13661 | .load_got, |
| 6040 | 13662 | .load_tlv, |
| 6041 | | => try self.genSetReg(addr_reg, Type.usize, array_mcv.address(), .{}), |
| 13663 | => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}), |
| 6042 | 13664 | .lea_symbol, .lea_direct, .lea_tlv => unreachable, |
| 6043 | 13665 | else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{ |
| 6044 | 13666 | @tagName(array_mcv), array_ty.fmt(pt), |
| ... | ... | @@ -6052,19 +13674,14 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 6052 | 13674 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 6053 | 13675 | // offset register. |
| 6054 | 13676 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 6055 | | try self.genBinOpMir( |
| 6056 | | .{ ._, .add }, |
| 6057 | | Type.usize, |
| 6058 | | .{ .register = addr_reg }, |
| 6059 | | .{ .register = offset_reg }, |
| 6060 | | ); |
| 13677 | try self.genBinOpMir(.{ ._, .add }, .usize, .{ .register = addr_reg }, .{ .register = offset_reg }); |
| 6061 | 13678 | try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }, .{}); |
| 6062 | 13679 | break :result dst_mcv; |
| 6063 | 13680 | }; |
| 6064 | 13681 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 6065 | 13682 | } |
| 6066 | 13683 | |
| 6067 | | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 13684 | fn airPtrElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6068 | 13685 | const pt = self.pt; |
| 6069 | 13686 | const zcu = pt.zcu; |
| 6070 | 13687 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -6115,7 +13732,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 6115 | 13732 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 6116 | 13733 | } |
| 6117 | 13734 | |
| 6118 | | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13735 | fn airPtrElemPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6119 | 13736 | const pt = self.pt; |
| 6120 | 13737 | const zcu = pt.zcu; |
| 6121 | 13738 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -6161,7 +13778,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6161 | 13778 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 6162 | 13779 | } |
| 6163 | 13780 | |
| 6164 | | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 13781 | fn airSetUnionTag(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6165 | 13782 | const pt = self.pt; |
| 6166 | 13783 | const zcu = pt.zcu; |
| 6167 | 13784 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -6206,7 +13823,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 6206 | 13823 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 6207 | 13824 | } |
| 6208 | 13825 | |
| 6209 | | fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 13826 | fn airGetUnionTag(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6210 | 13827 | const zcu = self.pt.zcu; |
| 6211 | 13828 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 6212 | 13829 | |
| ... | ... | @@ -6245,13 +13862,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 6245 | 13862 | .register => { |
| 6246 | 13863 | const shift: u6 = @intCast(layout.tagOffset() * 8); |
| 6247 | 13864 | const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand); |
| 6248 | | try self.genShiftBinOpMir( |
| 6249 | | .{ ._r, .sh }, |
| 6250 | | Type.usize, |
| 6251 | | result, |
| 6252 | | Type.u8, |
| 6253 | | .{ .immediate = shift }, |
| 6254 | | ); |
| 13865 | try self.genShiftBinOpMir(.{ ._r, .sh }, .usize, result, .u8, .{ .immediate = shift }); |
| 6255 | 13866 | break :blk MCValue{ |
| 6256 | 13867 | .register = registerAlias(result.register, @intCast(layout.tag_size)), |
| 6257 | 13868 | }; |
| ... | ... | @@ -6263,7 +13874,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 6263 | 13874 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 6264 | 13875 | } |
| 6265 | 13876 | |
| 6266 | | fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 13877 | fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6267 | 13878 | const pt = self.pt; |
| 6268 | 13879 | const zcu = pt.zcu; |
| 6269 | 13880 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -6296,53 +13907,62 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 6296 | 13907 | const src_bits: u31 = @intCast(src_ty.bitSize(zcu)); |
| 6297 | 13908 | const has_lzcnt = self.hasFeature(.lzcnt); |
| 6298 | 13909 | if (src_bits > @as(u32, if (has_lzcnt) 128 else 64)) { |
| 6299 | | const limbs_len = math.divCeil(u32, abi_size, 8) catch unreachable; |
| 13910 | const src_frame_addr: bits.FrameAddr = src_frame_addr: switch (src_mcv) { |
| 13911 | .load_frame => |src_frame_addr| src_frame_addr, |
| 13912 | else => { |
| 13913 | const src_frame_addr = try self.allocFrameIndex(.initSpill(src_ty, zcu)); |
| 13914 | try self.genSetMem(.{ .frame = src_frame_addr }, 0, src_ty, src_mcv, .{}); |
| 13915 | break :src_frame_addr .{ .index = src_frame_addr }; |
| 13916 | }, |
| 13917 | }; |
| 13918 | |
| 13919 | const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable; |
| 6300 | 13920 | const extra_bits = abi_size * 8 - src_bits; |
| 6301 | 13921 | |
| 6302 | 13922 | const index_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 6303 | 13923 | const index_lock = self.register_manager.lockRegAssumeUnused(index_reg); |
| 6304 | 13924 | defer self.register_manager.unlockReg(index_lock); |
| 6305 | 13925 | |
| 6306 | | try self.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), Immediate.u(limbs_len)); |
| 13926 | try self.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .u(limbs_len)); |
| 6307 | 13927 | switch (extra_bits) { |
| 6308 | 13928 | 1 => try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()), |
| 6309 | 13929 | else => try self.asmRegisterImmediate( |
| 6310 | 13930 | .{ ._, .mov }, |
| 6311 | 13931 | dst_reg.to32(), |
| 6312 | | Immediate.s(@as(i32, extra_bits) - 1), |
| 13932 | .s(@as(i32, extra_bits) - 1), |
| 6313 | 13933 | ), |
| 6314 | 13934 | } |
| 6315 | 13935 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 6316 | 13936 | try self.asmRegisterRegister(.{ ._, .@"test" }, index_reg.to32(), index_reg.to32()); |
| 6317 | 13937 | const zero = try self.asmJccReloc(.z, undefined); |
| 6318 | 13938 | if (self.hasFeature(.slow_incdec)) { |
| 6319 | | try self.asmRegisterImmediate(.{ ._, .sub }, index_reg.to32(), Immediate.u(1)); |
| 13939 | try self.asmRegisterImmediate(.{ ._, .sub }, index_reg.to32(), .u(1)); |
| 6320 | 13940 | } else { |
| 6321 | 13941 | try self.asmRegister(.{ ._, .dec }, index_reg.to32()); |
| 6322 | 13942 | } |
| 6323 | 13943 | try self.asmMemoryImmediate(.{ ._, .cmp }, .{ |
| 6324 | | .base = .{ .frame = src_mcv.load_frame.index }, |
| 13944 | .base = .{ .frame = src_frame_addr.index }, |
| 6325 | 13945 | .mod = .{ .rm = .{ |
| 6326 | 13946 | .size = .qword, |
| 6327 | 13947 | .index = index_reg.to64(), |
| 6328 | 13948 | .scale = .@"8", |
| 6329 | | .disp = src_mcv.load_frame.off, |
| 13949 | .disp = src_frame_addr.off, |
| 6330 | 13950 | } }, |
| 6331 | | }, Immediate.u(0)); |
| 13951 | }, .u(0)); |
| 6332 | 13952 | _ = try self.asmJccReloc(.e, loop); |
| 6333 | | try self.asmRegisterMemory(.{ ._, .bsr }, dst_reg.to64(), .{ |
| 6334 | | .base = .{ .frame = src_mcv.load_frame.index }, |
| 13953 | try self.asmRegisterMemory(.{ ._r, .bs }, dst_reg.to64(), .{ |
| 13954 | .base = .{ .frame = src_frame_addr.index }, |
| 6335 | 13955 | .mod = .{ .rm = .{ |
| 6336 | 13956 | .size = .qword, |
| 6337 | 13957 | .index = index_reg.to64(), |
| 6338 | 13958 | .scale = .@"8", |
| 6339 | | .disp = src_mcv.load_frame.off, |
| 13959 | .disp = src_frame_addr.off, |
| 6340 | 13960 | } }, |
| 6341 | 13961 | }); |
| 6342 | 13962 | self.performReloc(zero); |
| 6343 | | try self.asmRegisterImmediate(.{ ._l, .sh }, index_reg.to32(), Immediate.u(6)); |
| 13963 | try self.asmRegisterImmediate(.{ ._l, .sh }, index_reg.to32(), .u(6)); |
| 6344 | 13964 | try self.asmRegisterRegister(.{ ._, .add }, index_reg.to32(), dst_reg.to32()); |
| 6345 | | try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), Immediate.u(src_bits - 1)); |
| 13965 | try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), .u(src_bits - 1)); |
| 6346 | 13966 | try self.asmRegisterRegister(.{ ._, .sub }, dst_reg.to32(), index_reg.to32()); |
| 6347 | 13967 | break :result dst_mcv; |
| 6348 | 13968 | } |
| ... | ... | @@ -6351,7 +13971,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 6351 | 13971 | if (src_bits <= 8) { |
| 6352 | 13972 | const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv); |
| 6353 | 13973 | try self.truncateRegister(src_ty, wide_reg); |
| 6354 | | try self.genBinOpMir(.{ ._, .lzcnt }, Type.u32, dst_mcv, .{ .register = wide_reg }); |
| 13974 | try self.genBinOpMir(.{ ._, .lzcnt }, .u32, dst_mcv, .{ .register = wide_reg }); |
| 6355 | 13975 | try self.genBinOpMir( |
| 6356 | 13976 | .{ ._, .sub }, |
| 6357 | 13977 | dst_ty, |
| ... | ... | @@ -6371,25 +13991,15 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 6371 | 13991 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 6372 | 13992 | defer self.register_manager.unlockReg(tmp_lock); |
| 6373 | 13993 | |
| 6374 | | try self.genBinOpMir( |
| 6375 | | .{ ._, .lzcnt }, |
| 6376 | | Type.u64, |
| 6377 | | dst_mcv, |
| 6378 | | if (mat_src_mcv.isMemory()) |
| 6379 | | mat_src_mcv |
| 6380 | | else |
| 6381 | | .{ .register = mat_src_mcv.register_pair[0] }, |
| 6382 | | ); |
| 13994 | try self.genBinOpMir(.{ ._, .lzcnt }, .u64, dst_mcv, if (mat_src_mcv.isBase()) |
| 13995 | mat_src_mcv |
| 13996 | else |
| 13997 | .{ .register = mat_src_mcv.register_pair[0] }); |
| 6383 | 13998 | try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 }); |
| 6384 | | try self.genBinOpMir( |
| 6385 | | .{ ._, .lzcnt }, |
| 6386 | | Type.u64, |
| 6387 | | tmp_mcv, |
| 6388 | | if (mat_src_mcv.isMemory()) |
| 6389 | | mat_src_mcv.address().offset(8).deref() |
| 6390 | | else |
| 6391 | | .{ .register = mat_src_mcv.register_pair[1] }, |
| 6392 | | ); |
| 13999 | try self.genBinOpMir(.{ ._, .lzcnt }, .u64, tmp_mcv, if (mat_src_mcv.isBase()) |
| 14000 | mat_src_mcv.address().offset(8).deref() |
| 14001 | else |
| 14002 | .{ .register = mat_src_mcv.register_pair[1] }); |
| 6393 | 14003 | try self.asmCmovccRegisterRegister(.nc, dst_reg.to32(), tmp_reg.to32()); |
| 6394 | 14004 | |
| 6395 | 14005 | if (src_bits < 128) try self.genBinOpMir( |
| ... | ... | @@ -6404,7 +14014,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 6404 | 14014 | |
| 6405 | 14015 | assert(src_bits <= 64); |
| 6406 | 14016 | const cmov_abi_size = @max(@as(u32, @intCast(dst_ty.abiSize(zcu))), 2); |
| 6407 | | if (math.isPowerOfTwo(src_bits)) { |
| 14017 | if (std.math.isPowerOfTwo(src_bits)) { |
| 6408 | 14018 | const imm_reg = try self.copyToTmpRegister(dst_ty, .{ |
| 6409 | 14019 | .immediate = src_bits ^ (src_bits - 1), |
| 6410 | 14020 | }); |
| ... | ... | @@ -6417,8 +14027,8 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 6417 | 14027 | defer self.register_manager.unlockReg(wide_lock); |
| 6418 | 14028 | |
| 6419 | 14029 | try self.truncateRegister(src_ty, wide_reg); |
| 6420 | | try self.genBinOpMir(.{ ._, .bsr }, Type.u16, dst_mcv, .{ .register = wide_reg }); |
| 6421 | | } else try self.genBinOpMir(.{ ._, .bsr }, src_ty, dst_mcv, mat_src_mcv); |
| 14030 | try self.genBinOpMir(.{ ._r, .bs }, .u16, dst_mcv, .{ .register = wide_reg }); |
| 14031 | } else try self.genBinOpMir(.{ ._r, .bs }, src_ty, dst_mcv, mat_src_mcv); |
| 6422 | 14032 | |
| 6423 | 14033 | try self.asmCmovccRegisterRegister( |
| 6424 | 14034 | .z, |
| ... | ... | @@ -6429,7 +14039,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 6429 | 14039 | try self.genBinOpMir(.{ ._, .xor }, dst_ty, dst_mcv, .{ .immediate = src_bits - 1 }); |
| 6430 | 14040 | } else { |
| 6431 | 14041 | const imm_reg = try self.copyToTmpRegister(dst_ty, .{ |
| 6432 | | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(64 - self.regBitSize(dst_ty)), |
| 14042 | .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - self.regBitSize(dst_ty)), |
| 6433 | 14043 | }); |
| 6434 | 14044 | const imm_lock = self.register_manager.lockRegAssumeUnused(imm_reg); |
| 6435 | 14045 | defer self.register_manager.unlockReg(imm_lock); |
| ... | ... | @@ -6440,8 +14050,8 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 6440 | 14050 | |
| 6441 | 14051 | try self.truncateRegister(src_ty, wide_reg); |
| 6442 | 14052 | try self.genBinOpMir( |
| 6443 | | .{ ._, .bsr }, |
| 6444 | | if (src_bits <= 8) Type.u16 else src_ty, |
| 14053 | .{ ._r, .bs }, |
| 14054 | if (src_bits <= 8) .u16 else src_ty, |
| 6445 | 14055 | dst_mcv, |
| 6446 | 14056 | .{ .register = wide_reg }, |
| 6447 | 14057 | ); |
| ... | ... | @@ -6460,7 +14070,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 6460 | 14070 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 6461 | 14071 | } |
| 6462 | 14072 | |
| 6463 | | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 14073 | fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6464 | 14074 | const pt = self.pt; |
| 6465 | 14075 | const zcu = pt.zcu; |
| 6466 | 14076 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -6493,57 +14103,66 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 6493 | 14103 | const src_bits: u31 = @intCast(src_ty.bitSize(zcu)); |
| 6494 | 14104 | const has_bmi = self.hasFeature(.bmi); |
| 6495 | 14105 | if (src_bits > @as(u32, if (has_bmi) 128 else 64)) { |
| 6496 | | const limbs_len = math.divCeil(u32, abi_size, 8) catch unreachable; |
| 14106 | const src_frame_addr: bits.FrameAddr = src_frame_addr: switch (src_mcv) { |
| 14107 | .load_frame => |src_frame_addr| src_frame_addr, |
| 14108 | else => { |
| 14109 | const src_frame_addr = try self.allocFrameIndex(.initSpill(src_ty, zcu)); |
| 14110 | try self.genSetMem(.{ .frame = src_frame_addr }, 0, src_ty, src_mcv, .{}); |
| 14111 | break :src_frame_addr .{ .index = src_frame_addr }; |
| 14112 | }, |
| 14113 | }; |
| 14114 | |
| 14115 | const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable; |
| 6497 | 14116 | const extra_bits = abi_size * 8 - src_bits; |
| 6498 | 14117 | |
| 6499 | 14118 | const index_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 6500 | 14119 | const index_lock = self.register_manager.lockRegAssumeUnused(index_reg); |
| 6501 | 14120 | defer self.register_manager.unlockReg(index_lock); |
| 6502 | 14121 | |
| 6503 | | try self.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), Immediate.s(-1)); |
| 14122 | try self.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .s(-1)); |
| 6504 | 14123 | switch (extra_bits) { |
| 6505 | 14124 | 0 => try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()), |
| 6506 | 14125 | 1 => try self.asmRegisterRegister(.{ ._, .mov }, dst_reg.to32(), dst_reg.to32()), |
| 6507 | 14126 | else => try self.asmRegisterImmediate( |
| 6508 | 14127 | .{ ._, .mov }, |
| 6509 | 14128 | dst_reg.to32(), |
| 6510 | | Immediate.s(-@as(i32, extra_bits)), |
| 14129 | .s(-@as(i32, extra_bits)), |
| 6511 | 14130 | ), |
| 6512 | 14131 | } |
| 6513 | 14132 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 6514 | 14133 | if (self.hasFeature(.slow_incdec)) { |
| 6515 | | try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), Immediate.u(1)); |
| 14134 | try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1)); |
| 6516 | 14135 | } else { |
| 6517 | 14136 | try self.asmRegister(.{ ._, .inc }, index_reg.to32()); |
| 6518 | 14137 | } |
| 6519 | | try self.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), Immediate.u(limbs_len)); |
| 14138 | try self.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(limbs_len)); |
| 6520 | 14139 | const zero = try self.asmJccReloc(.nb, undefined); |
| 6521 | 14140 | try self.asmMemoryImmediate(.{ ._, .cmp }, .{ |
| 6522 | | .base = .{ .frame = src_mcv.load_frame.index }, |
| 14141 | .base = .{ .frame = src_frame_addr.index }, |
| 6523 | 14142 | .mod = .{ .rm = .{ |
| 6524 | 14143 | .size = .qword, |
| 6525 | 14144 | .index = index_reg.to64(), |
| 6526 | 14145 | .scale = .@"8", |
| 6527 | | .disp = src_mcv.load_frame.off, |
| 14146 | .disp = src_frame_addr.off, |
| 6528 | 14147 | } }, |
| 6529 | | }, Immediate.u(0)); |
| 14148 | }, .u(0)); |
| 6530 | 14149 | _ = try self.asmJccReloc(.e, loop); |
| 6531 | | try self.asmRegisterMemory(.{ ._, .bsf }, dst_reg.to64(), .{ |
| 6532 | | .base = .{ .frame = src_mcv.load_frame.index }, |
| 14150 | try self.asmRegisterMemory(.{ ._f, .bs }, dst_reg.to64(), .{ |
| 14151 | .base = .{ .frame = src_frame_addr.index }, |
| 6533 | 14152 | .mod = .{ .rm = .{ |
| 6534 | 14153 | .size = .qword, |
| 6535 | 14154 | .index = index_reg.to64(), |
| 6536 | 14155 | .scale = .@"8", |
| 6537 | | .disp = src_mcv.load_frame.off, |
| 14156 | .disp = src_frame_addr.off, |
| 6538 | 14157 | } }, |
| 6539 | 14158 | }); |
| 6540 | 14159 | self.performReloc(zero); |
| 6541 | | try self.asmRegisterImmediate(.{ ._l, .sh }, index_reg.to32(), Immediate.u(6)); |
| 14160 | try self.asmRegisterImmediate(.{ ._l, .sh }, index_reg.to32(), .u(6)); |
| 6542 | 14161 | try self.asmRegisterRegister(.{ ._, .add }, dst_reg.to32(), index_reg.to32()); |
| 6543 | 14162 | break :result dst_mcv; |
| 6544 | 14163 | } |
| 6545 | 14164 | |
| 6546 | | const wide_ty = if (src_bits <= 8) Type.u16 else src_ty; |
| 14165 | const wide_ty: Type = if (src_bits <= 8) .u16 else src_ty; |
| 6547 | 14166 | if (has_bmi) { |
| 6548 | 14167 | if (src_bits <= 64) { |
| 6549 | 14168 | const extra_bits = self.regExtraBits(src_ty) + @as(u64, if (src_bits <= 8) 8 else 0); |
| ... | ... | @@ -6558,7 +14177,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 6558 | 14177 | .{ ._, .@"or" }, |
| 6559 | 14178 | wide_ty, |
| 6560 | 14179 | tmp_mcv, |
| 6561 | | .{ .immediate = (@as(u64, math.maxInt(u64)) >> @intCast(64 - extra_bits)) << |
| 14180 | .{ .immediate = (@as(u64, std.math.maxInt(u64)) >> @intCast(64 - extra_bits)) << |
| 6562 | 14181 | @intCast(src_bits) }, |
| 6563 | 14182 | ); |
| 6564 | 14183 | break :masked tmp_mcv; |
| ... | ... | @@ -6571,27 +14190,27 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 6571 | 14190 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 6572 | 14191 | defer self.register_manager.unlockReg(tmp_lock); |
| 6573 | 14192 | |
| 6574 | | const lo_mat_src_mcv: MCValue = if (mat_src_mcv.isMemory()) |
| 14193 | const lo_mat_src_mcv: MCValue = if (mat_src_mcv.isBase()) |
| 6575 | 14194 | mat_src_mcv |
| 6576 | 14195 | else |
| 6577 | 14196 | .{ .register = mat_src_mcv.register_pair[0] }; |
| 6578 | | const hi_mat_src_mcv: MCValue = if (mat_src_mcv.isMemory()) |
| 14197 | const hi_mat_src_mcv: MCValue = if (mat_src_mcv.isBase()) |
| 6579 | 14198 | mat_src_mcv.address().offset(8).deref() |
| 6580 | 14199 | else |
| 6581 | 14200 | .{ .register = mat_src_mcv.register_pair[1] }; |
| 6582 | 14201 | const masked_mcv = if (src_bits < 128) masked: { |
| 6583 | | try self.genCopy(Type.u64, dst_mcv, hi_mat_src_mcv, .{}); |
| 14202 | try self.genCopy(.u64, dst_mcv, hi_mat_src_mcv, .{}); |
| 6584 | 14203 | try self.genBinOpMir( |
| 6585 | 14204 | .{ ._, .@"or" }, |
| 6586 | | Type.u64, |
| 14205 | .u64, |
| 6587 | 14206 | dst_mcv, |
| 6588 | | .{ .immediate = @as(u64, math.maxInt(u64)) << @intCast(src_bits - 64) }, |
| 14207 | .{ .immediate = @as(u64, std.math.maxInt(u64)) << @intCast(src_bits - 64) }, |
| 6589 | 14208 | ); |
| 6590 | 14209 | break :masked dst_mcv; |
| 6591 | 14210 | } else hi_mat_src_mcv; |
| 6592 | | try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, dst_mcv, masked_mcv); |
| 14211 | try self.genBinOpMir(.{ ._, .tzcnt }, .u64, dst_mcv, masked_mcv); |
| 6593 | 14212 | try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 }); |
| 6594 | | try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, tmp_mcv, lo_mat_src_mcv); |
| 14213 | try self.genBinOpMir(.{ ._, .tzcnt }, .u64, tmp_mcv, lo_mat_src_mcv); |
| 6595 | 14214 | try self.asmCmovccRegisterRegister(.nc, dst_reg.to32(), tmp_reg.to32()); |
| 6596 | 14215 | } |
| 6597 | 14216 | break :result dst_mcv; |
| ... | ... | @@ -6602,14 +14221,14 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 6602 | 14221 | const width_lock = self.register_manager.lockRegAssumeUnused(width_reg); |
| 6603 | 14222 | defer self.register_manager.unlockReg(width_lock); |
| 6604 | 14223 | |
| 6605 | | if (src_bits <= 8 or !math.isPowerOfTwo(src_bits)) { |
| 14224 | if (src_bits <= 8 or !std.math.isPowerOfTwo(src_bits)) { |
| 6606 | 14225 | const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv); |
| 6607 | 14226 | const wide_lock = self.register_manager.lockRegAssumeUnused(wide_reg); |
| 6608 | 14227 | defer self.register_manager.unlockReg(wide_lock); |
| 6609 | 14228 | |
| 6610 | 14229 | try self.truncateRegister(src_ty, wide_reg); |
| 6611 | | try self.genBinOpMir(.{ ._, .bsf }, wide_ty, dst_mcv, .{ .register = wide_reg }); |
| 6612 | | } else try self.genBinOpMir(.{ ._, .bsf }, src_ty, dst_mcv, mat_src_mcv); |
| 14230 | try self.genBinOpMir(.{ ._f, .bs }, wide_ty, dst_mcv, .{ .register = wide_reg }); |
| 14231 | } else try self.genBinOpMir(.{ ._f, .bs }, src_ty, dst_mcv, mat_src_mcv); |
| 6613 | 14232 | |
| 6614 | 14233 | const cmov_abi_size = @max(@as(u32, @intCast(dst_ty.abiSize(zcu))), 2); |
| 6615 | 14234 | try self.asmCmovccRegisterRegister( |
| ... | ... | @@ -6622,7 +14241,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 6622 | 14241 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 6623 | 14242 | } |
| 6624 | 14243 | |
| 6625 | | fn airPopCount(self: *Self, inst: Air.Inst.Index) !void { |
| 14244 | fn airPopCount(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6626 | 14245 | const pt = self.pt; |
| 6627 | 14246 | const zcu = pt.zcu; |
| 6628 | 14247 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -6664,13 +14283,13 @@ fn airPopCount(self: *Self, inst: Air.Inst.Index) !void { |
| 6664 | 14283 | const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs); |
| 6665 | 14284 | defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); |
| 6666 | 14285 | |
| 6667 | | try self.genPopCount(tmp_regs[0], Type.usize, if (mat_src_mcv.isMemory()) |
| 14286 | try self.genPopCount(tmp_regs[0], .usize, if (mat_src_mcv.isBase()) |
| 6668 | 14287 | mat_src_mcv |
| 6669 | 14288 | else |
| 6670 | 14289 | .{ .register = mat_src_mcv.register_pair[0] }, false); |
| 6671 | 14290 | const src_info = src_ty.intInfo(zcu); |
| 6672 | 14291 | const hi_ty = try pt.intType(src_info.signedness, (src_info.bits - 1) % 64 + 1); |
| 6673 | | try self.genPopCount(tmp_regs[1], hi_ty, if (mat_src_mcv.isMemory()) |
| 14292 | try self.genPopCount(tmp_regs[1], hi_ty, if (mat_src_mcv.isBase()) |
| 6674 | 14293 | mat_src_mcv.address().offset(8).deref() |
| 6675 | 14294 | else |
| 6676 | 14295 | .{ .register = mat_src_mcv.register_pair[1] }, false); |
| ... | ... | @@ -6681,7 +14300,7 @@ fn airPopCount(self: *Self, inst: Air.Inst.Index) !void { |
| 6681 | 14300 | } |
| 6682 | 14301 | |
| 6683 | 14302 | fn genPopCount( |
| 6684 | | self: *Self, |
| 14303 | self: *CodeGen, |
| 6685 | 14304 | dst_reg: Register, |
| 6686 | 14305 | src_ty: Type, |
| 6687 | 14306 | src_mcv: MCValue, |
| ... | ... | @@ -6692,7 +14311,7 @@ fn genPopCount( |
| 6692 | 14311 | const src_abi_size: u32 = @intCast(src_ty.abiSize(pt.zcu)); |
| 6693 | 14312 | if (self.hasFeature(.popcnt)) return self.genBinOpMir( |
| 6694 | 14313 | .{ ._, .popcnt }, |
| 6695 | | if (src_abi_size > 1) src_ty else Type.u32, |
| 14314 | if (src_abi_size > 1) src_ty else .u32, |
| 6696 | 14315 | .{ .register = dst_reg }, |
| 6697 | 14316 | if (src_abi_size > 1) src_mcv else src: { |
| 6698 | 14317 | if (!dst_contains_src) try self.genSetReg(dst_reg, src_ty, src_mcv, .{}); |
| ... | ... | @@ -6701,11 +14320,11 @@ fn genPopCount( |
| 6701 | 14320 | }, |
| 6702 | 14321 | ); |
| 6703 | 14322 | |
| 6704 | | const mask = @as(u64, math.maxInt(u64)) >> @intCast(64 - src_abi_size * 8); |
| 6705 | | const imm_0_1 = Immediate.u(mask / 0b1_1); |
| 6706 | | const imm_00_11 = Immediate.u(mask / 0b01_01); |
| 6707 | | const imm_0000_1111 = Immediate.u(mask / 0b0001_0001); |
| 6708 | | const imm_0000_0001 = Immediate.u(mask / 0b1111_1111); |
| 14323 | const mask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - src_abi_size * 8); |
| 14324 | const imm_0_1: Immediate = .u(mask / 0b1_1); |
| 14325 | const imm_00_11: Immediate = .u(mask / 0b01_01); |
| 14326 | const imm_0000_1111: Immediate = .u(mask / 0b0001_0001); |
| 14327 | const imm_0000_0001: Immediate = .u(mask / 0b1111_1111); |
| 6709 | 14328 | |
| 6710 | 14329 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 6711 | 14330 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| ... | ... | @@ -6722,7 +14341,7 @@ fn genPopCount( |
| 6722 | 14341 | // dst = operand |
| 6723 | 14342 | try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst); |
| 6724 | 14343 | // tmp = operand |
| 6725 | | try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(1)); |
| 14344 | try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, .u(1)); |
| 6726 | 14345 | // tmp = operand >> 1 |
| 6727 | 14346 | if (src_abi_size > 4) { |
| 6728 | 14347 | try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0_1); |
| ... | ... | @@ -6733,7 +14352,7 @@ fn genPopCount( |
| 6733 | 14352 | // dst = temp1 = operand - ((operand >> 1) & 0x55...55) |
| 6734 | 14353 | try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst); |
| 6735 | 14354 | // tmp = temp1 |
| 6736 | | try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(2)); |
| 14355 | try self.asmRegisterImmediate(.{ ._r, .sh }, dst, .u(2)); |
| 6737 | 14356 | // dst = temp1 >> 2 |
| 6738 | 14357 | if (src_abi_size > 4) { |
| 6739 | 14358 | try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_00_11); |
| ... | ... | @@ -6749,7 +14368,7 @@ fn genPopCount( |
| 6749 | 14368 | // tmp = temp2 = (temp1 & 0x33...33) + ((temp1 >> 2) & 0x33...33) |
| 6750 | 14369 | try self.asmRegisterRegister(.{ ._, .mov }, dst, tmp); |
| 6751 | 14370 | // dst = temp2 |
| 6752 | | try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(4)); |
| 14371 | try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, .u(4)); |
| 6753 | 14372 | // tmp = temp2 >> 4 |
| 6754 | 14373 | try self.asmRegisterRegister(.{ ._, .add }, dst, tmp); |
| 6755 | 14374 | // dst = temp2 + (temp2 >> 4) |
| ... | ... | @@ -6767,13 +14386,13 @@ fn genPopCount( |
| 6767 | 14386 | // dst = temp3 = (temp2 + (temp2 >> 4)) & 0x0f...0f |
| 6768 | 14387 | // dst = temp3 * 0x01...01 |
| 6769 | 14388 | if (src_abi_size > 1) { |
| 6770 | | try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u((src_abi_size - 1) * 8)); |
| 14389 | try self.asmRegisterImmediate(.{ ._r, .sh }, dst, .u((src_abi_size - 1) * 8)); |
| 6771 | 14390 | } |
| 6772 | 14391 | // dst = (temp3 * 0x01...01) >> (bits - 8) |
| 6773 | 14392 | } |
| 6774 | 14393 | |
| 6775 | 14394 | fn genByteSwap( |
| 6776 | | self: *Self, |
| 14395 | self: *CodeGen, |
| 6777 | 14396 | inst: Air.Inst.Index, |
| 6778 | 14397 | src_ty: Type, |
| 6779 | 14398 | src_mcv: MCValue, |
| ... | ... | @@ -6814,13 +14433,18 @@ fn genByteSwap( |
| 6814 | 14433 | return src_mcv; |
| 6815 | 14434 | }, |
| 6816 | 14435 | 9...16 => { |
| 6817 | | switch (src_mcv) { |
| 14436 | const mat_src_mcv: MCValue = mat_src_mcv: switch (src_mcv) { |
| 14437 | .register => { |
| 14438 | const frame_index = try self.allocFrameIndex(.initSpill(src_ty, zcu)); |
| 14439 | try self.genSetMem(.{ .frame = frame_index }, 0, src_ty, src_mcv, .{}); |
| 14440 | break :mat_src_mcv .{ .load_frame = .{ .index = frame_index } }; |
| 14441 | }, |
| 6818 | 14442 | .register_pair => |src_regs| if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) { |
| 6819 | 14443 | for (src_regs) |src_reg| try self.asmRegister(.{ ._, .bswap }, src_reg.to64()); |
| 6820 | 14444 | return .{ .register_pair = .{ src_regs[1], src_regs[0] } }; |
| 6821 | | }, |
| 6822 | | else => {}, |
| 6823 | | } |
| 14445 | } else src_mcv, |
| 14446 | else => src_mcv, |
| 14447 | }; |
| 6824 | 14448 | |
| 6825 | 14449 | const dst_regs = |
| 6826 | 14450 | try self.register_manager.allocRegs(2, .{ inst, inst }, abi.RegisterClass.gp); |
| ... | ... | @@ -6828,18 +14452,18 @@ fn genByteSwap( |
| 6828 | 14452 | defer for (dst_locks) |lock| self.register_manager.unlockReg(lock); |
| 6829 | 14453 | |
| 6830 | 14454 | for (dst_regs, 0..) |dst_reg, limb_index| { |
| 6831 | | if (src_mcv.isMemory()) { |
| 14455 | if (mat_src_mcv.isBase()) { |
| 6832 | 14456 | try self.asmRegisterMemory( |
| 6833 | 14457 | .{ ._, if (has_movbe) .movbe else .mov }, |
| 6834 | 14458 | dst_reg.to64(), |
| 6835 | | try src_mcv.address().offset(@intCast(limb_index * 8)).deref().mem(self, .qword), |
| 14459 | try mat_src_mcv.address().offset(@intCast(limb_index * 8)).deref().mem(self, .{ .size = .qword }), |
| 6836 | 14460 | ); |
| 6837 | 14461 | if (!has_movbe) try self.asmRegister(.{ ._, .bswap }, dst_reg.to64()); |
| 6838 | 14462 | } else { |
| 6839 | 14463 | try self.asmRegisterRegister( |
| 6840 | 14464 | .{ ._, .mov }, |
| 6841 | 14465 | dst_reg.to64(), |
| 6842 | | src_mcv.register_pair[limb_index].to64(), |
| 14466 | mat_src_mcv.register_pair[limb_index].to64(), |
| 6843 | 14467 | ); |
| 6844 | 14468 | try self.asmRegister(.{ ._, .bswap }, dst_reg.to64()); |
| 6845 | 14469 | } |
| ... | ... | @@ -6847,20 +14471,16 @@ fn genByteSwap( |
| 6847 | 14471 | return .{ .register_pair = .{ dst_regs[1], dst_regs[0] } }; |
| 6848 | 14472 | }, |
| 6849 | 14473 | else => { |
| 6850 | | const limbs_len = math.divCeil(u32, abi_size, 8) catch unreachable; |
| 14474 | const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable; |
| 6851 | 14475 | |
| 6852 | 14476 | const temp_regs = |
| 6853 | | try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp); |
| 14477 | try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp); |
| 6854 | 14478 | const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs); |
| 6855 | 14479 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 6856 | 14480 | |
| 6857 | 14481 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 6858 | 14482 | try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[0].to32(), temp_regs[0].to32()); |
| 6859 | | try self.asmRegisterImmediate( |
| 6860 | | .{ ._, .mov }, |
| 6861 | | temp_regs[1].to32(), |
| 6862 | | Immediate.u(limbs_len - 1), |
| 6863 | | ); |
| 14483 | try self.asmRegisterImmediate(.{ ._, .mov }, temp_regs[1].to32(), .u(limbs_len - 1)); |
| 6864 | 14484 | |
| 6865 | 14485 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 6866 | 14486 | try self.asmRegisterMemory( |
| ... | ... | @@ -6912,8 +14532,8 @@ fn genByteSwap( |
| 6912 | 14532 | } }, |
| 6913 | 14533 | }, temp_regs[2].to64()); |
| 6914 | 14534 | if (self.hasFeature(.slow_incdec)) { |
| 6915 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), Immediate.u(1)); |
| 6916 | | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), Immediate.u(1)); |
| 14535 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1)); |
| 14536 | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1)); |
| 6917 | 14537 | } else { |
| 6918 | 14538 | try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32()); |
| 6919 | 14539 | try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32()); |
| ... | ... | @@ -6942,7 +14562,7 @@ fn genByteSwap( |
| 6942 | 14562 | return dst_mcv; |
| 6943 | 14563 | } |
| 6944 | 14564 | |
| 6945 | | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 14565 | fn airByteSwap(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6946 | 14566 | const pt = self.pt; |
| 6947 | 14567 | const zcu = pt.zcu; |
| 6948 | 14568 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -6959,13 +14579,13 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 6959 | 14579 | } }, |
| 6960 | 14580 | src_ty, |
| 6961 | 14581 | dst_mcv, |
| 6962 | | if (src_bits > 256) Type.u16 else Type.u8, |
| 14582 | if (src_bits > 256) .u16 else .u8, |
| 6963 | 14583 | .{ .immediate = src_ty.abiSize(zcu) * 8 - src_bits }, |
| 6964 | 14584 | ); |
| 6965 | 14585 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 6966 | 14586 | } |
| 6967 | 14587 | |
| 6968 | | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 14588 | fn airBitReverse(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 6969 | 14589 | const pt = self.pt; |
| 6970 | 14590 | const zcu = pt.zcu; |
| 6971 | 14591 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -6994,10 +14614,10 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 6994 | 14614 | else |
| 6995 | 14615 | undefined; |
| 6996 | 14616 | |
| 6997 | | const mask = @as(u64, math.maxInt(u64)) >> @intCast(64 - limb_abi_size * 8); |
| 6998 | | const imm_0000_1111 = Immediate.u(mask / 0b0001_0001); |
| 6999 | | const imm_00_11 = Immediate.u(mask / 0b01_01); |
| 7000 | | const imm_0_1 = Immediate.u(mask / 0b1_1); |
| 14617 | const mask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - limb_abi_size * 8); |
| 14618 | const imm_0000_1111: Immediate = .u(mask / 0b0001_0001); |
| 14619 | const imm_00_11: Immediate = .u(mask / 0b01_01); |
| 14620 | const imm_0_1: Immediate = .u(mask / 0b1_1); |
| 7001 | 14621 | |
| 7002 | 14622 | for (dst_mcv.getRegs()) |dst_reg| { |
| 7003 | 14623 | const dst = registerAlias(dst_reg, limb_abi_size); |
| ... | ... | @@ -7005,7 +14625,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 7005 | 14625 | // dst = temp1 = bswap(operand) |
| 7006 | 14626 | try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst); |
| 7007 | 14627 | // tmp = temp1 |
| 7008 | | try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(4)); |
| 14628 | try self.asmRegisterImmediate(.{ ._r, .sh }, dst, .u(4)); |
| 7009 | 14629 | // dst = temp1 >> 4 |
| 7010 | 14630 | if (limb_abi_size > 4) { |
| 7011 | 14631 | try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0000_1111); |
| ... | ... | @@ -7017,13 +14637,13 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 7017 | 14637 | } |
| 7018 | 14638 | // tmp = temp1 & 0x0F...0F |
| 7019 | 14639 | // dst = (temp1 >> 4) & 0x0F...0F |
| 7020 | | try self.asmRegisterImmediate(.{ ._l, .sh }, tmp, Immediate.u(4)); |
| 14640 | try self.asmRegisterImmediate(.{ ._l, .sh }, tmp, .u(4)); |
| 7021 | 14641 | // tmp = (temp1 & 0x0F...0F) << 4 |
| 7022 | 14642 | try self.asmRegisterRegister(.{ ._, .@"or" }, dst, tmp); |
| 7023 | 14643 | // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4) |
| 7024 | 14644 | try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst); |
| 7025 | 14645 | // tmp = temp2 |
| 7026 | | try self.asmRegisterImmediate(.{ ._r, .sh }, dst, Immediate.u(2)); |
| 14646 | try self.asmRegisterImmediate(.{ ._r, .sh }, dst, .u(2)); |
| 7027 | 14647 | // dst = temp2 >> 2 |
| 7028 | 14648 | if (limb_abi_size > 4) { |
| 7029 | 14649 | try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_00_11); |
| ... | ... | @@ -7050,7 +14670,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 7050 | 14670 | // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2) |
| 7051 | 14671 | try self.asmRegisterRegister(.{ ._, .mov }, dst, tmp); |
| 7052 | 14672 | // dst = temp3 |
| 7053 | | try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, Immediate.u(1)); |
| 14673 | try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, .u(1)); |
| 7054 | 14674 | // tmp = temp3 >> 1 |
| 7055 | 14675 | if (limb_abi_size > 4) { |
| 7056 | 14676 | try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0_1); |
| ... | ... | @@ -7083,12 +14703,12 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 7083 | 14703 | if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) { |
| 7084 | 14704 | .signed => .{ ._r, .sa }, |
| 7085 | 14705 | .unsigned => .{ ._r, .sh }, |
| 7086 | | }, src_ty, dst_mcv, Type.u8, .{ .immediate = extra_bits }); |
| 14706 | }, src_ty, dst_mcv, .u8, .{ .immediate = extra_bits }); |
| 7087 | 14707 | |
| 7088 | 14708 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 7089 | 14709 | } |
| 7090 | 14710 | |
| 7091 | | fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) !void { |
| 14711 | fn floatSign(self: *CodeGen, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) !void { |
| 7092 | 14712 | const pt = self.pt; |
| 7093 | 14713 | const zcu = pt.zcu; |
| 7094 | 14714 | const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; |
| ... | ... | @@ -7150,12 +14770,12 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) |
| 7150 | 14770 | .abs => try vec_ty.maxInt(pt, vec_ty), |
| 7151 | 14771 | else => unreachable, |
| 7152 | 14772 | }); |
| 7153 | | const sign_mem: Memory = if (sign_mcv.isMemory()) |
| 7154 | | try sign_mcv.mem(self, Memory.Size.fromSize(abi_size)) |
| 14773 | const sign_mem: Memory = if (sign_mcv.isBase()) |
| 14774 | try sign_mcv.mem(self, .{ .size = .fromSize(abi_size) }) |
| 7155 | 14775 | else |
| 7156 | 14776 | .{ |
| 7157 | | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, sign_mcv.address()) }, |
| 7158 | | .mod = .{ .rm = .{ .size = Memory.Size.fromSize(abi_size) } }, |
| 14777 | .base = .{ .reg = try self.copyToTmpRegister(.usize, sign_mcv.address()) }, |
| 14778 | .mod = .{ .rm = .{ .size = .fromSize(abi_size) } }, |
| 7159 | 14779 | }; |
| 7160 | 14780 | |
| 7161 | 14781 | if (self.hasFeature(.avx)) try self.asmRegisterRegisterMemory( |
| ... | ... | @@ -7216,7 +14836,7 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) |
| 7216 | 14836 | return self.finishAir(inst, result, .{ operand, .none, .none }); |
| 7217 | 14837 | } |
| 7218 | 14838 | |
| 7219 | | fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 14839 | fn airFloatSign(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 7220 | 14840 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 7221 | 14841 | const ty = self.typeOf(un_op); |
| 7222 | 14842 | return self.floatSign(inst, un_op, ty); |
| ... | ... | @@ -7241,7 +14861,7 @@ const RoundMode = packed struct(u5) { |
| 7241 | 14861 | } = .normal, |
| 7242 | 14862 | }; |
| 7243 | 14863 | |
| 7244 | | fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void { |
| 14864 | fn airRound(self: *CodeGen, inst: Air.Inst.Index, mode: RoundMode) !void { |
| 7245 | 14865 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 7246 | 14866 | const ty = self.typeOf(un_op); |
| 7247 | 14867 | |
| ... | ... | @@ -7265,7 +14885,7 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void { |
| 7265 | 14885 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 7266 | 14886 | } |
| 7267 | 14887 | |
| 7268 | | fn getRoundTag(self: *Self, ty: Type) ?Mir.Inst.FixedTag { |
| 14888 | fn getRoundTag(self: *CodeGen, ty: Type) ?Mir.Inst.FixedTag { |
| 7269 | 14889 | const pt = self.pt; |
| 7270 | 14890 | const zcu = pt.zcu; |
| 7271 | 14891 | return if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -7298,7 +14918,7 @@ fn getRoundTag(self: *Self, ty: Type) ?Mir.Inst.FixedTag { |
| 7298 | 14918 | } else null; |
| 7299 | 14919 | } |
| 7300 | 14920 | |
| 7301 | | fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MCValue { |
| 14921 | fn genRoundLibcall(self: *CodeGen, ty: Type, src_mcv: MCValue, mode: RoundMode) !MCValue { |
| 7302 | 14922 | const pt = self.pt; |
| 7303 | 14923 | const zcu = pt.zcu; |
| 7304 | 14924 | if (self.getRoundTag(ty)) |_| return .none; |
| ... | ... | @@ -7320,10 +14940,10 @@ fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MC |
| 7320 | 14940 | }, |
| 7321 | 14941 | floatLibcAbiSuffix(ty), |
| 7322 | 14942 | }) catch unreachable, |
| 7323 | | } }, &.{ty}, &.{src_mcv}); |
| 14943 | } }, &.{ty}, &.{src_mcv}, .{}); |
| 7324 | 14944 | } |
| 7325 | 14945 | |
| 7326 | | fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void { |
| 14946 | fn genRound(self: *CodeGen, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void { |
| 7327 | 14947 | const pt = self.pt; |
| 7328 | 14948 | const mir_tag = self.getRoundTag(ty) orelse { |
| 7329 | 14949 | const result = try self.genRoundLibcall(ty, src_mcv, mode); |
| ... | ... | @@ -7332,12 +14952,12 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro |
| 7332 | 14952 | const abi_size: u32 = @intCast(ty.abiSize(pt.zcu)); |
| 7333 | 14953 | const dst_alias = registerAlias(dst_reg, abi_size); |
| 7334 | 14954 | switch (mir_tag[0]) { |
| 7335 | | .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 14955 | .v_ss, .v_sd => if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 7336 | 14956 | mir_tag, |
| 7337 | 14957 | dst_alias, |
| 7338 | 14958 | dst_alias, |
| 7339 | | try src_mcv.mem(self, Memory.Size.fromSize(abi_size)), |
| 7340 | | Immediate.u(@as(u5, @bitCast(mode))), |
| 14959 | try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }), |
| 14960 | .u(@as(u5, @bitCast(mode))), |
| 7341 | 14961 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 7342 | 14962 | mir_tag, |
| 7343 | 14963 | dst_alias, |
| ... | ... | @@ -7346,13 +14966,13 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro |
| 7346 | 14966 | src_mcv.getReg().? |
| 7347 | 14967 | else |
| 7348 | 14968 | try self.copyToTmpRegister(ty, src_mcv), abi_size), |
| 7349 | | Immediate.u(@as(u5, @bitCast(mode))), |
| 14969 | .u(@as(u5, @bitCast(mode))), |
| 7350 | 14970 | ), |
| 7351 | | else => if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 14971 | else => if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate( |
| 7352 | 14972 | mir_tag, |
| 7353 | 14973 | dst_alias, |
| 7354 | | try src_mcv.mem(self, Memory.Size.fromSize(abi_size)), |
| 7355 | | Immediate.u(@as(u5, @bitCast(mode))), |
| 14974 | try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }), |
| 14975 | .u(@as(u5, @bitCast(mode))), |
| 7356 | 14976 | ) else try self.asmRegisterRegisterImmediate( |
| 7357 | 14977 | mir_tag, |
| 7358 | 14978 | dst_alias, |
| ... | ... | @@ -7360,12 +14980,12 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro |
| 7360 | 14980 | src_mcv.getReg().? |
| 7361 | 14981 | else |
| 7362 | 14982 | try self.copyToTmpRegister(ty, src_mcv), abi_size), |
| 7363 | | Immediate.u(@as(u5, @bitCast(mode))), |
| 14983 | .u(@as(u5, @bitCast(mode))), |
| 7364 | 14984 | ), |
| 7365 | 14985 | } |
| 7366 | 14986 | } |
| 7367 | 14987 | |
| 7368 | | fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 14988 | fn airAbs(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 7369 | 14989 | const pt = self.pt; |
| 7370 | 14990 | const zcu = pt.zcu; |
| 7371 | 14991 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -7393,7 +15013,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 7393 | 15013 | .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory( |
| 7394 | 15014 | .l, |
| 7395 | 15015 | registerAlias(dst_mcv.register, cmov_abi_size), |
| 7396 | | try src_mcv.mem(self, Memory.Size.fromSize(cmov_abi_size)), |
| 15016 | try src_mcv.mem(self, .{ .size = .fromSize(cmov_abi_size) }), |
| 7397 | 15017 | ), |
| 7398 | 15018 | else => { |
| 7399 | 15019 | const val_reg = try self.copyToTmpRegister(ty, src_mcv); |
| ... | ... | @@ -7433,7 +15053,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 7433 | 15053 | defer self.register_manager.unlockReg(tmp_lock); |
| 7434 | 15054 | |
| 7435 | 15055 | try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]); |
| 7436 | | try self.asmRegisterImmediate(.{ ._r, .sa }, tmp_reg, Immediate.u(63)); |
| 15056 | try self.asmRegisterImmediate(.{ ._r, .sa }, tmp_reg, .u(63)); |
| 7437 | 15057 | try self.asmRegisterRegister(.{ ._, .xor }, dst_regs[0], tmp_reg); |
| 7438 | 15058 | try self.asmRegisterRegister(.{ ._, .xor }, dst_regs[1], tmp_reg); |
| 7439 | 15059 | try self.asmRegisterRegister(.{ ._, .sub }, dst_regs[0], tmp_reg); |
| ... | ... | @@ -7443,10 +15063,10 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 7443 | 15063 | }, |
| 7444 | 15064 | else => { |
| 7445 | 15065 | const abi_size: u31 = @intCast(ty.abiSize(zcu)); |
| 7446 | | const limb_len = math.divCeil(u31, abi_size, 8) catch unreachable; |
| 15066 | const limb_len = std.math.divCeil(u31, abi_size, 8) catch unreachable; |
| 7447 | 15067 | |
| 7448 | 15068 | const tmp_regs = |
| 7449 | | try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp); |
| 15069 | try self.register_manager.allocRegs(3, @splat(null), abi.RegisterClass.gp); |
| 7450 | 15070 | const tmp_locks = self.register_manager.lockRegsAssumeUnused(3, tmp_regs); |
| 7451 | 15071 | defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); |
| 7452 | 15072 | |
| ... | ... | @@ -7459,8 +15079,8 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 7459 | 15079 | |
| 7460 | 15080 | try self.asmMemoryImmediate( |
| 7461 | 15081 | .{ ._, .cmp }, |
| 7462 | | try dst_mcv.address().offset((limb_len - 1) * 8).deref().mem(self, .qword), |
| 7463 | | Immediate.u(0), |
| 15082 | try dst_mcv.address().offset((limb_len - 1) * 8).deref().mem(self, .{ .size = .qword }), |
| 15083 | .u(0), |
| 7464 | 15084 | ); |
| 7465 | 15085 | const positive = try self.asmJccReloc(.ns, undefined); |
| 7466 | 15086 | |
| ... | ... | @@ -7469,7 +15089,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 7469 | 15089 | |
| 7470 | 15090 | const neg_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 7471 | 15091 | try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[2].to32(), tmp_regs[2].to32()); |
| 7472 | | try self.asmRegisterImmediate(.{ ._r, .sh }, tmp_regs[1].to8(), Immediate.u(1)); |
| 15092 | try self.asmRegisterImmediate(.{ ._r, .sh }, tmp_regs[1].to8(), .u(1)); |
| 7473 | 15093 | try self.asmRegisterMemory(.{ ._, .sbb }, tmp_regs[2].to64(), .{ |
| 7474 | 15094 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| 7475 | 15095 | .mod = .{ .rm = .{ |
| ... | ... | @@ -7491,11 +15111,11 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 7491 | 15111 | }, tmp_regs[2].to64()); |
| 7492 | 15112 | |
| 7493 | 15113 | if (self.hasFeature(.slow_incdec)) { |
| 7494 | | try self.asmRegisterImmediate(.{ ._, .add }, tmp_regs[0].to32(), Immediate.u(1)); |
| 15114 | try self.asmRegisterImmediate(.{ ._, .add }, tmp_regs[0].to32(), .u(1)); |
| 7495 | 15115 | } else { |
| 7496 | 15116 | try self.asmRegister(.{ ._, .inc }, tmp_regs[0].to32()); |
| 7497 | 15117 | } |
| 7498 | | try self.asmRegisterImmediate(.{ ._, .cmp }, tmp_regs[0].to32(), Immediate.u(limb_len)); |
| 15118 | try self.asmRegisterImmediate(.{ ._, .cmp }, tmp_regs[0].to32(), .u(limb_len)); |
| 7499 | 15119 | _ = try self.asmJccReloc(.b, neg_loop); |
| 7500 | 15120 | |
| 7501 | 15121 | self.performReloc(positive); |
| ... | ... | @@ -7547,12 +15167,12 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 7547 | 15167 | const dst_reg = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 7548 | 15168 | src_mcv.getReg().? |
| 7549 | 15169 | else |
| 7550 | | try self.register_manager.allocReg(inst, self.regClassForType(ty)); |
| 15170 | try self.register_manager.allocReg(inst, self.regSetForType(ty)); |
| 7551 | 15171 | const dst_alias = registerAlias(dst_reg, abi_size); |
| 7552 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 15172 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 7553 | 15173 | mir_tag, |
| 7554 | 15174 | dst_alias, |
| 7555 | | try src_mcv.mem(self, self.memSize(ty)), |
| 15175 | try src_mcv.mem(self, .{ .size = self.memSize(ty) }), |
| 7556 | 15176 | ) else try self.asmRegisterRegister( |
| 7557 | 15177 | mir_tag, |
| 7558 | 15178 | dst_alias, |
| ... | ... | @@ -7566,7 +15186,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 7566 | 15186 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 7567 | 15187 | } |
| 7568 | 15188 | |
| 7569 | | fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 15189 | fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 7570 | 15190 | const pt = self.pt; |
| 7571 | 15191 | const zcu = pt.zcu; |
| 7572 | 15192 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| ... | ... | @@ -7591,7 +15211,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 7591 | 15211 | floatLibcAbiPrefix(ty), |
| 7592 | 15212 | floatLibcAbiSuffix(ty), |
| 7593 | 15213 | }) catch unreachable, |
| 7594 | | } }, &.{ty}, &.{.{ .air_ref = un_op }}); |
| 15214 | } }, &.{ty}, &.{.{ .air_ref = un_op }}, .{}); |
| 7595 | 15215 | } |
| 7596 | 15216 | }, |
| 7597 | 15217 | else => {}, |
| ... | ... | @@ -7620,7 +15240,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 7620 | 15240 | .{ .v_, .cvtps2ph }, |
| 7621 | 15241 | dst_reg, |
| 7622 | 15242 | dst_reg, |
| 7623 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 15243 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 7624 | 15244 | ); |
| 7625 | 15245 | break :result dst_mcv; |
| 7626 | 15246 | }, |
| ... | ... | @@ -7650,18 +15270,18 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 7650 | 15270 | .{ .v_, .cvtps2ph }, |
| 7651 | 15271 | dst_reg, |
| 7652 | 15272 | dst_reg, |
| 7653 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 15273 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 7654 | 15274 | ); |
| 7655 | 15275 | break :result dst_mcv; |
| 7656 | 15276 | }, |
| 7657 | 15277 | 2...8 => { |
| 7658 | 15278 | const wide_reg = registerAlias(dst_reg, abi_size * 2); |
| 7659 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 15279 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 7660 | 15280 | .{ .v_ps, .cvtph2 }, |
| 7661 | 15281 | wide_reg, |
| 7662 | | try src_mcv.mem(self, Memory.Size.fromSize( |
| 15282 | try src_mcv.mem(self, .{ .size = .fromSize( |
| 7663 | 15283 | @intCast(@divExact(wide_reg.bitSize(), 16)), |
| 7664 | | )), |
| 15284 | ) }), |
| 7665 | 15285 | ) else try self.asmRegisterRegister( |
| 7666 | 15286 | .{ .v_ps, .cvtph2 }, |
| 7667 | 15287 | wide_reg, |
| ... | ... | @@ -7675,7 +15295,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 7675 | 15295 | .{ .v_, .cvtps2ph }, |
| 7676 | 15296 | dst_reg, |
| 7677 | 15297 | wide_reg, |
| 7678 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 15298 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 7679 | 15299 | ); |
| 7680 | 15300 | break :result dst_mcv; |
| 7681 | 15301 | }, |
| ... | ... | @@ -7699,15 +15319,13 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 7699 | 15319 | else => unreachable, |
| 7700 | 15320 | }, |
| 7701 | 15321 | else => unreachable, |
| 7702 | | }) orelse return self.fail("TODO implement airSqrt for {}", .{ |
| 7703 | | ty.fmt(pt), |
| 7704 | | }); |
| 15322 | }) orelse return self.fail("TODO implement airSqrt for {}", .{ty.fmt(pt)}); |
| 7705 | 15323 | switch (mir_tag[0]) { |
| 7706 | | .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 15324 | .v_ss, .v_sd => if (src_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 7707 | 15325 | mir_tag, |
| 7708 | 15326 | dst_reg, |
| 7709 | 15327 | dst_reg, |
| 7710 | | try src_mcv.mem(self, Memory.Size.fromSize(abi_size)), |
| 15328 | try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }), |
| 7711 | 15329 | ) else try self.asmRegisterRegisterRegister( |
| 7712 | 15330 | mir_tag, |
| 7713 | 15331 | dst_reg, |
| ... | ... | @@ -7717,10 +15335,10 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 7717 | 15335 | else |
| 7718 | 15336 | try self.copyToTmpRegister(ty, src_mcv), abi_size), |
| 7719 | 15337 | ), |
| 7720 | | else => if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 15338 | else => if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 7721 | 15339 | mir_tag, |
| 7722 | 15340 | dst_reg, |
| 7723 | | try src_mcv.mem(self, Memory.Size.fromSize(abi_size)), |
| 15341 | try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }), |
| 7724 | 15342 | ) else try self.asmRegisterRegister( |
| 7725 | 15343 | mir_tag, |
| 7726 | 15344 | dst_reg, |
| ... | ... | @@ -7735,7 +15353,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 7735 | 15353 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 7736 | 15354 | } |
| 7737 | 15355 | |
| 7738 | | fn airUnaryMath(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 15356 | fn airUnaryMath(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 7739 | 15357 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 7740 | 15358 | const ty = self.typeOf(un_op); |
| 7741 | 15359 | var callee_buf: ["__round?".len]u8 = undefined; |
| ... | ... | @@ -7759,12 +15377,12 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 7759 | 15377 | }, |
| 7760 | 15378 | floatLibcAbiSuffix(ty), |
| 7761 | 15379 | }) catch unreachable, |
| 7762 | | } }, &.{ty}, &.{.{ .air_ref = un_op }}); |
| 15380 | } }, &.{ty}, &.{.{ .air_ref = un_op }}, .{}); |
| 7763 | 15381 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 7764 | 15382 | } |
| 7765 | 15383 | |
| 7766 | 15384 | fn reuseOperand( |
| 7767 | | self: *Self, |
| 15385 | self: *CodeGen, |
| 7768 | 15386 | inst: Air.Inst.Index, |
| 7769 | 15387 | operand: Air.Inst.Ref, |
| 7770 | 15388 | op_index: Liveness.OperandInt, |
| ... | ... | @@ -7774,7 +15392,7 @@ fn reuseOperand( |
| 7774 | 15392 | } |
| 7775 | 15393 | |
| 7776 | 15394 | fn reuseOperandAdvanced( |
| 7777 | | self: *Self, |
| 15395 | self: *CodeGen, |
| 7778 | 15396 | inst: Air.Inst.Index, |
| 7779 | 15397 | operand: Air.Inst.Ref, |
| 7780 | 15398 | op_index: Liveness.OperandInt, |
| ... | ... | @@ -7785,7 +15403,7 @@ fn reuseOperandAdvanced( |
| 7785 | 15403 | return false; |
| 7786 | 15404 | |
| 7787 | 15405 | switch (mcv) { |
| 7788 | | .register, .register_pair, .register_overflow => for (mcv.getRegs()) |reg| { |
| 15406 | .register, .register_pair, .register_overflow, .register_mask => for (mcv.getRegs()) |reg| { |
| 7789 | 15407 | // If it's in the registers table, need to associate the register(s) with the |
| 7790 | 15408 | // new instruction. |
| 7791 | 15409 | if (maybe_tracked_inst) |tracked_inst| { |
| ... | ... | @@ -7805,19 +15423,19 @@ fn reuseOperandAdvanced( |
| 7805 | 15423 | } |
| 7806 | 15424 | |
| 7807 | 15425 | // Prevent the operand deaths processing code from deallocating it. |
| 7808 | | self.liveness.clearOperandDeath(inst, op_index); |
| 15426 | self.reused_operands.set(op_index); |
| 7809 | 15427 | const op_inst = operand.toIndex().?; |
| 7810 | 15428 | self.getResolvedInstValue(op_inst).reuse(self, maybe_tracked_inst, op_inst); |
| 7811 | 15429 | |
| 7812 | 15430 | return true; |
| 7813 | 15431 | } |
| 7814 | 15432 | |
| 7815 | | fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { |
| 15433 | fn packedLoad(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { |
| 7816 | 15434 | const pt = self.pt; |
| 7817 | 15435 | const zcu = pt.zcu; |
| 7818 | 15436 | |
| 7819 | 15437 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 7820 | | const val_ty = Type.fromInterned(ptr_info.child); |
| 15438 | const val_ty: Type = .fromInterned(ptr_info.child); |
| 7821 | 15439 | if (!val_ty.hasRuntimeBitsIgnoreComptime(zcu)) return; |
| 7822 | 15440 | const val_abi_size: u32 = @intCast(val_ty.abiSize(zcu)); |
| 7823 | 15441 | |
| ... | ... | @@ -7851,9 +15469,9 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn |
| 7851 | 15469 | defer self.register_manager.unlockReg(tmp_lock); |
| 7852 | 15470 | |
| 7853 | 15471 | const hi_mcv = dst_mcv.address().offset(@intCast(val_bit_size / 64 * 8)).deref(); |
| 7854 | | try self.genSetReg(tmp_reg, Type.usize, hi_mcv, .{}); |
| 15472 | try self.genSetReg(tmp_reg, .usize, hi_mcv, .{}); |
| 7855 | 15473 | try self.truncateRegister(val_ty, tmp_reg); |
| 7856 | | try self.genCopy(Type.usize, hi_mcv, .{ .register = tmp_reg }, .{}); |
| 15474 | try self.genCopy(.usize, hi_mcv, .{ .register = tmp_reg }, .{}); |
| 7857 | 15475 | } |
| 7858 | 15476 | } |
| 7859 | 15477 | return; |
| ... | ... | @@ -7885,12 +15503,12 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn |
| 7885 | 15503 | try self.asmRegisterMemory(.{ ._, .mov }, load_reg, .{ |
| 7886 | 15504 | .base = .{ .reg = ptr_reg }, |
| 7887 | 15505 | .mod = .{ .rm = .{ |
| 7888 | | .size = Memory.Size.fromSize(load_abi_size), |
| 15506 | .size = .fromSize(load_abi_size), |
| 7889 | 15507 | .disp = val_byte_off, |
| 7890 | 15508 | } }, |
| 7891 | 15509 | }); |
| 7892 | 15510 | try self.spillEflagsIfOccupied(); |
| 7893 | | try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(val_bit_off)); |
| 15511 | try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, .u(val_bit_off)); |
| 7894 | 15512 | } else { |
| 7895 | 15513 | const tmp_reg = |
| 7896 | 15514 | registerAlias(try self.register_manager.allocReg(null, abi.RegisterClass.gp), val_abi_size); |
| ... | ... | @@ -7901,31 +15519,26 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn |
| 7901 | 15519 | try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ |
| 7902 | 15520 | .base = .{ .reg = ptr_reg }, |
| 7903 | 15521 | .mod = .{ .rm = .{ |
| 7904 | | .size = Memory.Size.fromSize(val_abi_size), |
| 15522 | .size = .fromSize(val_abi_size), |
| 7905 | 15523 | .disp = val_byte_off, |
| 7906 | 15524 | } }, |
| 7907 | 15525 | }); |
| 7908 | 15526 | try self.asmRegisterMemory(.{ ._, .mov }, tmp_reg, .{ |
| 7909 | 15527 | .base = .{ .reg = ptr_reg }, |
| 7910 | 15528 | .mod = .{ .rm = .{ |
| 7911 | | .size = Memory.Size.fromSize(val_abi_size), |
| 15529 | .size = .fromSize(val_abi_size), |
| 7912 | 15530 | .disp = val_byte_off + limb_abi_size, |
| 7913 | 15531 | } }, |
| 7914 | 15532 | }); |
| 7915 | 15533 | try self.spillEflagsIfOccupied(); |
| 7916 | | try self.asmRegisterRegisterImmediate( |
| 7917 | | .{ ._rd, .sh }, |
| 7918 | | dst_alias, |
| 7919 | | tmp_reg, |
| 7920 | | Immediate.u(val_bit_off), |
| 7921 | | ); |
| 15534 | try self.asmRegisterRegisterImmediate(.{ ._rd, .sh }, dst_alias, tmp_reg, .u(val_bit_off)); |
| 7922 | 15535 | } |
| 7923 | 15536 | |
| 7924 | 15537 | if (val_extra_bits > 0) try self.truncateRegister(val_ty, dst_reg); |
| 7925 | 15538 | try self.genCopy(val_ty, dst_mcv, .{ .register = dst_reg }, .{}); |
| 7926 | 15539 | } |
| 7927 | 15540 | |
| 7928 | | fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { |
| 15541 | fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { |
| 7929 | 15542 | const pt = self.pt; |
| 7930 | 15543 | const zcu = pt.zcu; |
| 7931 | 15544 | const dst_ty = ptr_ty.childType(zcu); |
| ... | ... | @@ -7937,7 +15550,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 7937 | 15550 | .undef, |
| 7938 | 15551 | .eflags, |
| 7939 | 15552 | .register_pair, |
| 15553 | .register_triple, |
| 15554 | .register_quadruple, |
| 7940 | 15555 | .register_overflow, |
| 15556 | .register_mask, |
| 7941 | 15557 | .elementwise_regs_then_frame, |
| 7942 | 15558 | .reserved_frame, |
| 7943 | 15559 | => unreachable, // not a valid pointer |
| ... | ... | @@ -7968,7 +15584,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 7968 | 15584 | } |
| 7969 | 15585 | } |
| 7970 | 15586 | |
| 7971 | | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 15587 | fn airLoad(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 7972 | 15588 | const pt = self.pt; |
| 7973 | 15589 | const zcu = pt.zcu; |
| 7974 | 15590 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -7983,12 +15599,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 7983 | 15599 | const ptr_ty = self.typeOf(ty_op.operand); |
| 7984 | 15600 | const elem_size = elem_ty.abiSize(zcu); |
| 7985 | 15601 | |
| 7986 | | const elem_rc = self.regClassForType(elem_ty); |
| 7987 | | const ptr_rc = self.regClassForType(ptr_ty); |
| 15602 | const elem_rs = self.regSetForType(elem_ty); |
| 15603 | const ptr_rs = self.regSetForType(ptr_ty); |
| 7988 | 15604 | |
| 7989 | 15605 | const ptr_mcv = try self.resolveInst(ty_op.operand); |
| 7990 | | const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and |
| 7991 | | self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv)) |
| 15606 | const dst_mcv = if (elem_size <= 8 and std.math.isPowerOfTwo(elem_size) and |
| 15607 | elem_rs.supersetOf(ptr_rs) and self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv)) |
| 7992 | 15608 | // The MCValue that holds the pointer can be re-used as the value. |
| 7993 | 15609 | ptr_mcv |
| 7994 | 15610 | else |
| ... | ... | @@ -8010,13 +15626,13 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 8010 | 15626 | const high_reg = if (high_mcv.isRegister()) |
| 8011 | 15627 | high_mcv.getReg().? |
| 8012 | 15628 | else |
| 8013 | | try self.copyToTmpRegister(Type.usize, high_mcv); |
| 15629 | try self.copyToTmpRegister(.usize, high_mcv); |
| 8014 | 15630 | const high_lock = self.register_manager.lockReg(high_reg); |
| 8015 | 15631 | defer if (high_lock) |lock| self.register_manager.unlockReg(lock); |
| 8016 | 15632 | |
| 8017 | 15633 | try self.truncateRegister(elem_ty, high_reg); |
| 8018 | 15634 | if (!high_mcv.isRegister()) try self.genCopy( |
| 8019 | | if (elem_size <= 8) elem_ty else Type.usize, |
| 15635 | if (elem_size <= 8) elem_ty else .usize, |
| 8020 | 15636 | high_mcv, |
| 8021 | 15637 | .{ .register = high_reg }, |
| 8022 | 15638 | .{}, |
| ... | ... | @@ -8027,11 +15643,11 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 8027 | 15643 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8028 | 15644 | } |
| 8029 | 15645 | |
| 8030 | | fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 15646 | fn packedStore(self: *CodeGen, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 8031 | 15647 | const pt = self.pt; |
| 8032 | 15648 | const zcu = pt.zcu; |
| 8033 | 15649 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 8034 | | const src_ty = Type.fromInterned(ptr_info.child); |
| 15650 | const src_ty: Type = .fromInterned(ptr_info.child); |
| 8035 | 15651 | if (!src_ty.hasRuntimeBitsIgnoreComptime(zcu)) return; |
| 8036 | 15652 | |
| 8037 | 15653 | const limb_abi_size: u16 = @min(ptr_info.packed_offset.host_size, 8); |
| ... | ... | @@ -8051,6 +15667,15 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In |
| 8051 | 15667 | const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg); |
| 8052 | 15668 | defer self.register_manager.unlockReg(ptr_lock); |
| 8053 | 15669 | |
| 15670 | const mat_src_mcv: MCValue = mat_src_mcv: switch (src_mcv) { |
| 15671 | .register => if (src_bit_size > 64) { |
| 15672 | const frame_index = try self.allocFrameIndex(.initSpill(src_ty, self.pt.zcu)); |
| 15673 | try self.genSetMem(.{ .frame = frame_index }, 0, src_ty, src_mcv, .{}); |
| 15674 | break :mat_src_mcv .{ .load_frame = .{ .index = frame_index } }; |
| 15675 | } else src_mcv, |
| 15676 | else => src_mcv, |
| 15677 | }; |
| 15678 | |
| 8054 | 15679 | var limb_i: u16 = 0; |
| 8055 | 15680 | while (limb_i * limb_abi_bits < src_bit_off + src_bit_size) : (limb_i += 1) { |
| 8056 | 15681 | const part_bit_off = if (limb_i == 0) src_bit_off else 0; |
| ... | ... | @@ -8059,21 +15684,21 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In |
| 8059 | 15684 | const limb_mem: Memory = .{ |
| 8060 | 15685 | .base = .{ .reg = ptr_reg }, |
| 8061 | 15686 | .mod = .{ .rm = .{ |
| 8062 | | .size = Memory.Size.fromSize(limb_abi_size), |
| 15687 | .size = .fromSize(limb_abi_size), |
| 8063 | 15688 | .disp = src_byte_off + limb_i * limb_abi_size, |
| 8064 | 15689 | } }, |
| 8065 | 15690 | }; |
| 8066 | 15691 | |
| 8067 | | const part_mask = (@as(u64, math.maxInt(u64)) >> @intCast(64 - part_bit_size)) << |
| 15692 | const part_mask = (@as(u64, std.math.maxInt(u64)) >> @intCast(64 - part_bit_size)) << |
| 8068 | 15693 | @intCast(part_bit_off); |
| 8069 | | const part_mask_not = part_mask ^ (@as(u64, math.maxInt(u64)) >> @intCast(64 - limb_abi_bits)); |
| 15694 | const part_mask_not = part_mask ^ (@as(u64, std.math.maxInt(u64)) >> @intCast(64 - limb_abi_bits)); |
| 8070 | 15695 | if (limb_abi_size <= 4) { |
| 8071 | | try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, Immediate.u(part_mask_not)); |
| 8072 | | } else if (math.cast(i32, @as(i64, @bitCast(part_mask_not)))) |small| { |
| 8073 | | try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, Immediate.s(small)); |
| 15696 | try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, .u(part_mask_not)); |
| 15697 | } else if (std.math.cast(i32, @as(i64, @bitCast(part_mask_not)))) |small| { |
| 15698 | try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, .s(small)); |
| 8074 | 15699 | } else { |
| 8075 | 15700 | const part_mask_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 8076 | | try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, Immediate.u(part_mask_not)); |
| 15701 | try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, .u(part_mask_not)); |
| 8077 | 15702 | try self.asmMemoryRegister(.{ ._, .@"and" }, limb_mem, part_mask_reg); |
| 8078 | 15703 | } |
| 8079 | 15704 | |
| ... | ... | @@ -8083,20 +15708,20 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In |
| 8083 | 15708 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 8084 | 15709 | defer self.register_manager.unlockReg(tmp_lock); |
| 8085 | 15710 | |
| 8086 | | try self.genSetReg(tmp_reg, limb_ty, src_mcv, .{}); |
| 15711 | try self.genSetReg(tmp_reg, limb_ty, mat_src_mcv, .{}); |
| 8087 | 15712 | switch (limb_i) { |
| 8088 | 15713 | 0 => try self.genShiftBinOpMir( |
| 8089 | 15714 | .{ ._l, .sh }, |
| 8090 | 15715 | limb_ty, |
| 8091 | 15716 | tmp_mcv, |
| 8092 | | Type.u8, |
| 15717 | .u8, |
| 8093 | 15718 | .{ .immediate = src_bit_off }, |
| 8094 | 15719 | ), |
| 8095 | 15720 | 1 => try self.genShiftBinOpMir( |
| 8096 | 15721 | .{ ._r, .sh }, |
| 8097 | 15722 | limb_ty, |
| 8098 | 15723 | tmp_mcv, |
| 8099 | | Type.u8, |
| 15724 | .u8, |
| 8100 | 15725 | .{ .immediate = limb_abi_bits - src_bit_off }, |
| 8101 | 15726 | ), |
| 8102 | 15727 | else => unreachable, |
| ... | ... | @@ -8114,8 +15739,8 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In |
| 8114 | 15739 | defer self.register_manager.unlockReg(tmp_lock); |
| 8115 | 15740 | |
| 8116 | 15741 | try self.genSetReg(tmp_reg, limb_ty, switch (limb_i) { |
| 8117 | | 0 => src_mcv, |
| 8118 | | else => src_mcv.address().offset(limb_i * limb_abi_size).deref(), |
| 15742 | 0 => mat_src_mcv, |
| 15743 | else => mat_src_mcv.address().offset(limb_i * limb_abi_size).deref(), |
| 8119 | 15744 | }, .{}); |
| 8120 | 15745 | try self.genBinOpMir(.{ ._, .@"and" }, limb_ty, tmp_mcv, .{ .immediate = part_mask }); |
| 8121 | 15746 | try self.asmMemoryRegister( |
| ... | ... | @@ -8128,7 +15753,7 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In |
| 8128 | 15753 | } |
| 8129 | 15754 | |
| 8130 | 15755 | fn store( |
| 8131 | | self: *Self, |
| 15756 | self: *CodeGen, |
| 8132 | 15757 | ptr_ty: Type, |
| 8133 | 15758 | ptr_mcv: MCValue, |
| 8134 | 15759 | src_mcv: MCValue, |
| ... | ... | @@ -8145,7 +15770,10 @@ fn store( |
| 8145 | 15770 | .undef, |
| 8146 | 15771 | .eflags, |
| 8147 | 15772 | .register_pair, |
| 15773 | .register_triple, |
| 15774 | .register_quadruple, |
| 8148 | 15775 | .register_overflow, |
| 15776 | .register_mask, |
| 8149 | 15777 | .elementwise_regs_then_frame, |
| 8150 | 15778 | .reserved_frame, |
| 8151 | 15779 | => unreachable, // not a valid pointer |
| ... | ... | @@ -8176,7 +15804,7 @@ fn store( |
| 8176 | 15804 | } |
| 8177 | 15805 | } |
| 8178 | 15806 | |
| 8179 | | fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 15807 | fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { |
| 8180 | 15808 | const pt = self.pt; |
| 8181 | 15809 | const zcu = pt.zcu; |
| 8182 | 15810 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -8202,32 +15830,21 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 8202 | 15830 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 8203 | 15831 | } |
| 8204 | 15832 | |
| 8205 | | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 15833 | fn airStructFieldPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 8206 | 15834 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 8207 | 15835 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 8208 | 15836 | const result = try self.fieldPtr(inst, extra.struct_operand, extra.field_index); |
| 8209 | 15837 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 8210 | 15838 | } |
| 8211 | 15839 | |
| 8212 | | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 15840 | fn airStructFieldPtrIndex(self: *CodeGen, inst: Air.Inst.Index, field_index: u8) !void { |
| 8213 | 15841 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 8214 | | const result = try self.fieldPtr(inst, ty_op.operand, index); |
| 15842 | const result = try self.fieldPtr(inst, ty_op.operand, field_index); |
| 8215 | 15843 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8216 | 15844 | } |
| 8217 | 15845 | |
| 8218 | | fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 8219 | | const pt = self.pt; |
| 8220 | | const zcu = pt.zcu; |
| 15846 | fn fieldPtr(self: *CodeGen, inst: Air.Inst.Index, operand: Air.Inst.Ref, field_index: u32) !MCValue { |
| 8221 | 15847 | const ptr_field_ty = self.typeOfIndex(inst); |
| 8222 | | const ptr_container_ty = self.typeOf(operand); |
| 8223 | | const container_ty = ptr_container_ty.childType(zcu); |
| 8224 | | |
| 8225 | | const field_off: i32 = switch (container_ty.containerLayout(zcu)) { |
| 8226 | | .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, zcu)), |
| 8227 | | .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) + |
| 8228 | | (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) - |
| 8229 | | ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), |
| 8230 | | }; |
| 8231 | 15848 | |
| 8232 | 15849 | const src_mcv = try self.resolveInst(operand); |
| 8233 | 15850 | const dst_mcv = if (switch (src_mcv) { |
| ... | ... | @@ -8235,10 +15852,22 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 |
| 8235 | 15852 | .register, .register_offset => self.reuseOperand(inst, operand, 0, src_mcv), |
| 8236 | 15853 | else => false, |
| 8237 | 15854 | }) src_mcv else try self.copyToRegisterWithInstTracking(inst, ptr_field_ty, src_mcv); |
| 8238 | | return dst_mcv.offset(field_off); |
| 15855 | return dst_mcv.offset(self.fieldOffset(self.typeOf(operand), ptr_field_ty, field_index)); |
| 15856 | } |
| 15857 | |
| 15858 | fn fieldOffset(self: *CodeGen, ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32) i32 { |
| 15859 | const pt = self.pt; |
| 15860 | const zcu = pt.zcu; |
| 15861 | const agg_ty = ptr_agg_ty.childType(zcu); |
| 15862 | return switch (agg_ty.containerLayout(zcu)) { |
| 15863 | .auto, .@"extern" => @intCast(agg_ty.structFieldOffset(field_index, zcu)), |
| 15864 | .@"packed" => @divExact(@as(i32, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) + |
| 15865 | (if (zcu.typeToStruct(agg_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0) - |
| 15866 | ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), |
| 15867 | }; |
| 8239 | 15868 | } |
| 8240 | 15869 | |
| 8241 | | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 15870 | fn airStructFieldVal(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 8242 | 15871 | const pt = self.pt; |
| 8243 | 15872 | const zcu = pt.zcu; |
| 8244 | 15873 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -8248,16 +15877,19 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8248 | 15877 | const index = extra.field_index; |
| 8249 | 15878 | |
| 8250 | 15879 | const container_ty = self.typeOf(operand); |
| 8251 | | const container_rc = self.regClassForType(container_ty); |
| 15880 | const container_rc = self.regSetForType(container_ty); |
| 8252 | 15881 | const field_ty = container_ty.fieldType(index, zcu); |
| 8253 | 15882 | if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none; |
| 8254 | | const field_rc = self.regClassForType(field_ty); |
| 15883 | const field_rc = self.regSetForType(field_ty); |
| 8255 | 15884 | const field_is_gp = field_rc.supersetOf(abi.RegisterClass.gp); |
| 8256 | 15885 | |
| 8257 | 15886 | const src_mcv = try self.resolveInst(operand); |
| 8258 | 15887 | const field_off: u32 = switch (container_ty.containerLayout(zcu)) { |
| 8259 | 15888 | .auto, .@"extern" => @intCast(container_ty.structFieldOffset(extra.field_index, zcu) * 8), |
| 8260 | | .@"packed" => if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, extra.field_index) else 0, |
| 15889 | .@"packed" => if (zcu.typeToStruct(container_ty)) |loaded_struct| |
| 15890 | pt.structPackedFieldBitOffset(loaded_struct, extra.field_index) |
| 15891 | else |
| 15892 | 0, |
| 8261 | 15893 | }; |
| 8262 | 15894 | |
| 8263 | 15895 | switch (src_mcv) { |
| ... | ... | @@ -8272,20 +15904,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8272 | 15904 | else if (field_off == 0) |
| 8273 | 15905 | (try self.copyToRegisterWithInstTracking(inst, field_ty, src_mcv)).register |
| 8274 | 15906 | else |
| 8275 | | try self.copyToTmpRegister(Type.usize, .{ .register = src_reg }); |
| 15907 | try self.copyToTmpRegister(.usize, .{ .register = src_reg }); |
| 8276 | 15908 | const dst_mcv: MCValue = .{ .register = dst_reg }; |
| 8277 | 15909 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 8278 | 15910 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 8279 | 15911 | |
| 8280 | 15912 | if (field_off > 0) { |
| 8281 | 15913 | try self.spillEflagsIfOccupied(); |
| 8282 | | try self.genShiftBinOpMir( |
| 8283 | | .{ ._r, .sh }, |
| 8284 | | Type.usize, |
| 8285 | | dst_mcv, |
| 8286 | | Type.u8, |
| 8287 | | .{ .immediate = field_off }, |
| 8288 | | ); |
| 15914 | try self.genShiftBinOpMir(.{ ._r, .sh }, .usize, dst_mcv, .u8, .{ .immediate = field_off }); |
| 8289 | 15915 | } |
| 8290 | 15916 | if (abi.RegisterClass.gp.isSet(RegisterManager.indexOfRegIntoTracked(dst_reg).?) and |
| 8291 | 15917 | container_ty.abiSize(zcu) * 8 > field_ty.bitSize(zcu)) |
| ... | ... | @@ -8309,7 +15935,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8309 | 15935 | const dst_regs: [2]Register = if (field_rc.supersetOf(container_rc) and |
| 8310 | 15936 | self.reuseOperand(inst, operand, 0, src_mcv)) src_regs else dst: { |
| 8311 | 15937 | const dst_regs = |
| 8312 | | try self.register_manager.allocRegs(2, .{null} ** 2, field_rc); |
| 15938 | try self.register_manager.allocRegs(2, @splat(null), field_rc); |
| 8313 | 15939 | const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs); |
| 8314 | 15940 | defer for (dst_locks) |lock| self.register_manager.unlockReg(lock); |
| 8315 | 15941 | |
| ... | ... | @@ -8323,13 +15949,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8323 | 15949 | |
| 8324 | 15950 | if (field_off > 0) { |
| 8325 | 15951 | try self.spillEflagsIfOccupied(); |
| 8326 | | try self.genShiftBinOpMir( |
| 8327 | | .{ ._r, .sh }, |
| 8328 | | Type.u128, |
| 8329 | | dst_mcv, |
| 8330 | | Type.u8, |
| 8331 | | .{ .immediate = field_off }, |
| 8332 | | ); |
| 15952 | try self.genShiftBinOpMir(.{ ._r, .sh }, .u128, dst_mcv, .u8, .{ .immediate = field_off }); |
| 8333 | 15953 | } |
| 8334 | 15954 | |
| 8335 | 15955 | if (field_bit_size <= 64) { |
| ... | ... | @@ -8353,20 +15973,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8353 | 15973 | try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv); |
| 8354 | 15974 | }; |
| 8355 | 15975 | |
| 8356 | | const dst_reg = try self.copyToTmpRegister(Type.usize, .{ .register = src_reg }); |
| 15976 | const dst_reg = try self.copyToTmpRegister(.usize, .{ .register = src_reg }); |
| 8357 | 15977 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 8358 | 15978 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 8359 | 15979 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 8360 | 15980 | |
| 8361 | 15981 | if (field_off % 64 > 0) { |
| 8362 | 15982 | try self.spillEflagsIfOccupied(); |
| 8363 | | try self.genShiftBinOpMir( |
| 8364 | | .{ ._r, .sh }, |
| 8365 | | Type.usize, |
| 8366 | | dst_mcv, |
| 8367 | | Type.u8, |
| 8368 | | .{ .immediate = field_off % 64 }, |
| 8369 | | ); |
| 15983 | try self.genShiftBinOpMir(.{ ._r, .sh }, .usize, dst_mcv, .u8, .{ .immediate = field_off % 64 }); |
| 8370 | 15984 | } |
| 8371 | 15985 | if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg); |
| 8372 | 15986 | |
| ... | ... | @@ -8381,11 +15995,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8381 | 15995 | 0 => if (self.reuseOperand(inst, extra.struct_operand, 0, src_mcv)) { |
| 8382 | 15996 | self.eflags_inst = null; // actually stop tracking the overflow part |
| 8383 | 15997 | break :result .{ .register = ro.reg }; |
| 8384 | | } else break :result try self.copyToRegisterWithInstTracking( |
| 8385 | | inst, |
| 8386 | | Type.usize, |
| 8387 | | .{ .register = ro.reg }, |
| 8388 | | ), |
| 15998 | } else break :result try self.copyToRegisterWithInstTracking(inst, .usize, .{ .register = ro.reg }), |
| 8389 | 15999 | // Get overflow bit. |
| 8390 | 16000 | 1 => if (self.reuseOperandAdvanced(inst, extra.struct_operand, 0, src_mcv, null)) { |
| 8391 | 16001 | self.eflags_inst = inst; // actually keep tracking the overflow part |
| ... | ... | @@ -8436,16 +16046,16 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8436 | 16046 | try self.genCopy(field_ty, dst_mcv, off_mcv, .{}); |
| 8437 | 16047 | break :dst dst_mcv; |
| 8438 | 16048 | }; |
| 8439 | | if (field_abi_size * 8 > field_bit_size and dst_mcv.isMemory()) { |
| 16049 | if (field_abi_size * 8 > field_bit_size and dst_mcv.isBase()) { |
| 8440 | 16050 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 8441 | 16051 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 8442 | 16052 | defer self.register_manager.unlockReg(tmp_lock); |
| 8443 | 16053 | |
| 8444 | 16054 | const hi_mcv = |
| 8445 | 16055 | dst_mcv.address().offset(@intCast(field_bit_size / 64 * 8)).deref(); |
| 8446 | | try self.genSetReg(tmp_reg, Type.usize, hi_mcv, .{}); |
| 16056 | try self.genSetReg(tmp_reg, .usize, hi_mcv, .{}); |
| 8447 | 16057 | try self.truncateRegister(field_ty, tmp_reg); |
| 8448 | | try self.genCopy(Type.usize, hi_mcv, .{ .register = tmp_reg }, .{}); |
| 16058 | try self.genCopy(.usize, hi_mcv, .{ .register = tmp_reg }, .{}); |
| 8449 | 16059 | } |
| 8450 | 16060 | break :result dst_mcv; |
| 8451 | 16061 | } |
| ... | ... | @@ -8471,12 +16081,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8471 | 16081 | try self.asmRegisterMemory(.{ ._, .mov }, load_reg, .{ |
| 8472 | 16082 | .base = .{ .frame = frame_addr.index }, |
| 8473 | 16083 | .mod = .{ .rm = .{ |
| 8474 | | .size = Memory.Size.fromSize(load_abi_size), |
| 16084 | .size = .fromSize(load_abi_size), |
| 8475 | 16085 | .disp = frame_addr.off + field_byte_off, |
| 8476 | 16086 | } }, |
| 8477 | 16087 | }); |
| 8478 | 16088 | try self.spillEflagsIfOccupied(); |
| 8479 | | try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(field_bit_off)); |
| 16089 | try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, .u(field_bit_off)); |
| 8480 | 16090 | } else { |
| 8481 | 16091 | const tmp_reg = registerAlias( |
| 8482 | 16092 | try self.register_manager.allocReg(null, abi.RegisterClass.gp), |
| ... | ... | @@ -8492,7 +16102,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8492 | 16102 | .{ |
| 8493 | 16103 | .base = .{ .frame = frame_addr.index }, |
| 8494 | 16104 | .mod = .{ .rm = .{ |
| 8495 | | .size = Memory.Size.fromSize(field_abi_size), |
| 16105 | .size = .fromSize(field_abi_size), |
| 8496 | 16106 | .disp = frame_addr.off + field_byte_off, |
| 8497 | 16107 | } }, |
| 8498 | 16108 | }, |
| ... | ... | @@ -8500,7 +16110,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8500 | 16110 | try self.asmRegisterMemory(.{ ._, .mov }, tmp_reg, .{ |
| 8501 | 16111 | .base = .{ .frame = frame_addr.index }, |
| 8502 | 16112 | .mod = .{ .rm = .{ |
| 8503 | | .size = Memory.Size.fromSize(field_abi_size), |
| 16113 | .size = .fromSize(field_abi_size), |
| 8504 | 16114 | .disp = frame_addr.off + field_byte_off + limb_abi_size, |
| 8505 | 16115 | } }, |
| 8506 | 16116 | }); |
| ... | ... | @@ -8509,7 +16119,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8509 | 16119 | .{ ._rd, .sh }, |
| 8510 | 16120 | dst_alias, |
| 8511 | 16121 | tmp_reg, |
| 8512 | | Immediate.u(field_bit_off), |
| 16122 | .u(field_bit_off), |
| 8513 | 16123 | ); |
| 8514 | 16124 | } |
| 8515 | 16125 | |
| ... | ... | @@ -8527,32 +16137,22 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 8527 | 16137 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 8528 | 16138 | } |
| 8529 | 16139 | |
| 8530 | | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8531 | | const pt = self.pt; |
| 8532 | | const zcu = pt.zcu; |
| 16140 | fn airFieldParentPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 8533 | 16141 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 8534 | 16142 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 8535 | 16143 | |
| 8536 | | const inst_ty = self.typeOfIndex(inst); |
| 8537 | | const parent_ty = inst_ty.childType(zcu); |
| 8538 | | const field_off: i32 = switch (parent_ty.containerLayout(zcu)) { |
| 8539 | | .auto, .@"extern" => @intCast(parent_ty.structFieldOffset(extra.field_index, zcu)), |
| 8540 | | .@"packed" => @divExact(@as(i32, inst_ty.ptrInfo(zcu).packed_offset.bit_offset) + |
| 8541 | | (if (zcu.typeToStruct(parent_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, extra.field_index) else 0) - |
| 8542 | | self.typeOf(extra.field_ptr).ptrInfo(zcu).packed_offset.bit_offset, 8), |
| 8543 | | }; |
| 8544 | | |
| 16144 | const ptr_agg_ty = self.typeOfIndex(inst); |
| 8545 | 16145 | const src_mcv = try self.resolveInst(extra.field_ptr); |
| 8546 | 16146 | const dst_mcv = if (src_mcv.isRegisterOffset() and |
| 8547 | 16147 | self.reuseOperand(inst, extra.field_ptr, 0, src_mcv)) |
| 8548 | 16148 | src_mcv |
| 8549 | 16149 | else |
| 8550 | | try self.copyToRegisterWithInstTracking(inst, inst_ty, src_mcv); |
| 8551 | | const result = dst_mcv.offset(-field_off); |
| 16150 | try self.copyToRegisterWithInstTracking(inst, ptr_agg_ty, src_mcv); |
| 16151 | const result = dst_mcv.offset(-self.fieldOffset(ptr_agg_ty, self.typeOf(extra.field_ptr), extra.field_index)); |
| 8552 | 16152 | return self.finishAir(inst, result, .{ extra.field_ptr, .none, .none }); |
| 8553 | 16153 | } |
| 8554 | 16154 | |
| 8555 | | fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| 16155 | fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| 8556 | 16156 | const pt = self.pt; |
| 8557 | 16157 | const zcu = pt.zcu; |
| 8558 | 16158 | const src_ty = self.typeOf(src_air); |
| ... | ... | @@ -8596,8 +16196,8 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 8596 | 16196 | switch (tag) { |
| 8597 | 16197 | .not => { |
| 8598 | 16198 | const limb_abi_size: u16 = @min(abi_size, 8); |
| 8599 | | const int_info = if (src_ty.ip_index == .bool_type) |
| 8600 | | std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } |
| 16199 | const int_info: InternPool.Key.IntType = if (src_ty.ip_index == .bool_type) |
| 16200 | .{ .signedness = .unsigned, .bits = 1 } |
| 8601 | 16201 | else |
| 8602 | 16202 | src_ty.intInfo(zcu); |
| 8603 | 16203 | var byte_off: i32 = 0; |
| ... | ... | @@ -8613,7 +16213,7 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 8613 | 16213 | }; |
| 8614 | 16214 | |
| 8615 | 16215 | if (int_info.signedness == .unsigned and self.regExtraBits(limb_ty) > 0) { |
| 8616 | | const mask = @as(u64, math.maxInt(u64)) >> @intCast(64 - limb_bits); |
| 16216 | const mask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - limb_bits); |
| 8617 | 16217 | try self.genBinOpMir(.{ ._, .xor }, limb_ty, limb_mcv, .{ .immediate = mask }); |
| 8618 | 16218 | } else try self.genUnOpMir(.{ ._, .not }, limb_ty, limb_mcv); |
| 8619 | 16219 | } |
| ... | ... | @@ -8630,9 +16230,9 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 8630 | 16230 | defer self.register_manager.unlockReg(tmp_lock); |
| 8631 | 16231 | |
| 8632 | 16232 | const hi_mcv = dst_mcv.address().offset(@intCast(bit_size / 64 * 8)).deref(); |
| 8633 | | try self.genSetReg(tmp_reg, Type.usize, hi_mcv, .{}); |
| 16233 | try self.genSetReg(tmp_reg, .usize, hi_mcv, .{}); |
| 8634 | 16234 | try self.truncateRegister(src_ty, tmp_reg); |
| 8635 | | try self.genCopy(Type.usize, hi_mcv, .{ .register = tmp_reg }, .{}); |
| 16235 | try self.genCopy(.usize, hi_mcv, .{ .register = tmp_reg }, .{}); |
| 8636 | 16236 | } |
| 8637 | 16237 | } |
| 8638 | 16238 | }, |
| ... | ... | @@ -8641,7 +16241,7 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 8641 | 16241 | return dst_mcv; |
| 8642 | 16242 | } |
| 8643 | 16243 | |
| 8644 | | fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void { |
| 16244 | fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void { |
| 8645 | 16245 | const pt = self.pt; |
| 8646 | 16246 | const abi_size: u32 = @intCast(dst_ty.abiSize(pt.zcu)); |
| 8647 | 16247 | if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ mir_tag, dst_ty.fmt(pt) }); |
| ... | ... | @@ -8654,6 +16254,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC |
| 8654 | 16254 | .register_offset, |
| 8655 | 16255 | .eflags, |
| 8656 | 16256 | .register_overflow, |
| 16257 | .register_mask, |
| 8657 | 16258 | .lea_symbol, |
| 8658 | 16259 | .lea_direct, |
| 8659 | 16260 | .lea_got, |
| ... | ... | @@ -8664,27 +16265,27 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC |
| 8664 | 16265 | .air_ref, |
| 8665 | 16266 | => unreachable, // unmodifiable destination |
| 8666 | 16267 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), |
| 8667 | | .register_pair => unreachable, // unimplemented |
| 16268 | .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented |
| 8668 | 16269 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => { |
| 8669 | 16270 | const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 8670 | 16271 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 8671 | 16272 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 8672 | 16273 | |
| 8673 | | try self.genSetReg(addr_reg, Type.usize, dst_mcv.address(), .{}); |
| 16274 | try self.genSetReg(addr_reg, .usize, dst_mcv.address(), .{}); |
| 8674 | 16275 | try self.asmMemory(mir_tag, .{ .base = .{ .reg = addr_reg }, .mod = .{ .rm = .{ |
| 8675 | | .size = Memory.Size.fromSize(abi_size), |
| 16276 | .size = .fromSize(abi_size), |
| 8676 | 16277 | } } }); |
| 8677 | 16278 | }, |
| 8678 | 16279 | .indirect, .load_frame => try self.asmMemory( |
| 8679 | 16280 | mir_tag, |
| 8680 | | try dst_mcv.mem(self, Memory.Size.fromSize(abi_size)), |
| 16281 | try dst_mcv.mem(self, .{ .size = .fromSize(abi_size) }), |
| 8681 | 16282 | ), |
| 8682 | 16283 | } |
| 8683 | 16284 | } |
| 8684 | 16285 | |
| 8685 | 16286 | /// Clobbers .rcx for non-immediate shift value. |
| 8686 | 16287 | fn genShiftBinOpMir( |
| 8687 | | self: *Self, |
| 16288 | self: *CodeGen, |
| 8688 | 16289 | tag: Mir.Inst.FixedTag, |
| 8689 | 16290 | lhs_ty: Type, |
| 8690 | 16291 | lhs_mcv: MCValue, |
| ... | ... | @@ -8698,7 +16299,7 @@ fn genShiftBinOpMir( |
| 8698 | 16299 | try self.spillEflagsIfOccupied(); |
| 8699 | 16300 | |
| 8700 | 16301 | if (abi_size > 16) { |
| 8701 | | const limbs_len = math.divCeil(u32, abi_size, 8) catch unreachable; |
| 16302 | const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable; |
| 8702 | 16303 | assert(shift_abi_size >= 1 and shift_abi_size <= 2); |
| 8703 | 16304 | |
| 8704 | 16305 | const rcx_lock: ?RegisterLock = switch (rhs_mcv) { |
| ... | ... | @@ -8719,18 +16320,18 @@ fn genShiftBinOpMir( |
| 8719 | 16320 | }; |
| 8720 | 16321 | defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock); |
| 8721 | 16322 | |
| 8722 | | const temp_regs = try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp); |
| 16323 | const temp_regs = try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp); |
| 8723 | 16324 | const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs); |
| 8724 | 16325 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 8725 | 16326 | |
| 8726 | 16327 | switch (tag[0]) { |
| 8727 | 16328 | ._l => { |
| 8728 | | try self.asmRegisterImmediate(.{ ._, .mov }, temp_regs[1].to32(), Immediate.u(limbs_len - 1)); |
| 16329 | try self.asmRegisterImmediate(.{ ._, .mov }, temp_regs[1].to32(), .u(limbs_len - 1)); |
| 8729 | 16330 | switch (rhs_mcv) { |
| 8730 | 16331 | .immediate => |shift_imm| try self.asmRegisterImmediate( |
| 8731 | 16332 | .{ ._, .mov }, |
| 8732 | 16333 | temp_regs[0].to32(), |
| 8733 | | Immediate.u(limbs_len - (shift_imm >> 6) - 1), |
| 16334 | .u(limbs_len - (shift_imm >> 6) - 1), |
| 8734 | 16335 | ), |
| 8735 | 16336 | else => { |
| 8736 | 16337 | try self.asmRegisterRegister( |
| ... | ... | @@ -8738,16 +16339,8 @@ fn genShiftBinOpMir( |
| 8738 | 16339 | temp_regs[2].to32(), |
| 8739 | 16340 | registerAlias(.rcx, shift_abi_size), |
| 8740 | 16341 | ); |
| 8741 | | try self.asmRegisterImmediate( |
| 8742 | | .{ ._, .@"and" }, |
| 8743 | | .cl, |
| 8744 | | Immediate.u(math.maxInt(u6)), |
| 8745 | | ); |
| 8746 | | try self.asmRegisterImmediate( |
| 8747 | | .{ ._r, .sh }, |
| 8748 | | temp_regs[2].to32(), |
| 8749 | | Immediate.u(6), |
| 8750 | | ); |
| 16342 | try self.asmRegisterImmediate(.{ ._, .@"and" }, .cl, .u(std.math.maxInt(u6))); |
| 16343 | try self.asmRegisterImmediate(.{ ._r, .sh }, temp_regs[2].to32(), .u(6)); |
| 8751 | 16344 | try self.asmRegisterRegister( |
| 8752 | 16345 | .{ ._, .mov }, |
| 8753 | 16346 | temp_regs[0].to32(), |
| ... | ... | @@ -8767,7 +16360,7 @@ fn genShiftBinOpMir( |
| 8767 | 16360 | .immediate => |shift_imm| try self.asmRegisterImmediate( |
| 8768 | 16361 | .{ ._, .mov }, |
| 8769 | 16362 | temp_regs[0].to32(), |
| 8770 | | Immediate.u(shift_imm >> 6), |
| 16363 | .u(shift_imm >> 6), |
| 8771 | 16364 | ), |
| 8772 | 16365 | else => { |
| 8773 | 16366 | try self.asmRegisterRegister( |
| ... | ... | @@ -8775,16 +16368,8 @@ fn genShiftBinOpMir( |
| 8775 | 16368 | temp_regs[0].to32(), |
| 8776 | 16369 | registerAlias(.rcx, shift_abi_size), |
| 8777 | 16370 | ); |
| 8778 | | try self.asmRegisterImmediate( |
| 8779 | | .{ ._, .@"and" }, |
| 8780 | | .cl, |
| 8781 | | Immediate.u(math.maxInt(u6)), |
| 8782 | | ); |
| 8783 | | try self.asmRegisterImmediate( |
| 8784 | | .{ ._r, .sh }, |
| 8785 | | temp_regs[0].to32(), |
| 8786 | | Immediate.u(6), |
| 8787 | | ); |
| 16371 | try self.asmRegisterImmediate(.{ ._, .@"and" }, .cl, .u(std.math.maxInt(u6))); |
| 16372 | try self.asmRegisterImmediate(.{ ._r, .sh }, temp_regs[0].to32(), .u(6)); |
| 8788 | 16373 | }, |
| 8789 | 16374 | } |
| 8790 | 16375 | }, |
| ... | ... | @@ -8813,7 +16398,7 @@ fn genShiftBinOpMir( |
| 8813 | 16398 | try self.asmRegisterImmediate( |
| 8814 | 16399 | .{ ._, .cmp }, |
| 8815 | 16400 | temp_regs[0].to32(), |
| 8816 | | Immediate.u(limbs_len - 1), |
| 16401 | .u(limbs_len - 1), |
| 8817 | 16402 | ); |
| 8818 | 16403 | break :skip try self.asmJccReloc(.nb, undefined); |
| 8819 | 16404 | }, |
| ... | ... | @@ -8843,7 +16428,7 @@ fn genShiftBinOpMir( |
| 8843 | 16428 | }, .sh }, |
| 8844 | 16429 | temp_regs[2].to64(), |
| 8845 | 16430 | temp_regs[3].to64(), |
| 8846 | | Immediate.u(shift_imm & math.maxInt(u6)), |
| 16431 | .u(shift_imm & std.math.maxInt(u6)), |
| 8847 | 16432 | ), |
| 8848 | 16433 | else => try self.asmRegisterRegisterRegister(.{ switch (tag[0]) { |
| 8849 | 16434 | ._l => ._ld, |
| ... | ... | @@ -8864,8 +16449,8 @@ fn genShiftBinOpMir( |
| 8864 | 16449 | switch (tag[0]) { |
| 8865 | 16450 | ._l => { |
| 8866 | 16451 | if (slow_inc_dec) { |
| 8867 | | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), Immediate.u(1)); |
| 8868 | | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[0].to32(), Immediate.u(1)); |
| 16452 | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1)); |
| 16453 | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[0].to32(), .u(1)); |
| 8869 | 16454 | } else { |
| 8870 | 16455 | try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32()); |
| 8871 | 16456 | try self.asmRegister(.{ ._, .dec }, temp_regs[0].to32()); |
| ... | ... | @@ -8874,8 +16459,8 @@ fn genShiftBinOpMir( |
| 8874 | 16459 | }, |
| 8875 | 16460 | ._r => { |
| 8876 | 16461 | if (slow_inc_dec) { |
| 8877 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), Immediate.u(1)); |
| 8878 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), Immediate.u(1)); |
| 16462 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), .u(1)); |
| 16463 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1)); |
| 8879 | 16464 | } else { |
| 8880 | 16465 | try self.asmRegister(.{ ._, .inc }, temp_regs[1].to32()); |
| 8881 | 16466 | try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32()); |
| ... | ... | @@ -8883,7 +16468,7 @@ fn genShiftBinOpMir( |
| 8883 | 16468 | try self.asmRegisterImmediate( |
| 8884 | 16469 | .{ ._, .cmp }, |
| 8885 | 16470 | temp_regs[0].to32(), |
| 8886 | | Immediate.u(limbs_len - 1), |
| 16471 | .u(limbs_len - 1), |
| 8887 | 16472 | ); |
| 8888 | 16473 | _ = try self.asmJccReloc(.b, loop); |
| 8889 | 16474 | }, |
| ... | ... | @@ -8898,7 +16483,7 @@ fn genShiftBinOpMir( |
| 8898 | 16483 | .immediate => |shift_imm| try self.asmRegisterImmediate( |
| 8899 | 16484 | tag, |
| 8900 | 16485 | temp_regs[2].to64(), |
| 8901 | | Immediate.u(shift_imm & math.maxInt(u6)), |
| 16486 | .u(shift_imm & std.math.maxInt(u6)), |
| 8902 | 16487 | ), |
| 8903 | 16488 | else => try self.asmRegisterRegister(tag, temp_regs[2].to64(), .cl), |
| 8904 | 16489 | } |
| ... | ... | @@ -8914,7 +16499,7 @@ fn genShiftBinOpMir( |
| 8914 | 16499 | if (tag[0] == ._r and tag[1] == .sa) try self.asmRegisterImmediate( |
| 8915 | 16500 | tag, |
| 8916 | 16501 | temp_regs[2].to64(), |
| 8917 | | Immediate.u(63), |
| 16502 | .u(63), |
| 8918 | 16503 | ); |
| 8919 | 16504 | if (switch (rhs_mcv) { |
| 8920 | 16505 | .immediate => |shift_imm| shift_imm >> 6 > 0, |
| ... | ... | @@ -8935,7 +16520,7 @@ fn genShiftBinOpMir( |
| 8935 | 16520 | try self.asmRegisterImmediate( |
| 8936 | 16521 | .{ ._, .cmp }, |
| 8937 | 16522 | temp_regs[1].to32(), |
| 8938 | | Immediate.u(limbs_len - 1), |
| 16523 | .u(limbs_len - 1), |
| 8939 | 16524 | ); |
| 8940 | 16525 | break :skip try self.asmJccReloc(.nb, undefined); |
| 8941 | 16526 | }, |
| ... | ... | @@ -8945,12 +16530,12 @@ fn genShiftBinOpMir( |
| 8945 | 16530 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 8946 | 16531 | switch (tag[0]) { |
| 8947 | 16532 | ._l => if (slow_inc_dec) { |
| 8948 | | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), Immediate.u(1)); |
| 16533 | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1)); |
| 8949 | 16534 | } else { |
| 8950 | 16535 | try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32()); |
| 8951 | 16536 | }, |
| 8952 | 16537 | ._r => if (slow_inc_dec) { |
| 8953 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), Immediate.u(1)); |
| 16538 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), .u(1)); |
| 8954 | 16539 | } else { |
| 8955 | 16540 | try self.asmRegister(.{ ._, .inc }, temp_regs[1].to32()); |
| 8956 | 16541 | }, |
| ... | ... | @@ -8972,14 +16557,14 @@ fn genShiftBinOpMir( |
| 8972 | 16557 | .scale = .@"8", |
| 8973 | 16558 | .disp = lhs_mcv.load_frame.off, |
| 8974 | 16559 | } }, |
| 8975 | | }, Immediate.u(0)); |
| 16560 | }, .u(0)); |
| 8976 | 16561 | switch (tag[0]) { |
| 8977 | 16562 | ._l => _ = try self.asmJccReloc(.nz, loop), |
| 8978 | 16563 | ._r => { |
| 8979 | 16564 | try self.asmRegisterImmediate( |
| 8980 | 16565 | .{ ._, .cmp }, |
| 8981 | 16566 | temp_regs[1].to32(), |
| 8982 | | Immediate.u(limbs_len - 1), |
| 16567 | .u(limbs_len - 1), |
| 8983 | 16568 | ); |
| 8984 | 16569 | _ = try self.asmJccReloc(.b, loop); |
| 8985 | 16570 | }, |
| ... | ... | @@ -9021,12 +16606,12 @@ fn genShiftBinOpMir( |
| 9021 | 16606 | info.double_tag, |
| 9022 | 16607 | lhs_regs[info.indices[1]], |
| 9023 | 16608 | lhs_regs[info.indices[0]], |
| 9024 | | Immediate.u(shift_imm), |
| 16609 | .u(shift_imm), |
| 9025 | 16610 | ); |
| 9026 | 16611 | try self.asmRegisterImmediate( |
| 9027 | 16612 | tag, |
| 9028 | 16613 | lhs_regs[info.indices[0]], |
| 9029 | | Immediate.u(shift_imm), |
| 16614 | .u(shift_imm), |
| 9030 | 16615 | ); |
| 9031 | 16616 | return; |
| 9032 | 16617 | } else { |
| ... | ... | @@ -9039,7 +16624,7 @@ fn genShiftBinOpMir( |
| 9039 | 16624 | if (tag[0] == ._r and tag[1] == .sa) try self.asmRegisterImmediate( |
| 9040 | 16625 | tag, |
| 9041 | 16626 | lhs_regs[info.indices[0]], |
| 9042 | | Immediate.u(63), |
| 16627 | .u(63), |
| 9043 | 16628 | ) else try self.asmRegisterRegister( |
| 9044 | 16629 | .{ ._, .xor }, |
| 9045 | 16630 | lhs_regs[info.indices[0]], |
| ... | ... | @@ -9048,7 +16633,7 @@ fn genShiftBinOpMir( |
| 9048 | 16633 | if (shift_imm > 64) try self.asmRegisterImmediate( |
| 9049 | 16634 | tag, |
| 9050 | 16635 | lhs_regs[info.indices[1]], |
| 9051 | | Immediate.u(shift_imm - 64), |
| 16636 | .u(shift_imm - 64), |
| 9052 | 16637 | ); |
| 9053 | 16638 | return; |
| 9054 | 16639 | }, |
| ... | ... | @@ -9059,7 +16644,7 @@ fn genShiftBinOpMir( |
| 9059 | 16644 | |
| 9060 | 16645 | if (tag[0] == ._r and tag[1] == .sa) { |
| 9061 | 16646 | try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, lhs_regs[info.indices[0]]); |
| 9062 | | try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63)); |
| 16647 | try self.asmRegisterImmediate(tag, tmp_reg, .u(63)); |
| 9063 | 16648 | } else try self.asmRegisterRegister( |
| 9064 | 16649 | .{ ._, .xor }, |
| 9065 | 16650 | tmp_reg.to32(), |
| ... | ... | @@ -9076,11 +16661,7 @@ fn genShiftBinOpMir( |
| 9076 | 16661 | lhs_regs[info.indices[0]], |
| 9077 | 16662 | registerAlias(shift_reg, 1), |
| 9078 | 16663 | ); |
| 9079 | | try self.asmRegisterImmediate( |
| 9080 | | .{ ._, .cmp }, |
| 9081 | | registerAlias(shift_reg, 1), |
| 9082 | | Immediate.u(64), |
| 9083 | | ); |
| 16664 | try self.asmRegisterImmediate(.{ ._, .cmp }, registerAlias(shift_reg, 1), .u(64)); |
| 9084 | 16665 | try self.asmCmovccRegisterRegister( |
| 9085 | 16666 | .ae, |
| 9086 | 16667 | lhs_regs[info.indices[1]], |
| ... | ... | @@ -9119,7 +16700,7 @@ fn genShiftBinOpMir( |
| 9119 | 16700 | } }, |
| 9120 | 16701 | }, |
| 9121 | 16702 | tmp_reg, |
| 9122 | | Immediate.u(shift_imm), |
| 16703 | .u(shift_imm), |
| 9123 | 16704 | ); |
| 9124 | 16705 | try self.asmMemoryImmediate( |
| 9125 | 16706 | tag, |
| ... | ... | @@ -9130,7 +16711,7 @@ fn genShiftBinOpMir( |
| 9130 | 16711 | .disp = dst_frame_addr.off + info.indices[0] * 8, |
| 9131 | 16712 | } }, |
| 9132 | 16713 | }, |
| 9133 | | Immediate.u(shift_imm), |
| 16714 | .u(shift_imm), |
| 9134 | 16715 | ); |
| 9135 | 16716 | return; |
| 9136 | 16717 | } else { |
| ... | ... | @@ -9149,7 +16730,7 @@ fn genShiftBinOpMir( |
| 9149 | 16730 | if (shift_imm > 64) try self.asmRegisterImmediate( |
| 9150 | 16731 | tag, |
| 9151 | 16732 | tmp_reg, |
| 9152 | | Immediate.u(shift_imm - 64), |
| 16733 | .u(shift_imm - 64), |
| 9153 | 16734 | ); |
| 9154 | 16735 | try self.asmMemoryRegister( |
| 9155 | 16736 | .{ ._, .mov }, |
| ... | ... | @@ -9171,7 +16752,7 @@ fn genShiftBinOpMir( |
| 9171 | 16752 | .disp = dst_frame_addr.off + info.indices[0] * 8, |
| 9172 | 16753 | } }, |
| 9173 | 16754 | }, |
| 9174 | | Immediate.u(63), |
| 16755 | .u(63), |
| 9175 | 16756 | ) else { |
| 9176 | 16757 | try self.asmRegisterRegister(.{ ._, .xor }, tmp_reg.to32(), tmp_reg.to32()); |
| 9177 | 16758 | try self.asmMemoryRegister( |
| ... | ... | @@ -9223,7 +16804,7 @@ fn genShiftBinOpMir( |
| 9223 | 16804 | ); |
| 9224 | 16805 | if (tag[0] == ._r and tag[1] == .sa) { |
| 9225 | 16806 | try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, first_reg); |
| 9226 | | try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63)); |
| 16807 | try self.asmRegisterImmediate(tag, tmp_reg, .u(63)); |
| 9227 | 16808 | } else try self.asmRegisterRegister( |
| 9228 | 16809 | .{ ._, .xor }, |
| 9229 | 16810 | tmp_reg.to32(), |
| ... | ... | @@ -9239,7 +16820,7 @@ fn genShiftBinOpMir( |
| 9239 | 16820 | try self.asmRegisterImmediate( |
| 9240 | 16821 | .{ ._, .cmp }, |
| 9241 | 16822 | registerAlias(shift_reg, 1), |
| 9242 | | Immediate.u(64), |
| 16823 | .u(64), |
| 9243 | 16824 | ); |
| 9244 | 16825 | try self.asmCmovccRegisterRegister(.ae, second_reg, first_reg); |
| 9245 | 16826 | try self.asmCmovccRegisterRegister(.ae, first_reg, tmp_reg); |
| ... | ... | @@ -9277,7 +16858,7 @@ fn genShiftBinOpMir( |
| 9277 | 16858 | .immediate => |shift_imm| return self.asmRegisterImmediate( |
| 9278 | 16859 | tag, |
| 9279 | 16860 | registerAlias(lhs_reg, abi_size), |
| 9280 | | Immediate.u(shift_imm), |
| 16861 | .u(shift_imm), |
| 9281 | 16862 | ), |
| 9282 | 16863 | .register => |shift_reg| return self.asmRegisterRegister( |
| 9283 | 16864 | tag, |
| ... | ... | @@ -9291,8 +16872,8 @@ fn genShiftBinOpMir( |
| 9291 | 16872 | .memory => |addr| .{ |
| 9292 | 16873 | .base = .{ .reg = .ds }, |
| 9293 | 16874 | .mod = .{ .rm = .{ |
| 9294 | | .size = Memory.Size.fromSize(abi_size), |
| 9295 | | .disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse |
| 16875 | .size = .fromSize(abi_size), |
| 16876 | .disp = std.math.cast(i32, @as(i64, @bitCast(addr))) orelse |
| 9296 | 16877 | return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 9297 | 16878 | @tagName(lhs_mcv), |
| 9298 | 16879 | @tagName(shift_mcv), |
| ... | ... | @@ -9302,25 +16883,21 @@ fn genShiftBinOpMir( |
| 9302 | 16883 | .indirect => |reg_off| .{ |
| 9303 | 16884 | .base = .{ .reg = reg_off.reg }, |
| 9304 | 16885 | .mod = .{ .rm = .{ |
| 9305 | | .size = Memory.Size.fromSize(abi_size), |
| 16886 | .size = .fromSize(abi_size), |
| 9306 | 16887 | .disp = reg_off.off, |
| 9307 | 16888 | } }, |
| 9308 | 16889 | }, |
| 9309 | 16890 | .load_frame => |frame_addr| .{ |
| 9310 | 16891 | .base = .{ .frame = frame_addr.index }, |
| 9311 | 16892 | .mod = .{ .rm = .{ |
| 9312 | | .size = Memory.Size.fromSize(abi_size), |
| 16893 | .size = .fromSize(abi_size), |
| 9313 | 16894 | .disp = frame_addr.off, |
| 9314 | 16895 | } }, |
| 9315 | 16896 | }, |
| 9316 | 16897 | else => unreachable, |
| 9317 | 16898 | }; |
| 9318 | 16899 | switch (shift_mcv) { |
| 9319 | | .immediate => |shift_imm| return self.asmMemoryImmediate( |
| 9320 | | tag, |
| 9321 | | lhs_mem, |
| 9322 | | Immediate.u(shift_imm), |
| 9323 | | ), |
| 16900 | .immediate => |shift_imm| return self.asmMemoryImmediate(tag, lhs_mem, .u(shift_imm)), |
| 9324 | 16901 | .register => |shift_reg| return self.asmMemoryRegister( |
| 9325 | 16902 | tag, |
| 9326 | 16903 | lhs_mem, |
| ... | ... | @@ -9341,7 +16918,7 @@ fn genShiftBinOpMir( |
| 9341 | 16918 | /// Clobbers .rcx for non-immediate rhs, therefore care is needed to spill .rcx upfront. |
| 9342 | 16919 | /// Asserts .rcx is free. |
| 9343 | 16920 | fn genShiftBinOp( |
| 9344 | | self: *Self, |
| 16921 | self: *CodeGen, |
| 9345 | 16922 | air_tag: Air.Inst.Tag, |
| 9346 | 16923 | maybe_inst: ?Air.Inst.Index, |
| 9347 | 16924 | lhs_mcv: MCValue, |
| ... | ... | @@ -9359,7 +16936,18 @@ fn genShiftBinOp( |
| 9359 | 16936 | const rcx_lock = self.register_manager.lockReg(.rcx); |
| 9360 | 16937 | defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock); |
| 9361 | 16938 | |
| 9362 | | const lhs_lock = switch (lhs_mcv) { |
| 16939 | const mat_lhs_mcv: MCValue, const can_reuse_lhs = switch (lhs_mcv) { |
| 16940 | .register => |lhs_reg| switch (lhs_reg.class()) { |
| 16941 | .general_purpose => .{ lhs_mcv, true }, |
| 16942 | else => lhs: { |
| 16943 | const mat_lhs_mcv = try self.allocTempRegOrMem(lhs_ty, true); |
| 16944 | try self.genCopy(lhs_ty, mat_lhs_mcv, lhs_mcv, .{}); |
| 16945 | break :lhs .{ mat_lhs_mcv, false }; |
| 16946 | }, |
| 16947 | }, |
| 16948 | else => .{ lhs_mcv, true }, |
| 16949 | }; |
| 16950 | const lhs_lock = switch (mat_lhs_mcv) { |
| 9363 | 16951 | .register => |reg| self.register_manager.lockReg(reg), |
| 9364 | 16952 | else => null, |
| 9365 | 16953 | }; |
| ... | ... | @@ -9372,12 +16960,12 @@ fn genShiftBinOp( |
| 9372 | 16960 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 9373 | 16961 | |
| 9374 | 16962 | const dst_mcv: MCValue = dst: { |
| 9375 | | if (maybe_inst) |inst| { |
| 16963 | if (can_reuse_lhs) if (maybe_inst) |inst| { |
| 9376 | 16964 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 9377 | | if (self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) break :dst lhs_mcv; |
| 9378 | | } |
| 16965 | if (self.reuseOperand(inst, bin_op.lhs, 0, mat_lhs_mcv)) break :dst mat_lhs_mcv; |
| 16966 | }; |
| 9379 | 16967 | const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, maybe_inst, true); |
| 9380 | | try self.genCopy(lhs_ty, dst_mcv, lhs_mcv, .{}); |
| 16968 | try self.genCopy(lhs_ty, dst_mcv, mat_lhs_mcv, .{}); |
| 9381 | 16969 | break :dst dst_mcv; |
| 9382 | 16970 | }; |
| 9383 | 16971 | |
| ... | ... | @@ -9400,7 +16988,7 @@ fn genShiftBinOp( |
| 9400 | 16988 | /// Clobbers .rax and .rdx therefore care is needed to spill .rax and .rdx upfront. |
| 9401 | 16989 | /// Asserts .rax and .rdx are free. |
| 9402 | 16990 | fn genMulDivBinOp( |
| 9403 | | self: *Self, |
| 16991 | self: *CodeGen, |
| 9404 | 16992 | tag: Air.Inst.Tag, |
| 9405 | 16993 | maybe_inst: ?Air.Inst.Index, |
| 9406 | 16994 | dst_ty: Type, |
| ... | ... | @@ -9430,7 +17018,7 @@ fn genMulDivBinOp( |
| 9430 | 17018 | const mat_lhs_mcv = switch (lhs_mcv) { |
| 9431 | 17019 | .load_symbol => mat_lhs_mcv: { |
| 9432 | 17020 | // TODO clean this up! |
| 9433 | | const addr_reg = try self.copyToTmpRegister(Type.usize, lhs_mcv.address()); |
| 17021 | const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address()); |
| 9434 | 17022 | break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 9435 | 17023 | }, |
| 9436 | 17024 | else => lhs_mcv, |
| ... | ... | @@ -9443,7 +17031,7 @@ fn genMulDivBinOp( |
| 9443 | 17031 | const mat_rhs_mcv = switch (rhs_mcv) { |
| 9444 | 17032 | .load_symbol => mat_rhs_mcv: { |
| 9445 | 17033 | // TODO clean this up! |
| 9446 | | const addr_reg = try self.copyToTmpRegister(Type.usize, rhs_mcv.address()); |
| 17034 | const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); |
| 9447 | 17035 | break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; |
| 9448 | 17036 | }, |
| 9449 | 17037 | else => rhs_mcv, |
| ... | ... | @@ -9458,28 +17046,28 @@ fn genMulDivBinOp( |
| 9458 | 17046 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 9459 | 17047 | defer self.register_manager.unlockReg(tmp_lock); |
| 9460 | 17048 | |
| 9461 | | if (mat_lhs_mcv.isMemory()) |
| 9462 | | try self.asmRegisterMemory(.{ ._, .mov }, .rax, try mat_lhs_mcv.mem(self, .qword)) |
| 17049 | if (mat_lhs_mcv.isBase()) |
| 17050 | try self.asmRegisterMemory(.{ ._, .mov }, .rax, try mat_lhs_mcv.mem(self, .{ .size = .qword })) |
| 9463 | 17051 | else |
| 9464 | 17052 | try self.asmRegisterRegister(.{ ._, .mov }, .rax, mat_lhs_mcv.register_pair[0]); |
| 9465 | | if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 17053 | if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory( |
| 9466 | 17054 | .{ ._, .mov }, |
| 9467 | 17055 | tmp_reg, |
| 9468 | | try mat_rhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 17056 | try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 9469 | 17057 | ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_rhs_mcv.register_pair[1]); |
| 9470 | 17058 | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, .rax); |
| 9471 | | if (mat_rhs_mcv.isMemory()) |
| 9472 | | try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .qword)) |
| 17059 | if (mat_rhs_mcv.isBase()) |
| 17060 | try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword })) |
| 9473 | 17061 | else |
| 9474 | 17062 | try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]); |
| 9475 | 17063 | try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg); |
| 9476 | | if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 17064 | if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory( |
| 9477 | 17065 | .{ ._, .mov }, |
| 9478 | 17066 | tmp_reg, |
| 9479 | | try mat_lhs_mcv.address().offset(8).deref().mem(self, .qword), |
| 17067 | try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 9480 | 17068 | ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_lhs_mcv.register_pair[1]); |
| 9481 | | if (mat_rhs_mcv.isMemory()) |
| 9482 | | try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, try mat_rhs_mcv.mem(self, .qword)) |
| 17069 | if (mat_rhs_mcv.isBase()) |
| 17070 | try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, try mat_rhs_mcv.mem(self, .{ .size = .qword })) |
| 9483 | 17071 | else |
| 9484 | 17072 | try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, mat_rhs_mcv.register_pair[0]); |
| 9485 | 17073 | try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg); |
| ... | ... | @@ -9495,7 +17083,7 @@ fn genMulDivBinOp( |
| 9495 | 17083 | switch (tag) { |
| 9496 | 17084 | .mul, .mul_wrap => { |
| 9497 | 17085 | const slow_inc = self.hasFeature(.slow_incdec); |
| 9498 | | const limb_len = math.divCeil(u32, src_abi_size, 8) catch unreachable; |
| 17086 | const limb_len = std.math.divCeil(u32, src_abi_size, 8) catch unreachable; |
| 9499 | 17087 | |
| 9500 | 17088 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| 9501 | 17089 | const reg_locks = self.register_manager.lockRegs(3, .{ .rax, .rcx, .rdx }); |
| ... | ... | @@ -9511,7 +17099,7 @@ fn genMulDivBinOp( |
| 9511 | 17099 | ); |
| 9512 | 17100 | |
| 9513 | 17101 | const temp_regs = |
| 9514 | | try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp); |
| 17102 | try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp); |
| 9515 | 17103 | const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs); |
| 9516 | 17104 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 9517 | 17105 | |
| ... | ... | @@ -9536,7 +17124,7 @@ fn genMulDivBinOp( |
| 9536 | 17124 | try self.asmRegisterRegister(.{ ._, .xor }, .edx, .edx); |
| 9537 | 17125 | |
| 9538 | 17126 | const inner_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 9539 | | try self.asmRegisterImmediate(.{ ._r, .sh }, .cl, Immediate.u(1)); |
| 17127 | try self.asmRegisterImmediate(.{ ._r, .sh }, .cl, .u(1)); |
| 9540 | 17128 | try self.asmMemoryRegister(.{ ._, .adc }, .{ |
| 9541 | 17129 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| 9542 | 17130 | .mod = .{ .rm = .{ |
| ... | ... | @@ -9559,7 +17147,7 @@ fn genMulDivBinOp( |
| 9559 | 17147 | }); |
| 9560 | 17148 | try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64()); |
| 9561 | 17149 | |
| 9562 | | try self.asmRegisterImmediate(.{ ._r, .sh }, .ch, Immediate.u(1)); |
| 17150 | try self.asmRegisterImmediate(.{ ._r, .sh }, .ch, .u(1)); |
| 9563 | 17151 | try self.asmMemoryRegister(.{ ._, .adc }, .{ |
| 9564 | 17152 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| 9565 | 17153 | .mod = .{ .rm = .{ |
| ... | ... | @@ -9572,30 +17160,22 @@ fn genMulDivBinOp( |
| 9572 | 17160 | try self.asmSetccRegister(.c, .ch); |
| 9573 | 17161 | |
| 9574 | 17162 | if (slow_inc) { |
| 9575 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), Immediate.u(1)); |
| 9576 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), Immediate.u(1)); |
| 17163 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1)); |
| 17164 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), .u(1)); |
| 9577 | 17165 | } else { |
| 9578 | 17166 | try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32()); |
| 9579 | 17167 | try self.asmRegister(.{ ._, .inc }, temp_regs[3].to32()); |
| 9580 | 17168 | } |
| 9581 | | try self.asmRegisterImmediate( |
| 9582 | | .{ ._, .cmp }, |
| 9583 | | temp_regs[3].to32(), |
| 9584 | | Immediate.u(limb_len), |
| 9585 | | ); |
| 17169 | try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[3].to32(), .u(limb_len)); |
| 9586 | 17170 | _ = try self.asmJccReloc(.b, inner_loop); |
| 9587 | 17171 | |
| 9588 | 17172 | self.performReloc(skip_inner); |
| 9589 | 17173 | if (slow_inc) { |
| 9590 | | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), Immediate.u(1)); |
| 17174 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1)); |
| 9591 | 17175 | } else { |
| 9592 | 17176 | try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32()); |
| 9593 | 17177 | } |
| 9594 | | try self.asmRegisterImmediate( |
| 9595 | | .{ ._, .cmp }, |
| 9596 | | temp_regs[0].to32(), |
| 9597 | | Immediate.u(limb_len), |
| 9598 | | ); |
| 17178 | try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[0].to32(), .u(limb_len)); |
| 9599 | 17179 | _ = try self.asmJccReloc(.b, outer_loop); |
| 9600 | 17180 | |
| 9601 | 17181 | return dst_mcv; |
| ... | ... | @@ -9639,13 +17219,13 @@ fn genMulDivBinOp( |
| 9639 | 17219 | manyptr_u32_ty, |
| 9640 | 17220 | manyptr_const_u32_ty, |
| 9641 | 17221 | manyptr_const_u32_ty, |
| 9642 | | Type.usize, |
| 17222 | .usize, |
| 9643 | 17223 | }, &.{ |
| 9644 | 17224 | dst_mcv.address(), |
| 9645 | 17225 | lhs_mcv.address(), |
| 9646 | 17226 | rhs_mcv.address(), |
| 9647 | | .{ .immediate = src_info.bits }, |
| 9648 | | }); |
| 17227 | .{ .immediate = 8 * src_abi_size }, |
| 17228 | }, .{}); |
| 9649 | 17229 | return dst_mcv; |
| 9650 | 17230 | }, |
| 9651 | 17231 | }, |
| ... | ... | @@ -9662,7 +17242,8 @@ fn genMulDivBinOp( |
| 9662 | 17242 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 9663 | 17243 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 9664 | 17244 | |
| 9665 | | const signedness = ty.intInfo(zcu).signedness; |
| 17245 | const int_info = ty.intInfo(zcu); |
| 17246 | const signedness = int_info.signedness; |
| 9666 | 17247 | switch (tag) { |
| 9667 | 17248 | .mul, |
| 9668 | 17249 | .mul_wrap, |
| ... | ... | @@ -9695,6 +17276,15 @@ fn genMulDivBinOp( |
| 9695 | 17276 | }, |
| 9696 | 17277 | }, ty, lhs_mcv, rhs_mcv); |
| 9697 | 17278 | |
| 17279 | switch (tag) { |
| 17280 | .mul, .rem, .div_trunc, .div_exact => {}, |
| 17281 | .mul_wrap => if (dst_ty.intInfo(zcu).bits < 8 * dst_abi_size) try self.truncateRegister( |
| 17282 | dst_ty, |
| 17283 | if (dst_abi_size <= 8) .rax else .rdx, |
| 17284 | ), |
| 17285 | else => unreachable, |
| 17286 | } |
| 17287 | |
| 9698 | 17288 | if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) { |
| 9699 | 17289 | .mul, .mul_wrap, .div_trunc, .div_exact => .rax, |
| 9700 | 17290 | .rem => .rdx, |
| ... | ... | @@ -9814,7 +17404,7 @@ fn genMulDivBinOp( |
| 9814 | 17404 | } |
| 9815 | 17405 | |
| 9816 | 17406 | fn genBinOp( |
| 9817 | | self: *Self, |
| 17407 | self: *CodeGen, |
| 9818 | 17408 | maybe_inst: ?Air.Inst.Index, |
| 9819 | 17409 | air_tag: Air.Inst.Tag, |
| 9820 | 17410 | lhs_air: Air.Inst.Ref, |
| ... | ... | @@ -9869,7 +17459,7 @@ fn genBinOp( |
| 9869 | 17459 | .return_type = lhs_ty.toIntern(), |
| 9870 | 17460 | .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, |
| 9871 | 17461 | .callee = callee, |
| 9872 | | } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } }); |
| 17462 | } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } }, .{}); |
| 9873 | 17463 | return switch (air_tag) { |
| 9874 | 17464 | .mod => result: { |
| 9875 | 17465 | const adjusted: MCValue = if (type_needs_libcall) adjusted: { |
| ... | ... | @@ -9883,7 +17473,7 @@ fn genBinOp( |
| 9883 | 17473 | .callee = std.fmt.bufPrint(&add_callee_buf, "__add{c}f3", .{ |
| 9884 | 17474 | floatCompilerRtAbiName(float_bits), |
| 9885 | 17475 | }) catch unreachable, |
| 9886 | | } }, &.{ lhs_ty, rhs_ty }, &.{ result, .{ .air_ref = rhs_air } }); |
| 17476 | } }, &.{ lhs_ty, rhs_ty }, &.{ result, .{ .air_ref = rhs_air } }, .{}); |
| 9887 | 17477 | } else switch (float_bits) { |
| 9888 | 17478 | 16, 32, 64 => adjusted: { |
| 9889 | 17479 | const dst_reg = switch (result) { |
| ... | ... | @@ -9906,12 +17496,12 @@ fn genBinOp( |
| 9906 | 17496 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 9907 | 17497 | defer self.register_manager.unlockReg(tmp_lock); |
| 9908 | 17498 | |
| 9909 | | if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 17499 | if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 9910 | 17500 | .{ .vp_w, .insr }, |
| 9911 | 17501 | dst_reg, |
| 9912 | 17502 | dst_reg, |
| 9913 | | try rhs_mcv.mem(self, .word), |
| 9914 | | Immediate.u(1), |
| 17503 | try rhs_mcv.mem(self, .{ .size = .word }), |
| 17504 | .u(1), |
| 9915 | 17505 | ) else try self.asmRegisterRegisterRegister( |
| 9916 | 17506 | .{ .vp_, .unpcklwd }, |
| 9917 | 17507 | dst_reg, |
| ... | ... | @@ -9931,11 +17521,11 @@ fn genBinOp( |
| 9931 | 17521 | 64 => .{ .v_sd, .add }, |
| 9932 | 17522 | else => unreachable, |
| 9933 | 17523 | }; |
| 9934 | | if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 17524 | if (src_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 9935 | 17525 | mir_tag, |
| 9936 | 17526 | dst_reg, |
| 9937 | 17527 | dst_reg, |
| 9938 | | try src_mcv.mem(self, Memory.Size.fromBitSize(float_bits)), |
| 17528 | try src_mcv.mem(self, .{ .size = .fromBitSize(float_bits) }), |
| 9939 | 17529 | ) else try self.asmRegisterRegisterRegister( |
| 9940 | 17530 | mir_tag, |
| 9941 | 17531 | dst_reg, |
| ... | ... | @@ -9951,10 +17541,10 @@ fn genBinOp( |
| 9951 | 17541 | 64 => .{ ._sd, .add }, |
| 9952 | 17542 | else => unreachable, |
| 9953 | 17543 | }; |
| 9954 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 17544 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 9955 | 17545 | mir_tag, |
| 9956 | 17546 | dst_reg, |
| 9957 | | try src_mcv.mem(self, Memory.Size.fromBitSize(float_bits)), |
| 17547 | try src_mcv.mem(self, .{ .size = .fromBitSize(float_bits) }), |
| 9958 | 17548 | ) else try self.asmRegisterRegister( |
| 9959 | 17549 | mir_tag, |
| 9960 | 17550 | dst_reg, |
| ... | ... | @@ -9969,7 +17559,7 @@ fn genBinOp( |
| 9969 | 17559 | .{ .v_, .cvtps2ph }, |
| 9970 | 17560 | dst_reg, |
| 9971 | 17561 | dst_reg, |
| 9972 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 17562 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 9973 | 17563 | ); |
| 9974 | 17564 | break :adjusted .{ .register = dst_reg }; |
| 9975 | 17565 | }, |
| ... | ... | @@ -9982,7 +17572,7 @@ fn genBinOp( |
| 9982 | 17572 | .return_type = lhs_ty.toIntern(), |
| 9983 | 17573 | .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, |
| 9984 | 17574 | .callee = callee, |
| 9985 | | } }, &.{ lhs_ty, rhs_ty }, &.{ adjusted, .{ .air_ref = rhs_air } }); |
| 17575 | } }, &.{ lhs_ty, rhs_ty }, &.{ adjusted, .{ .air_ref = rhs_air } }, .{}); |
| 9986 | 17576 | }, |
| 9987 | 17577 | .div_trunc, .div_floor => try self.genRoundLibcall(lhs_ty, result, .{ |
| 9988 | 17578 | .mode = switch (air_tag) { |
| ... | ... | @@ -10006,7 +17596,7 @@ fn genBinOp( |
| 10006 | 17596 | }; |
| 10007 | 17597 | if (sse_op and ((lhs_ty.scalarType(zcu).isRuntimeFloat() and |
| 10008 | 17598 | lhs_ty.scalarType(zcu).floatBits(self.target.*) == 80) or |
| 10009 | | lhs_ty.abiSize(zcu) > @as(u6, if (self.hasFeature(.avx)) 32 else 16))) |
| 17599 | lhs_ty.abiSize(zcu) > self.vectorSize(.float))) |
| 10010 | 17600 | return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(air_tag), lhs_ty.fmt(pt) }); |
| 10011 | 17601 | |
| 10012 | 17602 | const maybe_mask_reg = switch (air_tag) { |
| ... | ... | @@ -10085,14 +17675,14 @@ fn genBinOp( |
| 10085 | 17675 | const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs); |
| 10086 | 17676 | break :locks .{ locks[0], locks[1] }; |
| 10087 | 17677 | }, |
| 10088 | | else => .{null} ** 2, |
| 17678 | else => @splat(null), |
| 10089 | 17679 | }; |
| 10090 | 17680 | defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 10091 | 17681 | |
| 10092 | 17682 | const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) { |
| 10093 | 17683 | .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null }, |
| 10094 | 17684 | .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs), |
| 10095 | | else => .{null} ** 2, |
| 17685 | else => @splat(null), |
| 10096 | 17686 | }; |
| 10097 | 17687 | defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 10098 | 17688 | |
| ... | ... | @@ -10125,7 +17715,7 @@ fn genBinOp( |
| 10125 | 17715 | const dst_locks: [2]?RegisterLock = switch (dst_mcv) { |
| 10126 | 17716 | .register => |dst_reg| .{ self.register_manager.lockReg(dst_reg), null }, |
| 10127 | 17717 | .register_pair => |dst_regs| self.register_manager.lockRegs(2, dst_regs), |
| 10128 | | else => .{null} ** 2, |
| 17718 | else => @splat(null), |
| 10129 | 17719 | }; |
| 10130 | 17720 | defer for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 10131 | 17721 | |
| ... | ... | @@ -10141,7 +17731,7 @@ fn genBinOp( |
| 10141 | 17731 | const src_locks: [2]?RegisterLock = switch (src_mcv) { |
| 10142 | 17732 | .register => |src_reg| .{ self.register_manager.lockReg(src_reg), null }, |
| 10143 | 17733 | .register_pair => |src_regs| self.register_manager.lockRegs(2, src_regs), |
| 10144 | | else => .{null} ** 2, |
| 17734 | else => @splat(null), |
| 10145 | 17735 | }; |
| 10146 | 17736 | defer for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 10147 | 17737 | |
| ... | ... | @@ -10199,11 +17789,7 @@ fn genBinOp( |
| 10199 | 17789 | const dst_regs = switch (dst_mcv) { |
| 10200 | 17790 | .register_pair => |dst_regs| dst_regs, |
| 10201 | 17791 | else => dst: { |
| 10202 | | const dst_regs = try self.register_manager.allocRegs( |
| 10203 | | 2, |
| 10204 | | .{null} ** 2, |
| 10205 | | abi.RegisterClass.gp, |
| 10206 | | ); |
| 17792 | const dst_regs = try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp); |
| 10207 | 17793 | const dst_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs); |
| 10208 | 17794 | defer for (dst_regs_locks) |lock| self.register_manager.unlockReg(lock); |
| 10209 | 17795 | |
| ... | ... | @@ -10227,26 +17813,26 @@ fn genBinOp( |
| 10227 | 17813 | }; |
| 10228 | 17814 | |
| 10229 | 17815 | try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]); |
| 10230 | | if (src_mcv.isMemory()) { |
| 17816 | if (src_mcv.isBase()) { |
| 10231 | 17817 | try self.asmRegisterMemory( |
| 10232 | 17818 | .{ ._, .cmp }, |
| 10233 | 17819 | dst_regs[0], |
| 10234 | | try src_mcv.mem(self, .qword), |
| 17820 | try src_mcv.mem(self, .{ .size = .qword }), |
| 10235 | 17821 | ); |
| 10236 | 17822 | try self.asmRegisterMemory( |
| 10237 | 17823 | .{ ._, .sbb }, |
| 10238 | 17824 | tmp_reg, |
| 10239 | | try src_mcv.address().offset(8).deref().mem(self, .qword), |
| 17825 | try src_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 10240 | 17826 | ); |
| 10241 | 17827 | try self.asmCmovccRegisterMemory( |
| 10242 | 17828 | cc, |
| 10243 | 17829 | dst_regs[0], |
| 10244 | | try src_mcv.mem(self, .qword), |
| 17830 | try src_mcv.mem(self, .{ .size = .qword }), |
| 10245 | 17831 | ); |
| 10246 | 17832 | try self.asmCmovccRegisterMemory( |
| 10247 | 17833 | cc, |
| 10248 | 17834 | dst_regs[1], |
| 10249 | | try src_mcv.address().offset(8).deref().mem(self, .qword), |
| 17835 | try src_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 10250 | 17836 | ); |
| 10251 | 17837 | } else { |
| 10252 | 17838 | try self.asmRegisterRegister( |
| ... | ... | @@ -10278,7 +17864,7 @@ fn genBinOp( |
| 10278 | 17864 | .lea_tlv, |
| 10279 | 17865 | .lea_frame, |
| 10280 | 17866 | => true, |
| 10281 | | .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null, |
| 17867 | .memory => |addr| std.math.cast(i32, @as(i64, @bitCast(addr))) == null, |
| 10282 | 17868 | else => false, |
| 10283 | 17869 | .register_pair, |
| 10284 | 17870 | .register_overflow, |
| ... | ... | @@ -10324,8 +17910,11 @@ fn genBinOp( |
| 10324 | 17910 | .immediate, |
| 10325 | 17911 | .eflags, |
| 10326 | 17912 | .register_pair, |
| 17913 | .register_triple, |
| 17914 | .register_quadruple, |
| 10327 | 17915 | .register_offset, |
| 10328 | 17916 | .register_overflow, |
| 17917 | .register_mask, |
| 10329 | 17918 | .load_symbol, |
| 10330 | 17919 | .lea_symbol, |
| 10331 | 17920 | .load_direct, |
| ... | ... | @@ -10351,21 +17940,21 @@ fn genBinOp( |
| 10351 | 17940 | .memory => |addr| .{ |
| 10352 | 17941 | .base = .{ .reg = .ds }, |
| 10353 | 17942 | .mod = .{ .rm = .{ |
| 10354 | | .size = Memory.Size.fromSize(cmov_abi_size), |
| 17943 | .size = .fromSize(cmov_abi_size), |
| 10355 | 17944 | .disp = @intCast(@as(i64, @bitCast(addr))), |
| 10356 | 17945 | } }, |
| 10357 | 17946 | }, |
| 10358 | 17947 | .indirect => |reg_off| .{ |
| 10359 | 17948 | .base = .{ .reg = reg_off.reg }, |
| 10360 | 17949 | .mod = .{ .rm = .{ |
| 10361 | | .size = Memory.Size.fromSize(cmov_abi_size), |
| 17950 | .size = .fromSize(cmov_abi_size), |
| 10362 | 17951 | .disp = reg_off.off, |
| 10363 | 17952 | } }, |
| 10364 | 17953 | }, |
| 10365 | 17954 | .load_frame => |frame_addr| .{ |
| 10366 | 17955 | .base = .{ .frame = frame_addr.index }, |
| 10367 | 17956 | .mod = .{ .rm = .{ |
| 10368 | | .size = Memory.Size.fromSize(cmov_abi_size), |
| 17957 | .size = .fromSize(cmov_abi_size), |
| 10369 | 17958 | .disp = frame_addr.off, |
| 10370 | 17959 | } }, |
| 10371 | 17960 | }, |
| ... | ... | @@ -10400,21 +17989,22 @@ fn genBinOp( |
| 10400 | 17989 | .float => switch (lhs_ty.floatBits(self.target.*)) { |
| 10401 | 17990 | 16 => { |
| 10402 | 17991 | assert(self.hasFeature(.f16c)); |
| 10403 | | const tmp_reg = |
| 10404 | | (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128(); |
| 17992 | const lhs_reg = if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size); |
| 17993 | |
| 17994 | const tmp_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128(); |
| 10405 | 17995 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 10406 | 17996 | defer self.register_manager.unlockReg(tmp_lock); |
| 10407 | 17997 | |
| 10408 | | if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 17998 | if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 10409 | 17999 | .{ .vp_w, .insr }, |
| 10410 | 18000 | dst_reg, |
| 10411 | | dst_reg, |
| 10412 | | try src_mcv.mem(self, .word), |
| 10413 | | Immediate.u(1), |
| 18001 | lhs_reg, |
| 18002 | try src_mcv.mem(self, .{ .size = .word }), |
| 18003 | .u(1), |
| 10414 | 18004 | ) else try self.asmRegisterRegisterRegister( |
| 10415 | 18005 | .{ .vp_, .unpcklwd }, |
| 10416 | 18006 | dst_reg, |
| 10417 | | dst_reg, |
| 18007 | lhs_reg, |
| 10418 | 18008 | (if (src_mcv.isRegister()) |
| 10419 | 18009 | src_mcv.getReg().? |
| 10420 | 18010 | else |
| ... | ... | @@ -10442,7 +18032,7 @@ fn genBinOp( |
| 10442 | 18032 | dst_reg, |
| 10443 | 18033 | dst_reg, |
| 10444 | 18034 | dst_reg, |
| 10445 | | Immediate.u(@as(u5, @bitCast(RoundMode{ |
| 18035 | .u(@as(u5, @bitCast(RoundMode{ |
| 10446 | 18036 | .mode = switch (air_tag) { |
| 10447 | 18037 | .div_trunc => .zero, |
| 10448 | 18038 | .div_floor => .down, |
| ... | ... | @@ -10457,7 +18047,7 @@ fn genBinOp( |
| 10457 | 18047 | .{ .v_, .cvtps2ph }, |
| 10458 | 18048 | dst_reg, |
| 10459 | 18049 | dst_reg, |
| 10460 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 18050 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 10461 | 18051 | ); |
| 10462 | 18052 | return dst_mcv; |
| 10463 | 18053 | }, |
| ... | ... | @@ -10842,25 +18432,24 @@ fn genBinOp( |
| 10842 | 18432 | .float => switch (lhs_ty.childType(zcu).floatBits(self.target.*)) { |
| 10843 | 18433 | 16 => tag: { |
| 10844 | 18434 | assert(self.hasFeature(.f16c)); |
| 18435 | const lhs_reg = if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size); |
| 10845 | 18436 | switch (lhs_ty.vectorLen(zcu)) { |
| 10846 | 18437 | 1 => { |
| 10847 | | const tmp_reg = (try self.register_manager.allocReg( |
| 10848 | | null, |
| 10849 | | abi.RegisterClass.sse, |
| 10850 | | )).to128(); |
| 18438 | const tmp_reg = |
| 18439 | (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128(); |
| 10851 | 18440 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 10852 | 18441 | defer self.register_manager.unlockReg(tmp_lock); |
| 10853 | 18442 | |
| 10854 | | if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 18443 | if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 10855 | 18444 | .{ .vp_w, .insr }, |
| 10856 | 18445 | dst_reg, |
| 10857 | | dst_reg, |
| 10858 | | try src_mcv.mem(self, .word), |
| 10859 | | Immediate.u(1), |
| 18446 | lhs_reg, |
| 18447 | try src_mcv.mem(self, .{ .size = .word }), |
| 18448 | .u(1), |
| 10860 | 18449 | ) else try self.asmRegisterRegisterRegister( |
| 10861 | 18450 | .{ .vp_, .unpcklwd }, |
| 10862 | 18451 | dst_reg, |
| 10863 | | dst_reg, |
| 18452 | lhs_reg, |
| 10864 | 18453 | (if (src_mcv.isRegister()) |
| 10865 | 18454 | src_mcv.getReg().? |
| 10866 | 18455 | else |
| ... | ... | @@ -10886,7 +18475,7 @@ fn genBinOp( |
| 10886 | 18475 | .{ .v_, .cvtps2ph }, |
| 10887 | 18476 | dst_reg, |
| 10888 | 18477 | dst_reg, |
| 10889 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 18478 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 10890 | 18479 | ); |
| 10891 | 18480 | return dst_mcv; |
| 10892 | 18481 | }, |
| ... | ... | @@ -10898,15 +18487,16 @@ fn genBinOp( |
| 10898 | 18487 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 10899 | 18488 | defer self.register_manager.unlockReg(tmp_lock); |
| 10900 | 18489 | |
| 10901 | | if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 18490 | if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 10902 | 18491 | .{ .vp_d, .insr }, |
| 10903 | 18492 | dst_reg, |
| 10904 | | try src_mcv.mem(self, .dword), |
| 10905 | | Immediate.u(1), |
| 18493 | lhs_reg, |
| 18494 | try src_mcv.mem(self, .{ .size = .dword }), |
| 18495 | .u(1), |
| 10906 | 18496 | ) else try self.asmRegisterRegisterRegister( |
| 10907 | 18497 | .{ .v_ps, .unpckl }, |
| 10908 | 18498 | dst_reg, |
| 10909 | | dst_reg, |
| 18499 | lhs_reg, |
| 10910 | 18500 | (if (src_mcv.isRegister()) |
| 10911 | 18501 | src_mcv.getReg().? |
| 10912 | 18502 | else |
| ... | ... | @@ -10937,7 +18527,7 @@ fn genBinOp( |
| 10937 | 18527 | .{ .v_, .cvtps2ph }, |
| 10938 | 18528 | dst_reg, |
| 10939 | 18529 | dst_reg, |
| 10940 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 18530 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 10941 | 18531 | ); |
| 10942 | 18532 | return dst_mcv; |
| 10943 | 18533 | }, |
| ... | ... | @@ -10949,11 +18539,11 @@ fn genBinOp( |
| 10949 | 18539 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 10950 | 18540 | defer self.register_manager.unlockReg(tmp_lock); |
| 10951 | 18541 | |
| 10952 | | try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg); |
| 10953 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 18542 | try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, lhs_reg); |
| 18543 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 10954 | 18544 | .{ .v_ps, .cvtph2 }, |
| 10955 | 18545 | tmp_reg, |
| 10956 | | try src_mcv.mem(self, .qword), |
| 18546 | try src_mcv.mem(self, .{ .size = .qword }), |
| 10957 | 18547 | ) else try self.asmRegisterRegister( |
| 10958 | 18548 | .{ .v_ps, .cvtph2 }, |
| 10959 | 18549 | tmp_reg, |
| ... | ... | @@ -10980,7 +18570,7 @@ fn genBinOp( |
| 10980 | 18570 | .{ .v_, .cvtps2ph }, |
| 10981 | 18571 | dst_reg, |
| 10982 | 18572 | dst_reg, |
| 10983 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 18573 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 10984 | 18574 | ); |
| 10985 | 18575 | return dst_mcv; |
| 10986 | 18576 | }, |
| ... | ... | @@ -10992,11 +18582,11 @@ fn genBinOp( |
| 10992 | 18582 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 10993 | 18583 | defer self.register_manager.unlockReg(tmp_lock); |
| 10994 | 18584 | |
| 10995 | | try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg.to256(), dst_reg); |
| 10996 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 18585 | try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg.to256(), lhs_reg); |
| 18586 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 10997 | 18587 | .{ .v_ps, .cvtph2 }, |
| 10998 | 18588 | tmp_reg, |
| 10999 | | try src_mcv.mem(self, .xword), |
| 18589 | try src_mcv.mem(self, .{ .size = .xword }), |
| 11000 | 18590 | ) else try self.asmRegisterRegister( |
| 11001 | 18591 | .{ .v_ps, .cvtph2 }, |
| 11002 | 18592 | tmp_reg, |
| ... | ... | @@ -11023,7 +18613,7 @@ fn genBinOp( |
| 11023 | 18613 | .{ .v_, .cvtps2ph }, |
| 11024 | 18614 | dst_reg, |
| 11025 | 18615 | dst_reg.to256(), |
| 11026 | | Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 18616 | .u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))), |
| 11027 | 18617 | ); |
| 11028 | 18618 | return dst_mcv; |
| 11029 | 18619 | }, |
| ... | ... | @@ -11153,16 +18743,15 @@ fn genBinOp( |
| 11153 | 18743 | |
| 11154 | 18744 | switch (mir_tag[1]) { |
| 11155 | 18745 | else => if (self.hasFeature(.avx)) { |
| 11156 | | const lhs_reg = |
| 11157 | | if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size); |
| 11158 | | if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 18746 | const lhs_reg = if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size); |
| 18747 | if (src_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 11159 | 18748 | mir_tag, |
| 11160 | 18749 | dst_reg, |
| 11161 | 18750 | lhs_reg, |
| 11162 | | try src_mcv.mem(self, switch (lhs_ty.zigTypeTag(zcu)) { |
| 11163 | | else => Memory.Size.fromSize(abi_size), |
| 11164 | | .vector => Memory.Size.fromBitSize(dst_reg.bitSize()), |
| 11165 | | }), |
| 18751 | try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) { |
| 18752 | else => .fromSize(abi_size), |
| 18753 | .vector => .fromBitSize(dst_reg.bitSize()), |
| 18754 | } }), |
| 11166 | 18755 | ) else try self.asmRegisterRegisterRegister( |
| 11167 | 18756 | mir_tag, |
| 11168 | 18757 | dst_reg, |
| ... | ... | @@ -11174,13 +18763,13 @@ fn genBinOp( |
| 11174 | 18763 | ); |
| 11175 | 18764 | } else { |
| 11176 | 18765 | assert(copied_to_dst); |
| 11177 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 18766 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 11178 | 18767 | mir_tag, |
| 11179 | 18768 | dst_reg, |
| 11180 | | try src_mcv.mem(self, switch (lhs_ty.zigTypeTag(zcu)) { |
| 11181 | | else => Memory.Size.fromSize(abi_size), |
| 11182 | | .vector => Memory.Size.fromBitSize(dst_reg.bitSize()), |
| 11183 | | }), |
| 18769 | try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) { |
| 18770 | else => .fromSize(abi_size), |
| 18771 | .vector => .fromBitSize(dst_reg.bitSize()), |
| 18772 | } }), |
| 11184 | 18773 | ) else try self.asmRegisterRegister( |
| 11185 | 18774 | mir_tag, |
| 11186 | 18775 | dst_reg, |
| ... | ... | @@ -11191,7 +18780,7 @@ fn genBinOp( |
| 11191 | 18780 | ); |
| 11192 | 18781 | }, |
| 11193 | 18782 | .cmp => { |
| 11194 | | const imm = Immediate.u(switch (air_tag) { |
| 18783 | const imm: Immediate = .u(switch (air_tag) { |
| 11195 | 18784 | .cmp_eq => 0, |
| 11196 | 18785 | .cmp_lt, .cmp_gt => 1, |
| 11197 | 18786 | .cmp_lte, .cmp_gte => 2, |
| ... | ... | @@ -11201,14 +18790,14 @@ fn genBinOp( |
| 11201 | 18790 | if (self.hasFeature(.avx)) { |
| 11202 | 18791 | const lhs_reg = |
| 11203 | 18792 | if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size); |
| 11204 | | if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 18793 | if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 11205 | 18794 | mir_tag, |
| 11206 | 18795 | dst_reg, |
| 11207 | 18796 | lhs_reg, |
| 11208 | | try src_mcv.mem(self, switch (lhs_ty.zigTypeTag(zcu)) { |
| 11209 | | else => Memory.Size.fromSize(abi_size), |
| 11210 | | .vector => Memory.Size.fromBitSize(dst_reg.bitSize()), |
| 11211 | | }), |
| 18797 | try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) { |
| 18798 | else => .fromSize(abi_size), |
| 18799 | .vector => .fromBitSize(dst_reg.bitSize()), |
| 18800 | } }), |
| 11212 | 18801 | imm, |
| 11213 | 18802 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 11214 | 18803 | mir_tag, |
| ... | ... | @@ -11222,13 +18811,13 @@ fn genBinOp( |
| 11222 | 18811 | ); |
| 11223 | 18812 | } else { |
| 11224 | 18813 | assert(copied_to_dst); |
| 11225 | | if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 18814 | if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate( |
| 11226 | 18815 | mir_tag, |
| 11227 | 18816 | dst_reg, |
| 11228 | | try src_mcv.mem(self, switch (lhs_ty.zigTypeTag(zcu)) { |
| 11229 | | else => Memory.Size.fromSize(abi_size), |
| 11230 | | .vector => Memory.Size.fromBitSize(dst_reg.bitSize()), |
| 11231 | | }), |
| 18817 | try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) { |
| 18818 | else => .fromSize(abi_size), |
| 18819 | .vector => .fromBitSize(dst_reg.bitSize()), |
| 18820 | } }), |
| 11232 | 18821 | imm, |
| 11233 | 18822 | ) else try self.asmRegisterRegisterImmediate( |
| 11234 | 18823 | mir_tag, |
| ... | ... | @@ -11289,7 +18878,7 @@ fn genBinOp( |
| 11289 | 18878 | mask_reg, |
| 11290 | 18879 | rhs_copy_reg, |
| 11291 | 18880 | rhs_copy_reg, |
| 11292 | | Immediate.u(3), // unord |
| 18881 | .u(3), // unord |
| 11293 | 18882 | ); |
| 11294 | 18883 | try self.asmRegisterRegisterRegisterRegister( |
| 11295 | 18884 | @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -11356,7 +18945,7 @@ fn genBinOp( |
| 11356 | 18945 | }), |
| 11357 | 18946 | mask_reg, |
| 11358 | 18947 | mask_reg, |
| 11359 | | Immediate.u(if (has_blend) 3 else 7), // unord, ord |
| 18948 | .u(if (has_blend) 3 else 7), // unord, ord |
| 11360 | 18949 | ); |
| 11361 | 18950 | if (has_blend) try self.asmRegisterRegisterRegister( |
| 11362 | 18951 | @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -11433,12 +19022,12 @@ fn genBinOp( |
| 11433 | 19022 | => { |
| 11434 | 19023 | const unsigned_ty = try lhs_ty.toUnsigned(pt); |
| 11435 | 19024 | const not_mcv = try self.genTypedValue(try unsigned_ty.maxInt(pt, unsigned_ty)); |
| 11436 | | const not_mem: Memory = if (not_mcv.isMemory()) |
| 11437 | | try not_mcv.mem(self, Memory.Size.fromSize(abi_size)) |
| 19025 | const not_mem: Memory = if (not_mcv.isBase()) |
| 19026 | try not_mcv.mem(self, .{ .size = .fromSize(abi_size) }) |
| 11438 | 19027 | else |
| 11439 | 19028 | .{ .base = .{ |
| 11440 | | .reg = try self.copyToTmpRegister(Type.usize, not_mcv.address()), |
| 11441 | | }, .mod = .{ .rm = .{ .size = Memory.Size.fromSize(abi_size) } } }; |
| 19029 | .reg = try self.copyToTmpRegister(.usize, not_mcv.address()), |
| 19030 | }, .mod = .{ .rm = .{ .size = .fromSize(abi_size) } } }; |
| 11442 | 19031 | switch (mir_tag[0]) { |
| 11443 | 19032 | .vp_b, .vp_d, .vp_q, .vp_w => try self.asmRegisterRegisterMemory( |
| 11444 | 19033 | .{ .vp_, .xor }, |
| ... | ... | @@ -11495,7 +19084,7 @@ fn genBinOp( |
| 11495 | 19084 | } |
| 11496 | 19085 | |
| 11497 | 19086 | fn genBinOpMir( |
| 11498 | | self: *Self, |
| 19087 | self: *CodeGen, |
| 11499 | 19088 | mir_tag: Mir.Inst.FixedTag, |
| 11500 | 19089 | ty: Type, |
| 11501 | 19090 | dst_mcv: MCValue, |
| ... | ... | @@ -11513,6 +19102,7 @@ fn genBinOpMir( |
| 11513 | 19102 | .immediate, |
| 11514 | 19103 | .eflags, |
| 11515 | 19104 | .register_overflow, |
| 19105 | .register_mask, |
| 11516 | 19106 | .lea_direct, |
| 11517 | 19107 | .lea_got, |
| 11518 | 19108 | .lea_tlv, |
| ... | ... | @@ -11522,9 +19112,9 @@ fn genBinOpMir( |
| 11522 | 19112 | .reserved_frame, |
| 11523 | 19113 | .air_ref, |
| 11524 | 19114 | => unreachable, // unmodifiable destination |
| 11525 | | .register, .register_pair, .register_offset => { |
| 19115 | .register, .register_pair, .register_triple, .register_quadruple, .register_offset => { |
| 11526 | 19116 | switch (dst_mcv) { |
| 11527 | | .register, .register_pair => {}, |
| 19117 | .register, .register_pair, .register_triple, .register_quadruple => {}, |
| 11528 | 19118 | .register_offset => |ro| assert(ro.off == 0), |
| 11529 | 19119 | else => unreachable, |
| 11530 | 19120 | } |
| ... | ... | @@ -11553,10 +19143,15 @@ fn genBinOpMir( |
| 11553 | 19143 | .dead, |
| 11554 | 19144 | .undef, |
| 11555 | 19145 | .register_overflow, |
| 19146 | .register_mask, |
| 11556 | 19147 | .elementwise_regs_then_frame, |
| 11557 | 19148 | .reserved_frame, |
| 11558 | 19149 | => unreachable, |
| 11559 | | .register, .register_pair => try self.asmRegisterRegister( |
| 19150 | .register, |
| 19151 | .register_pair, |
| 19152 | .register_triple, |
| 19153 | .register_quadruple, |
| 19154 | => try self.asmRegisterRegister( |
| 11560 | 19155 | mir_limb_tag, |
| 11561 | 19156 | dst_alias, |
| 11562 | 19157 | registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size), |
| ... | ... | @@ -11567,29 +19162,29 @@ fn genBinOpMir( |
| 11567 | 19162 | 8 => try self.asmRegisterImmediate( |
| 11568 | 19163 | mir_limb_tag, |
| 11569 | 19164 | dst_alias, |
| 11570 | | if (math.cast(i8, @as(i64, @bitCast(imm)))) |small| |
| 11571 | | Immediate.s(small) |
| 19165 | if (std.math.cast(i8, @as(i64, @bitCast(imm)))) |small| |
| 19166 | .s(small) |
| 11572 | 19167 | else |
| 11573 | | Immediate.u(@as(u8, @intCast(imm))), |
| 19168 | .u(@as(u8, @intCast(imm))), |
| 11574 | 19169 | ), |
| 11575 | 19170 | 16 => try self.asmRegisterImmediate( |
| 11576 | 19171 | mir_limb_tag, |
| 11577 | 19172 | dst_alias, |
| 11578 | | if (math.cast(i16, @as(i64, @bitCast(imm)))) |small| |
| 11579 | | Immediate.s(small) |
| 19173 | if (std.math.cast(i16, @as(i64, @bitCast(imm)))) |small| |
| 19174 | .s(small) |
| 11580 | 19175 | else |
| 11581 | | Immediate.u(@as(u16, @intCast(imm))), |
| 19176 | .u(@as(u16, @intCast(imm))), |
| 11582 | 19177 | ), |
| 11583 | 19178 | 32 => try self.asmRegisterImmediate( |
| 11584 | 19179 | mir_limb_tag, |
| 11585 | 19180 | dst_alias, |
| 11586 | | if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 11587 | | Immediate.s(small) |
| 19181 | if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 19182 | .s(small) |
| 11588 | 19183 | else |
| 11589 | | Immediate.u(@as(u32, @intCast(imm))), |
| 19184 | .u(@as(u32, @intCast(imm))), |
| 11590 | 19185 | ), |
| 11591 | | 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 11592 | | try self.asmRegisterImmediate(mir_limb_tag, dst_alias, Immediate.s(small)) |
| 19186 | 64 => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 19187 | try self.asmRegisterImmediate(mir_limb_tag, dst_alias, .s(small)) |
| 11593 | 19188 | else |
| 11594 | 19189 | try self.asmRegisterRegister(mir_limb_tag, dst_alias, registerAlias( |
| 11595 | 19190 | try self.copyToTmpRegister(ty, src_mcv), |
| ... | ... | @@ -11618,21 +19213,21 @@ fn genBinOpMir( |
| 11618 | 19213 | .memory => |addr| .{ |
| 11619 | 19214 | .base = .{ .reg = .ds }, |
| 11620 | 19215 | .mod = .{ .rm = .{ |
| 11621 | | .size = Memory.Size.fromSize(limb_abi_size), |
| 11622 | | .disp = math.cast(i32, addr + off) orelse break :direct, |
| 19216 | .size = .fromSize(limb_abi_size), |
| 19217 | .disp = std.math.cast(i32, addr + off) orelse break :direct, |
| 11623 | 19218 | } }, |
| 11624 | 19219 | }, |
| 11625 | 19220 | .indirect => |reg_off| .{ |
| 11626 | 19221 | .base = .{ .reg = reg_off.reg }, |
| 11627 | 19222 | .mod = .{ .rm = .{ |
| 11628 | | .size = Memory.Size.fromSize(limb_abi_size), |
| 19223 | .size = .fromSize(limb_abi_size), |
| 11629 | 19224 | .disp = reg_off.off + off, |
| 11630 | 19225 | } }, |
| 11631 | 19226 | }, |
| 11632 | 19227 | .load_frame => |frame_addr| .{ |
| 11633 | 19228 | .base = .{ .frame = frame_addr.index }, |
| 11634 | 19229 | .mod = .{ .rm = .{ |
| 11635 | | .size = Memory.Size.fromSize(limb_abi_size), |
| 19230 | .size = .fromSize(limb_abi_size), |
| 11636 | 19231 | .disp = frame_addr.off + off, |
| 11637 | 19232 | } }, |
| 11638 | 19233 | }, |
| ... | ... | @@ -11695,7 +19290,7 @@ fn genBinOpMir( |
| 11695 | 19290 | const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); |
| 11696 | 19291 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| 11697 | 19292 | |
| 11698 | | try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address(), .{}); |
| 19293 | try self.genSetReg(dst_addr_reg, .usize, dst_mcv.address(), .{}); |
| 11699 | 19294 | break :dst .{ .addr_reg = dst_addr_reg, .addr_lock = dst_addr_lock }; |
| 11700 | 19295 | }, |
| 11701 | 19296 | .load_frame => null, |
| ... | ... | @@ -11712,6 +19307,7 @@ fn genBinOpMir( |
| 11712 | 19307 | .dead, |
| 11713 | 19308 | .undef, |
| 11714 | 19309 | .register_overflow, |
| 19310 | .register_mask, |
| 11715 | 19311 | .elementwise_regs_then_frame, |
| 11716 | 19312 | .reserved_frame, |
| 11717 | 19313 | .air_ref, |
| ... | ... | @@ -11720,6 +19316,8 @@ fn genBinOpMir( |
| 11720 | 19316 | .eflags, |
| 11721 | 19317 | .register, |
| 11722 | 19318 | .register_pair, |
| 19319 | .register_triple, |
| 19320 | .register_quadruple, |
| 11723 | 19321 | .register_offset, |
| 11724 | 19322 | .indirect, |
| 11725 | 19323 | .lea_direct, |
| ... | ... | @@ -11731,8 +19329,8 @@ fn genBinOpMir( |
| 11731 | 19329 | => null, |
| 11732 | 19330 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: { |
| 11733 | 19331 | switch (resolved_src_mcv) { |
| 11734 | | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr))) != null and |
| 11735 | | math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null) |
| 19332 | .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and |
| 19333 | std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null) |
| 11736 | 19334 | break :src null, |
| 11737 | 19335 | .load_symbol, .load_got, .load_direct, .load_tlv => {}, |
| 11738 | 19336 | else => unreachable, |
| ... | ... | @@ -11743,7 +19341,7 @@ fn genBinOpMir( |
| 11743 | 19341 | const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg); |
| 11744 | 19342 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 11745 | 19343 | |
| 11746 | | try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address(), .{}); |
| 19344 | try self.genSetReg(src_addr_reg, .usize, resolved_src_mcv.address(), .{}); |
| 11747 | 19345 | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; |
| 11748 | 19346 | }, |
| 11749 | 19347 | }; |
| ... | ... | @@ -11751,9 +19349,9 @@ fn genBinOpMir( |
| 11751 | 19349 | |
| 11752 | 19350 | const ty_signedness = |
| 11753 | 19351 | if (ty.isAbiInt(zcu)) ty.intInfo(zcu).signedness else .unsigned; |
| 11754 | | const limb_ty = if (abi_size <= 8) ty else switch (ty_signedness) { |
| 11755 | | .signed => Type.usize, |
| 11756 | | .unsigned => Type.isize, |
| 19352 | const limb_ty: Type = if (abi_size <= 8) ty else switch (ty_signedness) { |
| 19353 | .signed => .usize, |
| 19354 | .unsigned => .isize, |
| 11757 | 19355 | }; |
| 11758 | 19356 | var limb_i: usize = 0; |
| 11759 | 19357 | var off: i32 = 0; |
| ... | ... | @@ -11781,21 +19379,21 @@ fn genBinOpMir( |
| 11781 | 19379 | => .{ |
| 11782 | 19380 | .base = .{ .reg = dst_info.?.addr_reg }, |
| 11783 | 19381 | .mod = .{ .rm = .{ |
| 11784 | | .size = Memory.Size.fromSize(limb_abi_size), |
| 19382 | .size = .fromSize(limb_abi_size), |
| 11785 | 19383 | .disp = off, |
| 11786 | 19384 | } }, |
| 11787 | 19385 | }, |
| 11788 | 19386 | .indirect => |reg_off| .{ |
| 11789 | 19387 | .base = .{ .reg = reg_off.reg }, |
| 11790 | 19388 | .mod = .{ .rm = .{ |
| 11791 | | .size = Memory.Size.fromSize(limb_abi_size), |
| 19389 | .size = .fromSize(limb_abi_size), |
| 11792 | 19390 | .disp = reg_off.off + off, |
| 11793 | 19391 | } }, |
| 11794 | 19392 | }, |
| 11795 | 19393 | .load_frame => |frame_addr| .{ |
| 11796 | 19394 | .base = .{ .frame = frame_addr.index }, |
| 11797 | 19395 | .mod = .{ .rm = .{ |
| 11798 | | .size = Memory.Size.fromSize(limb_abi_size), |
| 19396 | .size = .fromSize(limb_abi_size), |
| 11799 | 19397 | .disp = frame_addr.off + off, |
| 11800 | 19398 | } }, |
| 11801 | 19399 | }, |
| ... | ... | @@ -11807,6 +19405,7 @@ fn genBinOpMir( |
| 11807 | 19405 | .dead, |
| 11808 | 19406 | .undef, |
| 11809 | 19407 | .register_overflow, |
| 19408 | .register_mask, |
| 11810 | 19409 | .elementwise_regs_then_frame, |
| 11811 | 19410 | .reserved_frame, |
| 11812 | 19411 | .air_ref, |
| ... | ... | @@ -11823,33 +19422,29 @@ fn genBinOpMir( |
| 11823 | 19422 | 8 => try self.asmMemoryImmediate( |
| 11824 | 19423 | mir_limb_tag, |
| 11825 | 19424 | dst_limb_mem, |
| 11826 | | if (math.cast(i8, @as(i64, @bitCast(imm)))) |small| |
| 11827 | | Immediate.s(small) |
| 19425 | if (std.math.cast(i8, @as(i64, @bitCast(imm)))) |small| |
| 19426 | .s(small) |
| 11828 | 19427 | else |
| 11829 | | Immediate.u(@as(u8, @intCast(imm))), |
| 19428 | .u(@as(u8, @intCast(imm))), |
| 11830 | 19429 | ), |
| 11831 | 19430 | 16 => try self.asmMemoryImmediate( |
| 11832 | 19431 | mir_limb_tag, |
| 11833 | 19432 | dst_limb_mem, |
| 11834 | | if (math.cast(i16, @as(i64, @bitCast(imm)))) |small| |
| 11835 | | Immediate.s(small) |
| 19433 | if (std.math.cast(i16, @as(i64, @bitCast(imm)))) |small| |
| 19434 | .s(small) |
| 11836 | 19435 | else |
| 11837 | | Immediate.u(@as(u16, @intCast(imm))), |
| 19436 | .u(@as(u16, @intCast(imm))), |
| 11838 | 19437 | ), |
| 11839 | 19438 | 32 => try self.asmMemoryImmediate( |
| 11840 | 19439 | mir_limb_tag, |
| 11841 | 19440 | dst_limb_mem, |
| 11842 | | if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 11843 | | Immediate.s(small) |
| 19441 | if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 19442 | .s(small) |
| 11844 | 19443 | else |
| 11845 | | Immediate.u(@as(u32, @intCast(imm))), |
| 19444 | .u(@as(u32, @intCast(imm))), |
| 11846 | 19445 | ), |
| 11847 | | 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 11848 | | try self.asmMemoryImmediate( |
| 11849 | | mir_limb_tag, |
| 11850 | | dst_limb_mem, |
| 11851 | | Immediate.s(small), |
| 11852 | | ) |
| 19446 | 64 => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 19447 | try self.asmMemoryImmediate(mir_limb_tag, dst_limb_mem, .s(small)) |
| 11853 | 19448 | else |
| 11854 | 19449 | try self.asmMemoryRegister( |
| 11855 | 19450 | mir_limb_tag, |
| ... | ... | @@ -11864,6 +19459,8 @@ fn genBinOpMir( |
| 11864 | 19459 | }, |
| 11865 | 19460 | .register, |
| 11866 | 19461 | .register_pair, |
| 19462 | .register_triple, |
| 19463 | .register_quadruple, |
| 11867 | 19464 | .register_offset, |
| 11868 | 19465 | .eflags, |
| 11869 | 19466 | .memory, |
| ... | ... | @@ -11882,7 +19479,7 @@ fn genBinOpMir( |
| 11882 | 19479 | const src_limb_mcv: MCValue = if (src_info) |info| .{ |
| 11883 | 19480 | .indirect = .{ .reg = info.addr_reg, .off = off }, |
| 11884 | 19481 | } else switch (resolved_src_mcv) { |
| 11885 | | .register, .register_pair => .{ |
| 19482 | .register, .register_pair, .register_triple, .register_quadruple => .{ |
| 11886 | 19483 | .register = resolved_src_mcv.getRegs()[limb_i], |
| 11887 | 19484 | }, |
| 11888 | 19485 | .eflags, |
| ... | ... | @@ -11925,7 +19522,7 @@ fn genBinOpMir( |
| 11925 | 19522 | |
| 11926 | 19523 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 11927 | 19524 | /// Does not support byte-size operands. |
| 11928 | | fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 19525 | fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 11929 | 19526 | const pt = self.pt; |
| 11930 | 19527 | const abi_size: u32 = @intCast(dst_ty.abiSize(pt.zcu)); |
| 11931 | 19528 | try self.spillEflagsIfOccupied(); |
| ... | ... | @@ -11938,6 +19535,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 11938 | 19535 | .eflags, |
| 11939 | 19536 | .register_offset, |
| 11940 | 19537 | .register_overflow, |
| 19538 | .register_mask, |
| 11941 | 19539 | .lea_symbol, |
| 11942 | 19540 | .lea_direct, |
| 11943 | 19541 | .lea_got, |
| ... | ... | @@ -11948,10 +19546,19 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 11948 | 19546 | .air_ref, |
| 11949 | 19547 | => unreachable, // unmodifiable destination |
| 11950 | 19548 | .register => |dst_reg| { |
| 11951 | | const dst_alias = registerAlias(dst_reg, abi_size); |
| 19549 | const alias_size = switch (abi_size) { |
| 19550 | 1 => 4, |
| 19551 | else => abi_size, |
| 19552 | }; |
| 19553 | const dst_alias = registerAlias(dst_reg, alias_size); |
| 11952 | 19554 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 11953 | 19555 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 11954 | 19556 | |
| 19557 | switch (abi_size) { |
| 19558 | 1 => try self.asmRegisterRegister(.{ ._, .movzx }, dst_reg.to32(), dst_reg.to8()), |
| 19559 | else => {}, |
| 19560 | } |
| 19561 | |
| 11955 | 19562 | const resolved_src_mcv = switch (src_mcv) { |
| 11956 | 19563 | else => src_mcv, |
| 11957 | 19564 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| ... | ... | @@ -11962,24 +19569,28 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 11962 | 19569 | .dead, |
| 11963 | 19570 | .undef, |
| 11964 | 19571 | .register_pair, |
| 19572 | .register_triple, |
| 19573 | .register_quadruple, |
| 11965 | 19574 | .register_overflow, |
| 19575 | .register_mask, |
| 11966 | 19576 | .elementwise_regs_then_frame, |
| 11967 | 19577 | .reserved_frame, |
| 11968 | 19578 | .air_ref, |
| 11969 | 19579 | => unreachable, |
| 11970 | | .register => |src_reg| try self.asmRegisterRegister( |
| 11971 | | .{ .i_, .mul }, |
| 11972 | | dst_alias, |
| 11973 | | registerAlias(src_reg, abi_size), |
| 11974 | | ), |
| 19580 | .register => |src_reg| { |
| 19581 | switch (abi_size) { |
| 19582 | 1 => try self.asmRegisterRegister(.{ ._, .movzx }, src_reg.to32(), src_reg.to8()), |
| 19583 | else => {}, |
| 19584 | } |
| 19585 | try self.asmRegisterRegister( |
| 19586 | .{ .i_, .mul }, |
| 19587 | dst_alias, |
| 19588 | registerAlias(src_reg, alias_size), |
| 19589 | ); |
| 19590 | }, |
| 11975 | 19591 | .immediate => |imm| { |
| 11976 | | if (math.cast(i32, imm)) |small| { |
| 11977 | | try self.asmRegisterRegisterImmediate( |
| 11978 | | .{ .i_, .mul }, |
| 11979 | | dst_alias, |
| 11980 | | dst_alias, |
| 11981 | | Immediate.s(small), |
| 11982 | | ); |
| 19592 | if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| { |
| 19593 | try self.asmRegisterRegisterImmediate(.{ .i_, .mul }, dst_alias, dst_alias, .s(small)); |
| 11983 | 19594 | } else { |
| 11984 | 19595 | const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv); |
| 11985 | 19596 | return self.genIntMulComplexOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg }); |
| ... | ... | @@ -11996,50 +19607,60 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 11996 | 19607 | .load_tlv, |
| 11997 | 19608 | .lea_tlv, |
| 11998 | 19609 | .lea_frame, |
| 11999 | | => try self.asmRegisterRegister( |
| 12000 | | .{ .i_, .mul }, |
| 12001 | | dst_alias, |
| 12002 | | registerAlias(try self.copyToTmpRegister(dst_ty, resolved_src_mcv), abi_size), |
| 12003 | | ), |
| 12004 | | .memory, .indirect, .load_frame => try self.asmRegisterMemory( |
| 12005 | | .{ .i_, .mul }, |
| 12006 | | dst_alias, |
| 12007 | | switch (resolved_src_mcv) { |
| 12008 | | .memory => |addr| .{ |
| 12009 | | .base = .{ .reg = .ds }, |
| 12010 | | .mod = .{ .rm = .{ |
| 12011 | | .size = Memory.Size.fromSize(abi_size), |
| 12012 | | .disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse |
| 12013 | | return self.asmRegisterRegister( |
| 12014 | | .{ .i_, .mul }, |
| 12015 | | dst_alias, |
| 12016 | | registerAlias( |
| 12017 | | try self.copyToTmpRegister(dst_ty, resolved_src_mcv), |
| 12018 | | abi_size, |
| 19610 | => { |
| 19611 | const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv); |
| 19612 | switch (abi_size) { |
| 19613 | 1 => try self.asmRegisterRegister(.{ ._, .movzx }, src_reg.to32(), src_reg.to8()), |
| 19614 | else => {}, |
| 19615 | } |
| 19616 | try self.asmRegisterRegister(.{ .i_, .mul }, dst_alias, registerAlias(src_reg, alias_size)); |
| 19617 | }, |
| 19618 | .memory, .indirect, .load_frame => switch (abi_size) { |
| 19619 | 1 => { |
| 19620 | const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv); |
| 19621 | try self.asmRegisterRegister(.{ ._, .movzx }, src_reg.to32(), src_reg.to8()); |
| 19622 | try self.asmRegisterRegister(.{ .i_, .mul }, dst_alias, registerAlias(src_reg, alias_size)); |
| 19623 | }, |
| 19624 | else => try self.asmRegisterMemory( |
| 19625 | .{ .i_, .mul }, |
| 19626 | dst_alias, |
| 19627 | switch (resolved_src_mcv) { |
| 19628 | .memory => |addr| .{ |
| 19629 | .base = .{ .reg = .ds }, |
| 19630 | .mod = .{ .rm = .{ |
| 19631 | .size = .fromSize(abi_size), |
| 19632 | .disp = std.math.cast(i32, @as(i64, @bitCast(addr))) orelse |
| 19633 | return self.asmRegisterRegister( |
| 19634 | .{ .i_, .mul }, |
| 19635 | dst_alias, |
| 19636 | registerAlias( |
| 19637 | try self.copyToTmpRegister(dst_ty, resolved_src_mcv), |
| 19638 | abi_size, |
| 19639 | ), |
| 12019 | 19640 | ), |
| 12020 | | ), |
| 12021 | | } }, |
| 12022 | | }, |
| 12023 | | .indirect => |reg_off| .{ |
| 12024 | | .base = .{ .reg = reg_off.reg }, |
| 12025 | | .mod = .{ .rm = .{ |
| 12026 | | .size = Memory.Size.fromSize(abi_size), |
| 12027 | | .disp = reg_off.off, |
| 12028 | | } }, |
| 12029 | | }, |
| 12030 | | .load_frame => |frame_addr| .{ |
| 12031 | | .base = .{ .frame = frame_addr.index }, |
| 12032 | | .mod = .{ .rm = .{ |
| 12033 | | .size = Memory.Size.fromSize(abi_size), |
| 12034 | | .disp = frame_addr.off, |
| 12035 | | } }, |
| 19641 | } }, |
| 19642 | }, |
| 19643 | .indirect => |reg_off| .{ |
| 19644 | .base = .{ .reg = reg_off.reg }, |
| 19645 | .mod = .{ .rm = .{ |
| 19646 | .size = .fromSize(abi_size), |
| 19647 | .disp = reg_off.off, |
| 19648 | } }, |
| 19649 | }, |
| 19650 | .load_frame => |frame_addr| .{ |
| 19651 | .base = .{ .frame = frame_addr.index }, |
| 19652 | .mod = .{ .rm = .{ |
| 19653 | .size = .fromSize(abi_size), |
| 19654 | .disp = frame_addr.off, |
| 19655 | } }, |
| 19656 | }, |
| 19657 | else => unreachable, |
| 12036 | 19658 | }, |
| 12037 | | else => unreachable, |
| 12038 | | }, |
| 12039 | | ), |
| 19659 | ), |
| 19660 | }, |
| 12040 | 19661 | } |
| 12041 | 19662 | }, |
| 12042 | | .register_pair => unreachable, // unimplemented |
| 19663 | .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented |
| 12043 | 19664 | .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_tlv, .load_frame => { |
| 12044 | 19665 | const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); |
| 12045 | 19666 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| ... | ... | @@ -12052,7 +19673,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 12052 | 19673 | } |
| 12053 | 19674 | } |
| 12054 | 19675 | |
| 12055 | | fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 19676 | fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 12056 | 19677 | const pt = self.pt; |
| 12057 | 19678 | const zcu = pt.zcu; |
| 12058 | 19679 | // skip zero-bit arguments as they don't have a corresponding arg instruction |
| ... | ... | @@ -12078,8 +19699,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 12078 | 19699 | try self.spillEflagsIfOccupied(); |
| 12079 | 19700 | |
| 12080 | 19701 | const fn_info = zcu.typeToFunc(self.fn_type).?; |
| 12081 | | const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); |
| 12082 | | const param_int_regs = abi.getCAbiIntParamRegs(cc); |
| 19702 | const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); |
| 12083 | 19703 | var prev_reg: Register = undefined; |
| 12084 | 19704 | for ( |
| 12085 | 19705 | param_int_regs[param_int_regs.len - regs_frame_addr.regs ..], |
| ... | ... | @@ -12087,11 +19707,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 12087 | 19707 | ) |dst_reg, elem_index| { |
| 12088 | 19708 | assert(self.register_manager.isRegFree(dst_reg)); |
| 12089 | 19709 | if (elem_index > 0) { |
| 12090 | | try self.asmRegisterImmediate( |
| 12091 | | .{ ._l, .sh }, |
| 12092 | | dst_reg.to8(), |
| 12093 | | Immediate.u(elem_index), |
| 12094 | | ); |
| 19710 | try self.asmRegisterImmediate(.{ ._l, .sh }, dst_reg.to8(), .u(elem_index)); |
| 12095 | 19711 | try self.asmRegisterRegister( |
| 12096 | 19712 | .{ ._, .@"or" }, |
| 12097 | 19713 | dst_reg.to8(), |
| ... | ... | @@ -12110,7 +19726,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 12110 | 19726 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 12111 | 19727 | if (regs_frame_addr.regs > 0) try self.asmMemoryRegister( |
| 12112 | 19728 | .{ ._, .mov }, |
| 12113 | | try dst_mcv.mem(self, .byte), |
| 19729 | try dst_mcv.mem(self, .{ .size = .byte }), |
| 12114 | 19730 | prev_reg.to8(), |
| 12115 | 19731 | ); |
| 12116 | 19732 | try self.genInlineMemset( |
| ... | ... | @@ -12127,7 +19743,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 12127 | 19743 | try self.asmRegisterImmediate( |
| 12128 | 19744 | .{ ._, .mov }, |
| 12129 | 19745 | index_reg.to32(), |
| 12130 | | Immediate.u(regs_frame_addr.regs), |
| 19746 | .u(regs_frame_addr.regs), |
| 12131 | 19747 | ); |
| 12132 | 19748 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 12133 | 19749 | try self.asmMemoryImmediate(.{ ._, .cmp }, .{ |
| ... | ... | @@ -12142,19 +19758,19 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 12142 | 19758 | const unset = try self.asmJccReloc(.e, undefined); |
| 12143 | 19759 | try self.asmMemoryRegister( |
| 12144 | 19760 | .{ ._s, .bt }, |
| 12145 | | try dst_mcv.mem(self, .dword), |
| 19761 | try dst_mcv.mem(self, .{ .size = .dword }), |
| 12146 | 19762 | index_reg.to32(), |
| 12147 | 19763 | ); |
| 12148 | 19764 | self.performReloc(unset); |
| 12149 | 19765 | if (self.hasFeature(.slow_incdec)) { |
| 12150 | | try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), Immediate.u(1)); |
| 19766 | try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1)); |
| 12151 | 19767 | } else { |
| 12152 | 19768 | try self.asmRegister(.{ ._, .inc }, index_reg.to32()); |
| 12153 | 19769 | } |
| 12154 | 19770 | try self.asmRegisterImmediate( |
| 12155 | 19771 | .{ ._, .cmp }, |
| 12156 | 19772 | index_reg.to32(), |
| 12157 | | Immediate.u(arg_ty.vectorLen(zcu)), |
| 19773 | .u(arg_ty.vectorLen(zcu)), |
| 12158 | 19774 | ); |
| 12159 | 19775 | _ = try self.asmJccReloc(.b, loop); |
| 12160 | 19776 | |
| ... | ... | @@ -12166,7 +19782,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 12166 | 19782 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 12167 | 19783 | } |
| 12168 | 19784 | |
| 12169 | | fn airDbgArg(self: *Self, inst: Air.Inst.Index) !void { |
| 19785 | fn airDbgArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 12170 | 19786 | // skip zero-bit arguments as they don't have a corresponding arg instruction |
| 12171 | 19787 | var arg_index = self.arg_index; |
| 12172 | 19788 | while (self.args[arg_index] == .none) arg_index += 1; |
| ... | ... | @@ -12180,16 +19796,14 @@ fn airDbgArg(self: *Self, inst: Air.Inst.Index) !void { |
| 12180 | 19796 | for (self.args[self.arg_index..]) |arg| { |
| 12181 | 19797 | if (arg != .none) break; |
| 12182 | 19798 | } else try self.airDbgVarArgs(); |
| 12183 | | self.finishAirBookkeeping(); |
| 12184 | 19799 | } |
| 12185 | 19800 | |
| 12186 | | fn airDbgVarArgs(self: *Self) !void { |
| 12187 | | if (self.pt.zcu.typeToFunc(self.fn_type).?.is_var_args) |
| 12188 | | try self.asmPseudo(.pseudo_dbg_var_args_none); |
| 19801 | fn airDbgVarArgs(self: *CodeGen) !void { |
| 19802 | if (self.pt.zcu.typeToFunc(self.fn_type).?.is_var_args) try self.asmPseudo(.pseudo_dbg_var_args_none); |
| 12189 | 19803 | } |
| 12190 | 19804 | |
| 12191 | 19805 | fn genLocalDebugInfo( |
| 12192 | | self: *Self, |
| 19806 | self: *CodeGen, |
| 12193 | 19807 | inst: Air.Inst.Index, |
| 12194 | 19808 | mcv: MCValue, |
| 12195 | 19809 | ) !void { |
| ... | ... | @@ -12200,9 +19814,9 @@ fn genLocalDebugInfo( |
| 12200 | 19814 | switch (mcv) { |
| 12201 | 19815 | .none => try self.asmAir(.dbg_local, inst), |
| 12202 | 19816 | .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable, |
| 12203 | | .immediate => |imm| try self.asmAirImmediate(.dbg_local, inst, Immediate.u(imm)), |
| 19817 | .immediate => |imm| try self.asmAirImmediate(.dbg_local, inst, .u(imm)), |
| 12204 | 19818 | .lea_frame => |frame_addr| try self.asmAirFrameAddress(.dbg_local, inst, frame_addr), |
| 12205 | | .lea_symbol => |sym_off| try self.asmAirImmediate(.dbg_local, inst, Immediate.rel(sym_off)), |
| 19819 | .lea_symbol => |sym_off| try self.asmAirImmediate(.dbg_local, inst, .rel(sym_off)), |
| 12206 | 19820 | else => { |
| 12207 | 19821 | const ty = switch (tag) { |
| 12208 | 19822 | else => unreachable, |
| ... | ... | @@ -12211,7 +19825,7 @@ fn genLocalDebugInfo( |
| 12211 | 19825 | self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op.operand, |
| 12212 | 19826 | ), |
| 12213 | 19827 | }; |
| 12214 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ty, self.pt.zcu)); |
| 19828 | const frame_index = try self.allocFrameIndex(.initSpill(ty, self.pt.zcu)); |
| 12215 | 19829 | try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{}); |
| 12216 | 19830 | try self.asmAirMemory(.dbg_local, inst, .{ |
| 12217 | 19831 | .base = .{ .frame = frame_index }, |
| ... | ... | @@ -12245,29 +19859,19 @@ fn genLocalDebugInfo( |
| 12245 | 19859 | } |
| 12246 | 19860 | } |
| 12247 | 19861 | |
| 12248 | | fn airTrap(self: *Self) !void { |
| 12249 | | try self.asmOpOnly(.{ ._, .ud2 }); |
| 12250 | | self.finishAirBookkeeping(); |
| 12251 | | } |
| 12252 | | |
| 12253 | | fn airBreakpoint(self: *Self) !void { |
| 12254 | | try self.asmOpOnly(.{ ._, .int3 }); |
| 12255 | | self.finishAirBookkeeping(); |
| 12256 | | } |
| 12257 | | |
| 12258 | | fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void { |
| 19862 | fn airRetAddr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 12259 | 19863 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 12260 | | try self.genCopy(Type.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } }, .{}); |
| 19864 | try self.genCopy(.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } }, .{}); |
| 12261 | 19865 | return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 12262 | 19866 | } |
| 12263 | 19867 | |
| 12264 | | fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void { |
| 19868 | fn airFrameAddress(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 12265 | 19869 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 12266 | | try self.genCopy(Type.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } }, .{}); |
| 19870 | try self.genCopy(.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } }, .{}); |
| 12267 | 19871 | return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 12268 | 19872 | } |
| 12269 | 19873 | |
| 12270 | | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 19874 | fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier, opts: CopyOptions) !void { |
| 12271 | 19875 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{}); |
| 12272 | 19876 | |
| 12273 | 19877 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| ... | ... | @@ -12291,7 +19895,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 12291 | 19895 | defer allocator.free(arg_vals); |
| 12292 | 19896 | for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref }; |
| 12293 | 19897 | |
| 12294 | | const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals); |
| 19898 | const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals, opts); |
| 12295 | 19899 | |
| 12296 | 19900 | var bt = self.liveness.iterateBigTomb(inst); |
| 12297 | 19901 | try self.feed(&bt, pl_op.operand); |
| ... | ... | @@ -12301,7 +19905,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 12301 | 19905 | return self.finishAirResult(inst, result); |
| 12302 | 19906 | } |
| 12303 | 19907 | |
| 12304 | | fn genCall(self: *Self, info: union(enum) { |
| 19908 | fn genCall(self: *CodeGen, info: union(enum) { |
| 12305 | 19909 | air: Air.Inst.Ref, |
| 12306 | 19910 | lib: struct { |
| 12307 | 19911 | return_type: InternPool.Index, |
| ... | ... | @@ -12309,7 +19913,7 @@ fn genCall(self: *Self, info: union(enum) { |
| 12309 | 19913 | lib: ?[]const u8 = null, |
| 12310 | 19914 | callee: []const u8, |
| 12311 | 19915 | }, |
| 12312 | | }, arg_types: []const Type, args: []const MCValue) !MCValue { |
| 19916 | }, arg_types: []const Type, args: []const MCValue, opts: CopyOptions) !MCValue { |
| 12313 | 19917 | const pt = self.pt; |
| 12314 | 19918 | const zcu = pt.zcu; |
| 12315 | 19919 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -12330,7 +19934,6 @@ fn genCall(self: *Self, info: union(enum) { |
| 12330 | 19934 | }), |
| 12331 | 19935 | }; |
| 12332 | 19936 | const fn_info = zcu.typeToFunc(fn_ty).?; |
| 12333 | | const resolved_cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); |
| 12334 | 19937 | |
| 12335 | 19938 | const ExpectedContents = extern struct { |
| 12336 | 19939 | var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)), |
| ... | ... | @@ -12348,7 +19951,7 @@ fn genCall(self: *Self, info: union(enum) { |
| 12348 | 19951 | const frame_indices = try allocator.alloc(FrameIndex, args.len); |
| 12349 | 19952 | defer allocator.free(frame_indices); |
| 12350 | 19953 | |
| 12351 | | var reg_locks = std.ArrayList(?RegisterLock).init(allocator); |
| 19954 | var reg_locks: std.ArrayList(?RegisterLock) = .init(allocator); |
| 12352 | 19955 | defer reg_locks.deinit(); |
| 12353 | 19956 | try reg_locks.ensureTotalCapacity(16); |
| 12354 | 19957 | defer for (reg_locks.items) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -12358,7 +19961,7 @@ fn genCall(self: *Self, info: union(enum) { |
| 12358 | 19961 | |
| 12359 | 19962 | // We need a properly aligned and sized call frame to be able to call this function. |
| 12360 | 19963 | { |
| 12361 | | const needed_call_frame = FrameAlloc.init(.{ |
| 19964 | const needed_call_frame: FrameAlloc = .init(.{ |
| 12362 | 19965 | .size = call_info.stack_byte_count, |
| 12363 | 19966 | .alignment = call_info.stack_align, |
| 12364 | 19967 | }); |
| ... | ... | @@ -12372,7 +19975,7 @@ fn genCall(self: *Self, info: union(enum) { |
| 12372 | 19975 | } |
| 12373 | 19976 | |
| 12374 | 19977 | try self.spillEflagsIfOccupied(); |
| 12375 | | try self.spillCallerPreservedRegs(resolved_cc); |
| 19978 | try self.spillCallerPreservedRegs(fn_info.cc); |
| 12376 | 19979 | |
| 12377 | 19980 | // set stack arguments first because this can clobber registers |
| 12378 | 19981 | // also clobber spill arguments as we go |
| ... | ... | @@ -12393,13 +19996,13 @@ fn genCall(self: *Self, info: union(enum) { |
| 12393 | 19996 | try reg_locks.appendSlice(&self.register_manager.lockRegs(2, regs)); |
| 12394 | 19997 | }, |
| 12395 | 19998 | .indirect => |reg_off| { |
| 12396 | | frame_index.* = try self.allocFrameIndex(FrameAlloc.initType(arg_ty, zcu)); |
| 12397 | | try self.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, .{}); |
| 19999 | frame_index.* = try self.allocFrameIndex(.initType(arg_ty, zcu)); |
| 20000 | try self.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts); |
| 12398 | 20001 | try self.register_manager.getReg(reg_off.reg, null); |
| 12399 | 20002 | try reg_locks.append(self.register_manager.lockReg(reg_off.reg)); |
| 12400 | 20003 | }, |
| 12401 | 20004 | .load_frame => { |
| 12402 | | try self.genCopy(arg_ty, dst_arg, src_arg, .{}); |
| 20005 | try self.genCopy(arg_ty, dst_arg, src_arg, opts); |
| 12403 | 20006 | try self.freeValue(src_arg); |
| 12404 | 20007 | }, |
| 12405 | 20008 | .elementwise_regs_then_frame => |regs_frame_addr| { |
| ... | ... | @@ -12407,14 +20010,11 @@ fn genCall(self: *Self, info: union(enum) { |
| 12407 | 20010 | const index_lock = self.register_manager.lockRegAssumeUnused(index_reg); |
| 12408 | 20011 | defer self.register_manager.unlockReg(index_lock); |
| 12409 | 20012 | |
| 12410 | | const src_mem: Memory = if (src_arg.isMemory()) try src_arg.mem(self, .dword) else .{ |
| 12411 | | .base = .{ .reg = try self.copyToTmpRegister( |
| 12412 | | Type.usize, |
| 12413 | | switch (src_arg) { |
| 12414 | | else => src_arg, |
| 12415 | | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 12416 | | }.address(), |
| 12417 | | ) }, |
| 20013 | const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(self, .{ .size = .dword }) else .{ |
| 20014 | .base = .{ .reg = try self.copyToTmpRegister(.usize, switch (src_arg) { |
| 20015 | else => src_arg, |
| 20016 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 20017 | }.address()) }, |
| 12418 | 20018 | .mod = .{ .rm = .{ .size = .dword } }, |
| 12419 | 20019 | }; |
| 12420 | 20020 | const src_lock = switch (src_mem.base) { |
| ... | ... | @@ -12426,7 +20026,7 @@ fn genCall(self: *Self, info: union(enum) { |
| 12426 | 20026 | try self.asmRegisterImmediate( |
| 12427 | 20027 | .{ ._, .mov }, |
| 12428 | 20028 | index_reg.to32(), |
| 12429 | | Immediate.u(regs_frame_addr.regs), |
| 20029 | .u(regs_frame_addr.regs), |
| 12430 | 20030 | ); |
| 12431 | 20031 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 12432 | 20032 | try self.asmMemoryRegister(.{ ._, .bt }, src_mem, index_reg.to32()); |
| ... | ... | @@ -12440,18 +20040,18 @@ fn genCall(self: *Self, info: union(enum) { |
| 12440 | 20040 | } }, |
| 12441 | 20041 | }); |
| 12442 | 20042 | if (self.hasFeature(.slow_incdec)) { |
| 12443 | | try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), Immediate.u(1)); |
| 20043 | try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1)); |
| 12444 | 20044 | } else { |
| 12445 | 20045 | try self.asmRegister(.{ ._, .inc }, index_reg.to32()); |
| 12446 | 20046 | } |
| 12447 | 20047 | try self.asmRegisterImmediate( |
| 12448 | 20048 | .{ ._, .cmp }, |
| 12449 | 20049 | index_reg.to32(), |
| 12450 | | Immediate.u(arg_ty.vectorLen(zcu)), |
| 20050 | .u(arg_ty.vectorLen(zcu)), |
| 12451 | 20051 | ); |
| 12452 | 20052 | _ = try self.asmJccReloc(.b, loop); |
| 12453 | 20053 | |
| 12454 | | const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 20054 | const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); |
| 12455 | 20055 | for (param_int_regs[param_int_regs.len - regs_frame_addr.regs ..]) |dst_reg| { |
| 12456 | 20056 | try self.register_manager.getReg(dst_reg, null); |
| 12457 | 20057 | try reg_locks.append(self.register_manager.lockReg(dst_reg)); |
| ... | ... | @@ -12464,9 +20064,9 @@ fn genCall(self: *Self, info: union(enum) { |
| 12464 | 20064 | switch (call_info.return_value.long) { |
| 12465 | 20065 | .none, .unreach => {}, |
| 12466 | 20066 | .indirect => |reg_off| { |
| 12467 | | const ret_ty = Type.fromInterned(fn_info.return_type); |
| 12468 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ret_ty, zcu)); |
| 12469 | | try self.genSetReg(reg_off.reg, Type.usize, .{ |
| 20067 | const ret_ty: Type = .fromInterned(fn_info.return_type); |
| 20068 | const frame_index = try self.allocFrameIndex(.initSpill(ret_ty, zcu)); |
| 20069 | try self.genSetReg(reg_off.reg, .usize, .{ |
| 12470 | 20070 | .lea_frame = .{ .index = frame_index, .off = -reg_off.off }, |
| 12471 | 20071 | }, .{}); |
| 12472 | 20072 | call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } }; |
| ... | ... | @@ -12479,29 +20079,27 @@ fn genCall(self: *Self, info: union(enum) { |
| 12479 | 20079 | switch (dst_arg) { |
| 12480 | 20080 | .none, .load_frame => {}, |
| 12481 | 20081 | .register => |dst_reg| switch (fn_info.cc) { |
| 12482 | | else => try self.genSetReg( |
| 12483 | | registerAlias(dst_reg, @intCast(arg_ty.abiSize(zcu))), |
| 12484 | | arg_ty, |
| 12485 | | src_arg, |
| 12486 | | .{}, |
| 12487 | | ), |
| 20082 | else => try self.genSetReg(registerAlias( |
| 20083 | dst_reg, |
| 20084 | @intCast(arg_ty.abiSize(zcu)), |
| 20085 | ), arg_ty, src_arg, opts), |
| 12488 | 20086 | .x86_64_sysv, .x86_64_win => { |
| 12489 | 20087 | const promoted_ty = self.promoteInt(arg_ty); |
| 12490 | 20088 | const promoted_abi_size: u32 = @intCast(promoted_ty.abiSize(zcu)); |
| 12491 | 20089 | const dst_alias = registerAlias(dst_reg, promoted_abi_size); |
| 12492 | | try self.genSetReg(dst_alias, promoted_ty, src_arg, .{}); |
| 20090 | try self.genSetReg(dst_alias, promoted_ty, src_arg, opts); |
| 12493 | 20091 | if (promoted_ty.toIntern() != arg_ty.toIntern()) |
| 12494 | 20092 | try self.truncateRegister(arg_ty, dst_alias); |
| 12495 | 20093 | }, |
| 12496 | 20094 | }, |
| 12497 | | .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg, .{}), |
| 12498 | | .indirect => |reg_off| try self.genSetReg(reg_off.reg, Type.usize, .{ |
| 20095 | .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg, opts), |
| 20096 | .indirect => |reg_off| try self.genSetReg(reg_off.reg, .usize, .{ |
| 12499 | 20097 | .lea_frame = .{ .index = frame_index, .off = -reg_off.off }, |
| 12500 | 20098 | }, .{}), |
| 12501 | 20099 | .elementwise_regs_then_frame => |regs_frame_addr| { |
| 12502 | | const src_mem: Memory = if (src_arg.isMemory()) try src_arg.mem(self, .dword) else .{ |
| 20100 | const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(self, .{ .size = .dword }) else .{ |
| 12503 | 20101 | .base = .{ .reg = try self.copyToTmpRegister( |
| 12504 | | Type.usize, |
| 20102 | .usize, |
| 12505 | 20103 | switch (src_arg) { |
| 12506 | 20104 | else => src_arg, |
| 12507 | 20105 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| ... | ... | @@ -12515,25 +20113,20 @@ fn genCall(self: *Self, info: union(enum) { |
| 12515 | 20113 | }; |
| 12516 | 20114 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 12517 | 20115 | |
| 12518 | | const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 20116 | const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); |
| 12519 | 20117 | for ( |
| 12520 | 20118 | param_int_regs[param_int_regs.len - regs_frame_addr.regs ..], |
| 12521 | 20119 | 0.., |
| 12522 | 20120 | ) |dst_reg, elem_index| { |
| 12523 | 20121 | try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()); |
| 12524 | | try self.asmMemoryImmediate( |
| 12525 | | .{ ._, .bt }, |
| 12526 | | src_mem, |
| 12527 | | Immediate.u(elem_index), |
| 12528 | | ); |
| 20122 | try self.asmMemoryImmediate(.{ ._, .bt }, src_mem, .u(elem_index)); |
| 12529 | 20123 | try self.asmSetccRegister(.c, dst_reg.to8()); |
| 12530 | 20124 | } |
| 12531 | 20125 | }, |
| 12532 | 20126 | else => unreachable, |
| 12533 | 20127 | }; |
| 12534 | 20128 | |
| 12535 | | if (fn_info.is_var_args) |
| 12536 | | try self.asmRegisterImmediate(.{ ._, .mov }, .al, Immediate.u(call_info.fp_count)); |
| 20129 | if (fn_info.is_var_args) try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); |
| 12537 | 20130 | |
| 12538 | 20131 | // Due to incremental compilation, how function calls are generated depends |
| 12539 | 20132 | // on linking. |
| ... | ... | @@ -12551,17 +20144,18 @@ fn genCall(self: *Self, info: union(enum) { |
| 12551 | 20144 | if (self.bin_file.cast(.elf)) |elf_file| { |
| 12552 | 20145 | const zo = elf_file.zigObjectPtr().?; |
| 12553 | 20146 | const sym_index = try zo.getOrCreateMetadataForNav(zcu, func.owner_nav); |
| 12554 | | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym_index })); |
| 20147 | try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym_index })); |
| 12555 | 20148 | } else if (self.bin_file.cast(.coff)) |coff_file| { |
| 12556 | 20149 | const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); |
| 12557 | 20150 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; |
| 12558 | | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }, .{}); |
| 12559 | | try self.asmRegister(.{ ._, .call }, .rax); |
| 20151 | const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc); |
| 20152 | try self.genSetReg(scratch_reg, .usize, .{ .lea_got = sym_index }, .{}); |
| 20153 | try self.asmRegister(.{ ._, .call }, scratch_reg); |
| 12560 | 20154 | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 12561 | 20155 | const zo = macho_file.getZigObject().?; |
| 12562 | 20156 | const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav); |
| 12563 | 20157 | const sym = zo.symbols.items[sym_index]; |
| 12564 | | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym.nlist_idx })); |
| 20158 | try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym.nlist_idx })); |
| 12565 | 20159 | } else if (self.bin_file.cast(.plan9)) |p9| { |
| 12566 | 20160 | const atom_index = try p9.seeNav(pt, func.owner_nav); |
| 12567 | 20161 | const atom = p9.getAtom(atom_index); |
| ... | ... | @@ -12579,13 +20173,13 @@ fn genCall(self: *Self, info: union(enum) { |
| 12579 | 20173 | @"extern".name.toSlice(ip), |
| 12580 | 20174 | @"extern".lib_name.toSlice(ip), |
| 12581 | 20175 | ); |
| 12582 | | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); |
| 20176 | try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index })); |
| 12583 | 20177 | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 12584 | 20178 | const target_sym_index = try macho_file.getGlobalSymbol( |
| 12585 | 20179 | @"extern".name.toSlice(ip), |
| 12586 | 20180 | @"extern".lib_name.toSlice(ip), |
| 12587 | 20181 | ); |
| 12588 | | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); |
| 20182 | try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index })); |
| 12589 | 20183 | } else try self.genExternSymbolRef( |
| 12590 | 20184 | .call, |
| 12591 | 20185 | @"extern".lib_name.toSlice(ip), |
| ... | ... | @@ -12595,21 +20189,22 @@ fn genCall(self: *Self, info: union(enum) { |
| 12595 | 20189 | } |
| 12596 | 20190 | } else { |
| 12597 | 20191 | assert(self.typeOf(callee).zigTypeTag(zcu) == .pointer); |
| 12598 | | try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{}); |
| 12599 | | try self.asmRegister(.{ ._, .call }, .rax); |
| 20192 | const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc); |
| 20193 | try self.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, .{}); |
| 20194 | try self.asmRegister(.{ ._, .call }, scratch_reg); |
| 12600 | 20195 | }, |
| 12601 | 20196 | .lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| { |
| 12602 | 20197 | const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib); |
| 12603 | | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); |
| 20198 | try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index })); |
| 12604 | 20199 | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 12605 | 20200 | const target_sym_index = try macho_file.getGlobalSymbol(lib.callee, lib.lib); |
| 12606 | | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); |
| 20201 | try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index })); |
| 12607 | 20202 | } else try self.genExternSymbolRef(.call, lib.lib, lib.callee), |
| 12608 | 20203 | } |
| 12609 | 20204 | return call_info.return_value.short; |
| 12610 | 20205 | } |
| 12611 | 20206 | |
| 12612 | | fn airRet(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 20207 | fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { |
| 12613 | 20208 | const pt = self.pt; |
| 12614 | 20209 | const zcu = pt.zcu; |
| 12615 | 20210 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| ... | ... | @@ -12619,13 +20214,15 @@ fn airRet(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 12619 | 20214 | .none => {}, |
| 12620 | 20215 | .register, |
| 12621 | 20216 | .register_pair, |
| 20217 | .register_triple, |
| 20218 | .register_quadruple, |
| 12622 | 20219 | => try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }), |
| 12623 | 20220 | .indirect => |reg_off| { |
| 12624 | 20221 | try self.register_manager.getReg(reg_off.reg, null); |
| 12625 | 20222 | const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg); |
| 12626 | 20223 | defer self.register_manager.unlockReg(lock); |
| 12627 | 20224 | |
| 12628 | | try self.genSetReg(reg_off.reg, Type.usize, self.ret_mcv.long, .{}); |
| 20225 | try self.genSetReg(reg_off.reg, .usize, self.ret_mcv.long, .{}); |
| 12629 | 20226 | try self.genSetMem( |
| 12630 | 20227 | .{ .reg = reg_off.reg }, |
| 12631 | 20228 | reg_off.off, |
| ... | ... | @@ -12642,10 +20239,10 @@ fn airRet(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 12642 | 20239 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction |
| 12643 | 20240 | // which is available if the jump is 127 bytes or less forward. |
| 12644 | 20241 | const jmp_reloc = try self.asmJmpReloc(undefined); |
| 12645 | | try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); |
| 20242 | try self.epilogue_relocs.append(self.gpa, jmp_reloc); |
| 12646 | 20243 | } |
| 12647 | 20244 | |
| 12648 | | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 20245 | fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 12649 | 20246 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 12650 | 20247 | const ptr = try self.resolveInst(un_op); |
| 12651 | 20248 | |
| ... | ... | @@ -12662,10 +20259,10 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 12662 | 20259 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction |
| 12663 | 20260 | // which is available if the jump is 127 bytes or less forward. |
| 12664 | 20261 | const jmp_reloc = try self.asmJmpReloc(undefined); |
| 12665 | | try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); |
| 20262 | try self.epilogue_relocs.append(self.gpa, jmp_reloc); |
| 12666 | 20263 | } |
| 12667 | 20264 | |
| 12668 | | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 20265 | fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !void { |
| 12669 | 20266 | const pt = self.pt; |
| 12670 | 20267 | const zcu = pt.zcu; |
| 12671 | 20268 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -12686,7 +20283,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12686 | 20283 | self.register_manager.lockRegAssumeUnused(lhs_ro.reg), |
| 12687 | 20284 | null, |
| 12688 | 20285 | }, |
| 12689 | | else => .{null} ** 2, |
| 20286 | else => @splat(null), |
| 12690 | 20287 | }; |
| 12691 | 20288 | defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 12692 | 20289 | |
| ... | ... | @@ -12695,7 +20292,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12695 | 20292 | .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null }, |
| 12696 | 20293 | .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs), |
| 12697 | 20294 | .register_offset => |rhs_ro| .{ self.register_manager.lockReg(rhs_ro.reg), null }, |
| 12698 | | else => .{null} ** 2, |
| 20295 | else => @splat(null), |
| 12699 | 20296 | }; |
| 12700 | 20297 | defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 12701 | 20298 | |
| ... | ... | @@ -12723,8 +20320,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12723 | 20320 | }, |
| 12724 | 20321 | floatCompilerRtAbiName(float_bits), |
| 12725 | 20322 | }) catch unreachable, |
| 12726 | | } }, &.{ ty, ty }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } }); |
| 12727 | | try self.genBinOpMir(.{ ._, .@"test" }, Type.i32, ret, ret); |
| 20323 | } }, &.{ ty, ty }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } }, .{}); |
| 20324 | try self.genBinOpMir(.{ ._, .@"test" }, .i32, ret, ret); |
| 12728 | 20325 | break :result switch (op) { |
| 12729 | 20326 | .eq => .e, |
| 12730 | 20327 | .neq => .ne, |
| ... | ... | @@ -12745,23 +20342,23 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12745 | 20342 | const temp_lhs_lock = self.register_manager.lockRegAssumeUnused(temp_lhs_reg); |
| 12746 | 20343 | defer self.register_manager.unlockReg(temp_lhs_lock); |
| 12747 | 20344 | |
| 12748 | | if (lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 20345 | if (lhs_mcv.isBase()) try self.asmRegisterMemory( |
| 12749 | 20346 | .{ ._, .mov }, |
| 12750 | 20347 | temp_lhs_reg.to8(), |
| 12751 | | try lhs_mcv.address().offset(payload_abi_size).deref().mem(self, .byte), |
| 20348 | try lhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte }), |
| 12752 | 20349 | ) else { |
| 12753 | 20350 | try self.genSetReg(temp_lhs_reg, opt_ty, lhs_mcv, .{}); |
| 12754 | 20351 | try self.asmRegisterImmediate( |
| 12755 | 20352 | .{ ._r, .sh }, |
| 12756 | 20353 | registerAlias(temp_lhs_reg, opt_abi_size), |
| 12757 | | Immediate.u(payload_abi_size * 8), |
| 20354 | .u(payload_abi_size * 8), |
| 12758 | 20355 | ); |
| 12759 | 20356 | } |
| 12760 | 20357 | |
| 12761 | 20358 | const payload_compare = payload_compare: { |
| 12762 | | if (rhs_mcv.isMemory()) { |
| 20359 | if (rhs_mcv.isBase()) { |
| 12763 | 20360 | const rhs_mem = |
| 12764 | | try rhs_mcv.address().offset(payload_abi_size).deref().mem(self, .byte); |
| 20361 | try rhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte }); |
| 12765 | 20362 | try self.asmMemoryRegister(.{ ._, .@"test" }, rhs_mem, temp_lhs_reg.to8()); |
| 12766 | 20363 | const payload_compare = try self.asmJccReloc(.nz, undefined); |
| 12767 | 20364 | try self.asmRegisterMemory(.{ ._, .cmp }, temp_lhs_reg.to8(), rhs_mem); |
| ... | ... | @@ -12775,7 +20372,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12775 | 20372 | try self.asmRegisterImmediate( |
| 12776 | 20373 | .{ ._r, .sh }, |
| 12777 | 20374 | registerAlias(temp_rhs_reg, opt_abi_size), |
| 12778 | | Immediate.u(payload_abi_size * 8), |
| 20375 | .u(payload_abi_size * 8), |
| 12779 | 20376 | ); |
| 12780 | 20377 | try self.asmRegisterRegister( |
| 12781 | 20378 | .{ ._, .@"test" }, |
| ... | ... | @@ -12810,13 +20407,13 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12810 | 20407 | } else .may_flip; |
| 12811 | 20408 | |
| 12812 | 20409 | const flipped = switch (may_flip) { |
| 12813 | | .may_flip => !lhs_mcv.isRegister() and !lhs_mcv.isMemory(), |
| 20410 | .may_flip => !lhs_mcv.isRegister() and !lhs_mcv.isBase(), |
| 12814 | 20411 | .must_flip => true, |
| 12815 | 20412 | .must_not_flip => false, |
| 12816 | 20413 | }; |
| 12817 | 20414 | const unmat_dst_mcv = if (flipped) rhs_mcv else lhs_mcv; |
| 12818 | 20415 | const dst_mcv = if (unmat_dst_mcv.isRegister() or |
| 12819 | | (abi_size <= 8 and unmat_dst_mcv.isMemory())) unmat_dst_mcv else dst: { |
| 20416 | (abi_size <= 8 and unmat_dst_mcv.isBase())) unmat_dst_mcv else dst: { |
| 12820 | 20417 | const dst_mcv = try self.allocTempRegOrMem(ty, true); |
| 12821 | 20418 | try self.genCopy(ty, dst_mcv, unmat_dst_mcv, .{}); |
| 12822 | 20419 | break :dst dst_mcv; |
| ... | ... | @@ -12830,7 +20427,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12830 | 20427 | if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 12831 | 20428 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 12832 | 20429 | |
| 12833 | | break :result Condition.fromCompareOperator( |
| 20430 | break :result .fromCompareOperator( |
| 12834 | 20431 | if (ty.isAbiInt(zcu)) ty.intInfo(zcu).signedness else .unsigned, |
| 12835 | 20432 | result_op: { |
| 12836 | 20433 | const flipped_op = if (flipped) op.reverse() else op; |
| ... | ... | @@ -12851,9 +20448,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12851 | 20448 | .undef, |
| 12852 | 20449 | .immediate, |
| 12853 | 20450 | .eflags, |
| 12854 | | .register, |
| 12855 | 20451 | .register_offset, |
| 12856 | 20452 | .register_overflow, |
| 20453 | .register_mask, |
| 12857 | 20454 | .indirect, |
| 12858 | 20455 | .lea_direct, |
| 12859 | 20456 | .lea_got, |
| ... | ... | @@ -12864,13 +20461,13 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12864 | 20461 | .reserved_frame, |
| 12865 | 20462 | .air_ref, |
| 12866 | 20463 | => unreachable, |
| 12867 | | .register_pair, .load_frame => null, |
| 20464 | .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null, |
| 12868 | 20465 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: { |
| 12869 | 20466 | switch (resolved_dst_mcv) { |
| 12870 | | .memory => |addr| if (math.cast( |
| 20467 | .memory => |addr| if (std.math.cast( |
| 12871 | 20468 | i32, |
| 12872 | 20469 | @as(i64, @bitCast(addr)), |
| 12873 | | ) != null and math.cast( |
| 20470 | ) != null and std.math.cast( |
| 12874 | 20471 | i32, |
| 12875 | 20472 | @as(i64, @bitCast(addr)) + abi_size - 8, |
| 12876 | 20473 | ) != null) break :dst null, |
| ... | ... | @@ -12886,20 +20483,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12886 | 20483 | self.register_manager.lockRegAssumeUnused(dst_addr_reg); |
| 12887 | 20484 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| 12888 | 20485 | |
| 12889 | | try self.genSetReg( |
| 12890 | | dst_addr_reg, |
| 12891 | | Type.usize, |
| 12892 | | resolved_dst_mcv.address(), |
| 12893 | | .{}, |
| 12894 | | ); |
| 20486 | try self.genSetReg(dst_addr_reg, .usize, resolved_dst_mcv.address(), .{}); |
| 12895 | 20487 | break :dst .{ |
| 12896 | 20488 | .addr_reg = dst_addr_reg, |
| 12897 | 20489 | .addr_lock = dst_addr_lock, |
| 12898 | 20490 | }; |
| 12899 | 20491 | }, |
| 12900 | 20492 | }; |
| 12901 | | defer if (dst_info) |info| |
| 12902 | | self.register_manager.unlockReg(info.addr_lock); |
| 20493 | defer if (dst_info) |info| self.register_manager.unlockReg(info.addr_lock); |
| 12903 | 20494 | |
| 12904 | 20495 | const resolved_src_mcv = switch (src_mcv) { |
| 12905 | 20496 | else => src_mcv, |
| ... | ... | @@ -12915,6 +20506,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12915 | 20506 | .register, |
| 12916 | 20507 | .register_offset, |
| 12917 | 20508 | .register_overflow, |
| 20509 | .register_mask, |
| 12918 | 20510 | .indirect, |
| 12919 | 20511 | .lea_symbol, |
| 12920 | 20512 | .lea_direct, |
| ... | ... | @@ -12925,13 +20517,13 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12925 | 20517 | .reserved_frame, |
| 12926 | 20518 | .air_ref, |
| 12927 | 20519 | => unreachable, |
| 12928 | | .register_pair, .load_frame => null, |
| 20520 | .register_pair, .register_triple, .register_quadruple, .load_frame => null, |
| 12929 | 20521 | .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: { |
| 12930 | 20522 | switch (resolved_src_mcv) { |
| 12931 | | .memory => |addr| if (math.cast( |
| 20523 | .memory => |addr| if (std.math.cast( |
| 12932 | 20524 | i32, |
| 12933 | 20525 | @as(i64, @bitCast(addr)), |
| 12934 | | ) != null and math.cast( |
| 20526 | ) != null and std.math.cast( |
| 12935 | 20527 | i32, |
| 12936 | 20528 | @as(i64, @bitCast(addr)) + abi_size - 8, |
| 12937 | 20529 | ) != null) break :src null, |
| ... | ... | @@ -12947,12 +20539,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12947 | 20539 | self.register_manager.lockRegAssumeUnused(src_addr_reg); |
| 12948 | 20540 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 12949 | 20541 | |
| 12950 | | try self.genSetReg( |
| 12951 | | src_addr_reg, |
| 12952 | | Type.usize, |
| 12953 | | resolved_src_mcv.address(), |
| 12954 | | .{}, |
| 12955 | | ); |
| 20542 | try self.genSetReg(src_addr_reg, .usize, resolved_src_mcv.address(), .{}); |
| 12956 | 20543 | break :src .{ |
| 12957 | 20544 | .addr_reg = src_addr_reg, |
| 12958 | 20545 | .addr_lock = src_addr_lock, |
| ... | ... | @@ -12962,25 +20549,24 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12962 | 20549 | defer if (src_info) |info| |
| 12963 | 20550 | self.register_manager.unlockReg(info.addr_lock); |
| 12964 | 20551 | |
| 12965 | | const regs = try self.register_manager.allocRegs( |
| 12966 | | 2, |
| 12967 | | .{null} ** 2, |
| 12968 | | abi.RegisterClass.gp, |
| 12969 | | ); |
| 20552 | const regs = try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp); |
| 12970 | 20553 | const acc_reg = regs[0].to64(); |
| 12971 | 20554 | const locks = self.register_manager.lockRegsAssumeUnused(2, regs); |
| 12972 | 20555 | defer for (locks) |lock| self.register_manager.unlockReg(lock); |
| 12973 | 20556 | |
| 12974 | | const limbs_len = math.divCeil(u16, abi_size, 8) catch unreachable; |
| 20557 | const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable; |
| 12975 | 20558 | var limb_i: u16 = 0; |
| 12976 | 20559 | while (limb_i < limbs_len) : (limb_i += 1) { |
| 12977 | 20560 | const off = limb_i * 8; |
| 12978 | 20561 | const tmp_reg = regs[@min(limb_i, 1)].to64(); |
| 12979 | 20562 | |
| 12980 | | try self.genSetReg(tmp_reg, Type.usize, if (dst_info) |info| .{ |
| 20563 | try self.genSetReg(tmp_reg, .usize, if (dst_info) |info| .{ |
| 12981 | 20564 | .indirect = .{ .reg = info.addr_reg, .off = off }, |
| 12982 | 20565 | } else switch (resolved_dst_mcv) { |
| 12983 | | .register_pair => |dst_regs| .{ .register = dst_regs[limb_i] }, |
| 20566 | inline .register_pair, |
| 20567 | .register_triple, |
| 20568 | .register_quadruple, |
| 20569 | => |dst_regs| .{ .register = dst_regs[limb_i] }, |
| 12984 | 20570 | .memory => |dst_addr| .{ |
| 12985 | 20571 | .memory = @bitCast(@as(i64, @bitCast(dst_addr)) + off), |
| 12986 | 20572 | }, |
| ... | ... | @@ -12997,14 +20583,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12997 | 20583 | |
| 12998 | 20584 | try self.genBinOpMir( |
| 12999 | 20585 | .{ ._, .xor }, |
| 13000 | | Type.usize, |
| 20586 | .usize, |
| 13001 | 20587 | .{ .register = tmp_reg }, |
| 13002 | 20588 | if (src_info) |info| .{ |
| 13003 | 20589 | .indirect = .{ .reg = info.addr_reg, .off = off }, |
| 13004 | 20590 | } else switch (resolved_src_mcv) { |
| 13005 | | .register_pair => |src_regs| .{ |
| 13006 | | .register = src_regs[limb_i], |
| 13007 | | }, |
| 20591 | inline .register_pair, |
| 20592 | .register_triple, |
| 20593 | .register_quadruple, |
| 20594 | => |src_regs| .{ .register = src_regs[limb_i] }, |
| 13008 | 20595 | .memory => |src_addr| .{ |
| 13009 | 20596 | .memory = @bitCast(@as(i64, @bitCast(src_addr)) + off), |
| 13010 | 20597 | }, |
| ... | ... | @@ -13062,12 +20649,12 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 13062 | 20649 | const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg); |
| 13063 | 20650 | defer self.register_manager.unlockReg(tmp2_lock); |
| 13064 | 20651 | |
| 13065 | | if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 20652 | if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 13066 | 20653 | .{ .vp_w, .insr }, |
| 13067 | 20654 | tmp1_reg, |
| 13068 | 20655 | dst_reg.to128(), |
| 13069 | | try src_mcv.mem(self, .word), |
| 13070 | | Immediate.u(1), |
| 20656 | try src_mcv.mem(self, .{ .size = .word }), |
| 20657 | .u(1), |
| 13071 | 20658 | ) else try self.asmRegisterRegisterRegister( |
| 13072 | 20659 | .{ .vp_, .unpcklwd }, |
| 13073 | 20660 | tmp1_reg, |
| ... | ... | @@ -13112,19 +20699,19 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 13112 | 20699 | return self.finishAir(inst, .{ .eflags = result }, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 13113 | 20700 | } |
| 13114 | 20701 | |
| 13115 | | fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { |
| 20702 | fn airCmpVector(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13116 | 20703 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 13117 | 20704 | const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data; |
| 13118 | 20705 | const dst_mcv = try self.genBinOp( |
| 13119 | 20706 | inst, |
| 13120 | | Air.Inst.Tag.fromCmpOp(extra.compareOperator(), false), |
| 20707 | .fromCmpOp(extra.compareOperator(), false), |
| 13121 | 20708 | extra.lhs, |
| 13122 | 20709 | extra.rhs, |
| 13123 | 20710 | ); |
| 13124 | 20711 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 13125 | 20712 | } |
| 13126 | 20713 | |
| 13127 | | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 20714 | fn airCmpLtErrorsLen(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13128 | 20715 | const pt = self.pt; |
| 13129 | 20716 | const zcu = pt.zcu; |
| 13130 | 20717 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| ... | ... | @@ -13149,7 +20736,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 13149 | 20736 | registerAlias(dst_reg, op_abi_size), |
| 13150 | 20737 | .{ |
| 13151 | 20738 | .base = .{ .reg = addr_reg }, |
| 13152 | | .mod = .{ .rm = .{ .size = Memory.Size.fromSize(op_abi_size) } }, |
| 20739 | .mod = .{ .rm = .{ .size = .fromSize(op_abi_size) } }, |
| 13153 | 20740 | }, |
| 13154 | 20741 | ); |
| 13155 | 20742 | |
| ... | ... | @@ -13157,7 +20744,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 13157 | 20744 | return self.finishAir(inst, .{ .eflags = .b }, .{ un_op, .none, .none }); |
| 13158 | 20745 | } |
| 13159 | 20746 | |
| 13160 | | fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 20747 | fn airTry(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13161 | 20748 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 13162 | 20749 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 13163 | 20750 | const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); |
| ... | ... | @@ -13166,7 +20753,7 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 13166 | 20753 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 13167 | 20754 | } |
| 13168 | 20755 | |
| 13169 | | fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 20756 | fn airTryPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13170 | 20757 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 13171 | 20758 | const extra = self.air.extraData(Air.TryPtr, ty_pl.payload); |
| 13172 | 20759 | const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); |
| ... | ... | @@ -13176,7 +20763,7 @@ fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13176 | 20763 | } |
| 13177 | 20764 | |
| 13178 | 20765 | fn genTry( |
| 13179 | | self: *Self, |
| 20766 | self: *CodeGen, |
| 13180 | 20767 | inst: Air.Inst.Index, |
| 13181 | 20768 | operand: Air.Inst.Ref, |
| 13182 | 20769 | body: []const Air.Inst.Index, |
| ... | ... | @@ -13191,7 +20778,7 @@ fn genTry( |
| 13191 | 20778 | else |
| 13192 | 20779 | try self.isErr(null, operand_ty, operand_mcv); |
| 13193 | 20780 | |
| 13194 | | const reloc = try self.genCondBrMir(Type.anyerror, is_err_mcv); |
| 20781 | const reloc = try self.genCondBrMir(.anyerror, is_err_mcv); |
| 13195 | 20782 | |
| 13196 | 20783 | if (self.liveness.operandDies(inst, 0)) { |
| 13197 | 20784 | if (operand.toIndex()) |operand_inst| try self.processDeath(operand_inst); |
| ... | ... | @@ -13222,7 +20809,7 @@ fn genTry( |
| 13222 | 20809 | return result; |
| 13223 | 20810 | } |
| 13224 | 20811 | |
| 13225 | | fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 20812 | fn airDbgStmt(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13226 | 20813 | const dbg_stmt = self.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; |
| 13227 | 20814 | _ = try self.addInst(.{ |
| 13228 | 20815 | .tag = .pseudo, |
| ... | ... | @@ -13232,18 +20819,16 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 13232 | 20819 | .column = dbg_stmt.column, |
| 13233 | 20820 | } }, |
| 13234 | 20821 | }); |
| 13235 | | self.finishAirBookkeeping(); |
| 13236 | 20822 | } |
| 13237 | 20823 | |
| 13238 | | fn airDbgEmptyStmt(self: *Self) !void { |
| 20824 | fn airDbgEmptyStmt(self: *CodeGen) !void { |
| 13239 | 20825 | if (self.mir_instructions.len > 0 and |
| 13240 | 20826 | self.mir_instructions.items(.ops)[self.mir_instructions.len - 1] == .pseudo_dbg_line_stmt_line_column) |
| 13241 | 20827 | self.mir_instructions.items(.ops)[self.mir_instructions.len - 1] = .pseudo_dbg_line_line_column; |
| 13242 | 20828 | try self.asmOpOnly(.{ ._, .nop }); |
| 13243 | | self.finishAirBookkeeping(); |
| 13244 | 20829 | } |
| 13245 | 20830 | |
| 13246 | | fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 20831 | fn airDbgInlineBlock(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13247 | 20832 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 13248 | 20833 | const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); |
| 13249 | 20834 | const old_inline_func = self.inline_func; |
| ... | ... | @@ -13262,13 +20847,13 @@ fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 13262 | 20847 | }); |
| 13263 | 20848 | } |
| 13264 | 20849 | |
| 13265 | | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 20850 | fn airDbgVar(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13266 | 20851 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 13267 | 20852 | try self.genLocalDebugInfo(inst, try self.resolveInst(pl_op.operand)); |
| 13268 | 20853 | return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); |
| 13269 | 20854 | } |
| 13270 | 20855 | |
| 13271 | | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index { |
| 20856 | fn genCondBrMir(self: *CodeGen, ty: Type, mcv: MCValue) !Mir.Inst.Index { |
| 13272 | 20857 | const pt = self.pt; |
| 13273 | 20858 | const abi_size = ty.abiSize(pt.zcu); |
| 13274 | 20859 | switch (mcv) { |
| ... | ... | @@ -13278,7 +20863,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index { |
| 13278 | 20863 | }, |
| 13279 | 20864 | .register => |reg| { |
| 13280 | 20865 | try self.spillEflagsIfOccupied(); |
| 13281 | | try self.asmRegisterImmediate(.{ ._, .@"test" }, reg.to8(), Immediate.u(1)); |
| 20866 | try self.asmRegisterImmediate(.{ ._, .@"test" }, reg.to8(), .u(1)); |
| 13282 | 20867 | return self.asmJccReloc(.z, undefined); |
| 13283 | 20868 | }, |
| 13284 | 20869 | .immediate, |
| ... | ... | @@ -13295,7 +20880,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index { |
| 13295 | 20880 | } |
| 13296 | 20881 | } |
| 13297 | 20882 | |
| 13298 | | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 20883 | fn airCondBr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13299 | 20884 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 13300 | 20885 | const cond = try self.resolveInst(pl_op.operand); |
| 13301 | 20886 | const cond_ty = self.typeOf(pl_op.operand); |
| ... | ... | @@ -13338,10 +20923,9 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 13338 | 20923 | }); |
| 13339 | 20924 | |
| 13340 | 20925 | // We already took care of pl_op.operand earlier, so there's nothing left to do. |
| 13341 | | self.finishAirBookkeeping(); |
| 13342 | 20926 | } |
| 13343 | 20927 | |
| 13344 | | fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue { |
| 20928 | fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue { |
| 13345 | 20929 | const pt = self.pt; |
| 13346 | 20930 | const zcu = pt.zcu; |
| 13347 | 20931 | switch (opt_mcv) { |
| ... | ... | @@ -13353,10 +20937,10 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 13353 | 20937 | |
| 13354 | 20938 | const pl_ty = opt_ty.optionalChild(zcu); |
| 13355 | 20939 | |
| 13356 | | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(zcu)) |
| 20940 | const some_info: struct { off: u31, ty: Type } = if (opt_ty.optionalReprIsPayload(zcu)) |
| 13357 | 20941 | .{ .off = 0, .ty = if (pl_ty.isSlice(zcu)) pl_ty.slicePtrFieldType(zcu) else pl_ty } |
| 13358 | 20942 | else |
| 13359 | | .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = Type.bool }; |
| 20943 | .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = .bool }; |
| 13360 | 20944 | |
| 13361 | 20945 | self.eflags_inst = inst; |
| 13362 | 20946 | switch (opt_mcv) { |
| ... | ... | @@ -13366,9 +20950,11 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 13366 | 20950 | .undef, |
| 13367 | 20951 | .immediate, |
| 13368 | 20952 | .eflags, |
| 13369 | | .register_pair, |
| 20953 | .register_triple, |
| 20954 | .register_quadruple, |
| 13370 | 20955 | .register_offset, |
| 13371 | 20956 | .register_overflow, |
| 20957 | .register_mask, |
| 13372 | 20958 | .lea_direct, |
| 13373 | 20959 | .lea_got, |
| 13374 | 20960 | .lea_tlv, |
| ... | ... | @@ -13396,7 +20982,25 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 13396 | 20982 | try self.asmRegisterImmediate( |
| 13397 | 20983 | .{ ._, .bt }, |
| 13398 | 20984 | registerAlias(opt_reg, opt_abi_size), |
| 13399 | | Immediate.u(@as(u6, @intCast(some_info.off * 8))), |
| 20985 | .u(@as(u6, @intCast(some_info.off * 8))), |
| 20986 | ); |
| 20987 | return .{ .eflags = .nc }; |
| 20988 | }, |
| 20989 | |
| 20990 | .register_pair => |opt_regs| { |
| 20991 | if (some_info.off == 0) { |
| 20992 | const some_abi_size: u32 = @intCast(some_info.ty.abiSize(zcu)); |
| 20993 | const alias_reg = registerAlias(opt_regs[0], some_abi_size); |
| 20994 | assert(some_abi_size * 8 == alias_reg.bitSize()); |
| 20995 | try self.asmRegisterRegister(.{ ._, .@"test" }, alias_reg, alias_reg); |
| 20996 | return .{ .eflags = .z }; |
| 20997 | } |
| 20998 | assert(some_info.ty.ip_index == .bool_type); |
| 20999 | const opt_abi_size: u32 = @intCast(opt_ty.abiSize(zcu)); |
| 21000 | try self.asmRegisterImmediate( |
| 21001 | .{ ._, .bt }, |
| 21002 | registerAlias(opt_regs[some_info.off / 8], opt_abi_size), |
| 21003 | .u(@as(u6, @truncate(some_info.off * 8))), |
| 13400 | 21004 | ); |
| 13401 | 21005 | return .{ .eflags = .nc }; |
| 13402 | 21006 | }, |
| ... | ... | @@ -13411,18 +21015,18 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 13411 | 21015 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 13412 | 21016 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 13413 | 21017 | |
| 13414 | | try self.genSetReg(addr_reg, Type.usize, opt_mcv.address(), .{}); |
| 21018 | try self.genSetReg(addr_reg, .usize, opt_mcv.address(), .{}); |
| 13415 | 21019 | const some_abi_size: u32 = @intCast(some_info.ty.abiSize(zcu)); |
| 13416 | 21020 | try self.asmMemoryImmediate( |
| 13417 | 21021 | .{ ._, .cmp }, |
| 13418 | 21022 | .{ |
| 13419 | 21023 | .base = .{ .reg = addr_reg }, |
| 13420 | 21024 | .mod = .{ .rm = .{ |
| 13421 | | .size = Memory.Size.fromSize(some_abi_size), |
| 21025 | .size = .fromSize(some_abi_size), |
| 13422 | 21026 | .disp = some_info.off, |
| 13423 | 21027 | } }, |
| 13424 | 21028 | }, |
| 13425 | | Immediate.u(0), |
| 21029 | .u(0), |
| 13426 | 21030 | ); |
| 13427 | 21031 | return .{ .eflags = .e }; |
| 13428 | 21032 | }, |
| ... | ... | @@ -13435,27 +21039,27 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 13435 | 21039 | .indirect => |reg_off| .{ |
| 13436 | 21040 | .base = .{ .reg = reg_off.reg }, |
| 13437 | 21041 | .mod = .{ .rm = .{ |
| 13438 | | .size = Memory.Size.fromSize(some_abi_size), |
| 21042 | .size = .fromSize(some_abi_size), |
| 13439 | 21043 | .disp = reg_off.off + some_info.off, |
| 13440 | 21044 | } }, |
| 13441 | 21045 | }, |
| 13442 | 21046 | .load_frame => |frame_addr| .{ |
| 13443 | 21047 | .base = .{ .frame = frame_addr.index }, |
| 13444 | 21048 | .mod = .{ .rm = .{ |
| 13445 | | .size = Memory.Size.fromSize(some_abi_size), |
| 21049 | .size = .fromSize(some_abi_size), |
| 13446 | 21050 | .disp = frame_addr.off + some_info.off, |
| 13447 | 21051 | } }, |
| 13448 | 21052 | }, |
| 13449 | 21053 | else => unreachable, |
| 13450 | 21054 | }, |
| 13451 | | Immediate.u(0), |
| 21055 | .u(0), |
| 13452 | 21056 | ); |
| 13453 | 21057 | return .{ .eflags = .e }; |
| 13454 | 21058 | }, |
| 13455 | 21059 | } |
| 13456 | 21060 | } |
| 13457 | 21061 | |
| 13458 | | fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 21062 | fn isNullPtr(self: *CodeGen, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 13459 | 21063 | const pt = self.pt; |
| 13460 | 21064 | const zcu = pt.zcu; |
| 13461 | 21065 | const opt_ty = ptr_ty.childType(zcu); |
| ... | ... | @@ -13466,7 +21070,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) |
| 13466 | 21070 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(zcu)) |
| 13467 | 21071 | .{ .off = 0, .ty = if (pl_ty.isSlice(zcu)) pl_ty.slicePtrFieldType(zcu) else pl_ty } |
| 13468 | 21072 | else |
| 13469 | | .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = Type.bool }; |
| 21073 | .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = .bool }; |
| 13470 | 21074 | |
| 13471 | 21075 | const ptr_reg = switch (ptr_mcv) { |
| 13472 | 21076 | .register => |reg| reg, |
| ... | ... | @@ -13481,18 +21085,18 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) |
| 13481 | 21085 | .{ |
| 13482 | 21086 | .base = .{ .reg = ptr_reg }, |
| 13483 | 21087 | .mod = .{ .rm = .{ |
| 13484 | | .size = Memory.Size.fromSize(some_abi_size), |
| 21088 | .size = .fromSize(some_abi_size), |
| 13485 | 21089 | .disp = some_info.off, |
| 13486 | 21090 | } }, |
| 13487 | 21091 | }, |
| 13488 | | Immediate.u(0), |
| 21092 | .u(0), |
| 13489 | 21093 | ); |
| 13490 | 21094 | |
| 13491 | 21095 | self.eflags_inst = inst; |
| 13492 | 21096 | return .{ .eflags = .e }; |
| 13493 | 21097 | } |
| 13494 | 21098 | |
| 13495 | | fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { |
| 21099 | fn isErr(self: *CodeGen, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { |
| 13496 | 21100 | const pt = self.pt; |
| 13497 | 21101 | const zcu = pt.zcu; |
| 13498 | 21102 | const err_ty = eu_ty.errorUnionSet(zcu); |
| ... | ... | @@ -13500,7 +21104,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) |
| 13500 | 21104 | |
| 13501 | 21105 | try self.spillEflagsIfOccupied(); |
| 13502 | 21106 | |
| 13503 | | const err_off: u31 = @intCast(errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu)); |
| 21107 | const err_off: u31 = @intCast(codegen.errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu)); |
| 13504 | 21108 | switch (eu_mcv) { |
| 13505 | 21109 | .register => |reg| { |
| 13506 | 21110 | const eu_lock = self.register_manager.lockReg(reg); |
| ... | ... | @@ -13512,22 +21116,17 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) |
| 13512 | 21116 | .{ ._r, .sh }, |
| 13513 | 21117 | eu_ty, |
| 13514 | 21118 | .{ .register = tmp_reg }, |
| 13515 | | Type.u8, |
| 21119 | .u8, |
| 13516 | 21120 | .{ .immediate = @as(u6, @intCast(err_off * 8)) }, |
| 13517 | 21121 | ); |
| 13518 | 21122 | } else { |
| 13519 | | try self.truncateRegister(Type.anyerror, tmp_reg); |
| 21123 | try self.truncateRegister(.anyerror, tmp_reg); |
| 13520 | 21124 | } |
| 13521 | | try self.genBinOpMir( |
| 13522 | | .{ ._, .cmp }, |
| 13523 | | Type.anyerror, |
| 13524 | | .{ .register = tmp_reg }, |
| 13525 | | .{ .immediate = 0 }, |
| 13526 | | ); |
| 21125 | try self.genBinOpMir(.{ ._, .cmp }, .anyerror, .{ .register = tmp_reg }, .{ .immediate = 0 }); |
| 13527 | 21126 | }, |
| 13528 | 21127 | .load_frame => |frame_addr| try self.genBinOpMir( |
| 13529 | 21128 | .{ ._, .cmp }, |
| 13530 | | Type.anyerror, |
| 21129 | .anyerror, |
| 13531 | 21130 | .{ .load_frame = .{ |
| 13532 | 21131 | .index = frame_addr.index, |
| 13533 | 21132 | .off = frame_addr.off + err_off, |
| ... | ... | @@ -13541,7 +21140,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) |
| 13541 | 21140 | return MCValue{ .eflags = .a }; |
| 13542 | 21141 | } |
| 13543 | 21142 | |
| 13544 | | fn isErrPtr(self: *Self, maybe_inst: ?Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 21143 | fn isErrPtr(self: *CodeGen, maybe_inst: ?Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 13545 | 21144 | const pt = self.pt; |
| 13546 | 21145 | const zcu = pt.zcu; |
| 13547 | 21146 | const eu_ty = ptr_ty.childType(zcu); |
| ... | ... | @@ -13557,24 +21156,24 @@ fn isErrPtr(self: *Self, maybe_inst: ?Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCV |
| 13557 | 21156 | const ptr_lock = self.register_manager.lockReg(ptr_reg); |
| 13558 | 21157 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 13559 | 21158 | |
| 13560 | | const err_off: u31 = @intCast(errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu)); |
| 21159 | const err_off: u31 = @intCast(codegen.errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu)); |
| 13561 | 21160 | try self.asmMemoryImmediate( |
| 13562 | 21161 | .{ ._, .cmp }, |
| 13563 | 21162 | .{ |
| 13564 | 21163 | .base = .{ .reg = ptr_reg }, |
| 13565 | 21164 | .mod = .{ .rm = .{ |
| 13566 | | .size = self.memSize(Type.anyerror), |
| 21165 | .size = self.memSize(.anyerror), |
| 13567 | 21166 | .disp = err_off, |
| 13568 | 21167 | } }, |
| 13569 | 21168 | }, |
| 13570 | | Immediate.u(0), |
| 21169 | .u(0), |
| 13571 | 21170 | ); |
| 13572 | 21171 | |
| 13573 | 21172 | if (maybe_inst) |inst| self.eflags_inst = inst; |
| 13574 | 21173 | return MCValue{ .eflags = .a }; |
| 13575 | 21174 | } |
| 13576 | 21175 | |
| 13577 | | fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { |
| 21176 | fn isNonErr(self: *CodeGen, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { |
| 13578 | 21177 | const is_err_res = try self.isErr(inst, eu_ty, eu_mcv); |
| 13579 | 21178 | switch (is_err_res) { |
| 13580 | 21179 | .eflags => |cc| { |
| ... | ... | @@ -13589,7 +21188,7 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC |
| 13589 | 21188 | } |
| 13590 | 21189 | } |
| 13591 | 21190 | |
| 13592 | | fn isNonErrPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 21191 | fn isNonErrPtr(self: *CodeGen, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 13593 | 21192 | const is_err_res = try self.isErrPtr(inst, ptr_ty, ptr_mcv); |
| 13594 | 21193 | switch (is_err_res) { |
| 13595 | 21194 | .eflags => |cc| { |
| ... | ... | @@ -13604,7 +21203,7 @@ fn isNonErrPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue |
| 13604 | 21203 | } |
| 13605 | 21204 | } |
| 13606 | 21205 | |
| 13607 | | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 21206 | fn airIsNull(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13608 | 21207 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 13609 | 21208 | const operand = try self.resolveInst(un_op); |
| 13610 | 21209 | const ty = self.typeOf(un_op); |
| ... | ... | @@ -13612,7 +21211,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 13612 | 21211 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 13613 | 21212 | } |
| 13614 | 21213 | |
| 13615 | | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 21214 | fn airIsNullPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13616 | 21215 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 13617 | 21216 | const operand = try self.resolveInst(un_op); |
| 13618 | 21217 | const ty = self.typeOf(un_op); |
| ... | ... | @@ -13620,7 +21219,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13620 | 21219 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 13621 | 21220 | } |
| 13622 | 21221 | |
| 13623 | | fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 21222 | fn airIsNonNull(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13624 | 21223 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 13625 | 21224 | const operand = try self.resolveInst(un_op); |
| 13626 | 21225 | const ty = self.typeOf(un_op); |
| ... | ... | @@ -13632,7 +21231,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 13632 | 21231 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 13633 | 21232 | } |
| 13634 | 21233 | |
| 13635 | | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 21234 | fn airIsNonNullPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13636 | 21235 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 13637 | 21236 | const operand = try self.resolveInst(un_op); |
| 13638 | 21237 | const ty = self.typeOf(un_op); |
| ... | ... | @@ -13643,7 +21242,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13643 | 21242 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 13644 | 21243 | } |
| 13645 | 21244 | |
| 13646 | | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 21245 | fn airIsErr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13647 | 21246 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 13648 | 21247 | const operand = try self.resolveInst(un_op); |
| 13649 | 21248 | const ty = self.typeOf(un_op); |
| ... | ... | @@ -13651,7 +21250,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 13651 | 21250 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 13652 | 21251 | } |
| 13653 | 21252 | |
| 13654 | | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 21253 | fn airIsErrPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13655 | 21254 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 13656 | 21255 | const operand = try self.resolveInst(un_op); |
| 13657 | 21256 | const ty = self.typeOf(un_op); |
| ... | ... | @@ -13659,7 +21258,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13659 | 21258 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 13660 | 21259 | } |
| 13661 | 21260 | |
| 13662 | | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 21261 | fn airIsNonErr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13663 | 21262 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 13664 | 21263 | const operand = try self.resolveInst(un_op); |
| 13665 | 21264 | const ty = self.typeOf(un_op); |
| ... | ... | @@ -13667,7 +21266,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 13667 | 21266 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 13668 | 21267 | } |
| 13669 | 21268 | |
| 13670 | | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 21269 | fn airIsNonErrPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13671 | 21270 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 13672 | 21271 | const operand = try self.resolveInst(un_op); |
| 13673 | 21272 | const ty = self.typeOf(un_op); |
| ... | ... | @@ -13675,7 +21274,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 13675 | 21274 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 13676 | 21275 | } |
| 13677 | 21276 | |
| 13678 | | fn airLoop(self: *Self, inst: Air.Inst.Index) !void { |
| 21277 | fn airLoop(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13679 | 21278 | // A loop is a setup to be able to jump back to the beginning. |
| 13680 | 21279 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 13681 | 21280 | const loop = self.air.extraData(Air.Block, ty_pl.payload); |
| ... | ... | @@ -13686,15 +21285,14 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { |
| 13686 | 21285 | |
| 13687 | 21286 | try self.loops.putNoClobber(self.gpa, inst, .{ |
| 13688 | 21287 | .state = state, |
| 13689 | | .jmp_target = @intCast(self.mir_instructions.len), |
| 21288 | .target = @intCast(self.mir_instructions.len), |
| 13690 | 21289 | }); |
| 13691 | 21290 | defer assert(self.loops.remove(inst)); |
| 13692 | 21291 | |
| 13693 | 21292 | try self.genBodyBlock(body); |
| 13694 | | self.finishAirBookkeeping(); |
| 13695 | 21293 | } |
| 13696 | 21294 | |
| 13697 | | fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 21295 | fn airBlock(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13698 | 21296 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 13699 | 21297 | const extra = self.air.extraData(Air.Block, ty_pl.payload); |
| 13700 | 21298 | try self.asmPseudo(.pseudo_dbg_enter_block_none); |
| ... | ... | @@ -13702,10 +21300,10 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 13702 | 21300 | try self.asmPseudo(.pseudo_dbg_leave_block_none); |
| 13703 | 21301 | } |
| 13704 | 21302 | |
| 13705 | | fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void { |
| 21303 | fn lowerBlock(self: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void { |
| 13706 | 21304 | // A block is a setup to be able to jump to the end. |
| 13707 | 21305 | const inst_tracking_i = self.inst_tracking.count(); |
| 13708 | | self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(.unreach)); |
| 21306 | self.inst_tracking.putAssumeCapacityNoClobber(inst, .init(.unreach)); |
| 13709 | 21307 | |
| 13710 | 21308 | self.scope_generation += 1; |
| 13711 | 21309 | try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() }); |
| ... | ... | @@ -13729,28 +21327,197 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! |
| 13729 | 21327 | const tracking = &self.inst_tracking.values()[inst_tracking_i]; |
| 13730 | 21328 | if (self.liveness.isUnused(inst)) try tracking.die(self, inst); |
| 13731 | 21329 | self.getValueIfFree(tracking.short, inst); |
| 13732 | | self.finishAirBookkeeping(); |
| 13733 | 21330 | } |
| 13734 | 21331 | |
| 13735 | | fn lowerSwitchBr(self: *Self, inst: Air.Inst.Index, switch_br: Air.UnwrappedSwitch, condition: MCValue) !void { |
| 21332 | fn lowerSwitchBr( |
| 21333 | self: *CodeGen, |
| 21334 | inst: Air.Inst.Index, |
| 21335 | switch_br: Air.UnwrappedSwitch, |
| 21336 | condition: MCValue, |
| 21337 | condition_dies: bool, |
| 21338 | is_loop: bool, |
| 21339 | ) !void { |
| 13736 | 21340 | const zcu = self.pt.zcu; |
| 13737 | 21341 | const condition_ty = self.typeOf(switch_br.operand); |
| 13738 | | const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1); |
| 13739 | | defer self.gpa.free(liveness.deaths); |
| 13740 | 21342 | |
| 13741 | | const signedness = switch (condition_ty.zigTypeTag(zcu)) { |
| 13742 | | .bool, .pointer => .unsigned, |
| 13743 | | .int, .@"enum", .error_set => condition_ty.intInfo(zcu).signedness, |
| 13744 | | else => unreachable, |
| 21343 | const ExpectedContents = extern struct { |
| 21344 | liveness_deaths: [1 << 8 | 1]Air.Inst.Index, |
| 21345 | bigint_limbs: [std.math.big.int.calcTwosCompLimbCount(1 << 8)]std.math.big.Limb, |
| 21346 | relocs: [1 << 6]Mir.Inst.Index, |
| 13745 | 21347 | }; |
| 21348 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = |
| 21349 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| 21350 | const allocator = stack.get(); |
| 13746 | 21351 | |
| 13747 | 21352 | self.scope_generation += 1; |
| 13748 | 21353 | const state = try self.saveState(); |
| 13749 | 21354 | |
| 13750 | | var it = switch_br.iterateCases(); |
| 13751 | | while (it.next()) |case| { |
| 13752 | | var relocs = try self.gpa.alloc(Mir.Inst.Index, case.items.len + case.ranges.len); |
| 13753 | | defer self.gpa.free(relocs); |
| 21355 | const liveness = try self.liveness.getSwitchBr(allocator, inst, switch_br.cases_len + 1); |
| 21356 | defer allocator.free(liveness.deaths); |
| 21357 | |
| 21358 | if (!self.mod.pic and self.target.ofmt == .elf) table: { |
| 21359 | var prong_items: u32 = 0; |
| 21360 | var min: ?Value = null; |
| 21361 | var max: ?Value = null; |
| 21362 | { |
| 21363 | var cases_it = switch_br.iterateCases(); |
| 21364 | while (cases_it.next()) |case| { |
| 21365 | prong_items += @intCast(case.items.len + case.ranges.len); |
| 21366 | for (case.items) |item| { |
| 21367 | const val = Value.fromInterned(item.toInterned().?); |
| 21368 | if (min == null or val.compareHetero(.lt, min.?, zcu)) min = val; |
| 21369 | if (max == null or val.compareHetero(.gt, max.?, zcu)) max = val; |
| 21370 | } |
| 21371 | for (case.ranges) |range| { |
| 21372 | const low = Value.fromInterned(range[0].toInterned().?); |
| 21373 | if (min == null or low.compareHetero(.lt, min.?, zcu)) min = low; |
| 21374 | const high = Value.fromInterned(range[1].toInterned().?); |
| 21375 | if (max == null or high.compareHetero(.gt, max.?, zcu)) max = high; |
| 21376 | } |
| 21377 | } |
| 21378 | } |
| 21379 | // This condition also triggers for switches with no non-else prongs and switches on bool. |
| 21380 | if (prong_items < 1 << 2 or prong_items > 1 << 8) break :table; |
| 21381 | |
| 21382 | var min_space: Value.BigIntSpace = undefined; |
| 21383 | const min_bigint = min.?.toBigInt(&min_space, zcu); |
| 21384 | var max_space: Value.BigIntSpace = undefined; |
| 21385 | const max_bigint = max.?.toBigInt(&max_space, zcu); |
| 21386 | const limbs = try allocator.alloc( |
| 21387 | std.math.big.Limb, |
| 21388 | @max(min_bigint.limbs.len, max_bigint.limbs.len) + 1, |
| 21389 | ); |
| 21390 | defer allocator.free(limbs); |
| 21391 | const table_len = table_len: { |
| 21392 | var table_len_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 21393 | table_len_bigint.sub(max_bigint, min_bigint); |
| 21394 | assert(table_len_bigint.positive); // min <= max |
| 21395 | break :table_len @as(u11, table_len_bigint.toConst().to(u10) catch break :table) + 1; // no more than a 1024 entry table |
| 21396 | }; |
| 21397 | assert(prong_items <= table_len); // each prong item introduces at least one unique integer to the range |
| 21398 | if (prong_items < table_len >> 2) break :table; // no more than 75% waste |
| 21399 | |
| 21400 | const condition_index = if (condition_dies and condition.isModifiable()) condition else condition_index: { |
| 21401 | const condition_index = try self.allocTempRegOrMem(condition_ty, true); |
| 21402 | try self.genCopy(condition_ty, condition_index, condition, .{}); |
| 21403 | break :condition_index condition_index; |
| 21404 | }; |
| 21405 | try self.spillEflagsIfOccupied(); |
| 21406 | if (min.?.orderAgainstZero(zcu).compare(.neq)) try self.genBinOpMir( |
| 21407 | .{ ._, .sub }, |
| 21408 | condition_ty, |
| 21409 | condition_index, |
| 21410 | .{ .air_ref = Air.internedToRef(min.?.toIntern()) }, |
| 21411 | ); |
| 21412 | const else_reloc = if (switch_br.else_body_len > 0) else_reloc: { |
| 21413 | try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_index, .{ .immediate = table_len - 1 }); |
| 21414 | break :else_reloc try self.asmJccReloc(.a, undefined); |
| 21415 | } else undefined; |
| 21416 | const table_start: u31 = @intCast(self.mir_table.items.len); |
| 21417 | { |
| 21418 | const condition_index_reg = if (condition_index.isRegister()) |
| 21419 | condition_index.getReg().? |
| 21420 | else |
| 21421 | try self.copyToTmpRegister(.usize, condition_index); |
| 21422 | const condition_index_lock = self.register_manager.lockReg(condition_index_reg); |
| 21423 | defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock); |
| 21424 | try self.truncateRegister(condition_ty, condition_index_reg); |
| 21425 | const ptr_size = @divExact(self.target.ptrBitWidth(), 8); |
| 21426 | try self.asmMemory(.{ ._, .jmp }, .{ |
| 21427 | .base = .table, |
| 21428 | .mod = .{ .rm = .{ |
| 21429 | .size = .ptr, |
| 21430 | .index = registerAlias(condition_index_reg, ptr_size), |
| 21431 | .scale = .fromFactor(@intCast(ptr_size)), |
| 21432 | .disp = table_start * ptr_size, |
| 21433 | } }, |
| 21434 | }); |
| 21435 | } |
| 21436 | const else_reloc_marker: u32 = 0; |
| 21437 | assert(self.mir_instructions.len > else_reloc_marker); |
| 21438 | try self.mir_table.appendNTimes(self.gpa, else_reloc_marker, table_len); |
| 21439 | if (is_loop) try self.loop_switches.putNoClobber(self.gpa, inst, .{ |
| 21440 | .start = table_start, |
| 21441 | .len = table_len, |
| 21442 | .min = min.?, |
| 21443 | .else_relocs = if (switch_br.else_body_len > 0) .{ .forward = .empty } else .@"unreachable", |
| 21444 | }); |
| 21445 | defer if (is_loop) { |
| 21446 | var loop_switch_data = self.loop_switches.fetchRemove(inst).?.value; |
| 21447 | switch (loop_switch_data.else_relocs) { |
| 21448 | .@"unreachable", .backward => {}, |
| 21449 | .forward => |*else_relocs| else_relocs.deinit(self.gpa), |
| 21450 | } |
| 21451 | }; |
| 21452 | var cases_it = switch_br.iterateCases(); |
| 21453 | while (cases_it.next()) |case| { |
| 21454 | { |
| 21455 | const table = self.mir_table.items[table_start..][0..table_len]; |
| 21456 | for (case.items) |item| { |
| 21457 | const val = Value.fromInterned(item.toInterned().?); |
| 21458 | var val_space: Value.BigIntSpace = undefined; |
| 21459 | const val_bigint = val.toBigInt(&val_space, zcu); |
| 21460 | var index_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 21461 | index_bigint.sub(val_bigint, min_bigint); |
| 21462 | table[index_bigint.toConst().to(u10) catch unreachable] = @intCast(self.mir_instructions.len); |
| 21463 | } |
| 21464 | for (case.ranges) |range| { |
| 21465 | var low_space: Value.BigIntSpace = undefined; |
| 21466 | const low_bigint = Value.fromInterned(range[0].toInterned().?).toBigInt(&low_space, zcu); |
| 21467 | var high_space: Value.BigIntSpace = undefined; |
| 21468 | const high_bigint = Value.fromInterned(range[1].toInterned().?).toBigInt(&high_space, zcu); |
| 21469 | var index_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 21470 | index_bigint.sub(low_bigint, min_bigint); |
| 21471 | const start = index_bigint.toConst().to(u10) catch unreachable; |
| 21472 | index_bigint.sub(high_bigint, min_bigint); |
| 21473 | const end = @as(u11, index_bigint.toConst().to(u10) catch unreachable) + 1; |
| 21474 | @memset(table[start..end], @intCast(self.mir_instructions.len)); |
| 21475 | } |
| 21476 | } |
| 21477 | |
| 21478 | for (liveness.deaths[case.idx]) |operand| try self.processDeath(operand); |
| 21479 | |
| 21480 | try self.genBodyBlock(case.body); |
| 21481 | try self.restoreState(state, &.{}, .{ |
| 21482 | .emit_instructions = false, |
| 21483 | .update_tracking = true, |
| 21484 | .resurrect = true, |
| 21485 | .close_scope = true, |
| 21486 | }); |
| 21487 | } |
| 21488 | if (switch_br.else_body_len > 0) { |
| 21489 | const else_body = cases_it.elseBody(); |
| 21490 | |
| 21491 | const else_deaths = liveness.deaths.len - 1; |
| 21492 | for (liveness.deaths[else_deaths]) |operand| try self.processDeath(operand); |
| 21493 | |
| 21494 | self.performReloc(else_reloc); |
| 21495 | if (is_loop) { |
| 21496 | const loop_switch_data = self.loop_switches.getPtr(inst).?; |
| 21497 | for (loop_switch_data.else_relocs.forward.items) |reloc| self.performReloc(reloc); |
| 21498 | loop_switch_data.else_relocs.forward.deinit(self.gpa); |
| 21499 | loop_switch_data.else_relocs = .{ .backward = @intCast(self.mir_instructions.len) }; |
| 21500 | } |
| 21501 | for (self.mir_table.items[table_start..][0..table_len]) |*entry| if (entry.* == else_reloc_marker) { |
| 21502 | entry.* = @intCast(self.mir_instructions.len); |
| 21503 | }; |
| 21504 | |
| 21505 | try self.genBodyBlock(else_body); |
| 21506 | try self.restoreState(state, &.{}, .{ |
| 21507 | .emit_instructions = false, |
| 21508 | .update_tracking = true, |
| 21509 | .resurrect = true, |
| 21510 | .close_scope = true, |
| 21511 | }); |
| 21512 | } |
| 21513 | return; |
| 21514 | } |
| 21515 | |
| 21516 | const signedness = if (condition_ty.isAbiInt(zcu)) condition_ty.intInfo(zcu).signedness else .unsigned; |
| 21517 | var cases_it = switch_br.iterateCases(); |
| 21518 | while (cases_it.next()) |case| { |
| 21519 | var relocs = try allocator.alloc(Mir.Inst.Index, case.items.len + case.ranges.len); |
| 21520 | defer allocator.free(relocs); |
| 13754 | 21521 | |
| 13755 | 21522 | try self.spillEflagsIfOccupied(); |
| 13756 | 21523 | for (case.items, relocs[0..case.items.len]) |item, *reloc| { |
| ... | ... | @@ -13833,9 +21600,8 @@ fn lowerSwitchBr(self: *Self, inst: Air.Inst.Index, switch_br: Air.UnwrappedSwit |
| 13833 | 21600 | // Relocate the "skip" branch to fall through to the next case. |
| 13834 | 21601 | self.performReloc(skip_case_reloc); |
| 13835 | 21602 | } |
| 13836 | | |
| 13837 | 21603 | if (switch_br.else_body_len > 0) { |
| 13838 | | const else_body = it.elseBody(); |
| 21604 | const else_body = cases_it.elseBody(); |
| 13839 | 21605 | |
| 13840 | 21606 | const else_deaths = liveness.deaths.len - 1; |
| 13841 | 21607 | for (liveness.deaths[else_deaths]) |operand| try self.processDeath(operand); |
| ... | ... | @@ -13850,24 +21616,23 @@ fn lowerSwitchBr(self: *Self, inst: Air.Inst.Index, switch_br: Air.UnwrappedSwit |
| 13850 | 21616 | } |
| 13851 | 21617 | } |
| 13852 | 21618 | |
| 13853 | | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 21619 | fn airSwitchBr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13854 | 21620 | const switch_br = self.air.unwrapSwitch(inst); |
| 13855 | 21621 | const condition = try self.resolveInst(switch_br.operand); |
| 13856 | 21622 | |
| 13857 | 21623 | // If the condition dies here in this switch instruction, process |
| 13858 | 21624 | // that death now instead of later as this has an effect on |
| 13859 | 21625 | // whether it needs to be spilled in the branches |
| 13860 | | if (self.liveness.operandDies(inst, 0)) { |
| 21626 | const condition_dies = self.liveness.operandDies(inst, 0); |
| 21627 | if (condition_dies) { |
| 13861 | 21628 | if (switch_br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); |
| 13862 | 21629 | } |
| 13863 | | |
| 13864 | | try self.lowerSwitchBr(inst, switch_br, condition); |
| 21630 | try self.lowerSwitchBr(inst, switch_br, condition, condition_dies, false); |
| 13865 | 21631 | |
| 13866 | 21632 | // We already took care of pl_op.operand earlier, so there's nothing left to do |
| 13867 | | self.finishAirBookkeeping(); |
| 13868 | 21633 | } |
| 13869 | 21634 | |
| 13870 | | fn airLoopSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 21635 | fn airLoopSwitchBr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13871 | 21636 | const switch_br = self.air.unwrapSwitch(inst); |
| 13872 | 21637 | const condition = try self.resolveInst(switch_br.operand); |
| 13873 | 21638 | |
| ... | ... | @@ -13879,7 +21644,7 @@ fn airLoopSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 13879 | 21644 | try self.genCopy(self.typeOf(switch_br.operand), mat_cond, condition, .{}); |
| 13880 | 21645 | break :mat_cond mat_cond; |
| 13881 | 21646 | }; |
| 13882 | | self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(mat_cond)); |
| 21647 | self.inst_tracking.putAssumeCapacityNoClobber(inst, .init(mat_cond)); |
| 13883 | 21648 | |
| 13884 | 21649 | // If the condition dies here in this switch instruction, process |
| 13885 | 21650 | // that death now instead of later as this has an effect on |
| ... | ... | @@ -13893,25 +21658,83 @@ fn airLoopSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 13893 | 21658 | |
| 13894 | 21659 | try self.loops.putNoClobber(self.gpa, inst, .{ |
| 13895 | 21660 | .state = state, |
| 13896 | | .jmp_target = @intCast(self.mir_instructions.len), |
| 21661 | .target = @intCast(self.mir_instructions.len), |
| 13897 | 21662 | }); |
| 13898 | 21663 | defer assert(self.loops.remove(inst)); |
| 13899 | 21664 | |
| 13900 | 21665 | // Stop tracking block result without forgetting tracking info |
| 13901 | 21666 | try self.freeValue(mat_cond); |
| 13902 | 21667 | |
| 13903 | | try self.lowerSwitchBr(inst, switch_br, mat_cond); |
| 21668 | try self.lowerSwitchBr(inst, switch_br, mat_cond, true, true); |
| 13904 | 21669 | |
| 13905 | 21670 | try self.processDeath(inst); |
| 13906 | | self.finishAirBookkeeping(); |
| 13907 | 21671 | } |
| 13908 | 21672 | |
| 13909 | | fn airSwitchDispatch(self: *Self, inst: Air.Inst.Index) !void { |
| 21673 | fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13910 | 21674 | const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br; |
| 13911 | 21675 | |
| 13912 | 21676 | const block_ty = self.typeOfIndex(br.block_inst); |
| 13913 | | const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; |
| 13914 | 21677 | const loop_data = self.loops.getPtr(br.block_inst).?; |
| 21678 | if (self.loop_switches.getPtr(br.block_inst)) |table| { |
| 21679 | // Process operand death so that it is properly accounted for in the State below. |
| 21680 | const condition_dies = self.liveness.operandDies(inst, 0); |
| 21681 | |
| 21682 | try self.restoreState(loop_data.state, &.{}, .{ |
| 21683 | .emit_instructions = true, |
| 21684 | .update_tracking = false, |
| 21685 | .resurrect = false, |
| 21686 | .close_scope = false, |
| 21687 | }); |
| 21688 | |
| 21689 | const condition_ty = self.typeOf(br.operand); |
| 21690 | const condition = try self.resolveInst(br.operand); |
| 21691 | const condition_index = if (condition_dies and condition.isModifiable()) condition else condition_index: { |
| 21692 | const condition_index = try self.allocTempRegOrMem(condition_ty, true); |
| 21693 | try self.genCopy(condition_ty, condition_index, condition, .{}); |
| 21694 | break :condition_index condition_index; |
| 21695 | }; |
| 21696 | try self.spillEflagsIfOccupied(); |
| 21697 | if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir( |
| 21698 | .{ ._, .sub }, |
| 21699 | condition_ty, |
| 21700 | condition_index, |
| 21701 | .{ .air_ref = Air.internedToRef(table.min.toIntern()) }, |
| 21702 | ); |
| 21703 | switch (table.else_relocs) { |
| 21704 | .@"unreachable" => {}, |
| 21705 | .forward => |*else_relocs| { |
| 21706 | try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_index, .{ .immediate = table.len - 1 }); |
| 21707 | try else_relocs.append(self.gpa, try self.asmJccReloc(.a, undefined)); |
| 21708 | }, |
| 21709 | .backward => |else_reloc| { |
| 21710 | try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition_index, .{ .immediate = table.len - 1 }); |
| 21711 | _ = try self.asmJccReloc(.a, else_reloc); |
| 21712 | }, |
| 21713 | } |
| 21714 | { |
| 21715 | const condition_index_reg = if (condition_index.isRegister()) |
| 21716 | condition_index.getReg().? |
| 21717 | else |
| 21718 | try self.copyToTmpRegister(.usize, condition_index); |
| 21719 | const condition_index_lock = self.register_manager.lockReg(condition_index_reg); |
| 21720 | defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock); |
| 21721 | try self.truncateRegister(condition_ty, condition_index_reg); |
| 21722 | const ptr_size = @divExact(self.target.ptrBitWidth(), 8); |
| 21723 | try self.asmMemory(.{ ._, .jmp }, .{ |
| 21724 | .base = .table, |
| 21725 | .mod = .{ .rm = .{ |
| 21726 | .size = .ptr, |
| 21727 | .index = registerAlias(condition_index_reg, ptr_size), |
| 21728 | .scale = .fromFactor(@intCast(ptr_size)), |
| 21729 | .disp = @intCast(table.start * ptr_size), |
| 21730 | } }, |
| 21731 | }); |
| 21732 | } |
| 21733 | |
| 21734 | return self.finishAir(inst, .none, .{ br.operand, .none, .none }); |
| 21735 | } |
| 21736 | |
| 21737 | const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; |
| 13915 | 21738 | done: { |
| 13916 | 21739 | try self.getValue(block_tracking.short, null); |
| 13917 | 21740 | const src_mcv = try self.resolveInst(br.operand); |
| ... | ... | @@ -13945,15 +21768,13 @@ fn airSwitchDispatch(self: *Self, inst: Air.Inst.Index) !void { |
| 13945 | 21768 | |
| 13946 | 21769 | // Emit a jump with a relocation. It will be patched up after the block ends. |
| 13947 | 21770 | // Leave the jump offset undefined |
| 13948 | | _ = try self.asmJmpReloc(loop_data.jmp_target); |
| 21771 | _ = try self.asmJmpReloc(loop_data.target); |
| 13949 | 21772 | |
| 13950 | 21773 | // Stop tracking block result without forgetting tracking info |
| 13951 | 21774 | try self.freeValue(block_tracking.short); |
| 13952 | | |
| 13953 | | self.finishAirBookkeeping(); |
| 13954 | 21775 | } |
| 13955 | 21776 | |
| 13956 | | fn performReloc(self: *Self, reloc: Mir.Inst.Index) void { |
| 21777 | fn performReloc(self: *CodeGen, reloc: Mir.Inst.Index) void { |
| 13957 | 21778 | const next_inst: u32 = @intCast(self.mir_instructions.len); |
| 13958 | 21779 | switch (self.mir_instructions.items(.tag)[reloc]) { |
| 13959 | 21780 | .j, .jmp => {}, |
| ... | ... | @@ -13966,7 +21787,7 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) void { |
| 13966 | 21787 | self.mir_instructions.items(.data)[reloc].inst.inst = next_inst; |
| 13967 | 21788 | } |
| 13968 | 21789 | |
| 13969 | | fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 21790 | fn airBr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 13970 | 21791 | const zcu = self.pt.zcu; |
| 13971 | 21792 | const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br; |
| 13972 | 21793 | |
| ... | ... | @@ -14007,7 +21828,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 14007 | 21828 | } |
| 14008 | 21829 | |
| 14009 | 21830 | if (first_br) { |
| 14010 | | block_tracking.* = InstTracking.init(block_result); |
| 21831 | block_tracking.* = .init(block_result); |
| 14011 | 21832 | try self.saveRetroactiveState(&block_data.state); |
| 14012 | 21833 | } else try self.restoreState(block_data.state, &.{}, .{ |
| 14013 | 21834 | .emit_instructions = true, |
| ... | ... | @@ -14023,11 +21844,9 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 14023 | 21844 | |
| 14024 | 21845 | // Stop tracking block result without forgetting tracking info |
| 14025 | 21846 | try self.freeValue(block_tracking.short); |
| 14026 | | |
| 14027 | | self.finishAirBookkeeping(); |
| 14028 | 21847 | } |
| 14029 | 21848 | |
| 14030 | | fn airRepeat(self: *Self, inst: Air.Inst.Index) !void { |
| 21849 | fn airRepeat(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 14031 | 21850 | const loop_inst = self.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst; |
| 14032 | 21851 | const repeat_info = self.loops.get(loop_inst).?; |
| 14033 | 21852 | try self.restoreState(repeat_info.state, &.{}, .{ |
| ... | ... | @@ -14036,11 +21855,10 @@ fn airRepeat(self: *Self, inst: Air.Inst.Index) !void { |
| 14036 | 21855 | .resurrect = false, |
| 14037 | 21856 | .close_scope = true, |
| 14038 | 21857 | }); |
| 14039 | | _ = try self.asmJmpReloc(repeat_info.jmp_target); |
| 14040 | | self.finishAirBookkeeping(); |
| 21858 | _ = try self.asmJmpReloc(repeat_info.target); |
| 14041 | 21859 | } |
| 14042 | 21860 | |
| 14043 | | fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 21861 | fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 14044 | 21862 | const pt = self.pt; |
| 14045 | 21863 | const zcu = pt.zcu; |
| 14046 | 21864 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -14054,7 +21872,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14054 | 21872 | extra_i += inputs.len; |
| 14055 | 21873 | |
| 14056 | 21874 | var result: MCValue = .none; |
| 14057 | | var args = std.ArrayList(MCValue).init(self.gpa); |
| 21875 | var args: std.ArrayList(MCValue) = .init(self.gpa); |
| 14058 | 21876 | try args.ensureTotalCapacity(outputs.len + inputs.len); |
| 14059 | 21877 | defer { |
| 14060 | 21878 | for (args.items) |arg| if (arg.getReg()) |reg| self.register_manager.unlockReg(.{ |
| ... | ... | @@ -14062,15 +21880,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14062 | 21880 | }); |
| 14063 | 21881 | args.deinit(); |
| 14064 | 21882 | } |
| 14065 | | var arg_map = std.StringHashMap(u8).init(self.gpa); |
| 21883 | var arg_map: std.StringHashMap(u8) = .init(self.gpa); |
| 14066 | 21884 | try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len)); |
| 14067 | 21885 | defer arg_map.deinit(); |
| 14068 | 21886 | |
| 14069 | 21887 | var outputs_extra_i = extra_i; |
| 14070 | 21888 | for (outputs) |output| { |
| 14071 | | const extra_bytes = mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 14072 | | const constraint = mem.sliceTo(mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 14073 | | const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 21889 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 21890 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 21891 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 14074 | 21892 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 14075 | 21893 | // for the string, we still use the next u32 for the null terminator. |
| 14076 | 21894 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| ... | ... | @@ -14097,8 +21915,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14097 | 21915 | const is_early_clobber = constraint[1] == '&'; |
| 14098 | 21916 | const rest = constraint[@as(usize, 1) + @intFromBool(is_early_clobber) ..]; |
| 14099 | 21917 | const arg_mcv: MCValue = arg_mcv: { |
| 14100 | | const arg_maybe_reg: ?Register = if (mem.eql(u8, rest, "r") or |
| 14101 | | mem.eql(u8, rest, "f") or mem.eql(u8, rest, "x")) |
| 21918 | const arg_maybe_reg: ?Register = if (std.mem.eql(u8, rest, "r") or |
| 21919 | std.mem.eql(u8, rest, "f") or std.mem.eql(u8, rest, "x")) |
| 14102 | 21920 | registerAlias( |
| 14103 | 21921 | self.register_manager.tryAllocReg(maybe_inst, switch (rest[0]) { |
| 14104 | 21922 | 'r' => abi.RegisterClass.gp, |
| ... | ... | @@ -14108,20 +21926,20 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14108 | 21926 | }) orelse return self.fail("ran out of registers lowering inline asm", .{}), |
| 14109 | 21927 | @intCast(ty.abiSize(zcu)), |
| 14110 | 21928 | ) |
| 14111 | | else if (mem.eql(u8, rest, "m")) |
| 21929 | else if (std.mem.eql(u8, rest, "m")) |
| 14112 | 21930 | if (output != .none) null else return self.fail( |
| 14113 | 21931 | "memory constraint unsupported for asm result: '{s}'", |
| 14114 | 21932 | .{constraint}, |
| 14115 | 21933 | ) |
| 14116 | | else if (mem.eql(u8, rest, "g") or |
| 14117 | | mem.eql(u8, rest, "rm") or mem.eql(u8, rest, "mr") or |
| 14118 | | mem.eql(u8, rest, "r,m") or mem.eql(u8, rest, "m,r")) |
| 21934 | else if (std.mem.eql(u8, rest, "g") or |
| 21935 | std.mem.eql(u8, rest, "rm") or std.mem.eql(u8, rest, "mr") or |
| 21936 | std.mem.eql(u8, rest, "r,m") or std.mem.eql(u8, rest, "m,r")) |
| 14119 | 21937 | self.register_manager.tryAllocReg(maybe_inst, abi.RegisterClass.gp) orelse |
| 14120 | 21938 | if (output != .none) |
| 14121 | 21939 | null |
| 14122 | 21940 | else |
| 14123 | 21941 | return self.fail("ran out of registers lowering inline asm", .{}) |
| 14124 | | else if (mem.startsWith(u8, rest, "{") and mem.endsWith(u8, rest, "}")) |
| 21942 | else if (std.mem.startsWith(u8, rest, "{") and std.mem.endsWith(u8, rest, "}")) |
| 14125 | 21943 | parseRegName(rest["{".len .. rest.len - "}".len]) orelse |
| 14126 | 21944 | return self.fail("invalid register constraint: '{s}'", .{constraint}) |
| 14127 | 21945 | else if (rest.len == 1 and std.ascii.isDigit(rest[0])) { |
| ... | ... | @@ -14134,18 +21952,19 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14134 | 21952 | break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: { |
| 14135 | 21953 | const ptr_mcv = try self.resolveInst(output); |
| 14136 | 21954 | switch (ptr_mcv) { |
| 14137 | | .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_| |
| 21955 | .immediate => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_| |
| 14138 | 21956 | break :arg ptr_mcv.deref(), |
| 14139 | 21957 | .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(), |
| 14140 | 21958 | else => {}, |
| 14141 | 21959 | } |
| 14142 | | break :arg .{ .indirect = .{ .reg = try self.copyToTmpRegister(Type.usize, ptr_mcv) } }; |
| 21960 | break :arg .{ .indirect = .{ .reg = try self.copyToTmpRegister(.usize, ptr_mcv) } }; |
| 14143 | 21961 | }; |
| 14144 | 21962 | }; |
| 14145 | | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { |
| 14146 | | _ = self.register_manager.lockReg(reg); |
| 21963 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |tracked_index| { |
| 21964 | try self.register_manager.getRegIndex(tracked_index, if (output == .none) inst else null); |
| 21965 | _ = self.register_manager.lockRegIndexAssumeUnused(tracked_index); |
| 14147 | 21966 | }; |
| 14148 | | if (!mem.eql(u8, name, "_")) |
| 21967 | if (!std.mem.eql(u8, name, "_")) |
| 14149 | 21968 | arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); |
| 14150 | 21969 | args.appendAssumeCapacity(arg_mcv); |
| 14151 | 21970 | if (output == .none) result = arg_mcv; |
| ... | ... | @@ -14153,17 +21972,17 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14153 | 21972 | } |
| 14154 | 21973 | |
| 14155 | 21974 | for (inputs) |input| { |
| 14156 | | const input_bytes = mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 14157 | | const constraint = mem.sliceTo(input_bytes, 0); |
| 14158 | | const name = mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); |
| 21975 | const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 21976 | const constraint = std.mem.sliceTo(input_bytes, 0); |
| 21977 | const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); |
| 14159 | 21978 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 14160 | 21979 | // for the string, we still use the next u32 for the null terminator. |
| 14161 | 21980 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 14162 | 21981 | |
| 14163 | 21982 | const ty = self.typeOf(input); |
| 14164 | 21983 | const input_mcv = try self.resolveInst(input); |
| 14165 | | const arg_mcv: MCValue = if (mem.eql(u8, constraint, "r") or |
| 14166 | | mem.eql(u8, constraint, "f") or mem.eql(u8, constraint, "x")) |
| 21984 | const arg_mcv: MCValue = if (std.mem.eql(u8, constraint, "r") or |
| 21985 | std.mem.eql(u8, constraint, "f") or std.mem.eql(u8, constraint, "x")) |
| 14167 | 21986 | arg: { |
| 14168 | 21987 | const rc = switch (constraint[0]) { |
| 14169 | 21988 | 'r' => abi.RegisterClass.gp, |
| ... | ... | @@ -14177,16 +21996,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14177 | 21996 | const reg = try self.register_manager.allocReg(null, rc); |
| 14178 | 21997 | try self.genSetReg(reg, ty, input_mcv, .{}); |
| 14179 | 21998 | break :arg .{ .register = registerAlias(reg, @intCast(ty.abiSize(zcu))) }; |
| 14180 | | } else if (mem.eql(u8, constraint, "i") or mem.eql(u8, constraint, "n")) |
| 21999 | } else if (std.mem.eql(u8, constraint, "i") or std.mem.eql(u8, constraint, "n")) |
| 14181 | 22000 | switch (input_mcv) { |
| 14182 | 22001 | .immediate => |imm| .{ .immediate = imm }, |
| 14183 | 22002 | else => return self.fail("immediate operand requires comptime value: '{s}'", .{ |
| 14184 | 22003 | constraint, |
| 14185 | 22004 | }), |
| 14186 | 22005 | } |
| 14187 | | else if (mem.eql(u8, constraint, "m")) arg: { |
| 22006 | else if (std.mem.eql(u8, constraint, "m")) arg: { |
| 14188 | 22007 | switch (input_mcv) { |
| 14189 | | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_| |
| 22008 | .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_| |
| 14190 | 22009 | break :arg input_mcv, |
| 14191 | 22010 | .indirect, .load_frame => break :arg input_mcv, |
| 14192 | 22011 | .load_symbol, .load_direct, .load_got, .load_tlv => {}, |
| ... | ... | @@ -14201,24 +22020,24 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14201 | 22020 | try self.genCopy(ty, temp_mcv, input_mcv, .{}); |
| 14202 | 22021 | break :arg temp_mcv; |
| 14203 | 22022 | }; |
| 14204 | | try self.genSetReg(addr_reg, Type.usize, input_mcv.address(), .{}); |
| 22023 | try self.genSetReg(addr_reg, .usize, input_mcv.address(), .{}); |
| 14205 | 22024 | break :arg .{ .indirect = .{ .reg = addr_reg } }; |
| 14206 | | } else if (mem.eql(u8, constraint, "g") or |
| 14207 | | mem.eql(u8, constraint, "rm") or mem.eql(u8, constraint, "mr") or |
| 14208 | | mem.eql(u8, constraint, "r,m") or mem.eql(u8, constraint, "m,r")) |
| 22025 | } else if (std.mem.eql(u8, constraint, "g") or |
| 22026 | std.mem.eql(u8, constraint, "rm") or std.mem.eql(u8, constraint, "mr") or |
| 22027 | std.mem.eql(u8, constraint, "r,m") or std.mem.eql(u8, constraint, "m,r")) |
| 14209 | 22028 | arg: { |
| 14210 | 22029 | switch (input_mcv) { |
| 14211 | 22030 | .register, .indirect, .load_frame => break :arg input_mcv, |
| 14212 | | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_| |
| 22031 | .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_| |
| 14213 | 22032 | break :arg input_mcv, |
| 14214 | 22033 | else => {}, |
| 14215 | 22034 | } |
| 14216 | 22035 | const temp_mcv = try self.allocTempRegOrMem(ty, true); |
| 14217 | 22036 | try self.genCopy(ty, temp_mcv, input_mcv, .{}); |
| 14218 | 22037 | break :arg temp_mcv; |
| 14219 | | } else if (mem.eql(u8, constraint, "X")) |
| 22038 | } else if (std.mem.eql(u8, constraint, "X")) |
| 14220 | 22039 | input_mcv |
| 14221 | | else if (mem.startsWith(u8, constraint, "{") and mem.endsWith(u8, constraint, "}")) arg: { |
| 22040 | else if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) arg: { |
| 14222 | 22041 | const reg = parseRegName(constraint["{".len .. constraint.len - "}".len]) orelse |
| 14223 | 22042 | return self.fail("invalid register constraint: '{s}'", .{constraint}); |
| 14224 | 22043 | try self.register_manager.getReg(reg, null); |
| ... | ... | @@ -14233,7 +22052,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14233 | 22052 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { |
| 14234 | 22053 | _ = self.register_manager.lockReg(reg); |
| 14235 | 22054 | }; |
| 14236 | | if (!mem.eql(u8, name, "_")) |
| 22055 | if (!std.mem.eql(u8, name, "_")) |
| 14237 | 22056 | arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); |
| 14238 | 22057 | args.appendAssumeCapacity(arg_mcv); |
| 14239 | 22058 | } |
| ... | ... | @@ -14241,7 +22060,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14241 | 22060 | { |
| 14242 | 22061 | var clobber_i: u32 = 0; |
| 14243 | 22062 | while (clobber_i < clobbers_len) : (clobber_i += 1) { |
| 14244 | | const clobber = mem.sliceTo(mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 22063 | const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 14245 | 22064 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 14246 | 22065 | // for the string, we still use the next u32 for the null terminator. |
| 14247 | 22066 | extra_i += clobber.len / 4 + 1; |
| ... | ... | @@ -14294,20 +22113,20 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14294 | 22113 | labels.deinit(self.gpa); |
| 14295 | 22114 | } |
| 14296 | 22115 | |
| 14297 | | const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; |
| 14298 | | var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;"); |
| 22116 | const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; |
| 22117 | var line_it = std.mem.tokenizeAny(u8, asm_source, "\n\r;"); |
| 14299 | 22118 | next_line: while (line_it.next()) |line| { |
| 14300 | | var mnem_it = mem.tokenizeAny(u8, line, " \t"); |
| 14301 | | var prefix: Instruction.Prefix = .none; |
| 22119 | var mnem_it = std.mem.tokenizeAny(u8, line, " \t"); |
| 22120 | var prefix: encoder.Instruction.Prefix = .none; |
| 14302 | 22121 | const mnem_str = while (mnem_it.next()) |mnem_str| { |
| 14303 | 22122 | if (mnem_str[0] == '#') continue :next_line; |
| 14304 | | if (mem.startsWith(u8, mnem_str, "//")) continue :next_line; |
| 14305 | | if (std.meta.stringToEnum(Instruction.Prefix, mnem_str)) |pre| { |
| 22123 | if (std.mem.startsWith(u8, mnem_str, "//")) continue :next_line; |
| 22124 | if (std.meta.stringToEnum(encoder.Instruction.Prefix, mnem_str)) |pre| { |
| 14306 | 22125 | if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str}); |
| 14307 | 22126 | prefix = pre; |
| 14308 | 22127 | continue; |
| 14309 | 22128 | } |
| 14310 | | if (!mem.endsWith(u8, mnem_str, ":")) break mnem_str; |
| 22129 | if (!std.mem.endsWith(u8, mnem_str, ":")) break mnem_str; |
| 14311 | 22130 | const label_name = mnem_str[0 .. mnem_str.len - ":".len]; |
| 14312 | 22131 | if (!Label.isValid(.definition, label_name)) |
| 14313 | 22132 | return self.fail("invalid label: '{s}'", .{label_name}); |
| ... | ... | @@ -14332,21 +22151,21 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14332 | 22151 | |
| 14333 | 22152 | var mnem_size: ?Memory.Size = if (prefix == .directive) |
| 14334 | 22153 | null |
| 14335 | | else if (mem.endsWith(u8, mnem_str, "b")) |
| 22154 | else if (std.mem.endsWith(u8, mnem_str, "b")) |
| 14336 | 22155 | .byte |
| 14337 | | else if (mem.endsWith(u8, mnem_str, "w")) |
| 22156 | else if (std.mem.endsWith(u8, mnem_str, "w")) |
| 14338 | 22157 | .word |
| 14339 | | else if (mem.endsWith(u8, mnem_str, "l")) |
| 22158 | else if (std.mem.endsWith(u8, mnem_str, "l")) |
| 14340 | 22159 | .dword |
| 14341 | | else if (mem.endsWith(u8, mnem_str, "q") and |
| 14342 | | (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !mem.endsWith(u8, mnem_str, "dq"))) |
| 22160 | else if (std.mem.endsWith(u8, mnem_str, "q") and |
| 22161 | (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq"))) |
| 14343 | 22162 | .qword |
| 14344 | | else if (mem.endsWith(u8, mnem_str, "t")) |
| 22163 | else if (std.mem.endsWith(u8, mnem_str, "t")) |
| 14345 | 22164 | .tbyte |
| 14346 | 22165 | else |
| 14347 | 22166 | null; |
| 14348 | 22167 | const mnem_tag = while (true) break std.meta.stringToEnum( |
| 14349 | | Instruction.Mnemonic, |
| 22168 | encoder.Instruction.Mnemonic, |
| 14350 | 22169 | mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size != null)], |
| 14351 | 22170 | ) orelse if (mnem_size) |_| { |
| 14352 | 22171 | mnem_size = null; |
| ... | ... | @@ -14367,18 +22186,18 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14367 | 22186 | .{ ._, .pseudo } |
| 14368 | 22187 | else for (std.enums.values(Mir.Inst.Fixes)) |fixes| { |
| 14369 | 22188 | const fixes_name = @tagName(fixes); |
| 14370 | | const space_i = mem.indexOfScalar(u8, fixes_name, ' '); |
| 22189 | const space_i = std.mem.indexOfScalar(u8, fixes_name, ' '); |
| 14371 | 22190 | const fixes_prefix = if (space_i) |i| |
| 14372 | | std.meta.stringToEnum(Instruction.Prefix, fixes_name[0..i]).? |
| 22191 | std.meta.stringToEnum(encoder.Instruction.Prefix, fixes_name[0..i]).? |
| 14373 | 22192 | else |
| 14374 | 22193 | .none; |
| 14375 | 22194 | if (fixes_prefix != prefix) continue; |
| 14376 | 22195 | const pattern = fixes_name[if (space_i) |i| i + " ".len else 0..]; |
| 14377 | | const wildcard_i = mem.indexOfScalar(u8, pattern, '_').?; |
| 22196 | const wildcard_i = std.mem.indexOfScalar(u8, pattern, '_').?; |
| 14378 | 22197 | const mnem_prefix = pattern[0..wildcard_i]; |
| 14379 | 22198 | const mnem_suffix = pattern[wildcard_i + "_".len ..]; |
| 14380 | | if (!mem.startsWith(u8, mnem_name, mnem_prefix)) continue; |
| 14381 | | if (!mem.endsWith(u8, mnem_name, mnem_suffix)) continue; |
| 22199 | if (!std.mem.startsWith(u8, mnem_name, mnem_prefix)) continue; |
| 22200 | if (!std.mem.endsWith(u8, mnem_name, mnem_suffix)) continue; |
| 14382 | 22201 | break .{ fixes, std.meta.stringToEnum( |
| 14383 | 22202 | Mir.Inst.Tag, |
| 14384 | 22203 | mnem_name[mnem_prefix.len .. mnem_name.len - mnem_suffix.len], |
| ... | ... | @@ -14390,31 +22209,25 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14390 | 22209 | }); |
| 14391 | 22210 | }; |
| 14392 | 22211 | |
| 14393 | | const Operand = union(enum) { |
| 14394 | | none, |
| 14395 | | reg: Register, |
| 14396 | | mem: Memory, |
| 14397 | | imm: Immediate, |
| 14398 | | inst: Mir.Inst.Index, |
| 14399 | | }; |
| 14400 | | var ops: [4]Operand = .{.none} ** 4; |
| 22212 | var ops: [4]Operand = @splat(.none); |
| 22213 | var ops_len: usize = 0; |
| 14401 | 22214 | |
| 14402 | 22215 | var last_op = false; |
| 14403 | | var op_it = mem.splitScalar(u8, mnem_it.rest(), ','); |
| 22216 | var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ','); |
| 14404 | 22217 | next_op: for (&ops) |*op| { |
| 14405 | 22218 | const op_str = while (!last_op) { |
| 14406 | 22219 | const full_str = op_it.next() orelse break :next_op; |
| 14407 | | const code_str = if (mem.indexOfScalar(u8, full_str, '#') orelse |
| 14408 | | mem.indexOf(u8, full_str, "//")) |comment| |
| 22220 | const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse |
| 22221 | std.mem.indexOf(u8, full_str, "//")) |comment| |
| 14409 | 22222 | code: { |
| 14410 | 22223 | last_op = true; |
| 14411 | 22224 | break :code full_str[0..comment]; |
| 14412 | 22225 | } else full_str; |
| 14413 | | const trim_str = mem.trim(u8, code_str, " \t*"); |
| 22226 | const trim_str = std.mem.trim(u8, code_str, " \t*"); |
| 14414 | 22227 | if (trim_str.len > 0) break trim_str; |
| 14415 | 22228 | } else break; |
| 14416 | | if (mem.startsWith(u8, op_str, "%%")) { |
| 14417 | | const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); |
| 22229 | if (std.mem.startsWith(u8, op_str, "%%")) { |
| 22230 | const colon = std.mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); |
| 14418 | 22231 | const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse |
| 14419 | 22232 | return self.fail("invalid register: '{s}'", .{op_str}); |
| 14420 | 22233 | if (colon) |colon_pos| { |
| ... | ... | @@ -14428,12 +22241,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14428 | 22241 | } }, |
| 14429 | 22242 | } }; |
| 14430 | 22243 | } else { |
| 14431 | | if (mnem_size) |size| if (reg.bitSize() != size.bitSize()) |
| 22244 | if (mnem_size) |size| if (reg.bitSize() != size.bitSize(self.target)) |
| 14432 | 22245 | return self.fail("invalid register size: '{s}'", .{op_str}); |
| 14433 | 22246 | op.* = .{ .reg = reg }; |
| 14434 | 22247 | } |
| 14435 | | } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) { |
| 14436 | | const colon = mem.indexOfScalarPos(u8, op_str, "%[".len, ':'); |
| 22248 | } else if (std.mem.startsWith(u8, op_str, "%[") and std.mem.endsWith(u8, op_str, "]")) { |
| 22249 | const colon = std.mem.indexOfScalarPos(u8, op_str, "%[".len, ':'); |
| 14437 | 22250 | const modifier = if (colon) |colon_pos| |
| 14438 | 22251 | op_str[colon_pos + ":".len .. op_str.len - "]".len] |
| 14439 | 22252 | else |
| ... | ... | @@ -14442,15 +22255,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14442 | 22255 | arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse |
| 14443 | 22256 | return self.fail("no matching constraint: '{s}'", .{op_str}) |
| 14444 | 22257 | ]) { |
| 14445 | | .immediate => |imm| if (mem.eql(u8, modifier, "") or mem.eql(u8, modifier, "c")) |
| 14446 | | .{ .imm = Immediate.u(imm) } |
| 22258 | .immediate => |imm| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "c")) |
| 22259 | .{ .imm = .u(imm) } |
| 14447 | 22260 | else |
| 14448 | 22261 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14449 | | .register => |reg| if (mem.eql(u8, modifier, "")) |
| 22262 | .register => |reg| if (std.mem.eql(u8, modifier, "")) |
| 14450 | 22263 | .{ .reg = reg } |
| 14451 | 22264 | else |
| 14452 | 22265 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14453 | | .memory => |addr| if (mem.eql(u8, modifier, "") or mem.eql(u8, modifier, "P")) |
| 22266 | .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P")) |
| 14454 | 22267 | .{ .mem = .{ |
| 14455 | 22268 | .base = .{ .reg = .ds }, |
| 14456 | 22269 | .mod = .{ .rm = .{ |
| ... | ... | @@ -14461,7 +22274,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14461 | 22274 | } } |
| 14462 | 22275 | else |
| 14463 | 22276 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14464 | | .indirect => |reg_off| if (mem.eql(u8, modifier, "")) |
| 22277 | .indirect => |reg_off| if (std.mem.eql(u8, modifier, "")) |
| 14465 | 22278 | .{ .mem = .{ |
| 14466 | 22279 | .base = .{ .reg = reg_off.reg }, |
| 14467 | 22280 | .mod = .{ .rm = .{ |
| ... | ... | @@ -14472,7 +22285,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14472 | 22285 | } } |
| 14473 | 22286 | else |
| 14474 | 22287 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14475 | | .load_frame => |frame_addr| if (mem.eql(u8, modifier, "")) |
| 22288 | .load_frame => |frame_addr| if (std.mem.eql(u8, modifier, "")) |
| 14476 | 22289 | .{ .mem = .{ |
| 14477 | 22290 | .base = .{ .frame = frame_addr.index }, |
| 14478 | 22291 | .mod = .{ .rm = .{ |
| ... | ... | @@ -14483,42 +22296,42 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14483 | 22296 | } } |
| 14484 | 22297 | else |
| 14485 | 22298 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14486 | | .lea_got => |sym_index| if (mem.eql(u8, modifier, "P")) |
| 14487 | | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) } |
| 22299 | .lea_got => |sym_index| if (std.mem.eql(u8, modifier, "P")) |
| 22300 | .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_got = sym_index }) } |
| 14488 | 22301 | else |
| 14489 | 22302 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14490 | | .lea_symbol => |sym_off| if (mem.eql(u8, modifier, "P")) |
| 14491 | | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_symbol = sym_off }) } |
| 22303 | .lea_symbol => |sym_off| if (std.mem.eql(u8, modifier, "P")) |
| 22304 | .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_symbol = sym_off }) } |
| 14492 | 22305 | else |
| 14493 | 22306 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14494 | 22307 | else => return self.fail("invalid constraint: '{s}'", .{op_str}), |
| 14495 | 22308 | }; |
| 14496 | | } else if (mem.startsWith(u8, op_str, "$")) { |
| 22309 | } else if (std.mem.startsWith(u8, op_str, "$")) { |
| 14497 | 22310 | if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| { |
| 14498 | 22311 | if (mnem_size) |size| { |
| 14499 | | const max = @as(u64, math.maxInt(u64)) >> @intCast(64 - (size.bitSize() - 1)); |
| 22312 | const max = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - (size.bitSize(self.target) - 1)); |
| 14500 | 22313 | if ((if (s < 0) ~s else s) > max) |
| 14501 | 22314 | return self.fail("invalid immediate size: '{s}'", .{op_str}); |
| 14502 | 22315 | } |
| 14503 | | op.* = .{ .imm = Immediate.s(s) }; |
| 22316 | op.* = .{ .imm = .s(s) }; |
| 14504 | 22317 | } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| { |
| 14505 | 22318 | if (mnem_size) |size| { |
| 14506 | | const max = @as(u64, math.maxInt(u64)) >> @intCast(64 - size.bitSize()); |
| 22319 | const max = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - size.bitSize(self.target)); |
| 14507 | 22320 | if (u > max) |
| 14508 | 22321 | return self.fail("invalid immediate size: '{s}'", .{op_str}); |
| 14509 | 22322 | } |
| 14510 | | op.* = .{ .imm = Immediate.u(u) }; |
| 22323 | op.* = .{ .imm = .u(u) }; |
| 14511 | 22324 | } else |_| return self.fail("invalid immediate: '{s}'", .{op_str}); |
| 14512 | | } else if (mem.endsWith(u8, op_str, ")")) { |
| 14513 | | const open = mem.indexOfScalar(u8, op_str, '(') orelse |
| 22325 | } else if (std.mem.endsWith(u8, op_str, ")")) { |
| 22326 | const open = std.mem.indexOfScalar(u8, op_str, '(') orelse |
| 14514 | 22327 | return self.fail("invalid operand: '{s}'", .{op_str}); |
| 14515 | | var sib_it = mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ','); |
| 22328 | var sib_it = std.mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ','); |
| 14516 | 22329 | const base_str = sib_it.next() orelse |
| 14517 | 22330 | return self.fail("invalid memory operand: '{s}'", .{op_str}); |
| 14518 | | if (base_str.len > 0 and !mem.startsWith(u8, base_str, "%%")) |
| 22331 | if (base_str.len > 0 and !std.mem.startsWith(u8, base_str, "%%")) |
| 14519 | 22332 | return self.fail("invalid memory operand: '{s}'", .{op_str}); |
| 14520 | 22333 | const index_str = sib_it.next() orelse ""; |
| 14521 | | if (index_str.len > 0 and !mem.startsWith(u8, base_str, "%%")) |
| 22334 | if (index_str.len > 0 and !std.mem.startsWith(u8, base_str, "%%")) |
| 14522 | 22335 | return self.fail("invalid memory operand: '{s}'", .{op_str}); |
| 14523 | 22336 | const scale_str = sib_it.next() orelse ""; |
| 14524 | 22337 | if (index_str.len == 0 and scale_str.len > 0) |
| ... | ... | @@ -14550,10 +22363,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14550 | 22363 | else |
| 14551 | 22364 | .none, |
| 14552 | 22365 | .scale = scale, |
| 14553 | | .disp = if (mem.startsWith(u8, op_str[0..open], "%[") and |
| 14554 | | mem.endsWith(u8, op_str[0..open], "]")) |
| 22366 | .disp = if (std.mem.startsWith(u8, op_str[0..open], "%[") and |
| 22367 | std.mem.endsWith(u8, op_str[0..open], "]")) |
| 14555 | 22368 | disp: { |
| 14556 | | const colon = mem.indexOfScalarPos(u8, op_str[0..open], "%[".len, ':'); |
| 22369 | const colon = std.mem.indexOfScalarPos(u8, op_str[0..open], "%[".len, ':'); |
| 14557 | 22370 | const modifier = if (colon) |colon_pos| |
| 14558 | 22371 | op_str[colon_pos + ":".len .. open - "]".len] |
| 14559 | 22372 | else |
| ... | ... | @@ -14562,9 +22375,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14562 | 22375 | arg_map.get(op_str["%[".len .. colon orelse open - "]".len]) orelse |
| 14563 | 22376 | return self.fail("no matching constraint: '{s}'", .{op_str}) |
| 14564 | 22377 | ]) { |
| 14565 | | .immediate => |imm| if (mem.eql(u8, modifier, "") or |
| 14566 | | mem.eql(u8, modifier, "c")) |
| 14567 | | math.cast(i32, @as(i64, @bitCast(imm))) orelse |
| 22378 | .immediate => |imm| if (std.mem.eql(u8, modifier, "") or |
| 22379 | std.mem.eql(u8, modifier, "c")) |
| 22380 | std.math.cast(i32, @as(i64, @bitCast(imm))) orelse |
| 14568 | 22381 | return self.fail("invalid displacement: '{s}'", .{op_str}) |
| 14569 | 22382 | else |
| 14570 | 22383 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| ... | ... | @@ -14592,8 +22405,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14592 | 22405 | try pending_relocs.append(self.gpa, @intCast(self.mir_instructions.len)); |
| 14593 | 22406 | op.* = .{ .inst = label_gop.value_ptr.target }; |
| 14594 | 22407 | } else return self.fail("invalid operand: '{s}'", .{op_str}); |
| 22408 | ops_len += 1; |
| 14595 | 22409 | } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str}); |
| 14596 | 22410 | |
| 22411 | // convert from att syntax to intel syntax |
| 22412 | std.mem.reverse(Operand, ops[0..ops_len]); |
| 22413 | |
| 14597 | 22414 | (if (prefix == .directive) switch (mnem_tag) { |
| 14598 | 22415 | .@".cfi_def_cfa" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none) |
| 14599 | 22416 | self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, ops[0].reg, ops[1].imm) |
| ... | ... | @@ -14649,68 +22466,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14649 | 22466 | error.InvalidInstruction, |
| 14650 | 22467 | .@".cfi_escape" => error.InvalidInstruction, |
| 14651 | 22468 | else => unreachable, |
| 14652 | | } else switch (ops[0]) { |
| 14653 | | .none => self.asmOpOnly(mnem_fixed_tag), |
| 14654 | | .reg => |reg0| switch (ops[1]) { |
| 14655 | | .none => self.asmRegister(mnem_fixed_tag, reg0), |
| 14656 | | .reg => |reg1| switch (ops[2]) { |
| 14657 | | .none => self.asmRegisterRegister(mnem_fixed_tag, reg1, reg0), |
| 14658 | | .reg => |reg2| switch (ops[3]) { |
| 14659 | | .none => self.asmRegisterRegisterRegister(mnem_fixed_tag, reg2, reg1, reg0), |
| 14660 | | else => error.InvalidInstruction, |
| 14661 | | }, |
| 14662 | | .mem => |mem2| switch (ops[3]) { |
| 14663 | | .none => self.asmMemoryRegisterRegister(mnem_fixed_tag, mem2, reg1, reg0), |
| 14664 | | else => error.InvalidInstruction, |
| 14665 | | }, |
| 14666 | | else => error.InvalidInstruction, |
| 14667 | | }, |
| 14668 | | .mem => |mem1| switch (ops[2]) { |
| 14669 | | .none => self.asmMemoryRegister(mnem_fixed_tag, mem1, reg0), |
| 14670 | | else => error.InvalidInstruction, |
| 14671 | | }, |
| 14672 | | else => error.InvalidInstruction, |
| 14673 | | }, |
| 14674 | | .mem => |mem0| switch (ops[1]) { |
| 14675 | | .none => self.asmMemory(mnem_fixed_tag, mem0), |
| 14676 | | .reg => |reg1| switch (ops[2]) { |
| 14677 | | .none => self.asmRegisterMemory(mnem_fixed_tag, reg1, mem0), |
| 14678 | | else => error.InvalidInstruction, |
| 14679 | | }, |
| 14680 | | else => error.InvalidInstruction, |
| 14681 | | }, |
| 14682 | | .imm => |imm0| switch (ops[1]) { |
| 14683 | | .none => self.asmImmediate(mnem_fixed_tag, imm0), |
| 14684 | | .reg => |reg1| switch (ops[2]) { |
| 14685 | | .none => self.asmRegisterImmediate(mnem_fixed_tag, reg1, imm0), |
| 14686 | | .reg => |reg2| switch (ops[3]) { |
| 14687 | | .none => self.asmRegisterRegisterImmediate(mnem_fixed_tag, reg2, reg1, imm0), |
| 14688 | | .reg => |reg3| self.asmRegisterRegisterRegisterImmediate( |
| 14689 | | mnem_fixed_tag, |
| 14690 | | reg3, |
| 14691 | | reg2, |
| 14692 | | reg1, |
| 14693 | | imm0, |
| 14694 | | ), |
| 14695 | | else => error.InvalidInstruction, |
| 14696 | | }, |
| 14697 | | .mem => |mem2| switch (ops[3]) { |
| 14698 | | .none => self.asmMemoryRegisterImmediate(mnem_fixed_tag, mem2, reg1, imm0), |
| 14699 | | else => error.InvalidInstruction, |
| 14700 | | }, |
| 14701 | | else => error.InvalidInstruction, |
| 14702 | | }, |
| 14703 | | .mem => |mem1| switch (ops[2]) { |
| 14704 | | .none => self.asmMemoryImmediate(mnem_fixed_tag, mem1, imm0), |
| 14705 | | else => error.InvalidInstruction, |
| 14706 | | }, |
| 14707 | | else => error.InvalidInstruction, |
| 14708 | | }, |
| 14709 | | .inst => |inst0| switch (ops[1]) { |
| 14710 | | .none => self.asmReloc(mnem_fixed_tag, inst0), |
| 14711 | | else => error.InvalidInstruction, |
| 14712 | | }, |
| 14713 | | }) catch |err| switch (err) { |
| 22469 | } else self.asmOps(mnem_fixed_tag, ops)) catch |err| switch (err) { |
| 14714 | 22470 | error.InvalidInstruction => return self.fail( |
| 14715 | 22471 | "invalid instruction: '{s} {s} {s} {s} {s}'", |
| 14716 | 22472 | .{ |
| ... | ... | @@ -14730,10 +22486,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14730 | 22486 | return self.fail("undefined label: '{s}'", .{label.key_ptr.*}); |
| 14731 | 22487 | |
| 14732 | 22488 | for (outputs, args.items[0..outputs.len]) |output, arg_mcv| { |
| 14733 | | const extra_bytes = mem.sliceAsBytes(self.air.extra[outputs_extra_i..]); |
| 22489 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]); |
| 14734 | 22490 | const constraint = |
| 14735 | | mem.sliceTo(mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0); |
| 14736 | | const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 22491 | std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0); |
| 22492 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| 14737 | 22493 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 14738 | 22494 | // for the string, we still use the next u32 for the null terminator. |
| 14739 | 22495 | outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| ... | ... | @@ -14745,7 +22501,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14745 | 22501 | } |
| 14746 | 22502 | |
| 14747 | 22503 | simple: { |
| 14748 | | var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); |
| 22504 | var buf: [Liveness.bpi - 1]Air.Inst.Ref = @splat(.none); |
| 14749 | 22505 | var buf_index: usize = 0; |
| 14750 | 22506 | for (outputs) |output| { |
| 14751 | 22507 | if (output == .none) continue; |
| ... | ... | @@ -14775,9 +22531,12 @@ const MoveStrategy = union(enum) { |
| 14775 | 22531 | extract: Mir.Inst.FixedTag, |
| 14776 | 22532 | }; |
| 14777 | 22533 | |
| 14778 | | pub fn read(strat: MoveStrategy, self: *Self, dst_reg: Register, src_mem: Memory) !void { |
| 22534 | pub fn read(strat: MoveStrategy, self: *CodeGen, dst_reg: Register, src_mem: Memory) !void { |
| 14779 | 22535 | switch (strat) { |
| 14780 | | .move => |tag| try self.asmRegisterMemory(tag, dst_reg, src_mem), |
| 22536 | .move => |tag| try self.asmRegisterMemory(tag, switch (tag[1]) { |
| 22537 | else => dst_reg, |
| 22538 | .lea => if (dst_reg.bitSize() >= 32) dst_reg else dst_reg.to32(), |
| 22539 | }, src_mem), |
| 14781 | 22540 | .x87_load_store => { |
| 14782 | 22541 | try self.asmMemory(.{ .f_, .ld }, src_mem); |
| 14783 | 22542 | assert(dst_reg != .st7); |
| ... | ... | @@ -14787,34 +22546,50 @@ const MoveStrategy = union(enum) { |
| 14787 | 22546 | ie.insert, |
| 14788 | 22547 | dst_reg, |
| 14789 | 22548 | src_mem, |
| 14790 | | Immediate.u(0), |
| 22549 | .u(0), |
| 14791 | 22550 | ), |
| 14792 | 22551 | .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate( |
| 14793 | 22552 | ie.insert, |
| 14794 | 22553 | dst_reg, |
| 14795 | 22554 | dst_reg, |
| 14796 | 22555 | src_mem, |
| 14797 | | Immediate.u(0), |
| 22556 | .u(0), |
| 14798 | 22557 | ), |
| 14799 | 22558 | } |
| 14800 | 22559 | } |
| 14801 | | pub fn write(strat: MoveStrategy, self: *Self, dst_mem: Memory, src_reg: Register) !void { |
| 22560 | pub fn write(strat: MoveStrategy, self: *CodeGen, dst_mem: Memory, src_reg: Register) !void { |
| 14802 | 22561 | switch (strat) { |
| 14803 | 22562 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_reg), |
| 14804 | 22563 | .x87_load_store => { |
| 14805 | 22564 | try self.asmRegister(.{ .f_, .ld }, src_reg); |
| 14806 | 22565 | try self.asmMemory(.{ .f_p, .st }, dst_mem); |
| 14807 | 22566 | }, |
| 14808 | | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| 14809 | | ie.extract, |
| 14810 | | dst_mem, |
| 14811 | | src_reg, |
| 14812 | | Immediate.u(0), |
| 14813 | | ), |
| 22567 | .insert_extract, .vex_insert_extract => |ie| if (ie.extract[0] != .p_w or self.hasFeature(.sse4_1)) |
| 22568 | try self.asmMemoryRegisterImmediate(ie.extract, dst_mem, src_reg, .u(0)) |
| 22569 | else if (self.hasFeature(.sse2)) { |
| 22570 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 22571 | try self.asmRegisterRegisterImmediate(ie.extract, tmp_reg.to32(), src_reg.to128(), .u(0)); |
| 22572 | try self.asmMemoryRegister(.{ ._, .mov }, dst_mem, tmp_reg.to16()); |
| 22573 | } else { |
| 22574 | const tmp_frame_index = try self.allocFrameIndex(.init(.{ |
| 22575 | .size = 16, |
| 22576 | .alignment = .@"16", |
| 22577 | })); |
| 22578 | try self.asmMemoryRegister(.{ ._ps, .mova }, .{ |
| 22579 | .base = .{ .frame = tmp_frame_index }, |
| 22580 | .mod = .{ .rm = .{ .size = .xword } }, |
| 22581 | }, src_reg.to128()); |
| 22582 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 22583 | try self.asmRegisterMemory(.{ ._, .mov }, tmp_reg.to16(), .{ |
| 22584 | .base = .{ .frame = tmp_frame_index }, |
| 22585 | .mod = .{ .rm = .{ .size = .word } }, |
| 22586 | }); |
| 22587 | try self.asmMemoryRegister(.{ ._, .mov }, dst_mem, tmp_reg.to16()); |
| 22588 | }, |
| 14814 | 22589 | } |
| 14815 | 22590 | } |
| 14816 | 22591 | }; |
| 14817 | | fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !MoveStrategy { |
| 22592 | fn moveStrategy(self: *CodeGen, ty: Type, class: Register.Class, aligned: bool) !MoveStrategy { |
| 14818 | 22593 | const pt = self.pt; |
| 14819 | 22594 | const zcu = pt.zcu; |
| 14820 | 22595 | switch (class) { |
| ... | ... | @@ -14823,7 +22598,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14823 | 22598 | .mmx => {}, |
| 14824 | 22599 | .sse => switch (ty.zigTypeTag(zcu)) { |
| 14825 | 22600 | else => { |
| 14826 | | const classes = mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none); |
| 22601 | const classes = std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none); |
| 14827 | 22602 | assert(std.mem.indexOfNone(abi.Class, classes, &.{ |
| 14828 | 22603 | .integer, .sse, .sseup, .memory, .float, .float_combine, |
| 14829 | 22604 | }) == null); |
| ... | ... | @@ -14853,10 +22628,13 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14853 | 22628 | else |
| 14854 | 22629 | .{ ._q, .mov } }, |
| 14855 | 22630 | 9...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 14856 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14857 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22631 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22632 | else if (self.hasFeature(.sse2)) |
| 22633 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22634 | else |
| 22635 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14858 | 22636 | 17...32 => if (self.hasFeature(.avx)) |
| 14859 | | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 22637 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14860 | 22638 | else => {}, |
| 14861 | 22639 | } else switch (abi_size) { |
| 14862 | 22640 | 4 => return .{ .move = if (self.hasFeature(.avx)) |
| ... | ... | @@ -14865,15 +22643,18 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14865 | 22643 | .{ ._ss, .mov } }, |
| 14866 | 22644 | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 14867 | 22645 | .{ .v_sd, .mov } |
| 22646 | else if (self.hasFeature(.sse2)) |
| 22647 | .{ ._sd, .mov } |
| 14868 | 22648 | else |
| 14869 | | .{ ._sd, .mov } }, |
| 22649 | .{ ._ps, .movl } }, |
| 14870 | 22650 | 9...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 14871 | | if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } |
| 14872 | | else if (aligned) .{ ._pd, .mova } else .{ ._pd, .movu } }, |
| 14873 | | 17...32 => if (self.hasFeature(.avx)) return .{ .move = if (aligned) |
| 14874 | | .{ .v_pd, .mova } |
| 22651 | .{ .v_pd, if (aligned) .mova else .movu } |
| 22652 | else if (self.hasFeature(.sse2)) |
| 22653 | .{ ._pd, if (aligned) .mova else .movu } |
| 14875 | 22654 | else |
| 14876 | | .{ .v_pd, .movu } }, |
| 22655 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 22656 | 17...32 => if (self.hasFeature(.avx)) |
| 22657 | return .{ .move = .{ .v_pd, if (aligned) .mova else .movu } }, |
| 14877 | 22658 | else => {}, |
| 14878 | 22659 | } |
| 14879 | 22660 | }, |
| ... | ... | @@ -14891,11 +22672,16 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14891 | 22672 | .{ ._ss, .mov } }, |
| 14892 | 22673 | 64 => return .{ .move = if (self.hasFeature(.avx)) |
| 14893 | 22674 | .{ .v_sd, .mov } |
| 22675 | else if (self.hasFeature(.sse2)) |
| 22676 | .{ ._sd, .mov } |
| 14894 | 22677 | else |
| 14895 | | .{ ._sd, .mov } }, |
| 22678 | .{ ._ps, .movl } }, |
| 14896 | 22679 | 128 => return .{ .move = if (self.hasFeature(.avx)) |
| 14897 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14898 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22680 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22681 | else if (self.hasFeature(.sse2)) |
| 22682 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22683 | else |
| 22684 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14899 | 22685 | else => {}, |
| 14900 | 22686 | }, |
| 14901 | 22687 | .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| ... | ... | @@ -14909,65 +22695,62 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14909 | 22695 | .int => switch (ty.childType(zcu).intInfo(zcu).bits) { |
| 14910 | 22696 | 1...8 => switch (ty.vectorLen(zcu)) { |
| 14911 | 22697 | 1...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 14912 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14913 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22698 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22699 | else if (self.hasFeature(.sse2)) |
| 22700 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22701 | else |
| 22702 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14914 | 22703 | 17...32 => if (self.hasFeature(.avx)) |
| 14915 | | return .{ .move = if (aligned) |
| 14916 | | .{ .v_, .movdqa } |
| 14917 | | else |
| 14918 | | .{ .v_, .movdqu } }, |
| 22704 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14919 | 22705 | else => {}, |
| 14920 | 22706 | }, |
| 14921 | 22707 | 9...16 => switch (ty.vectorLen(zcu)) { |
| 14922 | 22708 | 1...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 14923 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14924 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22709 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22710 | else if (self.hasFeature(.sse2)) |
| 22711 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22712 | else |
| 22713 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14925 | 22714 | 9...16 => if (self.hasFeature(.avx)) |
| 14926 | | return .{ .move = if (aligned) |
| 14927 | | .{ .v_, .movdqa } |
| 14928 | | else |
| 14929 | | .{ .v_, .movdqu } }, |
| 22715 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14930 | 22716 | else => {}, |
| 14931 | 22717 | }, |
| 14932 | 22718 | 17...32 => switch (ty.vectorLen(zcu)) { |
| 14933 | 22719 | 1...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 14934 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14935 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22720 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22721 | else if (self.hasFeature(.sse2)) |
| 22722 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22723 | else |
| 22724 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14936 | 22725 | 5...8 => if (self.hasFeature(.avx)) |
| 14937 | | return .{ .move = if (aligned) |
| 14938 | | .{ .v_, .movdqa } |
| 14939 | | else |
| 14940 | | .{ .v_, .movdqu } }, |
| 22726 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14941 | 22727 | else => {}, |
| 14942 | 22728 | }, |
| 14943 | 22729 | 33...64 => switch (ty.vectorLen(zcu)) { |
| 14944 | 22730 | 1...2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14945 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14946 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22731 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22732 | else if (self.hasFeature(.sse2)) |
| 22733 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22734 | else |
| 22735 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14947 | 22736 | 3...4 => if (self.hasFeature(.avx)) |
| 14948 | | return .{ .move = if (aligned) |
| 14949 | | .{ .v_, .movdqa } |
| 14950 | | else |
| 14951 | | .{ .v_, .movdqu } }, |
| 22737 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14952 | 22738 | else => {}, |
| 14953 | 22739 | }, |
| 14954 | 22740 | 65...128 => switch (ty.vectorLen(zcu)) { |
| 14955 | 22741 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 14956 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14957 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22742 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22743 | else if (self.hasFeature(.sse2)) |
| 22744 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22745 | else |
| 22746 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14958 | 22747 | 2 => if (self.hasFeature(.avx)) |
| 14959 | | return .{ .move = if (aligned) |
| 14960 | | .{ .v_, .movdqa } |
| 14961 | | else |
| 14962 | | .{ .v_, .movdqu } }, |
| 22748 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14963 | 22749 | else => {}, |
| 14964 | 22750 | }, |
| 14965 | 22751 | 129...256 => switch (ty.vectorLen(zcu)) { |
| 14966 | 22752 | 1 => if (self.hasFeature(.avx)) |
| 14967 | | return .{ .move = if (aligned) |
| 14968 | | .{ .v_, .movdqa } |
| 14969 | | else |
| 14970 | | .{ .v_, .movdqu } }, |
| 22753 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14971 | 22754 | else => {}, |
| 14972 | 22755 | }, |
| 14973 | 22756 | else => {}, |
| ... | ... | @@ -14975,13 +22758,13 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14975 | 22758 | .pointer, .optional => if (ty.childType(zcu).isPtrAtRuntime(zcu)) |
| 14976 | 22759 | switch (ty.vectorLen(zcu)) { |
| 14977 | 22760 | 1...2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14978 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14979 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22761 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22762 | else if (self.hasFeature(.sse2)) |
| 22763 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22764 | else |
| 22765 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14980 | 22766 | 3...4 => if (self.hasFeature(.avx)) |
| 14981 | | return .{ .move = if (aligned) |
| 14982 | | .{ .v_, .movdqa } |
| 14983 | | else |
| 14984 | | .{ .v_, .movdqu } }, |
| 22767 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14985 | 22768 | else => {}, |
| 14986 | 22769 | } |
| 14987 | 22770 | else |
| ... | ... | @@ -14989,46 +22772,42 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14989 | 22772 | .float => switch (ty.childType(zcu).floatBits(self.target.*)) { |
| 14990 | 22773 | 16 => switch (ty.vectorLen(zcu)) { |
| 14991 | 22774 | 1...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 14992 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14993 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22775 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22776 | else if (self.hasFeature(.sse2)) |
| 22777 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22778 | else |
| 22779 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 14994 | 22780 | 9...16 => if (self.hasFeature(.avx)) |
| 14995 | | return .{ .move = if (aligned) |
| 14996 | | .{ .v_, .movdqa } |
| 14997 | | else |
| 14998 | | .{ .v_, .movdqu } }, |
| 22781 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 14999 | 22782 | else => {}, |
| 15000 | 22783 | }, |
| 15001 | 22784 | 32 => switch (ty.vectorLen(zcu)) { |
| 15002 | 22785 | 1...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 15003 | | if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } |
| 15004 | | else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } }, |
| 22786 | .{ .v_ps, if (aligned) .mova else .movu } |
| 22787 | else |
| 22788 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 15005 | 22789 | 5...8 => if (self.hasFeature(.avx)) |
| 15006 | | return .{ .move = if (aligned) |
| 15007 | | .{ .v_ps, .mova } |
| 15008 | | else |
| 15009 | | .{ .v_ps, .movu } }, |
| 22790 | return .{ .move = .{ .v_ps, if (aligned) .mova else .movu } }, |
| 15010 | 22791 | else => {}, |
| 15011 | 22792 | }, |
| 15012 | 22793 | 64 => switch (ty.vectorLen(zcu)) { |
| 15013 | 22794 | 1...2 => return .{ .move = if (self.hasFeature(.avx)) |
| 15014 | | if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } |
| 15015 | | else if (aligned) .{ ._pd, .mova } else .{ ._pd, .movu } }, |
| 22795 | .{ .v_pd, if (aligned) .mova else .movu } |
| 22796 | else |
| 22797 | .{ ._pd, if (aligned) .mova else .movu } }, |
| 15016 | 22798 | 3...4 => if (self.hasFeature(.avx)) |
| 15017 | | return .{ .move = if (aligned) |
| 15018 | | .{ .v_pd, .mova } |
| 15019 | | else |
| 15020 | | .{ .v_pd, .movu } }, |
| 22799 | return .{ .move = .{ .v_pd, if (aligned) .mova else .movu } }, |
| 15021 | 22800 | else => {}, |
| 15022 | 22801 | }, |
| 15023 | 22802 | 128 => switch (ty.vectorLen(zcu)) { |
| 15024 | 22803 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 15025 | | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 15026 | | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 22804 | .{ if (aligned) .v_dqa else .v_dqu, .mov } |
| 22805 | else if (self.hasFeature(.sse2)) |
| 22806 | .{ if (aligned) ._dqa else ._dqu, .mov } |
| 22807 | else |
| 22808 | .{ ._ps, if (aligned) .mova else .movu } }, |
| 15027 | 22809 | 2 => if (self.hasFeature(.avx)) |
| 15028 | | return .{ .move = if (aligned) |
| 15029 | | .{ .v_, .movdqa } |
| 15030 | | else |
| 15031 | | .{ .v_, .movdqu } }, |
| 22810 | return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } }, |
| 15032 | 22811 | else => {}, |
| 15033 | 22812 | }, |
| 15034 | 22813 | else => {}, |
| ... | ... | @@ -15045,7 +22824,7 @@ const CopyOptions = struct { |
| 15045 | 22824 | safety: bool = false, |
| 15046 | 22825 | }; |
| 15047 | 22826 | |
| 15048 | | fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: CopyOptions) InnerError!void { |
| 22827 | fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: CopyOptions) InnerError!void { |
| 15049 | 22828 | const pt = self.pt; |
| 15050 | 22829 | |
| 15051 | 22830 | const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| ... | ... | @@ -15059,6 +22838,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: Copy |
| 15059 | 22838 | .immediate, |
| 15060 | 22839 | .eflags, |
| 15061 | 22840 | .register_overflow, |
| 22841 | .register_mask, |
| 15062 | 22842 | .lea_direct, |
| 15063 | 22843 | .lea_got, |
| 15064 | 22844 | .lea_tlv, |
| ... | ... | @@ -15088,42 +22868,93 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: Copy |
| 15088 | 22868 | .off = -dst_reg_off.off, |
| 15089 | 22869 | } }, |
| 15090 | 22870 | }, opts), |
| 15091 | | .register_pair => |dst_regs| { |
| 15092 | | const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) { |
| 15093 | | .register_pair, .memory, .indirect, .load_frame => null, |
| 15094 | | .load_symbol, .load_direct, .load_got, .load_tlv => src: { |
| 22871 | inline .register_pair, .register_triple, .register_quadruple => |dst_regs, dst_tag| { |
| 22872 | const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = src_info: switch (src_mcv) { |
| 22873 | .undef, .memory, .indirect, .load_frame => null, |
| 22874 | .register => |src_reg| switch (dst_regs[0].class()) { |
| 22875 | .general_purpose => switch (src_reg.class()) { |
| 22876 | else => unreachable, |
| 22877 | .sse => if (ty.abiSize(pt.zcu) <= 16) { |
| 22878 | if (self.hasFeature(.avx)) { |
| 22879 | try self.asmRegisterRegister(.{ .v_q, .mov }, dst_regs[0].to64(), src_reg.to128()); |
| 22880 | try self.asmRegisterRegisterImmediate(.{ .vp_q, .extr }, dst_regs[1].to64(), src_reg.to128(), .u(1)); |
| 22881 | } else if (self.hasFeature(.sse4_1)) { |
| 22882 | try self.asmRegisterRegister(.{ ._q, .mov }, dst_regs[0].to64(), src_reg.to128()); |
| 22883 | try self.asmRegisterRegisterImmediate(.{ .p_q, .extr }, dst_regs[1].to64(), src_reg.to128(), .u(1)); |
| 22884 | } else { |
| 22885 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse); |
| 22886 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 22887 | defer self.register_manager.unlockReg(tmp_lock); |
| 22888 | |
| 22889 | try self.asmRegisterRegister(.{ ._q, .mov }, dst_regs[0].to64(), src_reg.to128()); |
| 22890 | try self.asmRegisterRegister(.{ ._ps, .movhl }, tmp_reg.to128(), src_reg.to128()); |
| 22891 | try self.asmRegisterRegister(.{ ._q, .mov }, dst_regs[1].to64(), tmp_reg.to128()); |
| 22892 | } |
| 22893 | return; |
| 22894 | } else unreachable, |
| 22895 | }, |
| 22896 | else => unreachable, |
| 22897 | }, |
| 22898 | dst_tag => |src_regs| { |
| 22899 | var hazard_regs = src_regs; |
| 22900 | for (dst_regs, &hazard_regs, 1..) |dst_reg, src_reg, hazard_index| { |
| 22901 | const dst_id = dst_reg.id(); |
| 22902 | if (dst_id == src_reg.id()) continue; |
| 22903 | var mir_tag: Mir.Inst.Tag = .mov; |
| 22904 | for (hazard_regs[hazard_index..]) |*hazard_reg| { |
| 22905 | if (dst_id != hazard_reg.id()) continue; |
| 22906 | mir_tag = .xchg; |
| 22907 | hazard_reg.* = src_reg; |
| 22908 | } |
| 22909 | try self.asmRegisterRegister(.{ ._, mir_tag }, dst_reg.to64(), src_reg.to64()); |
| 22910 | } |
| 22911 | return; |
| 22912 | }, |
| 22913 | .load_symbol, .load_direct, .load_got, .load_tlv => { |
| 15095 | 22914 | const src_addr_reg = |
| 15096 | 22915 | (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); |
| 15097 | 22916 | const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg); |
| 15098 | 22917 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 15099 | 22918 | |
| 15100 | | try self.genSetReg(src_addr_reg, Type.usize, src_mcv.address(), opts); |
| 15101 | | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; |
| 22919 | try self.genSetReg(src_addr_reg, .usize, src_mcv.address(), opts); |
| 22920 | break :src_info .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; |
| 15102 | 22921 | }, |
| 15103 | | .air_ref => |src_ref| return self.genCopy( |
| 15104 | | ty, |
| 15105 | | dst_mcv, |
| 15106 | | try self.resolveInst(src_ref), |
| 15107 | | opts, |
| 15108 | | ), |
| 22922 | .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref), opts), |
| 15109 | 22923 | else => return self.fail("TODO implement genCopy for {s} of {}", .{ |
| 15110 | 22924 | @tagName(src_mcv), ty.fmt(pt), |
| 15111 | 22925 | }), |
| 15112 | 22926 | }; |
| 15113 | 22927 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); |
| 15114 | 22928 | |
| 15115 | | var part_disp: i32 = 0; |
| 15116 | | for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| { |
| 15117 | | try self.genSetReg(dst_reg, dst_ty, switch (src_mcv) { |
| 15118 | | .register_pair => |src_regs| .{ .register = src_regs[part_i] }, |
| 15119 | | .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(), |
| 15120 | | .load_symbol, .load_direct, .load_got, .load_tlv => .{ .indirect = .{ |
| 15121 | | .reg = src_info.?.addr_reg, |
| 15122 | | .off = part_disp, |
| 15123 | | } }, |
| 22929 | for ([_]bool{ false, true }) |emit_hazard| { |
| 22930 | var hazard_count: u3 = 0; |
| 22931 | var part_disp: i32 = 0; |
| 22932 | for (dst_regs, try self.splitType(dst_regs.len, ty), 0..) |dst_reg, dst_ty, part_i| { |
| 22933 | defer part_disp += @intCast(dst_ty.abiSize(pt.zcu)); |
| 22934 | const is_hazard = if (src_mcv.getReg()) |src_reg| |
| 22935 | dst_reg.id() == src_reg.id() |
| 22936 | else if (src_info) |info| |
| 22937 | dst_reg.id() == info.addr_reg.id() |
| 22938 | else |
| 22939 | false; |
| 22940 | if (is_hazard) hazard_count += 1; |
| 22941 | if (is_hazard != emit_hazard) continue; |
| 22942 | try self.genSetReg(dst_reg, dst_ty, switch (src_mcv) { |
| 22943 | .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef, |
| 22944 | dst_tag => |src_regs| .{ .register = src_regs[part_i] }, |
| 22945 | .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(), |
| 22946 | .load_symbol, .load_direct, .load_got, .load_tlv => .{ .indirect = .{ |
| 22947 | .reg = src_info.?.addr_reg, |
| 22948 | .off = part_disp, |
| 22949 | } }, |
| 22950 | else => unreachable, |
| 22951 | }, opts); |
| 22952 | } |
| 22953 | switch (hazard_count) { |
| 22954 | 0 => break, |
| 22955 | 1 => continue, |
| 15124 | 22956 | else => unreachable, |
| 15125 | | }, opts); |
| 15126 | | part_disp += @intCast(dst_ty.abiSize(pt.zcu)); |
| 22957 | } |
| 15127 | 22958 | } |
| 15128 | 22959 | }, |
| 15129 | 22960 | .indirect => |reg_off| try self.genSetMem( |
| ... | ... | @@ -15135,13 +22966,13 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: Copy |
| 15135 | 22966 | ), |
| 15136 | 22967 | .memory, .load_symbol, .load_direct, .load_got, .load_tlv => { |
| 15137 | 22968 | switch (dst_mcv) { |
| 15138 | | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| |
| 22969 | .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| |
| 15139 | 22970 | return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts), |
| 15140 | 22971 | .load_symbol, .load_direct, .load_got, .load_tlv => {}, |
| 15141 | 22972 | else => unreachable, |
| 15142 | 22973 | } |
| 15143 | 22974 | |
| 15144 | | const addr_reg = try self.copyToTmpRegister(Type.usize, dst_mcv.address()); |
| 22975 | const addr_reg = try self.copyToTmpRegister(.usize, dst_mcv.address()); |
| 15145 | 22976 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 15146 | 22977 | defer self.register_manager.unlockReg(addr_lock); |
| 15147 | 22978 | |
| ... | ... | @@ -15158,7 +22989,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: Copy |
| 15158 | 22989 | } |
| 15159 | 22990 | |
| 15160 | 22991 | fn genSetReg( |
| 15161 | | self: *Self, |
| 22992 | self: *CodeGen, |
| 15162 | 22993 | dst_reg: Register, |
| 15163 | 22994 | ty: Type, |
| 15164 | 22995 | src_mcv: MCValue, |
| ... | ... | @@ -15179,17 +23010,17 @@ fn genSetReg( |
| 15179 | 23010 | => unreachable, |
| 15180 | 23011 | .undef => if (opts.safety) switch (dst_reg.class()) { |
| 15181 | 23012 | .general_purpose => switch (abi_size) { |
| 15182 | | 1 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to8(), Immediate.u(0xAA)), |
| 15183 | | 2 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to16(), Immediate.u(0xAAAA)), |
| 23013 | 1 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to8(), .u(0xAA)), |
| 23014 | 2 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to16(), .u(0xAAAA)), |
| 15184 | 23015 | 3...4 => try self.asmRegisterImmediate( |
| 15185 | 23016 | .{ ._, .mov }, |
| 15186 | 23017 | dst_reg.to32(), |
| 15187 | | Immediate.s(@as(i32, @bitCast(@as(u32, 0xAAAAAAAA)))), |
| 23018 | .s(@as(i32, @bitCast(@as(u32, 0xAAAAAAAA)))), |
| 15188 | 23019 | ), |
| 15189 | 23020 | 5...8 => try self.asmRegisterImmediate( |
| 15190 | 23021 | .{ ._, .mov }, |
| 15191 | 23022 | dst_reg.to64(), |
| 15192 | | Immediate.u(0xAAAAAAAAAAAAAAAA), |
| 23023 | .u(0xAAAAAAAAAAAAAAAA), |
| 15193 | 23024 | ), |
| 15194 | 23025 | else => unreachable, |
| 15195 | 23026 | }, |
| ... | ... | @@ -15203,20 +23034,20 @@ fn genSetReg( |
| 15203 | 23034 | // register is the fastest way to zero a register. |
| 15204 | 23035 | try self.spillEflagsIfOccupied(); |
| 15205 | 23036 | try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()); |
| 15206 | | } else if (abi_size > 4 and math.cast(u32, imm) != null) { |
| 23037 | } else if (abi_size > 4 and std.math.cast(u32, imm) != null) { |
| 15207 | 23038 | // 32-bit moves zero-extend to 64-bit. |
| 15208 | | try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), Immediate.u(imm)); |
| 23039 | try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), .u(imm)); |
| 15209 | 23040 | } else if (abi_size <= 4 and @as(i64, @bitCast(imm)) < 0) { |
| 15210 | 23041 | try self.asmRegisterImmediate( |
| 15211 | 23042 | .{ ._, .mov }, |
| 15212 | 23043 | registerAlias(dst_reg, abi_size), |
| 15213 | | Immediate.s(@intCast(@as(i64, @bitCast(imm)))), |
| 23044 | .s(@intCast(@as(i64, @bitCast(imm)))), |
| 15214 | 23045 | ); |
| 15215 | 23046 | } else { |
| 15216 | 23047 | try self.asmRegisterImmediate( |
| 15217 | 23048 | .{ ._, .mov }, |
| 15218 | 23049 | registerAlias(dst_reg, abi_size), |
| 15219 | | Immediate.u(imm), |
| 23050 | .u(imm), |
| 15220 | 23051 | ); |
| 15221 | 23052 | } |
| 15222 | 23053 | }, |
| ... | ... | @@ -15233,7 +23064,7 @@ fn genSetReg( |
| 15233 | 23064 | src_reg, |
| 15234 | 23065 | ), |
| 15235 | 23066 | .x87, .mmx, .ip => unreachable, |
| 15236 | | .sse => try self.asmRegisterRegister( |
| 23067 | .sse => if (self.hasFeature(.sse2)) try self.asmRegisterRegister( |
| 15237 | 23068 | switch (abi_size) { |
| 15238 | 23069 | 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, |
| 15239 | 23070 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, |
| ... | ... | @@ -15241,7 +23072,20 @@ fn genSetReg( |
| 15241 | 23072 | }, |
| 15242 | 23073 | registerAlias(dst_reg, @max(abi_size, 4)), |
| 15243 | 23074 | src_reg.to128(), |
| 15244 | | ), |
| 23075 | ) else { |
| 23076 | const frame_index = try self.allocFrameIndex(.init(.{ |
| 23077 | .size = 4, |
| 23078 | .alignment = .@"4", |
| 23079 | })); |
| 23080 | try self.asmMemoryRegister(.{ ._ss, .mov }, .{ |
| 23081 | .base = .{ .frame = frame_index }, |
| 23082 | .mod = .{ .rm = .{ .size = .dword } }, |
| 23083 | }, src_reg.to128()); |
| 23084 | try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(dst_reg, abi_size), .{ |
| 23085 | .base = .{ .frame = frame_index }, |
| 23086 | .mod = .{ .rm = .{ .size = .fromSize(abi_size) } }, |
| 23087 | }); |
| 23088 | }, |
| 15245 | 23089 | }, |
| 15246 | 23090 | .segment => try self.asmRegisterRegister( |
| 15247 | 23091 | .{ ._, .mov }, |
| ... | ... | @@ -15286,17 +23130,17 @@ fn genSetReg( |
| 15286 | 23130 | .sse => try self.asmRegisterRegister( |
| 15287 | 23131 | @as(?Mir.Inst.FixedTag, switch (ty.scalarType(zcu).zigTypeTag(zcu)) { |
| 15288 | 23132 | else => switch (abi_size) { |
| 15289 | | 1...16 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else .{ ._, .movdqa }, |
| 15290 | | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, |
| 23133 | 1...16 => if (self.hasFeature(.avx)) .{ .v_dqa, .mov } else .{ ._dqa, .mov }, |
| 23134 | 17...32 => if (self.hasFeature(.avx)) .{ .v_dqa, .mov } else null, |
| 15291 | 23135 | else => null, |
| 15292 | 23136 | }, |
| 15293 | 23137 | .float => switch (ty.scalarType(zcu).floatBits(self.target.*)) { |
| 15294 | 23138 | 16, 128 => switch (abi_size) { |
| 15295 | 23139 | 2...16 => if (self.hasFeature(.avx)) |
| 15296 | | .{ .v_, .movdqa } |
| 23140 | .{ .v_dqa, .mov } |
| 15297 | 23141 | else |
| 15298 | | .{ ._, .movdqa }, |
| 15299 | | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, |
| 23142 | .{ ._dqa, .mov }, |
| 23143 | 17...32 => if (self.hasFeature(.avx)) .{ .v_dqa, .mov } else null, |
| 15300 | 23144 | else => null, |
| 15301 | 23145 | }, |
| 15302 | 23146 | 32 => if (self.hasFeature(.avx)) .{ .v_ps, .mova } else .{ ._ps, .mova }, |
| ... | ... | @@ -15311,7 +23155,42 @@ fn genSetReg( |
| 15311 | 23155 | }, |
| 15312 | 23156 | .ip => unreachable, |
| 15313 | 23157 | }, |
| 15314 | | .register_pair => |src_regs| try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts), |
| 23158 | inline .register_pair, |
| 23159 | .register_triple, |
| 23160 | .register_quadruple, |
| 23161 | => |src_regs| switch (dst_reg.class()) { |
| 23162 | .general_purpose => switch (src_regs[0].class()) { |
| 23163 | .general_purpose => try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts), |
| 23164 | else => unreachable, |
| 23165 | }, |
| 23166 | .sse => switch (src_regs[0].class()) { |
| 23167 | .general_purpose => if (abi_size <= 16) { |
| 23168 | if (self.hasFeature(.avx)) { |
| 23169 | try self.asmRegisterRegister(.{ .v_q, .mov }, dst_reg.to128(), src_regs[0].to64()); |
| 23170 | try self.asmRegisterRegisterRegisterImmediate( |
| 23171 | .{ .vp_q, .insr }, |
| 23172 | dst_reg.to128(), |
| 23173 | dst_reg.to128(), |
| 23174 | src_regs[1].to64(), |
| 23175 | .u(1), |
| 23176 | ); |
| 23177 | } else if (self.hasFeature(.sse4_1)) { |
| 23178 | try self.asmRegisterRegister(.{ ._q, .mov }, dst_reg.to128(), src_regs[0].to64()); |
| 23179 | try self.asmRegisterRegisterImmediate(.{ .p_q, .insr }, dst_reg.to128(), src_regs[1].to64(), .u(1)); |
| 23180 | } else { |
| 23181 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse); |
| 23182 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 23183 | defer self.register_manager.unlockReg(tmp_lock); |
| 23184 | |
| 23185 | try self.asmRegisterRegister(.{ ._q, .mov }, dst_reg.to128(), src_regs[0].to64()); |
| 23186 | try self.asmRegisterRegister(.{ ._q, .mov }, tmp_reg.to128(), src_regs[1].to64()); |
| 23187 | try self.asmRegisterRegister(.{ ._ps, .movlh }, dst_reg.to128(), tmp_reg.to128()); |
| 23188 | } |
| 23189 | } else unreachable, |
| 23190 | else => unreachable, |
| 23191 | }, |
| 23192 | else => unreachable, |
| 23193 | }, |
| 15315 | 23194 | .register_offset, |
| 15316 | 23195 | .indirect, |
| 15317 | 23196 | .load_frame, |
| ... | ... | @@ -15325,15 +23204,15 @@ fn genSetReg( |
| 15325 | 23204 | .load_frame => |frame_addr| try self.moveStrategy( |
| 15326 | 23205 | ty, |
| 15327 | 23206 | dst_reg.class(), |
| 15328 | | self.getFrameAddrAlignment(frame_addr).compare(.gte, Alignment.fromLog2Units( |
| 15329 | | math.log2_int_ceil(u10, @divExact(dst_reg.bitSize(), 8)), |
| 23207 | self.getFrameAddrAlignment(frame_addr).compare(.gte, .fromLog2Units( |
| 23208 | std.math.log2_int_ceil(u10, @divExact(dst_reg.bitSize(), 8)), |
| 15330 | 23209 | )), |
| 15331 | 23210 | ), |
| 15332 | 23211 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| 15333 | 23212 | else => unreachable, |
| 15334 | 23213 | }).read(self, registerAlias(dst_reg, abi_size), switch (src_mcv) { |
| 15335 | 23214 | .register_offset, .indirect => |reg_off| .{ |
| 15336 | | .base = .{ .reg = reg_off.reg }, |
| 23215 | .base = .{ .reg = reg_off.reg.to64() }, |
| 15337 | 23216 | .mod = .{ .rm = .{ |
| 15338 | 23217 | .size = self.memSize(ty), |
| 15339 | 23218 | .disp = reg_off.off, |
| ... | ... | @@ -15348,9 +23227,50 @@ fn genSetReg( |
| 15348 | 23227 | }, |
| 15349 | 23228 | else => unreachable, |
| 15350 | 23229 | }), |
| 23230 | .register_mask => |src_reg_mask| { |
| 23231 | assert(src_reg_mask.reg.class() == .sse); |
| 23232 | const has_avx = self.hasFeature(.avx); |
| 23233 | const bits_reg = switch (dst_reg.class()) { |
| 23234 | .general_purpose => dst_reg, |
| 23235 | else => try self.register_manager.allocReg(null, abi.RegisterClass.gp), |
| 23236 | }; |
| 23237 | const bits_lock = self.register_manager.lockReg(bits_reg); |
| 23238 | defer if (bits_lock) |lock| self.register_manager.unlockReg(lock); |
| 23239 | |
| 23240 | const pack_reg = switch (src_reg_mask.info.scalar) { |
| 23241 | else => src_reg_mask.reg, |
| 23242 | .word => try self.register_manager.allocReg(null, abi.RegisterClass.sse), |
| 23243 | }; |
| 23244 | const pack_lock = self.register_manager.lockReg(pack_reg); |
| 23245 | defer if (pack_lock) |lock| self.register_manager.unlockReg(lock); |
| 23246 | |
| 23247 | var mask_size: u32 = @intCast(ty.vectorLen(zcu) * @divExact(src_reg_mask.info.scalar.bitSize(self.target), 8)); |
| 23248 | switch (src_reg_mask.info.scalar) { |
| 23249 | else => {}, |
| 23250 | .word => { |
| 23251 | const src_alias = registerAlias(src_reg_mask.reg, mask_size); |
| 23252 | const pack_alias = registerAlias(pack_reg, mask_size); |
| 23253 | if (has_avx) { |
| 23254 | try self.asmRegisterRegisterRegister(.{ .vp_b, .ackssw }, pack_alias, src_alias, src_alias); |
| 23255 | } else { |
| 23256 | try self.asmRegisterRegister(.{ ._dqa, .mov }, pack_alias, src_alias); |
| 23257 | try self.asmRegisterRegister(.{ .p_b, .ackssw }, pack_alias, pack_alias); |
| 23258 | } |
| 23259 | mask_size = std.math.divCeil(u32, mask_size, 2) catch unreachable; |
| 23260 | }, |
| 23261 | } |
| 23262 | try self.asmRegisterRegister(.{ switch (src_reg_mask.info.scalar) { |
| 23263 | .byte, .word => if (has_avx) .vp_b else .p_b, |
| 23264 | .dword => if (has_avx) .v_ps else ._ps, |
| 23265 | .qword => if (has_avx) .v_pd else ._pd, |
| 23266 | else => unreachable, |
| 23267 | }, .movmsk }, bits_reg.to32(), registerAlias(pack_reg, mask_size)); |
| 23268 | if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size)); |
| 23269 | try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{}); |
| 23270 | }, |
| 15351 | 23271 | .memory, .load_symbol, .load_direct, .load_got, .load_tlv => { |
| 15352 | 23272 | switch (src_mcv) { |
| 15353 | | .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| |
| 23273 | .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| |
| 15354 | 23274 | return (try self.moveStrategy( |
| 15355 | 23275 | ty, |
| 15356 | 23276 | dst_reg.class(), |
| ... | ... | @@ -15396,18 +23316,14 @@ fn genSetReg( |
| 15396 | 23316 | else => unreachable, |
| 15397 | 23317 | } |
| 15398 | 23318 | |
| 15399 | | const addr_reg = try self.copyToTmpRegister(Type.usize, src_mcv.address()); |
| 23319 | const addr_reg = try self.copyToTmpRegister(.usize, src_mcv.address()); |
| 15400 | 23320 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 15401 | 23321 | defer self.register_manager.unlockReg(addr_lock); |
| 15402 | 23322 | |
| 15403 | | try (try self.moveStrategy(ty, dst_reg.class(), false)).read( |
| 15404 | | self, |
| 15405 | | registerAlias(dst_reg, abi_size), |
| 15406 | | .{ |
| 15407 | | .base = .{ .reg = addr_reg }, |
| 15408 | | .mod = .{ .rm = .{ .size = self.memSize(ty) } }, |
| 15409 | | }, |
| 15410 | | ); |
| 23323 | try (try self.moveStrategy(ty, dst_reg.class(), false)).read(self, registerAlias(dst_reg, abi_size), .{ |
| 23324 | .base = .{ .reg = addr_reg.to64() }, |
| 23325 | .mod = .{ .rm = .{ .size = self.memSize(ty) } }, |
| 23326 | }); |
| 15411 | 23327 | }, |
| 15412 | 23328 | .lea_symbol => |sym_off| switch (self.bin_file.tag) { |
| 15413 | 23329 | .elf, .macho => try self.asmRegisterMemory( |
| ... | ... | @@ -15447,7 +23363,7 @@ fn genSetReg( |
| 15447 | 23363 | } |
| 15448 | 23364 | |
| 15449 | 23365 | fn genSetMem( |
| 15450 | | self: *Self, |
| 23366 | self: *CodeGen, |
| 15451 | 23367 | base: Memory.Base, |
| 15452 | 23368 | disp: i32, |
| 15453 | 23369 | ty: Type, |
| ... | ... | @@ -15461,6 +23377,7 @@ fn genSetMem( |
| 15461 | 23377 | .none => .{ .immediate = @bitCast(@as(i64, disp)) }, |
| 15462 | 23378 | .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, |
| 15463 | 23379 | .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } }, |
| 23380 | .table => unreachable, |
| 15464 | 23381 | .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } }, |
| 15465 | 23382 | }; |
| 15466 | 23383 | switch (src_mcv) { |
| ... | ... | @@ -15478,31 +23395,31 @@ fn genSetMem( |
| 15478 | 23395 | ), |
| 15479 | 23396 | .immediate => |imm| switch (abi_size) { |
| 15480 | 23397 | 1, 2, 4 => { |
| 15481 | | const immediate = switch (if (ty.isAbiInt(zcu)) |
| 23398 | const immediate: Immediate = switch (if (ty.isAbiInt(zcu)) |
| 15482 | 23399 | ty.intInfo(zcu).signedness |
| 15483 | 23400 | else |
| 15484 | 23401 | .unsigned) { |
| 15485 | | .signed => Immediate.s(@truncate(@as(i64, @bitCast(imm)))), |
| 15486 | | .unsigned => Immediate.u(@as(u32, @intCast(imm))), |
| 23402 | .signed => .s(@truncate(@as(i64, @bitCast(imm)))), |
| 23403 | .unsigned => .u(@as(u32, @intCast(imm))), |
| 15487 | 23404 | }; |
| 15488 | 23405 | try self.asmMemoryImmediate( |
| 15489 | 23406 | .{ ._, .mov }, |
| 15490 | 23407 | .{ .base = base, .mod = .{ .rm = .{ |
| 15491 | | .size = Memory.Size.fromSize(abi_size), |
| 23408 | .size = .fromSize(abi_size), |
| 15492 | 23409 | .disp = disp, |
| 15493 | 23410 | } } }, |
| 15494 | 23411 | immediate, |
| 15495 | 23412 | ); |
| 15496 | 23413 | }, |
| 15497 | 23414 | 3, 5...7 => unreachable, |
| 15498 | | else => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| { |
| 23415 | else => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| { |
| 15499 | 23416 | try self.asmMemoryImmediate( |
| 15500 | 23417 | .{ ._, .mov }, |
| 15501 | 23418 | .{ .base = base, .mod = .{ .rm = .{ |
| 15502 | | .size = Memory.Size.fromSize(abi_size), |
| 23419 | .size = .fromSize(abi_size), |
| 15503 | 23420 | .disp = disp, |
| 15504 | 23421 | } } }, |
| 15505 | | Immediate.s(small), |
| 23422 | .s(small), |
| 15506 | 23423 | ); |
| 15507 | 23424 | } else { |
| 15508 | 23425 | var offset: i32 = 0; |
| ... | ... | @@ -15512,10 +23429,10 @@ fn genSetMem( |
| 15512 | 23429 | .size = .dword, |
| 15513 | 23430 | .disp = disp + offset, |
| 15514 | 23431 | } } }, |
| 15515 | | if (ty.isSignedInt(zcu)) Immediate.s( |
| 15516 | | @truncate(@as(i64, @bitCast(imm)) >> (math.cast(u6, offset * 8) orelse 63)), |
| 15517 | | ) else Immediate.u( |
| 15518 | | @as(u32, @truncate(if (math.cast(u6, offset * 8)) |shift| imm >> shift else 0)), |
| 23432 | if (ty.isSignedInt(zcu)) .s( |
| 23433 | @truncate(@as(i64, @bitCast(imm)) >> (std.math.cast(u6, offset * 8) orelse 63)), |
| 23434 | ) else .u( |
| 23435 | @as(u32, @truncate(if (std.math.cast(u6, offset * 8)) |shift| imm >> shift else 0)), |
| 15519 | 23436 | ), |
| 15520 | 23437 | ); |
| 15521 | 23438 | }, |
| ... | ... | @@ -15542,9 +23459,11 @@ fn genSetMem( |
| 15542 | 23459 | .general_purpose, .segment, .x87, .ip => @divExact(src_alias.bitSize(), 8), |
| 15543 | 23460 | .mmx, .sse => abi_size, |
| 15544 | 23461 | }); |
| 15545 | | const src_align = Alignment.fromNonzeroByteUnits(math.ceilPowerOfTwoAssert(u32, src_size)); |
| 23462 | const src_align: InternPool.Alignment = .fromNonzeroByteUnits( |
| 23463 | std.math.ceilPowerOfTwoAssert(u32, src_size), |
| 23464 | ); |
| 15546 | 23465 | if (src_size > mem_size) { |
| 15547 | | const frame_index = try self.allocFrameIndex(FrameAlloc.init(.{ |
| 23466 | const frame_index = try self.allocFrameIndex(.init(.{ |
| 15548 | 23467 | .size = src_size, |
| 15549 | 23468 | .alignment = src_align, |
| 15550 | 23469 | })); |
| ... | ... | @@ -15552,7 +23471,7 @@ fn genSetMem( |
| 15552 | 23471 | try (try self.moveStrategy(ty, src_alias.class(), true)).write( |
| 15553 | 23472 | self, |
| 15554 | 23473 | .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ |
| 15555 | | .size = Memory.Size.fromSize(src_size), |
| 23474 | .size = .fromSize(src_size), |
| 15556 | 23475 | } } }, |
| 15557 | 23476 | src_alias, |
| 15558 | 23477 | ); |
| ... | ... | @@ -15568,19 +23487,23 @@ fn genSetMem( |
| 15568 | 23487 | .index = frame_index, |
| 15569 | 23488 | .off = disp, |
| 15570 | 23489 | }).compare(.gte, src_align), |
| 23490 | .table => unreachable, |
| 15571 | 23491 | .reloc => false, |
| 15572 | 23492 | })).write( |
| 15573 | 23493 | self, |
| 15574 | 23494 | .{ .base = base, .mod = .{ .rm = .{ |
| 15575 | | .size = Memory.Size.fromBitSize(@min(self.memSize(ty).bitSize(), src_alias.bitSize())), |
| 23495 | .size = .fromBitSize(@min( |
| 23496 | self.memSize(ty).bitSize(self.target), |
| 23497 | src_alias.bitSize(), |
| 23498 | )), |
| 15576 | 23499 | .disp = disp, |
| 15577 | 23500 | } } }, |
| 15578 | 23501 | src_alias, |
| 15579 | 23502 | ); |
| 15580 | 23503 | }, |
| 15581 | | .register_pair => |src_regs| { |
| 23504 | inline .register_pair, .register_triple, .register_quadruple => |src_regs| { |
| 15582 | 23505 | var part_disp: i32 = disp; |
| 15583 | | for (try self.splitType(ty), src_regs) |src_ty, src_reg| { |
| 23506 | for (try self.splitType(src_regs.len, ty), src_regs) |src_ty, src_reg| { |
| 15584 | 23507 | try self.genSetMem(base, part_disp, src_ty, .{ .register = src_reg }, opts); |
| 15585 | 23508 | part_disp += @intCast(src_ty.abiSize(zcu)); |
| 15586 | 23509 | } |
| ... | ... | @@ -15609,7 +23532,7 @@ fn genSetMem( |
| 15609 | 23532 | try self.genSetMem( |
| 15610 | 23533 | base, |
| 15611 | 23534 | disp + @as(i32, @intCast(child_ty.abiSize(zcu))), |
| 15612 | | Type.bool, |
| 23535 | .bool, |
| 15613 | 23536 | .{ .eflags = ro.eflags }, |
| 15614 | 23537 | opts, |
| 15615 | 23538 | ); |
| ... | ... | @@ -15645,6 +23568,13 @@ fn genSetMem( |
| 15645 | 23568 | |
| 15646 | 23569 | try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); |
| 15647 | 23570 | }, |
| 23571 | .register_mask => { |
| 23572 | const src_reg = try self.copyToTmpRegister(ty, src_mcv); |
| 23573 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 23574 | defer self.register_manager.unlockReg(src_lock); |
| 23575 | |
| 23576 | try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); |
| 23577 | }, |
| 15648 | 23578 | .memory, |
| 15649 | 23579 | .indirect, |
| 15650 | 23580 | .load_direct, |
| ... | ... | @@ -15666,51 +23596,104 @@ fn genSetMem( |
| 15666 | 23596 | |
| 15667 | 23597 | try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); |
| 15668 | 23598 | }, |
| 15669 | | else => try self.genInlineMemcpy( |
| 15670 | | dst_ptr_mcv, |
| 15671 | | src_mcv.address(), |
| 15672 | | .{ .immediate = abi_size }, |
| 15673 | | ), |
| 23599 | else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }, .{ .no_alias = true }), |
| 15674 | 23600 | }, |
| 15675 | 23601 | .air_ref => |src_ref| try self.genSetMem(base, disp, ty, try self.resolveInst(src_ref), opts), |
| 15676 | 23602 | } |
| 15677 | 23603 | } |
| 15678 | 23604 | |
| 15679 | | fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue) InnerError!void { |
| 23605 | fn genInlineMemcpy(self: *CodeGen, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue, opts: struct { |
| 23606 | no_alias: bool, |
| 23607 | }) InnerError!void { |
| 23608 | if (opts.no_alias and dst_ptr.isAddress() and src_ptr.isAddress()) switch (len) { |
| 23609 | else => {}, |
| 23610 | .immediate => |len_imm| switch (len_imm) { |
| 23611 | else => {}, |
| 23612 | 1 => if (self.register_manager.tryAllocReg(null, abi.RegisterClass.gp)) |reg| { |
| 23613 | try self.asmRegisterMemory(.{ ._, .mov }, reg.to8(), try src_ptr.deref().mem(self, .{ .size = .byte })); |
| 23614 | try self.asmMemoryRegister(.{ ._, .mov }, try dst_ptr.deref().mem(self, .{ .size = .byte }), reg.to8()); |
| 23615 | return; |
| 23616 | }, |
| 23617 | 2 => if (self.register_manager.tryAllocReg(null, abi.RegisterClass.gp)) |reg| { |
| 23618 | try self.asmRegisterMemory(.{ ._, .mov }, reg.to16(), try src_ptr.deref().mem(self, .{ .size = .word })); |
| 23619 | try self.asmMemoryRegister(.{ ._, .mov }, try dst_ptr.deref().mem(self, .{ .size = .word }), reg.to16()); |
| 23620 | return; |
| 23621 | }, |
| 23622 | 4 => if (self.register_manager.tryAllocReg(null, abi.RegisterClass.gp)) |reg| { |
| 23623 | try self.asmRegisterMemory(.{ ._, .mov }, reg.to32(), try src_ptr.deref().mem(self, .{ .size = .dword })); |
| 23624 | try self.asmMemoryRegister(.{ ._, .mov }, try dst_ptr.deref().mem(self, .{ .size = .dword }), reg.to32()); |
| 23625 | return; |
| 23626 | }, |
| 23627 | 8 => if (self.target.cpu.arch == .x86_64) { |
| 23628 | if (self.register_manager.tryAllocReg(null, abi.RegisterClass.gp)) |reg| { |
| 23629 | try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), try src_ptr.deref().mem(self, .{ .size = .qword })); |
| 23630 | try self.asmMemoryRegister(.{ ._, .mov }, try dst_ptr.deref().mem(self, .{ .size = .qword }), reg.to64()); |
| 23631 | return; |
| 23632 | } |
| 23633 | }, |
| 23634 | 16 => if (self.hasFeature(.avx)) { |
| 23635 | if (self.register_manager.tryAllocReg(null, abi.RegisterClass.sse)) |reg| { |
| 23636 | try self.asmRegisterMemory(.{ .v_dqu, .mov }, reg.to128(), try src_ptr.deref().mem(self, .{ .size = .xword })); |
| 23637 | try self.asmMemoryRegister(.{ .v_dqu, .mov }, try dst_ptr.deref().mem(self, .{ .size = .xword }), reg.to128()); |
| 23638 | return; |
| 23639 | } |
| 23640 | } else if (self.hasFeature(.sse2)) { |
| 23641 | if (self.register_manager.tryAllocReg(null, abi.RegisterClass.sse)) |reg| { |
| 23642 | try self.asmRegisterMemory(.{ ._dqu, .mov }, reg.to128(), try src_ptr.deref().mem(self, .{ .size = .xword })); |
| 23643 | try self.asmMemoryRegister(.{ ._dqu, .mov }, try dst_ptr.deref().mem(self, .{ .size = .xword }), reg.to128()); |
| 23644 | return; |
| 23645 | } |
| 23646 | } else if (self.hasFeature(.sse)) { |
| 23647 | if (self.register_manager.tryAllocReg(null, abi.RegisterClass.sse)) |reg| { |
| 23648 | try self.asmRegisterMemory(.{ ._ps, .movu }, reg.to128(), try src_ptr.deref().mem(self, .{ .size = .xword })); |
| 23649 | try self.asmMemoryRegister(.{ ._ps, .movu }, try dst_ptr.deref().mem(self, .{ .size = .xword }), reg.to128()); |
| 23650 | return; |
| 23651 | } |
| 23652 | }, |
| 23653 | 32 => if (self.hasFeature(.avx)) { |
| 23654 | if (self.register_manager.tryAllocReg(null, abi.RegisterClass.sse)) |reg| { |
| 23655 | try self.asmRegisterMemory(.{ .v_dqu, .mov }, reg.to256(), try src_ptr.deref().mem(self, .{ .size = .yword })); |
| 23656 | try self.asmMemoryRegister(.{ .v_dqu, .mov }, try dst_ptr.deref().mem(self, .{ .size = .yword }), reg.to256()); |
| 23657 | return; |
| 23658 | } |
| 23659 | }, |
| 23660 | }, |
| 23661 | }; |
| 15680 | 23662 | try self.spillRegisters(&.{ .rsi, .rdi, .rcx }); |
| 15681 | | try self.genSetReg(.rsi, Type.usize, src_ptr, .{}); |
| 15682 | | try self.genSetReg(.rdi, Type.usize, dst_ptr, .{}); |
| 15683 | | try self.genSetReg(.rcx, Type.usize, len, .{}); |
| 23663 | try self.genSetReg(.rsi, .usize, src_ptr, .{}); |
| 23664 | try self.genSetReg(.rdi, .usize, dst_ptr, .{}); |
| 23665 | try self.genSetReg(.rcx, .usize, len, .{}); |
| 15684 | 23666 | try self.asmOpOnly(.{ .@"rep _sb", .mov }); |
| 15685 | 23667 | } |
| 15686 | 23668 | |
| 15687 | 23669 | fn genInlineMemset( |
| 15688 | | self: *Self, |
| 23670 | self: *CodeGen, |
| 15689 | 23671 | dst_ptr: MCValue, |
| 15690 | 23672 | value: MCValue, |
| 15691 | 23673 | len: MCValue, |
| 15692 | 23674 | opts: CopyOptions, |
| 15693 | 23675 | ) InnerError!void { |
| 15694 | 23676 | try self.spillRegisters(&.{ .rdi, .al, .rcx }); |
| 15695 | | try self.genSetReg(.rdi, Type.usize, dst_ptr, .{}); |
| 15696 | | try self.genSetReg(.al, Type.u8, value, opts); |
| 15697 | | try self.genSetReg(.rcx, Type.usize, len, .{}); |
| 23677 | try self.genSetReg(.rdi, .usize, dst_ptr, .{}); |
| 23678 | try self.genSetReg(.al, .u8, value, opts); |
| 23679 | try self.genSetReg(.rcx, .usize, len, .{}); |
| 15698 | 23680 | try self.asmOpOnly(.{ .@"rep _sb", .sto }); |
| 15699 | 23681 | } |
| 15700 | 23682 | |
| 15701 | 23683 | fn genExternSymbolRef( |
| 15702 | | self: *Self, |
| 23684 | self: *CodeGen, |
| 15703 | 23685 | comptime tag: Mir.Inst.Tag, |
| 15704 | 23686 | lib: ?[]const u8, |
| 15705 | 23687 | callee: []const u8, |
| 15706 | 23688 | ) InnerError!void { |
| 15707 | 23689 | if (self.bin_file.cast(.coff)) |coff_file| { |
| 15708 | 23690 | const global_index = try coff_file.getGlobalSymbol(callee, lib); |
| 23691 | const scratch_reg = abi.getCAbiLinkerScratchReg(self.fn_type.fnCallingConvention(self.pt.zcu)); |
| 15709 | 23692 | _ = try self.addInst(.{ |
| 15710 | 23693 | .tag = .mov, |
| 15711 | 23694 | .ops = .import_reloc, |
| 15712 | 23695 | .data = .{ .rx = .{ |
| 15713 | | .r1 = .rax, |
| 23696 | .r1 = scratch_reg, |
| 15714 | 23697 | .payload = try self.addExtra(bits.SymbolOffset{ |
| 15715 | 23698 | .sym_index = link.File.Coff.global_symbol_bit | global_index, |
| 15716 | 23699 | }), |
| ... | ... | @@ -15718,14 +23701,14 @@ fn genExternSymbolRef( |
| 15718 | 23701 | }); |
| 15719 | 23702 | switch (tag) { |
| 15720 | 23703 | .mov => {}, |
| 15721 | | .call => try self.asmRegister(.{ ._, .call }, .rax), |
| 23704 | .call => try self.asmRegister(.{ ._, .call }, scratch_reg), |
| 15722 | 23705 | else => unreachable, |
| 15723 | 23706 | } |
| 15724 | 23707 | } else return self.fail("TODO implement calling extern functions", .{}); |
| 15725 | 23708 | } |
| 15726 | 23709 | |
| 15727 | 23710 | fn genLazySymbolRef( |
| 15728 | | self: *Self, |
| 23711 | self: *CodeGen, |
| 15729 | 23712 | comptime tag: Mir.Inst.Tag, |
| 15730 | 23713 | reg: Register, |
| 15731 | 23714 | lazy_sym: link.File.LazySymbol, |
| ... | ... | @@ -15737,10 +23720,10 @@ fn genLazySymbolRef( |
| 15737 | 23720 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 15738 | 23721 | if (self.mod.pic) { |
| 15739 | 23722 | switch (tag) { |
| 15740 | | .lea, .call => try self.genSetReg(reg, Type.usize, .{ |
| 23723 | .lea, .call => try self.genSetReg(reg, .usize, .{ |
| 15741 | 23724 | .lea_symbol = .{ .sym_index = sym_index }, |
| 15742 | 23725 | }, .{}), |
| 15743 | | .mov => try self.genSetReg(reg, Type.usize, .{ |
| 23726 | .mov => try self.genSetReg(reg, .usize, .{ |
| 15744 | 23727 | .load_symbol = .{ .sym_index = sym_index }, |
| 15745 | 23728 | }, .{}), |
| 15746 | 23729 | else => unreachable, |
| ... | ... | @@ -15755,7 +23738,7 @@ fn genLazySymbolRef( |
| 15755 | 23738 | .base = .{ .reloc = sym_index }, |
| 15756 | 23739 | .mod = .{ .rm = .{ .size = .qword } }, |
| 15757 | 23740 | }), |
| 15758 | | .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym_index })), |
| 23741 | .call => try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym_index })), |
| 15759 | 23742 | else => unreachable, |
| 15760 | 23743 | } |
| 15761 | 23744 | } else if (self.bin_file.cast(.plan9)) |p9_file| { |
| ... | ... | @@ -15781,7 +23764,7 @@ fn genLazySymbolRef( |
| 15781 | 23764 | .mov => try self.asmRegisterMemory( |
| 15782 | 23765 | .{ ._, tag }, |
| 15783 | 23766 | reg.to64(), |
| 15784 | | Memory.initSib(.qword, .{ .base = .{ .reg = reg.to64() } }), |
| 23767 | .initSib(.qword, .{ .base = .{ .reg = reg.to64() } }), |
| 15785 | 23768 | ), |
| 15786 | 23769 | else => unreachable, |
| 15787 | 23770 | } |
| ... | ... | @@ -15790,8 +23773,8 @@ fn genLazySymbolRef( |
| 15790 | 23773 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 15791 | 23774 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 15792 | 23775 | switch (tag) { |
| 15793 | | .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }, .{}), |
| 15794 | | .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }, .{}), |
| 23776 | .lea, .call => try self.genSetReg(reg, .usize, .{ .lea_got = sym_index }, .{}), |
| 23777 | .mov => try self.genSetReg(reg, .usize, .{ .load_got = sym_index }, .{}), |
| 15795 | 23778 | else => unreachable, |
| 15796 | 23779 | } |
| 15797 | 23780 | switch (tag) { |
| ... | ... | @@ -15805,10 +23788,10 @@ fn genLazySymbolRef( |
| 15805 | 23788 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 15806 | 23789 | const sym = zo.symbols.items[sym_index]; |
| 15807 | 23790 | switch (tag) { |
| 15808 | | .lea, .call => try self.genSetReg(reg, Type.usize, .{ |
| 23791 | .lea, .call => try self.genSetReg(reg, .usize, .{ |
| 15809 | 23792 | .lea_symbol = .{ .sym_index = sym.nlist_idx }, |
| 15810 | 23793 | }, .{}), |
| 15811 | | .mov => try self.genSetReg(reg, Type.usize, .{ |
| 23794 | .mov => try self.genSetReg(reg, .usize, .{ |
| 15812 | 23795 | .load_symbol = .{ .sym_index = sym.nlist_idx }, |
| 15813 | 23796 | }, .{}), |
| 15814 | 23797 | else => unreachable, |
| ... | ... | @@ -15823,7 +23806,7 @@ fn genLazySymbolRef( |
| 15823 | 23806 | } |
| 15824 | 23807 | } |
| 15825 | 23808 | |
| 15826 | | fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 23809 | fn airIntFromPtr(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 15827 | 23810 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 15828 | 23811 | const result = result: { |
| 15829 | 23812 | // TODO: handle case where the operand is a slice not a raw pointer |
| ... | ... | @@ -15838,7 +23821,7 @@ fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 15838 | 23821 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 15839 | 23822 | } |
| 15840 | 23823 | |
| 15841 | | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 23824 | fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 15842 | 23825 | const pt = self.pt; |
| 15843 | 23826 | const zcu = pt.zcu; |
| 15844 | 23827 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -15852,18 +23835,20 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 15852 | 23835 | else => if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv, |
| 15853 | 23836 | }; |
| 15854 | 23837 | |
| 15855 | | const dst_rc = self.regClassForType(dst_ty); |
| 15856 | | const src_rc = self.regClassForType(src_ty); |
| 23838 | const dst_rc = self.regSetForType(dst_ty); |
| 23839 | const src_rc = self.regSetForType(src_ty); |
| 15857 | 23840 | |
| 15858 | | const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 23841 | const src_lock = if (src_mcv.getReg()) |src_reg| self.register_manager.lockReg(src_reg) else null; |
| 15859 | 23842 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 15860 | 23843 | |
| 15861 | | const dst_mcv = if (dst_rc.supersetOf(src_rc) and dst_ty.abiSize(zcu) <= src_ty.abiSize(zcu) and |
| 23844 | const dst_mcv = if ((if (src_mcv.getReg()) |src_reg| src_reg.class() == .general_purpose else true) and |
| 23845 | dst_rc.supersetOf(src_rc) and dst_ty.abiSize(zcu) <= src_ty.abiSize(zcu) and |
| 23846 | dst_ty.abiAlignment(zcu).order(src_ty.abiAlignment(zcu)).compare(.lte) and |
| 15862 | 23847 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { |
| 15863 | 23848 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 15864 | | try self.genCopy(switch (math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) { |
| 23849 | try self.genCopy(switch (std.math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) { |
| 15865 | 23850 | .lt => dst_ty, |
| 15866 | | .eq => if (!dst_mcv.isMemory() or src_mcv.isMemory()) dst_ty else src_ty, |
| 23851 | .eq => if (!dst_mcv.isBase() or src_mcv.isBase()) dst_ty else src_ty, |
| 15867 | 23852 | .gt => src_ty, |
| 15868 | 23853 | }, dst_mcv, src_mcv, .{}); |
| 15869 | 23854 | break :dst dst_mcv; |
| ... | ... | @@ -15878,7 +23863,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 15878 | 23863 | const bit_size = dst_ty.bitSize(zcu); |
| 15879 | 23864 | if (abi_size * 8 <= bit_size or dst_ty.isVector(zcu)) break :result dst_mcv; |
| 15880 | 23865 | |
| 15881 | | const dst_limbs_len = math.divCeil(i32, @intCast(bit_size), 64) catch unreachable; |
| 23866 | const dst_limbs_len = std.math.divCeil(u31, @intCast(bit_size), 64) catch unreachable; |
| 15882 | 23867 | const high_mcv: MCValue = switch (dst_mcv) { |
| 15883 | 23868 | .register => |dst_reg| .{ .register = dst_reg }, |
| 15884 | 23869 | .register_pair => |dst_regs| .{ .register = dst_regs[1] }, |
| ... | ... | @@ -15887,23 +23872,49 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 15887 | 23872 | const high_reg = if (high_mcv.isRegister()) |
| 15888 | 23873 | high_mcv.getReg().? |
| 15889 | 23874 | else |
| 15890 | | try self.copyToTmpRegister(Type.usize, high_mcv); |
| 23875 | try self.copyToTmpRegister(.usize, high_mcv); |
| 15891 | 23876 | const high_lock = self.register_manager.lockReg(high_reg); |
| 15892 | 23877 | defer if (high_lock) |lock| self.register_manager.unlockReg(lock); |
| 15893 | | |
| 15894 | 23878 | try self.truncateRegister(dst_ty, high_reg); |
| 15895 | 23879 | if (!high_mcv.isRegister()) try self.genCopy( |
| 15896 | | if (abi_size <= 8) dst_ty else Type.usize, |
| 23880 | if (abi_size <= 8) dst_ty else .usize, |
| 15897 | 23881 | high_mcv, |
| 15898 | 23882 | .{ .register = high_reg }, |
| 15899 | 23883 | .{}, |
| 15900 | 23884 | ); |
| 23885 | var offset = dst_limbs_len * 8; |
| 23886 | if (offset < abi_size) { |
| 23887 | const dst_signedness: std.builtin.Signedness = if (dst_ty.isAbiInt(zcu)) |
| 23888 | dst_ty.intInfo(zcu).signedness |
| 23889 | else |
| 23890 | .unsigned; |
| 23891 | const ext_mcv: MCValue = ext_mcv: switch (dst_signedness) { |
| 23892 | .signed => { |
| 23893 | try self.asmRegisterImmediate(.{ ._r, .sa }, high_reg, .u(63)); |
| 23894 | break :ext_mcv .{ .register = high_reg }; |
| 23895 | }, |
| 23896 | .unsigned => .{ .immediate = 0 }, |
| 23897 | }; |
| 23898 | while (offset < abi_size) : (offset += 8) { |
| 23899 | const limb_mcv: MCValue = switch (dst_mcv) { |
| 23900 | .register => |dst_reg| .{ .register = dst_reg }, |
| 23901 | .register_pair => |dst_regs| .{ .register = dst_regs[@divExact(offset, 8)] }, |
| 23902 | else => dst_mcv.address().offset(offset).deref(), |
| 23903 | }; |
| 23904 | const limb_lock = if (limb_mcv.isRegister()) |
| 23905 | self.register_manager.lockReg(limb_mcv.getReg().?) |
| 23906 | else |
| 23907 | null; |
| 23908 | defer if (limb_lock) |lock| self.register_manager.unlockReg(lock); |
| 23909 | try self.genCopy(.usize, limb_mcv, ext_mcv, .{}); |
| 23910 | } |
| 23911 | } |
| 15901 | 23912 | break :result dst_mcv; |
| 15902 | 23913 | }; |
| 15903 | 23914 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 15904 | 23915 | } |
| 15905 | 23916 | |
| 15906 | | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 23917 | fn airArrayToSlice(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 15907 | 23918 | const pt = self.pt; |
| 15908 | 23919 | const zcu = pt.zcu; |
| 15909 | 23920 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -15914,12 +23925,12 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 15914 | 23925 | const array_ty = ptr_ty.childType(zcu); |
| 15915 | 23926 | const array_len = array_ty.arrayLen(zcu); |
| 15916 | 23927 | |
| 15917 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(slice_ty, zcu)); |
| 23928 | const frame_index = try self.allocFrameIndex(.initSpill(slice_ty, zcu)); |
| 15918 | 23929 | try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr, .{}); |
| 15919 | 23930 | try self.genSetMem( |
| 15920 | 23931 | .{ .frame = frame_index }, |
| 15921 | 23932 | @intCast(ptr_ty.abiSize(zcu)), |
| 15922 | | Type.usize, |
| 23933 | .usize, |
| 15923 | 23934 | .{ .immediate = array_len }, |
| 15924 | 23935 | .{}, |
| 15925 | 23936 | ); |
| ... | ... | @@ -15928,7 +23939,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 15928 | 23939 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 15929 | 23940 | } |
| 15930 | 23941 | |
| 15931 | | fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { |
| 23942 | fn airFloatFromInt(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 15932 | 23943 | const pt = self.pt; |
| 15933 | 23944 | const zcu = pt.zcu; |
| 15934 | 23945 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -15940,7 +23951,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { |
| 15940 | 23951 | const src_bits: u32 = @intCast(src_ty.bitSize(zcu)); |
| 15941 | 23952 | const src_signedness = |
| 15942 | 23953 | if (src_ty.isAbiInt(zcu)) src_ty.intInfo(zcu).signedness else .unsigned; |
| 15943 | | const src_size = math.divCeil(u32, @max(switch (src_signedness) { |
| 23954 | const src_size = std.math.divCeil(u32, @max(switch (src_signedness) { |
| 15944 | 23955 | .signed => src_bits, |
| 15945 | 23956 | .unsigned => src_bits + 1, |
| 15946 | 23957 | }, 32), 8) catch unreachable; |
| ... | ... | @@ -15967,7 +23978,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { |
| 15967 | 23978 | intCompilerRtAbiName(src_bits), |
| 15968 | 23979 | floatCompilerRtAbiName(dst_bits), |
| 15969 | 23980 | }) catch unreachable, |
| 15970 | | } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}); |
| 23981 | } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}, .{}); |
| 15971 | 23982 | } |
| 15972 | 23983 | |
| 15973 | 23984 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -15980,7 +23991,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { |
| 15980 | 23991 | |
| 15981 | 23992 | if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg); |
| 15982 | 23993 | |
| 15983 | | const dst_reg = try self.register_manager.allocReg(inst, self.regClassForType(dst_ty)); |
| 23994 | const dst_reg = try self.register_manager.allocReg(inst, self.regSetForType(dst_ty)); |
| 15984 | 23995 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 15985 | 23996 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 15986 | 23997 | defer self.register_manager.unlockReg(dst_lock); |
| ... | ... | @@ -16008,7 +24019,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { |
| 16008 | 24019 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 16009 | 24020 | } |
| 16010 | 24021 | |
| 16011 | | fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 24022 | fn airIntFromFloat(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 16012 | 24023 | const pt = self.pt; |
| 16013 | 24024 | const zcu = pt.zcu; |
| 16014 | 24025 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| ... | ... | @@ -16017,7 +24028,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 16017 | 24028 | const dst_bits: u32 = @intCast(dst_ty.bitSize(zcu)); |
| 16018 | 24029 | const dst_signedness = |
| 16019 | 24030 | if (dst_ty.isAbiInt(zcu)) dst_ty.intInfo(zcu).signedness else .unsigned; |
| 16020 | | const dst_size = math.divCeil(u32, @max(switch (dst_signedness) { |
| 24031 | const dst_size = std.math.divCeil(u32, @max(switch (dst_signedness) { |
| 16021 | 24032 | .signed => dst_bits, |
| 16022 | 24033 | .unsigned => dst_bits + 1, |
| 16023 | 24034 | }, 32), 8) catch unreachable; |
| ... | ... | @@ -16047,7 +24058,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 16047 | 24058 | floatCompilerRtAbiName(src_bits), |
| 16048 | 24059 | intCompilerRtAbiName(dst_bits), |
| 16049 | 24060 | }) catch unreachable, |
| 16050 | | } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}); |
| 24061 | } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}, .{}); |
| 16051 | 24062 | } |
| 16052 | 24063 | |
| 16053 | 24064 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -16058,7 +24069,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 16058 | 24069 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 16059 | 24070 | defer self.register_manager.unlockReg(src_lock); |
| 16060 | 24071 | |
| 16061 | | const dst_reg = try self.register_manager.allocReg(inst, self.regClassForType(dst_ty)); |
| 24072 | const dst_reg = try self.register_manager.allocReg(inst, self.regSetForType(dst_ty)); |
| 16062 | 24073 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 16063 | 24074 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 16064 | 24075 | defer self.register_manager.unlockReg(dst_lock); |
| ... | ... | @@ -16080,7 +24091,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 16080 | 24091 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 16081 | 24092 | } |
| 16082 | 24093 | |
| 16083 | | fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 24094 | fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 16084 | 24095 | const pt = self.pt; |
| 16085 | 24096 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 16086 | 24097 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| ... | ... | @@ -16097,37 +24108,37 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 16097 | 24108 | if (val_abi_size > 8) { |
| 16098 | 24109 | const exp_addr_mcv: MCValue = switch (exp_mcv) { |
| 16099 | 24110 | .memory, .indirect, .load_frame => exp_mcv.address(), |
| 16100 | | else => .{ .register = try self.copyToTmpRegister(Type.usize, exp_mcv.address()) }, |
| 24111 | else => .{ .register = try self.copyToTmpRegister(.usize, exp_mcv.address()) }, |
| 16101 | 24112 | }; |
| 16102 | 24113 | const exp_addr_lock = |
| 16103 | 24114 | if (exp_addr_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 16104 | 24115 | defer if (exp_addr_lock) |lock| self.register_manager.unlockReg(lock); |
| 16105 | 24116 | |
| 16106 | | try self.genSetReg(.rax, Type.usize, exp_addr_mcv.deref(), .{}); |
| 16107 | | try self.genSetReg(.rdx, Type.usize, exp_addr_mcv.offset(8).deref(), .{}); |
| 24117 | try self.genSetReg(.rax, .usize, exp_addr_mcv.deref(), .{}); |
| 24118 | try self.genSetReg(.rdx, .usize, exp_addr_mcv.offset(8).deref(), .{}); |
| 16108 | 24119 | } else try self.genSetReg(.rax, val_ty, exp_mcv, .{}); |
| 16109 | 24120 | |
| 16110 | 24121 | const new_mcv = try self.resolveInst(extra.new_value); |
| 16111 | 24122 | const new_reg = if (val_abi_size > 8) new: { |
| 16112 | 24123 | const new_addr_mcv: MCValue = switch (new_mcv) { |
| 16113 | 24124 | .memory, .indirect, .load_frame => new_mcv.address(), |
| 16114 | | else => .{ .register = try self.copyToTmpRegister(Type.usize, new_mcv.address()) }, |
| 24125 | else => .{ .register = try self.copyToTmpRegister(.usize, new_mcv.address()) }, |
| 16115 | 24126 | }; |
| 16116 | 24127 | const new_addr_lock = |
| 16117 | 24128 | if (new_addr_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 16118 | 24129 | defer if (new_addr_lock) |lock| self.register_manager.unlockReg(lock); |
| 16119 | 24130 | |
| 16120 | | try self.genSetReg(.rbx, Type.usize, new_addr_mcv.deref(), .{}); |
| 16121 | | try self.genSetReg(.rcx, Type.usize, new_addr_mcv.offset(8).deref(), .{}); |
| 24131 | try self.genSetReg(.rbx, .usize, new_addr_mcv.deref(), .{}); |
| 24132 | try self.genSetReg(.rcx, .usize, new_addr_mcv.offset(8).deref(), .{}); |
| 16122 | 24133 | break :new null; |
| 16123 | 24134 | } else try self.copyToTmpRegister(val_ty, new_mcv); |
| 16124 | 24135 | const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; |
| 16125 | 24136 | defer if (new_lock) |lock| self.register_manager.unlockReg(lock); |
| 16126 | 24137 | |
| 16127 | 24138 | const ptr_mcv = try self.resolveInst(extra.ptr); |
| 16128 | | const mem_size = Memory.Size.fromSize(val_abi_size); |
| 24139 | const mem_size: Memory.Size = .fromSize(val_abi_size); |
| 16129 | 24140 | const ptr_mem: Memory = switch (ptr_mcv) { |
| 16130 | | .immediate, .register, .register_offset, .lea_frame => try ptr_mcv.deref().mem(self, mem_size), |
| 24141 | .immediate, .register, .register_offset, .lea_frame => try ptr_mcv.deref().mem(self, .{ .size = mem_size }), |
| 16131 | 24142 | else => .{ |
| 16132 | 24143 | .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, |
| 16133 | 24144 | .mod = .{ .rm = .{ .size = mem_size } }, |
| ... | ... | @@ -16140,6 +24151,7 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 16140 | 24151 | const ptr_lock = switch (ptr_mem.base) { |
| 16141 | 24152 | .none, .frame, .reloc => null, |
| 16142 | 24153 | .reg => |reg| self.register_manager.lockReg(reg), |
| 24154 | .table => unreachable, |
| 16143 | 24155 | }; |
| 16144 | 24156 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 16145 | 24157 | |
| ... | ... | @@ -16159,16 +24171,16 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 16159 | 24171 | } |
| 16160 | 24172 | |
| 16161 | 24173 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 16162 | | try self.genCopy(Type.usize, dst_mcv, .{ .register = .rax }, .{}); |
| 16163 | | try self.genCopy(Type.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx }, .{}); |
| 16164 | | try self.genCopy(Type.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne }, .{}); |
| 24174 | try self.genCopy(.usize, dst_mcv, .{ .register = .rax }, .{}); |
| 24175 | try self.genCopy(.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx }, .{}); |
| 24176 | try self.genCopy(.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne }, .{}); |
| 16165 | 24177 | break :result dst_mcv; |
| 16166 | 24178 | }; |
| 16167 | 24179 | return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value }); |
| 16168 | 24180 | } |
| 16169 | 24181 | |
| 16170 | 24182 | fn atomicOp( |
| 16171 | | self: *Self, |
| 24183 | self: *CodeGen, |
| 16172 | 24184 | ptr_mcv: MCValue, |
| 16173 | 24185 | val_mcv: MCValue, |
| 16174 | 24186 | ptr_ty: Type, |
| ... | ... | @@ -16192,9 +24204,9 @@ fn atomicOp( |
| 16192 | 24204 | defer if (val_lock) |lock| self.register_manager.unlockReg(lock); |
| 16193 | 24205 | |
| 16194 | 24206 | const val_abi_size: u32 = @intCast(val_ty.abiSize(zcu)); |
| 16195 | | const mem_size = Memory.Size.fromSize(val_abi_size); |
| 24207 | const mem_size: Memory.Size = .fromSize(val_abi_size); |
| 16196 | 24208 | const ptr_mem: Memory = switch (ptr_mcv) { |
| 16197 | | .immediate, .register, .register_offset, .lea_frame => try ptr_mcv.deref().mem(self, mem_size), |
| 24209 | .immediate, .register, .register_offset, .lea_frame => try ptr_mcv.deref().mem(self, .{ .size = mem_size }), |
| 16198 | 24210 | else => .{ |
| 16199 | 24211 | .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, |
| 16200 | 24212 | .mod = .{ .rm = .{ .size = mem_size } }, |
| ... | ... | @@ -16207,6 +24219,7 @@ fn atomicOp( |
| 16207 | 24219 | const mem_lock = switch (ptr_mem.base) { |
| 16208 | 24220 | .none, .frame, .reloc => null, |
| 16209 | 24221 | .reg => |reg| self.register_manager.lockReg(reg), |
| 24222 | .table => unreachable, |
| 16210 | 24223 | }; |
| 16211 | 24224 | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); |
| 16212 | 24225 | |
| ... | ... | @@ -16309,11 +24322,11 @@ fn atomicOp( |
| 16309 | 24322 | }); |
| 16310 | 24323 | try self.genSetReg(sse_reg, val_ty, .{ .register = .rax }, .{}); |
| 16311 | 24324 | switch (mir_tag[0]) { |
| 16312 | | .v_ss, .v_sd => if (val_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 24325 | .v_ss, .v_sd => if (val_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 16313 | 24326 | mir_tag, |
| 16314 | 24327 | sse_reg.to128(), |
| 16315 | 24328 | sse_reg.to128(), |
| 16316 | | try val_mcv.mem(self, self.memSize(val_ty)), |
| 24329 | try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }), |
| 16317 | 24330 | ) else try self.asmRegisterRegisterRegister( |
| 16318 | 24331 | mir_tag, |
| 16319 | 24332 | sse_reg.to128(), |
| ... | ... | @@ -16323,10 +24336,10 @@ fn atomicOp( |
| 16323 | 24336 | else |
| 16324 | 24337 | try self.copyToTmpRegister(val_ty, val_mcv)).to128(), |
| 16325 | 24338 | ), |
| 16326 | | ._ss, ._sd => if (val_mcv.isMemory()) try self.asmRegisterMemory( |
| 24339 | ._ss, ._sd => if (val_mcv.isBase()) try self.asmRegisterMemory( |
| 16327 | 24340 | mir_tag, |
| 16328 | 24341 | sse_reg.to128(), |
| 16329 | | try val_mcv.mem(self, self.memSize(val_ty)), |
| 24342 | try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }), |
| 16330 | 24343 | ) else try self.asmRegisterRegister( |
| 16331 | 24344 | mir_tag, |
| 16332 | 24345 | sse_reg.to128(), |
| ... | ... | @@ -16381,7 +24394,7 @@ fn atomicOp( |
| 16381 | 24394 | try self.asmCmovccRegisterMemory( |
| 16382 | 24395 | cc, |
| 16383 | 24396 | registerAlias(tmp_reg, cmov_abi_size), |
| 16384 | | try val_mcv.mem(self, Memory.Size.fromSize(cmov_abi_size)), |
| 24397 | try val_mcv.mem(self, .{ .size = .fromSize(cmov_abi_size) }), |
| 16385 | 24398 | ); |
| 16386 | 24399 | }, |
| 16387 | 24400 | else => { |
| ... | ... | @@ -16434,11 +24447,11 @@ fn atomicOp( |
| 16434 | 24447 | const val_mem_mcv: MCValue = switch (val_mcv) { |
| 16435 | 24448 | .memory, .indirect, .load_frame => val_mcv, |
| 16436 | 24449 | else => .{ .indirect = .{ |
| 16437 | | .reg = try self.copyToTmpRegister(Type.usize, val_mcv.address()), |
| 24450 | .reg = try self.copyToTmpRegister(.usize, val_mcv.address()), |
| 16438 | 24451 | } }, |
| 16439 | 24452 | }; |
| 16440 | | const val_lo_mem = try val_mem_mcv.mem(self, .qword); |
| 16441 | | const val_hi_mem = try val_mem_mcv.address().offset(8).deref().mem(self, .qword); |
| 24453 | const val_lo_mem = try val_mem_mcv.mem(self, .{ .size = .qword }); |
| 24454 | const val_hi_mem = try val_mem_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }); |
| 16442 | 24455 | if (rmw_op != std.builtin.AtomicRmwOp.Xchg) { |
| 16443 | 24456 | try self.asmRegisterRegister(.{ ._, .mov }, .rbx, .rax); |
| 16444 | 24457 | try self.asmRegisterRegister(.{ ._, .mov }, .rcx, .rdx); |
| ... | ... | @@ -16491,7 +24504,7 @@ fn atomicOp( |
| 16491 | 24504 | }, |
| 16492 | 24505 | }; |
| 16493 | 24506 | |
| 16494 | | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .register = .rcx }); |
| 24507 | const tmp_reg = try self.copyToTmpRegister(.usize, .{ .register = .rcx }); |
| 16495 | 24508 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 16496 | 24509 | defer self.register_manager.unlockReg(tmp_lock); |
| 16497 | 24510 | |
| ... | ... | @@ -16526,7 +24539,7 @@ fn atomicOp( |
| 16526 | 24539 | } |
| 16527 | 24540 | } |
| 16528 | 24541 | |
| 16529 | | fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { |
| 24542 | fn airAtomicRmw(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 16530 | 24543 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 16531 | 24544 | const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 16532 | 24545 | |
| ... | ... | @@ -16547,7 +24560,7 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { |
| 16547 | 24560 | return self.finishAir(inst, result, .{ pl_op.operand, extra.operand, .none }); |
| 16548 | 24561 | } |
| 16549 | 24562 | |
| 16550 | | fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 24563 | fn airAtomicLoad(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 16551 | 24564 | const atomic_load = self.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load; |
| 16552 | 24565 | |
| 16553 | 24566 | const ptr_ty = self.typeOf(atomic_load.ptr); |
| ... | ... | @@ -16568,7 +24581,7 @@ fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 16568 | 24581 | return self.finishAir(inst, dst_mcv, .{ atomic_load.ptr, .none, .none }); |
| 16569 | 24582 | } |
| 16570 | 24583 | |
| 16571 | | fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { |
| 24584 | fn airAtomicStore(self: *CodeGen, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { |
| 16572 | 24585 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 16573 | 24586 | |
| 16574 | 24587 | const ptr_ty = self.typeOf(bin_op.lhs); |
| ... | ... | @@ -16581,7 +24594,7 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr |
| 16581 | 24594 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 16582 | 24595 | } |
| 16583 | 24596 | |
| 16584 | | fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 24597 | fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { |
| 16585 | 24598 | const pt = self.pt; |
| 16586 | 24599 | const zcu = pt.zcu; |
| 16587 | 24600 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -16593,13 +24606,17 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 16593 | 24606 | const reg_locks = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdi, .rsi, .rcx }); |
| 16594 | 24607 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 16595 | 24608 | |
| 16596 | | const dst_ptr = try self.resolveInst(bin_op.lhs); |
| 16597 | | const dst_ptr_ty = self.typeOf(bin_op.lhs); |
| 16598 | | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 16599 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 16600 | | else => null, |
| 24609 | const dst = try self.resolveInst(bin_op.lhs); |
| 24610 | const dst_ty = self.typeOf(bin_op.lhs); |
| 24611 | const dst_locks: [2]?RegisterLock = switch (dst) { |
| 24612 | .register => |dst_reg| .{ self.register_manager.lockRegAssumeUnused(dst_reg), null }, |
| 24613 | .register_pair => |dst_regs| .{ |
| 24614 | self.register_manager.lockRegAssumeUnused(dst_regs[0]), |
| 24615 | self.register_manager.lockRegAssumeUnused(dst_regs[1]), |
| 24616 | }, |
| 24617 | else => @splat(null), |
| 16601 | 24618 | }; |
| 16602 | | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 24619 | for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 16603 | 24620 | |
| 16604 | 24621 | const src_val = try self.resolveInst(bin_op.rhs); |
| 16605 | 24622 | const elem_ty = self.typeOf(bin_op.rhs); |
| ... | ... | @@ -16612,16 +24629,20 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 16612 | 24629 | const elem_abi_size: u31 = @intCast(elem_ty.abiSize(zcu)); |
| 16613 | 24630 | |
| 16614 | 24631 | if (elem_abi_size == 1) { |
| 16615 | | const ptr: MCValue = switch (dst_ptr_ty.ptrSize(zcu)) { |
| 16616 | | // TODO: this only handles slices stored in the stack |
| 16617 | | .slice => dst_ptr, |
| 16618 | | .one => dst_ptr, |
| 24632 | const dst_ptr: MCValue = switch (dst_ty.ptrSize(zcu)) { |
| 24633 | .slice => switch (dst) { |
| 24634 | .register_pair => |dst_regs| .{ .register = dst_regs[0] }, |
| 24635 | else => dst, |
| 24636 | }, |
| 24637 | .one => dst, |
| 16619 | 24638 | .c, .many => unreachable, |
| 16620 | 24639 | }; |
| 16621 | | const len: MCValue = switch (dst_ptr_ty.ptrSize(zcu)) { |
| 16622 | | // TODO: this only handles slices stored in the stack |
| 16623 | | .slice => dst_ptr.address().offset(8).deref(), |
| 16624 | | .one => .{ .immediate = dst_ptr_ty.childType(zcu).arrayLen(zcu) }, |
| 24640 | const len: MCValue = switch (dst_ty.ptrSize(zcu)) { |
| 24641 | .slice => switch (dst) { |
| 24642 | .register_pair => |dst_regs| .{ .register = dst_regs[1] }, |
| 24643 | else => dst.address().offset(8).deref(), |
| 24644 | }, |
| 24645 | .one => .{ .immediate = dst_ty.childType(zcu).arrayLen(zcu) }, |
| 16625 | 24646 | .c, .many => unreachable, |
| 16626 | 24647 | }; |
| 16627 | 24648 | const len_lock: ?RegisterLock = switch (len) { |
| ... | ... | @@ -16630,20 +24651,25 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 16630 | 24651 | }; |
| 16631 | 24652 | defer if (len_lock) |lock| self.register_manager.unlockReg(lock); |
| 16632 | 24653 | |
| 16633 | | try self.genInlineMemset(ptr, src_val, len, .{ .safety = safety }); |
| 24654 | try self.genInlineMemset(dst_ptr, src_val, len, .{ .safety = safety }); |
| 16634 | 24655 | break :result; |
| 16635 | 24656 | } |
| 16636 | 24657 | |
| 16637 | 24658 | // Store the first element, and then rely on memcpy copying forwards. |
| 16638 | 24659 | // Length zero requires a runtime check - so we handle arrays specially |
| 16639 | 24660 | // here to elide it. |
| 16640 | | switch (dst_ptr_ty.ptrSize(zcu)) { |
| 24661 | switch (dst_ty.ptrSize(zcu)) { |
| 16641 | 24662 | .slice => { |
| 16642 | | const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(zcu); |
| 24663 | const slice_ptr_ty = dst_ty.slicePtrFieldType(zcu); |
| 16643 | 24664 | |
| 16644 | | // TODO: this only handles slices stored in the stack |
| 16645 | | const ptr = dst_ptr; |
| 16646 | | const len = dst_ptr.address().offset(8).deref(); |
| 24665 | const dst_ptr: MCValue = switch (dst) { |
| 24666 | .register_pair => |dst_regs| .{ .register = dst_regs[0] }, |
| 24667 | else => dst, |
| 24668 | }; |
| 24669 | const len: MCValue = switch (dst) { |
| 24670 | .register_pair => |dst_regs| .{ .register = dst_regs[1] }, |
| 24671 | else => dst.address().offset(8).deref(), |
| 24672 | }; |
| 16647 | 24673 | |
| 16648 | 24674 | // Used to store the number of elements for comparison. |
| 16649 | 24675 | // After comparison, updated to store number of bytes needed to copy. |
| ... | ... | @@ -16652,11 +24678,11 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 16652 | 24678 | const len_lock = self.register_manager.lockRegAssumeUnused(len_reg); |
| 16653 | 24679 | defer self.register_manager.unlockReg(len_lock); |
| 16654 | 24680 | |
| 16655 | | try self.genSetReg(len_reg, Type.usize, len, .{}); |
| 24681 | try self.genSetReg(len_reg, .usize, len, .{}); |
| 16656 | 24682 | try self.asmRegisterRegister(.{ ._, .@"test" }, len_reg, len_reg); |
| 16657 | 24683 | |
| 16658 | 24684 | const skip_reloc = try self.asmJccReloc(.z, undefined); |
| 16659 | | try self.store(slice_ptr_ty, ptr, src_val, .{ .safety = safety }); |
| 24685 | try self.store(slice_ptr_ty, dst_ptr, src_val, .{ .safety = safety }); |
| 16660 | 24686 | |
| 16661 | 24687 | const second_elem_ptr_reg = |
| 16662 | 24688 | try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| ... | ... | @@ -16665,29 +24691,29 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 16665 | 24691 | self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg); |
| 16666 | 24692 | defer self.register_manager.unlockReg(second_elem_ptr_lock); |
| 16667 | 24693 | |
| 16668 | | try self.genSetReg(second_elem_ptr_reg, Type.usize, .{ .register_offset = .{ |
| 16669 | | .reg = try self.copyToTmpRegister(Type.usize, ptr), |
| 24694 | try self.genSetReg(second_elem_ptr_reg, .usize, .{ .register_offset = .{ |
| 24695 | .reg = try self.copyToTmpRegister(.usize, dst_ptr), |
| 16670 | 24696 | .off = elem_abi_size, |
| 16671 | 24697 | } }, .{}); |
| 16672 | 24698 | |
| 16673 | | try self.genBinOpMir(.{ ._, .sub }, Type.usize, len_mcv, .{ .immediate = 1 }); |
| 24699 | try self.genBinOpMir(.{ ._, .sub }, .usize, len_mcv, .{ .immediate = 1 }); |
| 16674 | 24700 | try self.asmRegisterRegisterImmediate( |
| 16675 | 24701 | .{ .i_, .mul }, |
| 16676 | 24702 | len_reg, |
| 16677 | 24703 | len_reg, |
| 16678 | | Immediate.s(elem_abi_size), |
| 24704 | .s(elem_abi_size), |
| 16679 | 24705 | ); |
| 16680 | | try self.genInlineMemcpy(second_elem_ptr_mcv, ptr, len_mcv); |
| 24706 | try self.genInlineMemcpy(second_elem_ptr_mcv, dst_ptr, len_mcv, .{ .no_alias = false }); |
| 16681 | 24707 | |
| 16682 | 24708 | self.performReloc(skip_reloc); |
| 16683 | 24709 | }, |
| 16684 | 24710 | .one => { |
| 16685 | 24711 | const elem_ptr_ty = try pt.singleMutPtrType(elem_ty); |
| 16686 | 24712 | |
| 16687 | | const len = dst_ptr_ty.childType(zcu).arrayLen(zcu); |
| 24713 | const len = dst_ty.childType(zcu).arrayLen(zcu); |
| 16688 | 24714 | |
| 16689 | 24715 | assert(len != 0); // prevented by Sema |
| 16690 | | try self.store(elem_ptr_ty, dst_ptr, src_val, .{ .safety = safety }); |
| 24716 | try self.store(elem_ptr_ty, dst, src_val, .{ .safety = safety }); |
| 16691 | 24717 | |
| 16692 | 24718 | const second_elem_ptr_reg = |
| 16693 | 24719 | try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| ... | ... | @@ -16696,13 +24722,13 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 16696 | 24722 | self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg); |
| 16697 | 24723 | defer self.register_manager.unlockReg(second_elem_ptr_lock); |
| 16698 | 24724 | |
| 16699 | | try self.genSetReg(second_elem_ptr_reg, Type.usize, .{ .register_offset = .{ |
| 16700 | | .reg = try self.copyToTmpRegister(Type.usize, dst_ptr), |
| 24725 | try self.genSetReg(second_elem_ptr_reg, .usize, .{ .register_offset = .{ |
| 24726 | .reg = try self.copyToTmpRegister(.usize, dst), |
| 16701 | 24727 | .off = elem_abi_size, |
| 16702 | 24728 | } }, .{}); |
| 16703 | 24729 | |
| 16704 | 24730 | const bytes_to_copy: MCValue = .{ .immediate = elem_abi_size * (len - 1) }; |
| 16705 | | try self.genInlineMemcpy(second_elem_ptr_mcv, dst_ptr, bytes_to_copy); |
| 24731 | try self.genInlineMemcpy(second_elem_ptr_mcv, dst, bytes_to_copy, .{ .no_alias = false }); |
| 16706 | 24732 | }, |
| 16707 | 24733 | .c, .many => unreachable, |
| 16708 | 24734 | } |
| ... | ... | @@ -16710,7 +24736,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 16710 | 24736 | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 16711 | 24737 | } |
| 16712 | 24738 | |
| 16713 | | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 24739 | fn airMemcpy(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 16714 | 24740 | const pt = self.pt; |
| 16715 | 24741 | const zcu = pt.zcu; |
| 16716 | 24742 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | ... | @@ -16719,64 +24745,87 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 16719 | 24745 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx }); |
| 16720 | 24746 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 16721 | 24747 | |
| 16722 | | const dst_ptr = try self.resolveInst(bin_op.lhs); |
| 16723 | | const dst_ptr_ty = self.typeOf(bin_op.lhs); |
| 16724 | | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 16725 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 16726 | | else => null, |
| 24748 | const dst = try self.resolveInst(bin_op.lhs); |
| 24749 | const dst_ty = self.typeOf(bin_op.lhs); |
| 24750 | const dst_locks: [2]?RegisterLock = switch (dst) { |
| 24751 | .register => |dst_reg| .{ self.register_manager.lockRegAssumeUnused(dst_reg), null }, |
| 24752 | .register_pair => |dst_regs| .{ |
| 24753 | self.register_manager.lockRegAssumeUnused(dst_regs[0]), |
| 24754 | self.register_manager.lockReg(dst_regs[1]), |
| 24755 | }, |
| 24756 | else => @splat(null), |
| 16727 | 24757 | }; |
| 16728 | | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 24758 | for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 16729 | 24759 | |
| 16730 | | const src_ptr = try self.resolveInst(bin_op.rhs); |
| 16731 | | const src_ptr_lock: ?RegisterLock = switch (src_ptr) { |
| 16732 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 16733 | | else => null, |
| 24760 | const src = try self.resolveInst(bin_op.rhs); |
| 24761 | const src_locks: [2]?RegisterLock = switch (src) { |
| 24762 | .register => |src_reg| .{ self.register_manager.lockReg(src_reg), null }, |
| 24763 | .register_pair => |src_regs| .{ |
| 24764 | self.register_manager.lockRegAssumeUnused(src_regs[0]), |
| 24765 | self.register_manager.lockRegAssumeUnused(src_regs[1]), |
| 24766 | }, |
| 24767 | else => @splat(null), |
| 16734 | 24768 | }; |
| 16735 | | defer if (src_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 24769 | for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 16736 | 24770 | |
| 16737 | | const len: MCValue = switch (dst_ptr_ty.ptrSize(zcu)) { |
| 24771 | const len: MCValue = switch (dst_ty.ptrSize(zcu)) { |
| 16738 | 24772 | .slice => len: { |
| 16739 | 24773 | const len_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 16740 | 24774 | const len_lock = self.register_manager.lockRegAssumeUnused(len_reg); |
| 16741 | 24775 | defer self.register_manager.unlockReg(len_lock); |
| 16742 | 24776 | |
| 16743 | | try self.asmRegisterMemoryImmediate( |
| 16744 | | .{ .i_, .mul }, |
| 16745 | | len_reg, |
| 16746 | | try dst_ptr.address().offset(8).deref().mem(self, .qword), |
| 16747 | | Immediate.s(@intCast(dst_ptr_ty.childType(zcu).abiSize(zcu))), |
| 16748 | | ); |
| 24777 | switch (dst) { |
| 24778 | .register_pair => |dst_regs| try self.asmRegisterRegisterImmediate( |
| 24779 | .{ .i_, .mul }, |
| 24780 | len_reg, |
| 24781 | dst_regs[1], |
| 24782 | .s(@intCast(dst_ty.childType(zcu).abiSize(zcu))), |
| 24783 | ), |
| 24784 | else => try self.asmRegisterMemoryImmediate( |
| 24785 | .{ .i_, .mul }, |
| 24786 | len_reg, |
| 24787 | try dst.address().offset(8).deref().mem(self, .{ .size = .qword }), |
| 24788 | .s(@intCast(dst_ty.childType(zcu).abiSize(zcu))), |
| 24789 | ), |
| 24790 | } |
| 16749 | 24791 | break :len .{ .register = len_reg }; |
| 16750 | 24792 | }, |
| 16751 | 24793 | .one => len: { |
| 16752 | | const array_ty = dst_ptr_ty.childType(zcu); |
| 24794 | const array_ty = dst_ty.childType(zcu); |
| 16753 | 24795 | break :len .{ .immediate = array_ty.arrayLen(zcu) * array_ty.childType(zcu).abiSize(zcu) }; |
| 16754 | 24796 | }, |
| 16755 | 24797 | .c, .many => unreachable, |
| 16756 | 24798 | }; |
| 16757 | 24799 | const len_lock: ?RegisterLock = switch (len) { |
| 16758 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 24800 | .register => |reg| self.register_manager.lockReg(reg), |
| 16759 | 24801 | else => null, |
| 16760 | 24802 | }; |
| 16761 | 24803 | defer if (len_lock) |lock| self.register_manager.unlockReg(lock); |
| 16762 | 24804 | |
| 16763 | | // TODO: dst_ptr and src_ptr could be slices rather than raw pointers |
| 16764 | | try self.genInlineMemcpy(dst_ptr, src_ptr, len); |
| 24805 | const dst_ptr: MCValue = switch (dst) { |
| 24806 | .register_pair => |dst_regs| .{ .register = dst_regs[0] }, |
| 24807 | else => dst, |
| 24808 | }; |
| 24809 | const src_ptr: MCValue = switch (src) { |
| 24810 | .register_pair => |src_regs| .{ .register = src_regs[0] }, |
| 24811 | else => src, |
| 24812 | }; |
| 24813 | |
| 24814 | try self.genInlineMemcpy(dst_ptr, src_ptr, len, .{ .no_alias = true }); |
| 16765 | 24815 | |
| 16766 | 24816 | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 16767 | 24817 | } |
| 16768 | 24818 | |
| 16769 | | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 24819 | fn airTagName(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 16770 | 24820 | const pt = self.pt; |
| 16771 | 24821 | const zcu = pt.zcu; |
| 16772 | 24822 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 16773 | 24823 | const inst_ty = self.typeOfIndex(inst); |
| 16774 | 24824 | const enum_ty = self.typeOf(un_op); |
| 16775 | | const resolved_cc = abi.resolveCallingConvention(.auto, self.target.*); |
| 16776 | 24825 | |
| 16777 | 24826 | // We need a properly aligned and sized call frame to be able to call this function. |
| 16778 | 24827 | { |
| 16779 | | const needed_call_frame = FrameAlloc.init(.{ |
| 24828 | const needed_call_frame: FrameAlloc = .init(.{ |
| 16780 | 24829 | .size = inst_ty.abiSize(zcu), |
| 16781 | 24830 | .alignment = inst_ty.abiAlignment(zcu), |
| 16782 | 24831 | }); |
| ... | ... | @@ -16790,23 +24839,23 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 16790 | 24839 | } |
| 16791 | 24840 | |
| 16792 | 24841 | try self.spillEflagsIfOccupied(); |
| 16793 | | try self.spillCallerPreservedRegs(resolved_cc); |
| 24842 | try self.spillCallerPreservedRegs(.auto); |
| 16794 | 24843 | |
| 16795 | | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 24844 | const param_regs = abi.getCAbiIntParamRegs(.auto); |
| 16796 | 24845 | |
| 16797 | 24846 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 16798 | | try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address(), .{}); |
| 24847 | try self.genSetReg(param_regs[0], .usize, dst_mcv.address(), .{}); |
| 16799 | 24848 | |
| 16800 | 24849 | const operand = try self.resolveInst(un_op); |
| 16801 | 24850 | try self.genSetReg(param_regs[1], enum_ty, operand, .{}); |
| 16802 | 24851 | |
| 16803 | 24852 | const enum_lazy_sym: link.File.LazySymbol = .{ .kind = .code, .ty = enum_ty.toIntern() }; |
| 16804 | | try self.genLazySymbolRef(.call, .rax, enum_lazy_sym); |
| 24853 | try self.genLazySymbolRef(.call, abi.getCAbiLinkerScratchReg(self.fn_type.fnCallingConvention(zcu)), enum_lazy_sym); |
| 16805 | 24854 | |
| 16806 | 24855 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 16807 | 24856 | } |
| 16808 | 24857 | |
| 16809 | | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 24858 | fn airErrorName(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 16810 | 24859 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 16811 | 24860 | |
| 16812 | 24861 | const err_ty = self.typeOf(un_op); |
| ... | ... | @@ -16908,13 +24957,13 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 16908 | 24957 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 16909 | 24958 | } |
| 16910 | 24959 | |
| 16911 | | fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 24960 | fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 16912 | 24961 | const pt = self.pt; |
| 16913 | 24962 | const zcu = pt.zcu; |
| 16914 | 24963 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 16915 | 24964 | const vector_ty = self.typeOfIndex(inst); |
| 16916 | 24965 | const vector_len = vector_ty.vectorLen(zcu); |
| 16917 | | const dst_rc = self.regClassForType(vector_ty); |
| 24966 | const dst_rc = self.regSetForType(vector_ty); |
| 16918 | 24967 | const scalar_ty = self.typeOf(ty_op.operand); |
| 16919 | 24968 | |
| 16920 | 24969 | const result: MCValue = result: { |
| ... | ... | @@ -16930,27 +24979,23 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 16930 | 24979 | try self.genSetReg( |
| 16931 | 24980 | regs[1], |
| 16932 | 24981 | vector_ty, |
| 16933 | | .{ .immediate = @as(u64, math.maxInt(u64)) >> @intCast(64 - vector_len) }, |
| 24982 | .{ .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - vector_len) }, |
| 16934 | 24983 | .{}, |
| 16935 | 24984 | ); |
| 16936 | 24985 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 16937 | | const abi_size = @max(math.divCeil(u32, vector_len, 8) catch unreachable, 4); |
| 24986 | const abi_size = @max(std.math.divCeil(u32, vector_len, 8) catch unreachable, 4); |
| 16938 | 24987 | try self.asmCmovccRegisterRegister( |
| 16939 | 24988 | switch (src_mcv) { |
| 16940 | 24989 | .eflags => |cc| cc, |
| 16941 | 24990 | .register => |src_reg| cc: { |
| 16942 | | try self.asmRegisterImmediate( |
| 16943 | | .{ ._, .@"test" }, |
| 16944 | | src_reg.to8(), |
| 16945 | | Immediate.u(1), |
| 16946 | | ); |
| 24991 | try self.asmRegisterImmediate(.{ ._, .@"test" }, src_reg.to8(), .u(1)); |
| 16947 | 24992 | break :cc .nz; |
| 16948 | 24993 | }, |
| 16949 | 24994 | else => cc: { |
| 16950 | 24995 | try self.asmMemoryImmediate( |
| 16951 | 24996 | .{ ._, .@"test" }, |
| 16952 | | try src_mcv.mem(self, .byte), |
| 16953 | | Immediate.u(1), |
| 24997 | try src_mcv.mem(self, .{ .size = .byte }), |
| 24998 | .u(1), |
| 16954 | 24999 | ); |
| 16955 | 25000 | break :cc .nz; |
| 16956 | 25001 | }, |
| ... | ... | @@ -16990,10 +25035,10 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 16990 | 25035 | defer self.register_manager.unlockReg(dst_lock); |
| 16991 | 25036 | |
| 16992 | 25037 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 16993 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 25038 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 16994 | 25039 | mir_tag, |
| 16995 | 25040 | registerAlias(dst_reg, @intCast(vector_ty.abiSize(zcu))), |
| 16996 | | try src_mcv.mem(self, self.memSize(scalar_ty)), |
| 25041 | try src_mcv.mem(self, .{ .size = self.memSize(scalar_ty) }), |
| 16997 | 25042 | ) else { |
| 16998 | 25043 | if (mir_tag[0] == .v_i128) break :avx2; |
| 16999 | 25044 | try self.genSetReg(dst_reg, scalar_ty, src_mcv, .{}); |
| ... | ... | @@ -17037,7 +25082,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17037 | 25082 | .{ if (self.hasFeature(.avx)) .vp_w else .p_w, .shufl }, |
| 17038 | 25083 | dst_alias, |
| 17039 | 25084 | dst_alias, |
| 17040 | | Immediate.u(0b00_00_00_00), |
| 25085 | .u(0b00_00_00_00), |
| 17041 | 25086 | ); |
| 17042 | 25087 | if (switch (scalar_bits) { |
| 17043 | 25088 | 1...8 => vector_len > 4, |
| ... | ... | @@ -17049,7 +25094,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17049 | 25094 | .{ if (self.hasFeature(.avx)) .vp_d else .p_d, .shuf }, |
| 17050 | 25095 | dst_alias, |
| 17051 | 25096 | dst_alias, |
| 17052 | | Immediate.u(if (scalar_bits <= 64) 0b00_00_00_00 else 0b01_00_01_00), |
| 25097 | .u(if (scalar_bits <= 64) 0b00_00_00_00 else 0b01_00_01_00), |
| 17053 | 25098 | ); |
| 17054 | 25099 | break :result .{ .register = dst_reg }; |
| 17055 | 25100 | }, |
| ... | ... | @@ -17066,10 +25111,10 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17066 | 25111 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 17067 | 25112 | if (self.hasFeature(.avx)) { |
| 17068 | 25113 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); |
| 17069 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 25114 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 17070 | 25115 | .{ .v_ss, .broadcast }, |
| 17071 | 25116 | dst_reg.to128(), |
| 17072 | | try src_mcv.mem(self, .dword), |
| 25117 | try src_mcv.mem(self, .{ .size = .dword }), |
| 17073 | 25118 | ) else { |
| 17074 | 25119 | const src_reg = if (src_mcv.isRegister()) |
| 17075 | 25120 | src_mcv.getReg().? |
| ... | ... | @@ -17080,7 +25125,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17080 | 25125 | dst_reg.to128(), |
| 17081 | 25126 | src_reg.to128(), |
| 17082 | 25127 | src_reg.to128(), |
| 17083 | | Immediate.u(0), |
| 25128 | .u(0), |
| 17084 | 25129 | ); |
| 17085 | 25130 | } |
| 17086 | 25131 | break :result .{ .register = dst_reg }; |
| ... | ... | @@ -17095,7 +25140,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17095 | 25140 | .{ ._ps, .shuf }, |
| 17096 | 25141 | dst_reg.to128(), |
| 17097 | 25142 | dst_reg.to128(), |
| 17098 | | Immediate.u(0), |
| 25143 | .u(0), |
| 17099 | 25144 | ); |
| 17100 | 25145 | break :result dst_mcv; |
| 17101 | 25146 | } |
| ... | ... | @@ -17103,10 +25148,10 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17103 | 25148 | 5...8 => if (self.hasFeature(.avx)) { |
| 17104 | 25149 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 17105 | 25150 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); |
| 17106 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 25151 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 17107 | 25152 | .{ .v_ss, .broadcast }, |
| 17108 | 25153 | dst_reg.to256(), |
| 17109 | | try src_mcv.mem(self, .dword), |
| 25154 | try src_mcv.mem(self, .{ .size = .dword }), |
| 17110 | 25155 | ) else { |
| 17111 | 25156 | const src_reg = if (src_mcv.isRegister()) |
| 17112 | 25157 | src_mcv.getReg().? |
| ... | ... | @@ -17122,14 +25167,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17122 | 25167 | dst_reg.to128(), |
| 17123 | 25168 | src_reg.to128(), |
| 17124 | 25169 | src_reg.to128(), |
| 17125 | | Immediate.u(0), |
| 25170 | .u(0), |
| 17126 | 25171 | ); |
| 17127 | 25172 | try self.asmRegisterRegisterRegisterImmediate( |
| 17128 | 25173 | .{ .v_f128, .insert }, |
| 17129 | 25174 | dst_reg.to256(), |
| 17130 | 25175 | dst_reg.to256(), |
| 17131 | 25176 | dst_reg.to128(), |
| 17132 | | Immediate.u(1), |
| 25177 | .u(1), |
| 17133 | 25178 | ); |
| 17134 | 25179 | } |
| 17135 | 25180 | } |
| ... | ... | @@ -17149,10 +25194,10 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17149 | 25194 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 17150 | 25195 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); |
| 17151 | 25196 | if (self.hasFeature(.sse3)) { |
| 17152 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 25197 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 17153 | 25198 | if (self.hasFeature(.avx)) .{ .v_, .movddup } else .{ ._, .movddup }, |
| 17154 | 25199 | dst_reg.to128(), |
| 17155 | | try src_mcv.mem(self, .qword), |
| 25200 | try src_mcv.mem(self, .{ .size = .qword }), |
| 17156 | 25201 | ) else try self.asmRegisterRegister( |
| 17157 | 25202 | if (self.hasFeature(.avx)) .{ .v_, .movddup } else .{ ._, .movddup }, |
| 17158 | 25203 | dst_reg.to128(), |
| ... | ... | @@ -17174,10 +25219,10 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17174 | 25219 | 3...4 => if (self.hasFeature(.avx)) { |
| 17175 | 25220 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 17176 | 25221 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); |
| 17177 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 25222 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 17178 | 25223 | .{ .v_sd, .broadcast }, |
| 17179 | 25224 | dst_reg.to256(), |
| 17180 | | try src_mcv.mem(self, .qword), |
| 25225 | try src_mcv.mem(self, .{ .size = .qword }), |
| 17181 | 25226 | ) else { |
| 17182 | 25227 | const src_reg = if (src_mcv.isRegister()) |
| 17183 | 25228 | src_mcv.getReg().? |
| ... | ... | @@ -17198,7 +25243,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17198 | 25243 | dst_reg.to256(), |
| 17199 | 25244 | dst_reg.to256(), |
| 17200 | 25245 | dst_reg.to128(), |
| 17201 | | Immediate.u(1), |
| 25246 | .u(1), |
| 17202 | 25247 | ); |
| 17203 | 25248 | } |
| 17204 | 25249 | } |
| ... | ... | @@ -17217,10 +25262,10 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17217 | 25262 | 2 => if (self.hasFeature(.avx)) { |
| 17218 | 25263 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 17219 | 25264 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); |
| 17220 | | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 25265 | if (src_mcv.isBase()) try self.asmRegisterMemory( |
| 17221 | 25266 | .{ .v_f128, .broadcast }, |
| 17222 | 25267 | dst_reg.to256(), |
| 17223 | | try src_mcv.mem(self, .xword), |
| 25268 | try src_mcv.mem(self, .{ .size = .xword }), |
| 17224 | 25269 | ) else { |
| 17225 | 25270 | const src_reg = if (src_mcv.isRegister()) |
| 17226 | 25271 | src_mcv.getReg().? |
| ... | ... | @@ -17231,7 +25276,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17231 | 25276 | dst_reg.to256(), |
| 17232 | 25277 | src_reg.to256(), |
| 17233 | 25278 | src_reg.to128(), |
| 17234 | | Immediate.u(1), |
| 25279 | .u(1), |
| 17235 | 25280 | ); |
| 17236 | 25281 | } |
| 17237 | 25282 | break :result .{ .register = dst_reg }; |
| ... | ... | @@ -17247,7 +25292,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 17247 | 25292 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 17248 | 25293 | } |
| 17249 | 25294 | |
| 17250 | | fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 25295 | fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 17251 | 25296 | const pt = self.pt; |
| 17252 | 25297 | const zcu = pt.zcu; |
| 17253 | 25298 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| ... | ... | @@ -17308,7 +25353,7 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17308 | 25353 | mask_alias, |
| 17309 | 25354 | mask_alias, |
| 17310 | 25355 | mask_reg.to128(), |
| 17311 | | Immediate.u(1), |
| 25356 | .u(1), |
| 17312 | 25357 | ); |
| 17313 | 25358 | break :broadcast; |
| 17314 | 25359 | }, |
| ... | ... | @@ -17326,9 +25371,9 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17326 | 25371 | else => unreachable, |
| 17327 | 25372 | }, .broadcast }, |
| 17328 | 25373 | mask_alias, |
| 17329 | | if (pred_mcv.isMemory()) try pred_mcv.mem(self, .byte) else .{ |
| 25374 | if (pred_mcv.isBase()) try pred_mcv.mem(self, .{ .size = .byte }) else .{ |
| 17330 | 25375 | .base = .{ .reg = (try self.copyToTmpRegister( |
| 17331 | | Type.usize, |
| 25376 | .usize, |
| 17332 | 25377 | pred_mcv.address(), |
| 17333 | 25378 | )).to64() }, |
| 17334 | 25379 | .mod = .{ .rm = .{ .size = .byte } }, |
| ... | ... | @@ -17362,7 +25407,7 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17362 | 25407 | .{ if (has_avx) .vp_w else .p_w, .shufl }, |
| 17363 | 25408 | mask_alias, |
| 17364 | 25409 | mask_alias, |
| 17365 | | Immediate.u(0b00_00_00_00), |
| 25410 | .u(0b00_00_00_00), |
| 17366 | 25411 | ); |
| 17367 | 25412 | if (abi_size <= 8) break :broadcast; |
| 17368 | 25413 | } |
| ... | ... | @@ -17370,7 +25415,7 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17370 | 25415 | .{ if (has_avx) .vp_d else .p_d, .shuf }, |
| 17371 | 25416 | mask_alias, |
| 17372 | 25417 | mask_alias, |
| 17373 | | Immediate.u(switch (elem_abi_size) { |
| 25418 | .u(switch (elem_abi_size) { |
| 17374 | 25419 | 1...2, 5...8 => 0b01_00_01_00, |
| 17375 | 25420 | 3...4 => 0b00_00_00_00, |
| 17376 | 25421 | else => unreachable, |
| ... | ... | @@ -17386,12 +25431,12 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17386 | 25431 | .ty = mask_elem_ty.toIntern(), |
| 17387 | 25432 | .storage = .{ .u64 = bit / elem_bits }, |
| 17388 | 25433 | } }); |
| 17389 | | const mask_mcv = try self.genTypedValue(Value.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 25434 | const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 17390 | 25435 | .ty = mask_ty.toIntern(), |
| 17391 | 25436 | .storage = .{ .elems = mask_elems[0..vec_len] }, |
| 17392 | 25437 | } }))); |
| 17393 | 25438 | const mask_mem: Memory = .{ |
| 17394 | | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()) }, |
| 25439 | .base = .{ .reg = try self.copyToTmpRegister(.usize, mask_mcv.address()) }, |
| 17395 | 25440 | .mod = .{ .rm = .{ .size = self.memSize(ty) } }, |
| 17396 | 25441 | }; |
| 17397 | 25442 | if (has_avx) try self.asmRegisterRegisterMemory( |
| ... | ... | @@ -17411,12 +25456,12 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17411 | 25456 | .ty = mask_elem_ty.toIntern(), |
| 17412 | 25457 | .storage = .{ .u64 = @as(u32, 1) << @intCast(bit & (elem_bits - 1)) }, |
| 17413 | 25458 | } }); |
| 17414 | | const mask_mcv = try self.genTypedValue(Value.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 25459 | const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 17415 | 25460 | .ty = mask_ty.toIntern(), |
| 17416 | 25461 | .storage = .{ .elems = mask_elems[0..vec_len] }, |
| 17417 | 25462 | } }))); |
| 17418 | 25463 | const mask_mem: Memory = .{ |
| 17419 | | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()) }, |
| 25464 | .base = .{ .reg = try self.copyToTmpRegister(.usize, mask_mcv.address()) }, |
| 17420 | 25465 | .mod = .{ .rm = .{ .size = self.memSize(ty) } }, |
| 17421 | 25466 | }; |
| 17422 | 25467 | if (has_avx) { |
| ... | ... | @@ -17520,11 +25565,11 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17520 | 25565 | try self.genSetReg(dst_reg, ty, rhs_mcv, .{}); |
| 17521 | 25566 | break :rhs dst_alias; |
| 17522 | 25567 | }; |
| 17523 | | if (lhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryRegister( |
| 25568 | if (lhs_mcv.isBase()) try self.asmRegisterRegisterMemoryRegister( |
| 17524 | 25569 | mir_tag, |
| 17525 | 25570 | dst_alias, |
| 17526 | 25571 | rhs_alias, |
| 17527 | | try lhs_mcv.mem(self, self.memSize(ty)), |
| 25572 | try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }), |
| 17528 | 25573 | mask_alias, |
| 17529 | 25574 | ) else try self.asmRegisterRegisterRegisterRegister( |
| 17530 | 25575 | mir_tag, |
| ... | ... | @@ -17536,10 +25581,10 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17536 | 25581 | try self.copyToTmpRegister(ty, lhs_mcv), abi_size), |
| 17537 | 25582 | mask_alias, |
| 17538 | 25583 | ); |
| 17539 | | } else if (has_blend) if (lhs_mcv.isMemory()) try self.asmRegisterMemoryRegister( |
| 25584 | } else if (has_blend) if (lhs_mcv.isBase()) try self.asmRegisterMemoryRegister( |
| 17540 | 25585 | mir_tag, |
| 17541 | 25586 | dst_alias, |
| 17542 | | try lhs_mcv.mem(self, self.memSize(ty)), |
| 25587 | try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }), |
| 17543 | 25588 | mask_alias, |
| 17544 | 25589 | ) else try self.asmRegisterRegisterRegister( |
| 17545 | 25590 | mir_tag, |
| ... | ... | @@ -17561,10 +25606,10 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17561 | 25606 | }, |
| 17562 | 25607 | }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}); |
| 17563 | 25608 | try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias); |
| 17564 | | if (rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 25609 | if (rhs_mcv.isBase()) try self.asmRegisterMemory( |
| 17565 | 25610 | .{ mir_fixes, .andn }, |
| 17566 | 25611 | mask_alias, |
| 17567 | | try rhs_mcv.mem(self, Memory.Size.fromSize(abi_size)), |
| 25612 | try rhs_mcv.mem(self, .{ .size = .fromSize(abi_size) }), |
| 17568 | 25613 | ) else try self.asmRegisterRegister( |
| 17569 | 25614 | .{ mir_fixes, .andn }, |
| 17570 | 25615 | mask_alias, |
| ... | ... | @@ -17580,7 +25625,7 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 17580 | 25625 | return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs }); |
| 17581 | 25626 | } |
| 17582 | 25627 | |
| 17583 | | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 25628 | fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 17584 | 25629 | const pt = self.pt; |
| 17585 | 25630 | const zcu = pt.zcu; |
| 17586 | 25631 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -17640,16 +25685,13 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17640 | 25685 | |
| 17641 | 25686 | for ([_]Mir.Inst.Tag{ .unpckl, .unpckh }) |variant| unpck: { |
| 17642 | 25687 | if (elem_abi_size > 8) break :unpck; |
| 17643 | | if (dst_abi_size > @as(u32, if (if (elem_abi_size >= 4) |
| 17644 | | has_avx |
| 17645 | | else |
| 17646 | | self.hasFeature(.avx2)) 32 else 16)) break :unpck; |
| 25688 | if (dst_abi_size > self.vectorSize(if (elem_abi_size >= 4) .float else .int)) break :unpck; |
| 17647 | 25689 | |
| 17648 | | var sources = [1]?u1{null} ** 2; |
| 25690 | var sources: [2]?u1 = @splat(null); |
| 17649 | 25691 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17650 | 25692 | const mask_elem = maybe_mask_elem orelse continue; |
| 17651 | 25693 | const mask_elem_index = |
| 17652 | | math.cast(u5, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :unpck; |
| 25694 | std.math.cast(u5, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :unpck; |
| 17653 | 25695 | const elem_byte = (elem_index >> 1) * elem_abi_size; |
| 17654 | 25696 | if (mask_elem_index * elem_abi_size != (elem_byte & 0b0111) | @as(u4, switch (variant) { |
| 17655 | 25697 | .unpckl => 0b0000, |
| ... | ... | @@ -17701,11 +25743,11 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17701 | 25743 | }, |
| 17702 | 25744 | else => unreachable, |
| 17703 | 25745 | } }; |
| 17704 | | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 25746 | if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 17705 | 25747 | mir_tag, |
| 17706 | 25748 | dst_alias, |
| 17707 | 25749 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17708 | | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 25750 | try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }), |
| 17709 | 25751 | ) else try self.asmRegisterRegisterRegister( |
| 17710 | 25752 | mir_tag, |
| 17711 | 25753 | dst_alias, |
| ... | ... | @@ -17714,10 +25756,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17714 | 25756 | rhs_mcv.getReg().? |
| 17715 | 25757 | else |
| 17716 | 25758 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17717 | | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 25759 | ) else if (rhs_mcv.isBase()) try self.asmRegisterMemory( |
| 17718 | 25760 | mir_tag, |
| 17719 | 25761 | dst_alias, |
| 17720 | | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 25762 | try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }), |
| 17721 | 25763 | ) else try self.asmRegisterRegister( |
| 17722 | 25764 | mir_tag, |
| 17723 | 25765 | dst_alias, |
| ... | ... | @@ -17731,10 +25773,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17731 | 25773 | |
| 17732 | 25774 | pshufd: { |
| 17733 | 25775 | if (elem_abi_size != 4) break :pshufd; |
| 17734 | | if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :pshufd; |
| 25776 | if (max_abi_size > self.vectorSize(.float)) break :pshufd; |
| 17735 | 25777 | |
| 17736 | 25778 | var control: u8 = 0b00_00_00_00; |
| 17737 | | var sources = [1]?u1{null} ** 1; |
| 25779 | var sources: [1]?u1 = @splat(null); |
| 17738 | 25780 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17739 | 25781 | const mask_elem = maybe_mask_elem orelse continue; |
| 17740 | 25782 | const mask_elem_index: u3 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem); |
| ... | ... | @@ -17746,10 +25788,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17746 | 25788 | } else sources[(elem_index & 0b010) >> 1] = source; |
| 17747 | 25789 | |
| 17748 | 25790 | const select_bit: u3 = @intCast((elem_index & 0b011) << 1); |
| 17749 | | const select = @as(u8, @intCast(mask_elem_index & 0b011)) << select_bit; |
| 25791 | const select_mask = @as(u8, @intCast(mask_elem_index & 0b011)) << select_bit; |
| 17750 | 25792 | if (elem_index & 0b100 == 0) |
| 17751 | | control |= select |
| 17752 | | else if (control & @as(u8, 0b11) << select_bit != select) break :pshufd; |
| 25793 | control |= select_mask |
| 25794 | else if (control & @as(u8, 0b11) << select_bit != select_mask) break :pshufd; |
| 17753 | 25795 | } |
| 17754 | 25796 | |
| 17755 | 25797 | const operands = [2]Air.Inst.Ref{ extra.a, extra.b }; |
| ... | ... | @@ -17763,11 +25805,11 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17763 | 25805 | try self.register_manager.allocReg(inst, abi.RegisterClass.sse); |
| 17764 | 25806 | const dst_alias = registerAlias(dst_reg, max_abi_size); |
| 17765 | 25807 | |
| 17766 | | if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 25808 | if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate( |
| 17767 | 25809 | .{ if (has_avx) .vp_d else .p_d, .shuf }, |
| 17768 | 25810 | dst_alias, |
| 17769 | | try src_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17770 | | Immediate.u(control), |
| 25811 | try src_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }), |
| 25812 | .u(control), |
| 17771 | 25813 | ) else try self.asmRegisterRegisterImmediate( |
| 17772 | 25814 | .{ if (has_avx) .vp_d else .p_d, .shuf }, |
| 17773 | 25815 | dst_alias, |
| ... | ... | @@ -17775,17 +25817,17 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17775 | 25817 | src_mcv.getReg().? |
| 17776 | 25818 | else |
| 17777 | 25819 | try self.copyToTmpRegister(operand_tys[sources[0].?], src_mcv), max_abi_size), |
| 17778 | | Immediate.u(control), |
| 25820 | .u(control), |
| 17779 | 25821 | ); |
| 17780 | 25822 | break :result .{ .register = dst_reg }; |
| 17781 | 25823 | } |
| 17782 | 25824 | |
| 17783 | 25825 | shufps: { |
| 17784 | 25826 | if (elem_abi_size != 4) break :shufps; |
| 17785 | | if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :shufps; |
| 25827 | if (max_abi_size > self.vectorSize(.float)) break :shufps; |
| 17786 | 25828 | |
| 17787 | 25829 | var control: u8 = 0b00_00_00_00; |
| 17788 | | var sources = [1]?u1{null} ** 2; |
| 25830 | var sources: [2]?u1 = @splat(null); |
| 17789 | 25831 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17790 | 25832 | const mask_elem = maybe_mask_elem orelse continue; |
| 17791 | 25833 | const mask_elem_index: u3 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem); |
| ... | ... | @@ -17797,10 +25839,10 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17797 | 25839 | } else sources[(elem_index & 0b010) >> 1] = source; |
| 17798 | 25840 | |
| 17799 | 25841 | const select_bit: u3 = @intCast((elem_index & 0b011) << 1); |
| 17800 | | const select = @as(u8, @intCast(mask_elem_index & 0b011)) << select_bit; |
| 25842 | const select_mask = @as(u8, @intCast(mask_elem_index & 0b011)) << select_bit; |
| 17801 | 25843 | if (elem_index & 0b100 == 0) |
| 17802 | | control |= select |
| 17803 | | else if (control & @as(u8, 0b11) << select_bit != select) break :shufps; |
| 25844 | control |= select_mask |
| 25845 | else if (control & @as(u8, 0b11) << select_bit != select_mask) break :shufps; |
| 17804 | 25846 | } |
| 17805 | 25847 | if (sources[0] orelse break :shufps == sources[1] orelse break :shufps) break :shufps; |
| 17806 | 25848 | |
| ... | ... | @@ -17819,12 +25861,12 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17819 | 25861 | const dst_reg = dst_mcv.getReg().?; |
| 17820 | 25862 | const dst_alias = registerAlias(dst_reg, max_abi_size); |
| 17821 | 25863 | |
| 17822 | | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 25864 | if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 17823 | 25865 | .{ .v_ps, .shuf }, |
| 17824 | 25866 | dst_alias, |
| 17825 | 25867 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17826 | | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17827 | | Immediate.u(control), |
| 25868 | try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }), |
| 25869 | .u(control), |
| 17828 | 25870 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 17829 | 25871 | .{ .v_ps, .shuf }, |
| 17830 | 25872 | dst_alias, |
| ... | ... | @@ -17833,12 +25875,12 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17833 | 25875 | rhs_mcv.getReg().? |
| 17834 | 25876 | else |
| 17835 | 25877 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17836 | | Immediate.u(control), |
| 17837 | | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 25878 | .u(control), |
| 25879 | ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate( |
| 17838 | 25880 | .{ ._ps, .shuf }, |
| 17839 | 25881 | dst_alias, |
| 17840 | | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17841 | | Immediate.u(control), |
| 25882 | try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }), |
| 25883 | .u(control), |
| 17842 | 25884 | ) else try self.asmRegisterRegisterImmediate( |
| 17843 | 25885 | .{ ._ps, .shuf }, |
| 17844 | 25886 | dst_alias, |
| ... | ... | @@ -17846,17 +25888,17 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17846 | 25888 | rhs_mcv.getReg().? |
| 17847 | 25889 | else |
| 17848 | 25890 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17849 | | Immediate.u(control), |
| 25891 | .u(control), |
| 17850 | 25892 | ); |
| 17851 | 25893 | break :result dst_mcv; |
| 17852 | 25894 | } |
| 17853 | 25895 | |
| 17854 | 25896 | shufpd: { |
| 17855 | 25897 | if (elem_abi_size != 8) break :shufpd; |
| 17856 | | if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :shufpd; |
| 25898 | if (max_abi_size > self.vectorSize(.float)) break :shufpd; |
| 17857 | 25899 | |
| 17858 | 25900 | var control: u4 = 0b0_0_0_0; |
| 17859 | | var sources = [1]?u1{null} ** 2; |
| 25901 | var sources: [2]?u1 = @splat(null); |
| 17860 | 25902 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17861 | 25903 | const mask_elem = maybe_mask_elem orelse continue; |
| 17862 | 25904 | const mask_elem_index: u2 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem); |
| ... | ... | @@ -17886,12 +25928,12 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17886 | 25928 | const dst_reg = dst_mcv.getReg().?; |
| 17887 | 25929 | const dst_alias = registerAlias(dst_reg, max_abi_size); |
| 17888 | 25930 | |
| 17889 | | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 25931 | if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 17890 | 25932 | .{ .v_pd, .shuf }, |
| 17891 | 25933 | dst_alias, |
| 17892 | 25934 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17893 | | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17894 | | Immediate.u(control), |
| 25935 | try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }), |
| 25936 | .u(control), |
| 17895 | 25937 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 17896 | 25938 | .{ .v_pd, .shuf }, |
| 17897 | 25939 | dst_alias, |
| ... | ... | @@ -17900,12 +25942,12 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17900 | 25942 | rhs_mcv.getReg().? |
| 17901 | 25943 | else |
| 17902 | 25944 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17903 | | Immediate.u(control), |
| 17904 | | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 25945 | .u(control), |
| 25946 | ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate( |
| 17905 | 25947 | .{ ._pd, .shuf }, |
| 17906 | 25948 | dst_alias, |
| 17907 | | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17908 | | Immediate.u(control), |
| 25949 | try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }), |
| 25950 | .u(control), |
| 17909 | 25951 | ) else try self.asmRegisterRegisterImmediate( |
| 17910 | 25952 | .{ ._pd, .shuf }, |
| 17911 | 25953 | dst_alias, |
| ... | ... | @@ -17913,27 +25955,27 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17913 | 25955 | rhs_mcv.getReg().? |
| 17914 | 25956 | else |
| 17915 | 25957 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17916 | | Immediate.u(control), |
| 25958 | .u(control), |
| 17917 | 25959 | ); |
| 17918 | 25960 | break :result dst_mcv; |
| 17919 | 25961 | } |
| 17920 | 25962 | |
| 17921 | 25963 | blend: { |
| 17922 | 25964 | if (elem_abi_size < 2) break :blend; |
| 17923 | | if (dst_abi_size > @as(u32, if (has_avx) 32 else 16)) break :blend; |
| 25965 | if (dst_abi_size > self.vectorSize(.float)) break :blend; |
| 17924 | 25966 | if (!self.hasFeature(.sse4_1)) break :blend; |
| 17925 | 25967 | |
| 17926 | 25968 | var control: u8 = 0b0_0_0_0_0_0_0_0; |
| 17927 | 25969 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17928 | 25970 | const mask_elem = maybe_mask_elem orelse continue; |
| 17929 | 25971 | const mask_elem_index = |
| 17930 | | math.cast(u4, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :blend; |
| 25972 | std.math.cast(u4, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :blend; |
| 17931 | 25973 | if (mask_elem_index != elem_index) break :blend; |
| 17932 | 25974 | |
| 17933 | | const select = @as(u8, @intFromBool(mask_elem < 0)) << @truncate(elem_index); |
| 25975 | const select_mask = @as(u8, @intFromBool(mask_elem < 0)) << @truncate(elem_index); |
| 17934 | 25976 | if (elem_index & 0b1000 == 0) |
| 17935 | | control |= select |
| 17936 | | else if (control & @as(u8, 0b1) << @truncate(elem_index) != select) break :blend; |
| 25977 | control |= select_mask |
| 25978 | else if (control & @as(u8, 0b1) << @truncate(elem_index) != select_mask) break :blend; |
| 17937 | 25979 | } |
| 17938 | 25980 | |
| 17939 | 25981 | if (!elem_ty.isRuntimeFloat() and self.hasFeature(.avx2)) vpblendd: { |
| ... | ... | @@ -17956,12 +25998,12 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17956 | 25998 | |
| 17957 | 25999 | const rhs_mcv = try self.resolveInst(extra.b); |
| 17958 | 26000 | const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.sse); |
| 17959 | | if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 26001 | if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 17960 | 26002 | .{ .vp_d, .blend }, |
| 17961 | 26003 | registerAlias(dst_reg, dst_abi_size), |
| 17962 | 26004 | registerAlias(lhs_reg, dst_abi_size), |
| 17963 | | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17964 | | Immediate.u(expanded_control), |
| 26005 | try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }), |
| 26006 | .u(expanded_control), |
| 17965 | 26007 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 17966 | 26008 | .{ .vp_d, .blend }, |
| 17967 | 26009 | registerAlias(dst_reg, dst_abi_size), |
| ... | ... | @@ -17970,7 +26012,7 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17970 | 26012 | rhs_mcv.getReg().? |
| 17971 | 26013 | else |
| 17972 | 26014 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 17973 | | Immediate.u(expanded_control), |
| 26015 | .u(expanded_control), |
| 17974 | 26016 | ); |
| 17975 | 26017 | break :result .{ .register = dst_reg }; |
| 17976 | 26018 | } |
| ... | ... | @@ -18008,1810 +26050,4076 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 18008 | 26050 | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv); |
| 18009 | 26051 | const dst_reg = dst_mcv.getReg().?; |
| 18010 | 26052 | |
| 18011 | | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 26053 | if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 18012 | 26054 | .{ .vp_w, .blend }, |
| 18013 | 26055 | registerAlias(dst_reg, dst_abi_size), |
| 18014 | 26056 | registerAlias(if (lhs_mcv.isRegister()) |
| 18015 | 26057 | lhs_mcv.getReg().? |
| 18016 | 26058 | else |
| 18017 | 26059 | dst_reg, dst_abi_size), |
| 18018 | | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 18019 | | Immediate.u(expanded_control), |
| 26060 | try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }), |
| 26061 | .u(expanded_control), |
| 18020 | 26062 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 18021 | 26063 | .{ .vp_w, .blend }, |
| 18022 | 26064 | registerAlias(dst_reg, dst_abi_size), |
| 18023 | 26065 | registerAlias(if (lhs_mcv.isRegister()) |
| 18024 | 26066 | lhs_mcv.getReg().? |
| 18025 | 26067 | else |
| 18026 | | dst_reg, dst_abi_size), |
| 26068 | dst_reg, dst_abi_size), |
| 26069 | registerAlias(if (rhs_mcv.isRegister()) |
| 26070 | rhs_mcv.getReg().? |
| 26071 | else |
| 26072 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 26073 | .u(expanded_control), |
| 26074 | ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate( |
| 26075 | .{ .p_w, .blend }, |
| 26076 | registerAlias(dst_reg, dst_abi_size), |
| 26077 | try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }), |
| 26078 | .u(expanded_control), |
| 26079 | ) else try self.asmRegisterRegisterImmediate( |
| 26080 | .{ .p_w, .blend }, |
| 26081 | registerAlias(dst_reg, dst_abi_size), |
| 26082 | registerAlias(if (rhs_mcv.isRegister()) |
| 26083 | rhs_mcv.getReg().? |
| 26084 | else |
| 26085 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 26086 | .u(expanded_control), |
| 26087 | ); |
| 26088 | break :result .{ .register = dst_reg }; |
| 26089 | } |
| 26090 | |
| 26091 | const expanded_control = switch (elem_abi_size) { |
| 26092 | 4, 8 => control, |
| 26093 | 16 => @as(u4, if (control & 0b01 != 0) 0b00_11 else 0b00_00) | |
| 26094 | @as(u4, if (control & 0b10 != 0) 0b11_00 else 0b00_00), |
| 26095 | else => unreachable, |
| 26096 | }; |
| 26097 | |
| 26098 | const lhs_mcv = try self.resolveInst(extra.a); |
| 26099 | const rhs_mcv = try self.resolveInst(extra.b); |
| 26100 | |
| 26101 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 26102 | self.reuseOperand(inst, extra.a, 0, lhs_mcv)) |
| 26103 | lhs_mcv |
| 26104 | else if (has_avx and lhs_mcv.isRegister()) |
| 26105 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 26106 | else |
| 26107 | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv); |
| 26108 | const dst_reg = dst_mcv.getReg().?; |
| 26109 | |
| 26110 | if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate( |
| 26111 | switch (elem_abi_size) { |
| 26112 | 4 => .{ .v_ps, .blend }, |
| 26113 | 8, 16 => .{ .v_pd, .blend }, |
| 26114 | else => unreachable, |
| 26115 | }, |
| 26116 | registerAlias(dst_reg, dst_abi_size), |
| 26117 | registerAlias(if (lhs_mcv.isRegister()) |
| 26118 | lhs_mcv.getReg().? |
| 26119 | else |
| 26120 | dst_reg, dst_abi_size), |
| 26121 | try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }), |
| 26122 | .u(expanded_control), |
| 26123 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 26124 | switch (elem_abi_size) { |
| 26125 | 4 => .{ .v_ps, .blend }, |
| 26126 | 8, 16 => .{ .v_pd, .blend }, |
| 26127 | else => unreachable, |
| 26128 | }, |
| 26129 | registerAlias(dst_reg, dst_abi_size), |
| 26130 | registerAlias(if (lhs_mcv.isRegister()) |
| 26131 | lhs_mcv.getReg().? |
| 26132 | else |
| 26133 | dst_reg, dst_abi_size), |
| 26134 | registerAlias(if (rhs_mcv.isRegister()) |
| 26135 | rhs_mcv.getReg().? |
| 26136 | else |
| 26137 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 26138 | .u(expanded_control), |
| 26139 | ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate( |
| 26140 | switch (elem_abi_size) { |
| 26141 | 4 => .{ ._ps, .blend }, |
| 26142 | 8, 16 => .{ ._pd, .blend }, |
| 26143 | else => unreachable, |
| 26144 | }, |
| 26145 | registerAlias(dst_reg, dst_abi_size), |
| 26146 | try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }), |
| 26147 | .u(expanded_control), |
| 26148 | ) else try self.asmRegisterRegisterImmediate( |
| 26149 | switch (elem_abi_size) { |
| 26150 | 4 => .{ ._ps, .blend }, |
| 26151 | 8, 16 => .{ ._pd, .blend }, |
| 26152 | else => unreachable, |
| 26153 | }, |
| 26154 | registerAlias(dst_reg, dst_abi_size), |
| 26155 | registerAlias(if (rhs_mcv.isRegister()) |
| 26156 | rhs_mcv.getReg().? |
| 26157 | else |
| 26158 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 26159 | .u(expanded_control), |
| 26160 | ); |
| 26161 | break :result .{ .register = dst_reg }; |
| 26162 | } |
| 26163 | |
| 26164 | blendv: { |
| 26165 | if (dst_abi_size > self.vectorSize(if (elem_abi_size >= 4) .float else .int)) break :blendv; |
| 26166 | |
| 26167 | const select_mask_elem_ty = try pt.intType(.unsigned, elem_abi_size * 8); |
| 26168 | const select_mask_ty = try pt.vectorType(.{ |
| 26169 | .len = @intCast(mask_elems.len), |
| 26170 | .child = select_mask_elem_ty.toIntern(), |
| 26171 | }); |
| 26172 | var select_mask_elems: [32]InternPool.Index = undefined; |
| 26173 | for ( |
| 26174 | select_mask_elems[0..mask_elems.len], |
| 26175 | mask_elems, |
| 26176 | 0.., |
| 26177 | ) |*select_mask_elem, maybe_mask_elem, elem_index| { |
| 26178 | const mask_elem = maybe_mask_elem orelse continue; |
| 26179 | const mask_elem_index = |
| 26180 | std.math.cast(u5, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :blendv; |
| 26181 | if (mask_elem_index != elem_index) break :blendv; |
| 26182 | |
| 26183 | select_mask_elem.* = (if (mask_elem < 0) |
| 26184 | try select_mask_elem_ty.maxIntScalar(pt, select_mask_elem_ty) |
| 26185 | else |
| 26186 | try select_mask_elem_ty.minIntScalar(pt, select_mask_elem_ty)).toIntern(); |
| 26187 | } |
| 26188 | const select_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 26189 | .ty = select_mask_ty.toIntern(), |
| 26190 | .storage = .{ .elems = select_mask_elems[0..mask_elems.len] }, |
| 26191 | } }))); |
| 26192 | |
| 26193 | if (self.hasFeature(.sse4_1)) { |
| 26194 | const mir_tag: Mir.Inst.FixedTag = .{ |
| 26195 | if ((elem_abi_size >= 4 and elem_ty.isRuntimeFloat()) or |
| 26196 | (dst_abi_size > 16 and !self.hasFeature(.avx2))) switch (elem_abi_size) { |
| 26197 | 4 => if (has_avx) .v_ps else ._ps, |
| 26198 | 8 => if (has_avx) .v_pd else ._pd, |
| 26199 | else => unreachable, |
| 26200 | } else if (has_avx) .vp_b else .p_b, |
| 26201 | .blendv, |
| 26202 | }; |
| 26203 | |
| 26204 | const select_mask_reg = if (!has_avx) reg: { |
| 26205 | try self.register_manager.getKnownReg(.xmm0, null); |
| 26206 | try self.genSetReg(.xmm0, select_mask_elem_ty, select_mask_mcv, .{}); |
| 26207 | break :reg .xmm0; |
| 26208 | } else try self.copyToTmpRegister(select_mask_ty, select_mask_mcv); |
| 26209 | const select_mask_alias = registerAlias(select_mask_reg, dst_abi_size); |
| 26210 | const select_mask_lock = self.register_manager.lockRegAssumeUnused(select_mask_reg); |
| 26211 | defer self.register_manager.unlockReg(select_mask_lock); |
| 26212 | |
| 26213 | const lhs_mcv = try self.resolveInst(extra.a); |
| 26214 | const rhs_mcv = try self.resolveInst(extra.b); |
| 26215 | |
| 26216 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 26217 | self.reuseOperand(inst, extra.a, 0, lhs_mcv)) |
| 26218 | lhs_mcv |
| 26219 | else if (has_avx and lhs_mcv.isRegister()) |
| 26220 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 26221 | else |
| 26222 | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv); |
| 26223 | const dst_reg = dst_mcv.getReg().?; |
| 26224 | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 26225 | |
| 26226 | if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryRegister( |
| 26227 | mir_tag, |
| 26228 | dst_alias, |
| 26229 | if (lhs_mcv.isRegister()) |
| 26230 | registerAlias(lhs_mcv.getReg().?, dst_abi_size) |
| 26231 | else |
| 26232 | dst_alias, |
| 26233 | try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }), |
| 26234 | select_mask_alias, |
| 26235 | ) else try self.asmRegisterRegisterRegisterRegister( |
| 26236 | mir_tag, |
| 26237 | dst_alias, |
| 26238 | if (lhs_mcv.isRegister()) |
| 26239 | registerAlias(lhs_mcv.getReg().?, dst_abi_size) |
| 26240 | else |
| 26241 | dst_alias, |
| 18027 | 26242 | registerAlias(if (rhs_mcv.isRegister()) |
| 18028 | 26243 | rhs_mcv.getReg().? |
| 18029 | 26244 | else |
| 18030 | 26245 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 18031 | | Immediate.u(expanded_control), |
| 18032 | | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 18033 | | .{ .p_w, .blend }, |
| 18034 | | registerAlias(dst_reg, dst_abi_size), |
| 18035 | | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 18036 | | Immediate.u(expanded_control), |
| 18037 | | ) else try self.asmRegisterRegisterImmediate( |
| 18038 | | .{ .p_w, .blend }, |
| 18039 | | registerAlias(dst_reg, dst_abi_size), |
| 26246 | select_mask_alias, |
| 26247 | ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryRegister( |
| 26248 | mir_tag, |
| 26249 | dst_alias, |
| 26250 | try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }), |
| 26251 | select_mask_alias, |
| 26252 | ) else try self.asmRegisterRegisterRegister( |
| 26253 | mir_tag, |
| 26254 | dst_alias, |
| 18040 | 26255 | registerAlias(if (rhs_mcv.isRegister()) |
| 18041 | 26256 | rhs_mcv.getReg().? |
| 18042 | 26257 | else |
| 18043 | 26258 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 18044 | | Immediate.u(expanded_control), |
| 26259 | select_mask_alias, |
| 18045 | 26260 | ); |
| 18046 | | break :result .{ .register = dst_reg }; |
| 26261 | break :result dst_mcv; |
| 18047 | 26262 | } |
| 18048 | 26263 | |
| 18049 | | const expanded_control = switch (elem_abi_size) { |
| 18050 | | 4, 8 => control, |
| 18051 | | 16 => @as(u4, if (control & 0b01 != 0) 0b00_11 else 0b00_00) | |
| 18052 | | @as(u4, if (control & 0b10 != 0) 0b11_00 else 0b00_00), |
| 18053 | | else => unreachable, |
| 18054 | | }; |
| 18055 | | |
| 18056 | 26264 | const lhs_mcv = try self.resolveInst(extra.a); |
| 18057 | 26265 | const rhs_mcv = try self.resolveInst(extra.b); |
| 18058 | 26266 | |
| 18059 | | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 18060 | | self.reuseOperand(inst, extra.a, 0, lhs_mcv)) |
| 18061 | | lhs_mcv |
| 18062 | | else if (has_avx and lhs_mcv.isRegister()) |
| 18063 | | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 26267 | const dst_mcv: MCValue = if (rhs_mcv.isRegister() and |
| 26268 | self.reuseOperand(inst, extra.b, 1, rhs_mcv)) |
| 26269 | rhs_mcv |
| 18064 | 26270 | else |
| 18065 | | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv); |
| 26271 | try self.copyToRegisterWithInstTracking(inst, dst_ty, rhs_mcv); |
| 18066 | 26272 | const dst_reg = dst_mcv.getReg().?; |
| 26273 | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 18067 | 26274 | |
| 18068 | | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 18069 | | switch (elem_abi_size) { |
| 18070 | | 4 => .{ .v_ps, .blend }, |
| 18071 | | 8, 16 => .{ .v_pd, .blend }, |
| 18072 | | else => unreachable, |
| 18073 | | }, |
| 18074 | | registerAlias(dst_reg, dst_abi_size), |
| 18075 | | registerAlias(if (lhs_mcv.isRegister()) |
| 18076 | | lhs_mcv.getReg().? |
| 18077 | | else |
| 18078 | | dst_reg, dst_abi_size), |
| 18079 | | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 18080 | | Immediate.u(expanded_control), |
| 18081 | | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 18082 | | switch (elem_abi_size) { |
| 18083 | | 4 => .{ .v_ps, .blend }, |
| 18084 | | 8, 16 => .{ .v_pd, .blend }, |
| 26275 | const mask_reg = try self.copyToTmpRegister(select_mask_ty, select_mask_mcv); |
| 26276 | const mask_alias = registerAlias(mask_reg, dst_abi_size); |
| 26277 | const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg); |
| 26278 | defer self.register_manager.unlockReg(mask_lock); |
| 26279 | |
| 26280 | const mir_fixes: Mir.Inst.Fixes = if (elem_ty.isRuntimeFloat()) |
| 26281 | switch (elem_ty.floatBits(self.target.*)) { |
| 26282 | 16, 80, 128 => .p_, |
| 26283 | 32 => ._ps, |
| 26284 | 64 => ._pd, |
| 18085 | 26285 | else => unreachable, |
| 18086 | | }, |
| 18087 | | registerAlias(dst_reg, dst_abi_size), |
| 18088 | | registerAlias(if (lhs_mcv.isRegister()) |
| 26286 | } |
| 26287 | else |
| 26288 | .p_; |
| 26289 | try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias); |
| 26290 | if (lhs_mcv.isBase()) try self.asmRegisterMemory( |
| 26291 | .{ mir_fixes, .andn }, |
| 26292 | mask_alias, |
| 26293 | try lhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }), |
| 26294 | ) else try self.asmRegisterRegister( |
| 26295 | .{ mir_fixes, .andn }, |
| 26296 | mask_alias, |
| 26297 | if (lhs_mcv.isRegister()) |
| 18089 | 26298 | lhs_mcv.getReg().? |
| 18090 | 26299 | else |
| 18091 | | dst_reg, dst_abi_size), |
| 18092 | | registerAlias(if (rhs_mcv.isRegister()) |
| 18093 | | rhs_mcv.getReg().? |
| 18094 | | else |
| 18095 | | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 18096 | | Immediate.u(expanded_control), |
| 18097 | | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 18098 | | switch (elem_abi_size) { |
| 18099 | | 4 => .{ ._ps, .blend }, |
| 18100 | | 8, 16 => .{ ._pd, .blend }, |
| 26300 | try self.copyToTmpRegister(dst_ty, lhs_mcv), |
| 26301 | ); |
| 26302 | try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_alias, mask_alias); |
| 26303 | break :result dst_mcv; |
| 26304 | } |
| 26305 | |
| 26306 | pshufb: { |
| 26307 | if (max_abi_size > 16) break :pshufb; |
| 26308 | if (!self.hasFeature(.ssse3)) break :pshufb; |
| 26309 | |
| 26310 | const temp_regs = |
| 26311 | try self.register_manager.allocRegs(2, .{ inst, null }, abi.RegisterClass.sse); |
| 26312 | const temp_locks = self.register_manager.lockRegsAssumeUnused(2, temp_regs); |
| 26313 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 26314 | |
| 26315 | const lhs_temp_alias = registerAlias(temp_regs[0], max_abi_size); |
| 26316 | try self.genSetReg(temp_regs[0], lhs_ty, .{ .air_ref = extra.a }, .{}); |
| 26317 | |
| 26318 | const rhs_temp_alias = registerAlias(temp_regs[1], max_abi_size); |
| 26319 | try self.genSetReg(temp_regs[1], rhs_ty, .{ .air_ref = extra.b }, .{}); |
| 26320 | |
| 26321 | var lhs_mask_elems: [16]InternPool.Index = undefined; |
| 26322 | for (lhs_mask_elems[0..max_abi_size], 0..) |*lhs_mask_elem, byte_index| { |
| 26323 | const elem_index = byte_index / elem_abi_size; |
| 26324 | lhs_mask_elem.* = try pt.intern(.{ .int = .{ |
| 26325 | .ty = .u8_type, |
| 26326 | .storage = .{ .u64 = if (elem_index >= mask_elems.len) 0b1_00_00000 else elem: { |
| 26327 | const mask_elem = mask_elems[elem_index] orelse break :elem 0b1_00_00000; |
| 26328 | if (mask_elem < 0) break :elem 0b1_00_00000; |
| 26329 | const mask_elem_index: u31 = @intCast(mask_elem); |
| 26330 | const byte_off: u32 = @intCast(byte_index % elem_abi_size); |
| 26331 | break :elem @intCast(mask_elem_index * elem_abi_size + byte_off); |
| 26332 | } }, |
| 26333 | } }); |
| 26334 | } |
| 26335 | const lhs_mask_ty = try pt.vectorType(.{ .len = max_abi_size, .child = .u8_type }); |
| 26336 | const lhs_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 26337 | .ty = lhs_mask_ty.toIntern(), |
| 26338 | .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] }, |
| 26339 | } }))); |
| 26340 | const lhs_mask_mem: Memory = .{ |
| 26341 | .base = .{ .reg = try self.copyToTmpRegister(.usize, lhs_mask_mcv.address()) }, |
| 26342 | .mod = .{ .rm = .{ .size = .fromSize(@max(max_abi_size, 16)) } }, |
| 26343 | }; |
| 26344 | if (has_avx) try self.asmRegisterRegisterMemory( |
| 26345 | .{ .vp_b, .shuf }, |
| 26346 | lhs_temp_alias, |
| 26347 | lhs_temp_alias, |
| 26348 | lhs_mask_mem, |
| 26349 | ) else try self.asmRegisterMemory( |
| 26350 | .{ .p_b, .shuf }, |
| 26351 | lhs_temp_alias, |
| 26352 | lhs_mask_mem, |
| 26353 | ); |
| 26354 | |
| 26355 | var rhs_mask_elems: [16]InternPool.Index = undefined; |
| 26356 | for (rhs_mask_elems[0..max_abi_size], 0..) |*rhs_mask_elem, byte_index| { |
| 26357 | const elem_index = byte_index / elem_abi_size; |
| 26358 | rhs_mask_elem.* = try pt.intern(.{ .int = .{ |
| 26359 | .ty = .u8_type, |
| 26360 | .storage = .{ .u64 = if (elem_index >= mask_elems.len) 0b1_00_00000 else elem: { |
| 26361 | const mask_elem = mask_elems[elem_index] orelse break :elem 0b1_00_00000; |
| 26362 | if (mask_elem >= 0) break :elem 0b1_00_00000; |
| 26363 | const mask_elem_index: u31 = @intCast(~mask_elem); |
| 26364 | const byte_off: u32 = @intCast(byte_index % elem_abi_size); |
| 26365 | break :elem @intCast(mask_elem_index * elem_abi_size + byte_off); |
| 26366 | } }, |
| 26367 | } }); |
| 26368 | } |
| 26369 | const rhs_mask_ty = try pt.vectorType(.{ .len = max_abi_size, .child = .u8_type }); |
| 26370 | const rhs_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 26371 | .ty = rhs_mask_ty.toIntern(), |
| 26372 | .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] }, |
| 26373 | } }))); |
| 26374 | const rhs_mask_mem: Memory = .{ |
| 26375 | .base = .{ .reg = try self.copyToTmpRegister(.usize, rhs_mask_mcv.address()) }, |
| 26376 | .mod = .{ .rm = .{ .size = .fromSize(@max(max_abi_size, 16)) } }, |
| 26377 | }; |
| 26378 | if (has_avx) try self.asmRegisterRegisterMemory( |
| 26379 | .{ .vp_b, .shuf }, |
| 26380 | rhs_temp_alias, |
| 26381 | rhs_temp_alias, |
| 26382 | rhs_mask_mem, |
| 26383 | ) else try self.asmRegisterMemory( |
| 26384 | .{ .p_b, .shuf }, |
| 26385 | rhs_temp_alias, |
| 26386 | rhs_mask_mem, |
| 26387 | ); |
| 26388 | |
| 26389 | if (has_avx) try self.asmRegisterRegisterRegister( |
| 26390 | .{ switch (elem_ty.zigTypeTag(zcu)) { |
| 26391 | else => break :result null, |
| 26392 | .int => .vp_, |
| 26393 | .float => switch (elem_ty.floatBits(self.target.*)) { |
| 26394 | 32 => .v_ps, |
| 26395 | 64 => .v_pd, |
| 26396 | 16, 80, 128 => break :result null, |
| 26397 | else => unreachable, |
| 26398 | }, |
| 26399 | }, .@"or" }, |
| 26400 | lhs_temp_alias, |
| 26401 | lhs_temp_alias, |
| 26402 | rhs_temp_alias, |
| 26403 | ) else try self.asmRegisterRegister( |
| 26404 | .{ switch (elem_ty.zigTypeTag(zcu)) { |
| 26405 | else => break :result null, |
| 26406 | .int => .p_, |
| 26407 | .float => switch (elem_ty.floatBits(self.target.*)) { |
| 26408 | 32 => ._ps, |
| 26409 | 64 => ._pd, |
| 26410 | 16, 80, 128 => break :result null, |
| 26411 | else => unreachable, |
| 26412 | }, |
| 26413 | }, .@"or" }, |
| 26414 | lhs_temp_alias, |
| 26415 | rhs_temp_alias, |
| 26416 | ); |
| 26417 | break :result .{ .register = temp_regs[0] }; |
| 26418 | } |
| 26419 | |
| 26420 | break :result null; |
| 26421 | }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{ |
| 26422 | lhs_ty.fmt(pt), |
| 26423 | rhs_ty.fmt(pt), |
| 26424 | dst_ty.fmt(pt), |
| 26425 | Value.fromInterned(extra.mask).fmtValue(pt), |
| 26426 | }); |
| 26427 | return self.finishAir(inst, result, .{ extra.a, extra.b, .none }); |
| 26428 | } |
| 26429 | |
| 26430 | fn airReduce(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26431 | const pt = self.pt; |
| 26432 | const zcu = pt.zcu; |
| 26433 | const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce; |
| 26434 | |
| 26435 | const result: MCValue = result: { |
| 26436 | const operand_ty = self.typeOf(reduce.operand); |
| 26437 | if (operand_ty.isVector(zcu) and operand_ty.childType(zcu).toIntern() == .bool_type) { |
| 26438 | try self.spillEflagsIfOccupied(); |
| 26439 | |
| 26440 | const abi_size: u32 = @intCast(operand_ty.abiSize(zcu)); |
| 26441 | const operand_mcv = try self.resolveInst(reduce.operand); |
| 26442 | const mask_len = operand_ty.vectorLen(zcu); |
| 26443 | const mask_len_minus_one = (std.math.cast(u6, mask_len - 1) orelse { |
| 26444 | const acc_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 26445 | const acc_lock = self.register_manager.lockRegAssumeUnused(acc_reg); |
| 26446 | defer self.register_manager.unlockReg(acc_lock); |
| 26447 | var limb_offset: i31 = 0; |
| 26448 | while (limb_offset < abi_size) : (limb_offset += 8) { |
| 26449 | try self.asmRegisterMemory( |
| 26450 | .{ ._, if (limb_offset == 0) .mov else switch (reduce.operation) { |
| 26451 | .Or => .@"or", |
| 26452 | .And => .@"and", |
| 26453 | else => return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}), |
| 26454 | } }, |
| 26455 | acc_reg.to64(), |
| 26456 | try operand_mcv.mem(self, .{ |
| 26457 | .size = .qword, |
| 26458 | .disp = limb_offset, |
| 26459 | }), |
| 26460 | ); |
| 26461 | } |
| 26462 | switch (reduce.operation) { |
| 26463 | .Or => { |
| 26464 | try self.asmRegisterRegister(.{ ._, .@"test" }, acc_reg.to64(), acc_reg.to64()); |
| 26465 | break :result .{ .eflags = .nz }; |
| 26466 | }, |
| 26467 | .And => { |
| 26468 | try self.asmRegisterImmediate(.{ ._, .cmp }, acc_reg.to64(), .s(-1)); |
| 26469 | break :result .{ .eflags = .z }; |
| 26470 | }, |
| 18101 | 26471 | else => unreachable, |
| 26472 | } |
| 26473 | }); |
| 26474 | const mask = @as(u64, std.math.maxInt(u64)) >> ~mask_len_minus_one; |
| 26475 | switch (reduce.operation) { |
| 26476 | .Or => { |
| 26477 | if (operand_mcv.isBase()) try self.asmMemoryImmediate( |
| 26478 | .{ ._, .@"test" }, |
| 26479 | try operand_mcv.mem(self, .{ .size = .fromSize(abi_size) }), |
| 26480 | if (mask_len < abi_size * 8) |
| 26481 | .u(mask) |
| 26482 | else |
| 26483 | .s(-1), |
| 26484 | ) else { |
| 26485 | const operand_reg = registerAlias(operand_reg: { |
| 26486 | if (operand_mcv.isRegister()) { |
| 26487 | const operand_reg = operand_mcv.getReg().?; |
| 26488 | if (operand_reg.class() == .general_purpose) break :operand_reg operand_reg; |
| 26489 | } |
| 26490 | break :operand_reg try self.copyToTmpRegister(operand_ty, operand_mcv); |
| 26491 | }, abi_size); |
| 26492 | const operand_lock = self.register_manager.lockReg(operand_reg); |
| 26493 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 26494 | |
| 26495 | if (mask_len < abi_size * 8) try self.asmRegisterImmediate( |
| 26496 | .{ ._, .@"test" }, |
| 26497 | operand_reg, |
| 26498 | .u(mask), |
| 26499 | ) else try self.asmRegisterRegister( |
| 26500 | .{ ._, .@"test" }, |
| 26501 | operand_reg, |
| 26502 | operand_reg, |
| 26503 | ); |
| 26504 | } |
| 26505 | break :result .{ .eflags = .nz }; |
| 18102 | 26506 | }, |
| 18103 | | registerAlias(dst_reg, dst_abi_size), |
| 18104 | | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 18105 | | Immediate.u(expanded_control), |
| 18106 | | ) else try self.asmRegisterRegisterImmediate( |
| 18107 | | switch (elem_abi_size) { |
| 18108 | | 4 => .{ ._ps, .blend }, |
| 18109 | | 8, 16 => .{ ._pd, .blend }, |
| 18110 | | else => unreachable, |
| 26507 | .And => { |
| 26508 | const tmp_reg = registerAlias( |
| 26509 | try self.copyToTmpRegister(operand_ty, operand_mcv), |
| 26510 | abi_size, |
| 26511 | ); |
| 26512 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 26513 | defer self.register_manager.unlockReg(tmp_lock); |
| 26514 | |
| 26515 | try self.asmRegister(.{ ._, .not }, tmp_reg); |
| 26516 | if (mask_len < abi_size * 8) |
| 26517 | try self.asmRegisterImmediate(.{ ._, .@"test" }, tmp_reg, .u(mask)) |
| 26518 | else |
| 26519 | try self.asmRegisterRegister(.{ ._, .@"test" }, tmp_reg, tmp_reg); |
| 26520 | break :result .{ .eflags = .z }; |
| 18111 | 26521 | }, |
| 18112 | | registerAlias(dst_reg, dst_abi_size), |
| 18113 | | registerAlias(if (rhs_mcv.isRegister()) |
| 18114 | | rhs_mcv.getReg().? |
| 18115 | | else |
| 18116 | | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 18117 | | Immediate.u(expanded_control), |
| 18118 | | ); |
| 18119 | | break :result .{ .register = dst_reg }; |
| 26522 | else => return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}), |
| 26523 | } |
| 18120 | 26524 | } |
| 26525 | return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}); |
| 26526 | }; |
| 26527 | return self.finishAir(inst, result, .{ reduce.operand, .none, .none }); |
| 26528 | } |
| 18121 | 26529 | |
| 18122 | | blendv: { |
| 18123 | | if (dst_abi_size > @as(u32, if (if (elem_abi_size >= 4) |
| 18124 | | has_avx |
| 18125 | | else |
| 18126 | | self.hasFeature(.avx2)) 32 else 16)) break :blendv; |
| 26530 | fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26531 | const pt = self.pt; |
| 26532 | const zcu = pt.zcu; |
| 26533 | const result_ty = self.typeOfIndex(inst); |
| 26534 | const len: usize = @intCast(result_ty.arrayLen(zcu)); |
| 26535 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 26536 | const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]); |
| 26537 | const result: MCValue = result: { |
| 26538 | switch (result_ty.zigTypeTag(zcu)) { |
| 26539 | .@"struct" => { |
| 26540 | const frame_index = try self.allocFrameIndex(.initSpill(result_ty, zcu)); |
| 26541 | if (result_ty.containerLayout(zcu) == .@"packed") { |
| 26542 | const loaded_struct = zcu.intern_pool.loadStructType(result_ty.toIntern()); |
| 26543 | try self.genInlineMemset( |
| 26544 | .{ .lea_frame = .{ .index = frame_index } }, |
| 26545 | .{ .immediate = 0 }, |
| 26546 | .{ .immediate = result_ty.abiSize(zcu) }, |
| 26547 | .{}, |
| 26548 | ); |
| 26549 | for (elements, 0..) |elem, elem_i_usize| { |
| 26550 | const elem_i: u32 = @intCast(elem_i_usize); |
| 26551 | if ((try result_ty.structFieldValueComptime(pt, elem_i)) != null) continue; |
| 18127 | 26552 | |
| 18128 | | const select_mask_elem_ty = try pt.intType(.unsigned, elem_abi_size * 8); |
| 18129 | | const select_mask_ty = try pt.vectorType(.{ |
| 18130 | | .len = @intCast(mask_elems.len), |
| 18131 | | .child = select_mask_elem_ty.toIntern(), |
| 18132 | | }); |
| 18133 | | var select_mask_elems: [32]InternPool.Index = undefined; |
| 18134 | | for ( |
| 18135 | | select_mask_elems[0..mask_elems.len], |
| 18136 | | mask_elems, |
| 18137 | | 0.., |
| 18138 | | ) |*select_mask_elem, maybe_mask_elem, elem_index| { |
| 18139 | | const mask_elem = maybe_mask_elem orelse continue; |
| 18140 | | const mask_elem_index = |
| 18141 | | math.cast(u5, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :blendv; |
| 18142 | | if (mask_elem_index != elem_index) break :blendv; |
| 26553 | const elem_ty = result_ty.fieldType(elem_i, zcu); |
| 26554 | const elem_bit_size: u32 = @intCast(elem_ty.bitSize(zcu)); |
| 26555 | if (elem_bit_size > 64) { |
| 26556 | return self.fail( |
| 26557 | "TODO airAggregateInit implement packed structs with large fields", |
| 26558 | .{}, |
| 26559 | ); |
| 26560 | } |
| 26561 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 26562 | const elem_abi_bits = elem_abi_size * 8; |
| 26563 | const elem_off = pt.structPackedFieldBitOffset(loaded_struct, elem_i); |
| 26564 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 26565 | const elem_bit_off = elem_off % elem_abi_bits; |
| 26566 | const elem_mcv = try self.resolveInst(elem); |
| 26567 | const mat_elem_mcv = switch (elem_mcv) { |
| 26568 | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, |
| 26569 | else => elem_mcv, |
| 26570 | }; |
| 26571 | const elem_lock = switch (mat_elem_mcv) { |
| 26572 | .register => |reg| self.register_manager.lockReg(reg), |
| 26573 | .immediate => |imm| lock: { |
| 26574 | if (imm == 0) continue; |
| 26575 | break :lock null; |
| 26576 | }, |
| 26577 | else => null, |
| 26578 | }; |
| 26579 | defer if (elem_lock) |lock| self.register_manager.unlockReg(lock); |
| 18143 | 26580 | |
| 18144 | | select_mask_elem.* = (if (mask_elem < 0) |
| 18145 | | try select_mask_elem_ty.maxIntScalar(pt, select_mask_elem_ty) |
| 18146 | | else |
| 18147 | | try select_mask_elem_ty.minIntScalar(pt, select_mask_elem_ty)).toIntern(); |
| 18148 | | } |
| 18149 | | const select_mask_mcv = try self.genTypedValue(Value.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 18150 | | .ty = select_mask_ty.toIntern(), |
| 18151 | | .storage = .{ .elems = select_mask_elems[0..mask_elems.len] }, |
| 18152 | | } }))); |
| 26581 | const elem_extra_bits = self.regExtraBits(elem_ty); |
| 26582 | { |
| 26583 | const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv); |
| 26584 | const temp_alias = registerAlias(temp_reg, elem_abi_size); |
| 26585 | const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg); |
| 26586 | defer self.register_manager.unlockReg(temp_lock); |
| 18153 | 26587 | |
| 18154 | | if (self.hasFeature(.sse4_1)) { |
| 18155 | | const mir_tag: Mir.Inst.FixedTag = .{ |
| 18156 | | if ((elem_abi_size >= 4 and elem_ty.isRuntimeFloat()) or |
| 18157 | | (dst_abi_size > 16 and !self.hasFeature(.avx2))) switch (elem_abi_size) { |
| 18158 | | 4 => if (has_avx) .v_ps else ._ps, |
| 18159 | | 8 => if (has_avx) .v_pd else ._pd, |
| 18160 | | else => unreachable, |
| 18161 | | } else if (has_avx) .vp_b else .p_b, |
| 18162 | | .blendv, |
| 18163 | | }; |
| 26588 | if (elem_bit_off < elem_extra_bits) { |
| 26589 | try self.truncateRegister(elem_ty, temp_alias); |
| 26590 | } |
| 26591 | if (elem_bit_off > 0) try self.genShiftBinOpMir( |
| 26592 | .{ ._l, .sh }, |
| 26593 | elem_ty, |
| 26594 | .{ .register = temp_alias }, |
| 26595 | .u8, |
| 26596 | .{ .immediate = elem_bit_off }, |
| 26597 | ); |
| 26598 | try self.genBinOpMir( |
| 26599 | .{ ._, .@"or" }, |
| 26600 | elem_ty, |
| 26601 | .{ .load_frame = .{ .index = frame_index, .off = elem_byte_off } }, |
| 26602 | .{ .register = temp_alias }, |
| 26603 | ); |
| 26604 | } |
| 26605 | if (elem_bit_off > elem_extra_bits) { |
| 26606 | const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv); |
| 26607 | const temp_alias = registerAlias(temp_reg, elem_abi_size); |
| 26608 | const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg); |
| 26609 | defer self.register_manager.unlockReg(temp_lock); |
| 18164 | 26610 | |
| 18165 | | const select_mask_reg = if (!has_avx) reg: { |
| 18166 | | try self.register_manager.getKnownReg(.xmm0, null); |
| 18167 | | try self.genSetReg(.xmm0, select_mask_elem_ty, select_mask_mcv, .{}); |
| 18168 | | break :reg .xmm0; |
| 18169 | | } else try self.copyToTmpRegister(select_mask_ty, select_mask_mcv); |
| 18170 | | const select_mask_alias = registerAlias(select_mask_reg, dst_abi_size); |
| 18171 | | const select_mask_lock = self.register_manager.lockRegAssumeUnused(select_mask_reg); |
| 18172 | | defer self.register_manager.unlockReg(select_mask_lock); |
| 26611 | if (elem_extra_bits > 0) { |
| 26612 | try self.truncateRegister(elem_ty, temp_alias); |
| 26613 | } |
| 26614 | try self.genShiftBinOpMir( |
| 26615 | .{ ._r, .sh }, |
| 26616 | elem_ty, |
| 26617 | .{ .register = temp_reg }, |
| 26618 | .u8, |
| 26619 | .{ .immediate = elem_abi_bits - elem_bit_off }, |
| 26620 | ); |
| 26621 | try self.genBinOpMir( |
| 26622 | .{ ._, .@"or" }, |
| 26623 | elem_ty, |
| 26624 | .{ .load_frame = .{ |
| 26625 | .index = frame_index, |
| 26626 | .off = elem_byte_off + @as(i32, @intCast(elem_abi_size)), |
| 26627 | } }, |
| 26628 | .{ .register = temp_alias }, |
| 26629 | ); |
| 26630 | } |
| 26631 | } |
| 26632 | } else for (elements, 0..) |elem, elem_i| { |
| 26633 | if ((try result_ty.structFieldValueComptime(pt, elem_i)) != null) continue; |
| 18173 | 26634 | |
| 18174 | | const lhs_mcv = try self.resolveInst(extra.a); |
| 18175 | | const rhs_mcv = try self.resolveInst(extra.b); |
| 26635 | const elem_ty = result_ty.fieldType(elem_i, zcu); |
| 26636 | const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu)); |
| 26637 | const elem_mcv = try self.resolveInst(elem); |
| 26638 | const mat_elem_mcv = switch (elem_mcv) { |
| 26639 | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, |
| 26640 | else => elem_mcv, |
| 26641 | }; |
| 26642 | try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv, .{}); |
| 26643 | } |
| 26644 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 26645 | }, |
| 26646 | .array, .vector => { |
| 26647 | const elem_ty = result_ty.childType(zcu); |
| 26648 | if (result_ty.isVector(zcu) and elem_ty.toIntern() == .bool_type) { |
| 26649 | const result_size: u32 = @intCast(result_ty.abiSize(zcu)); |
| 26650 | const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp); |
| 26651 | try self.asmRegisterRegister( |
| 26652 | .{ ._, .xor }, |
| 26653 | registerAlias(dst_reg, @min(result_size, 4)), |
| 26654 | registerAlias(dst_reg, @min(result_size, 4)), |
| 26655 | ); |
| 18176 | 26656 | |
| 18177 | | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 18178 | | self.reuseOperand(inst, extra.a, 0, lhs_mcv)) |
| 18179 | | lhs_mcv |
| 18180 | | else if (has_avx and lhs_mcv.isRegister()) |
| 18181 | | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 18182 | | else |
| 18183 | | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv); |
| 18184 | | const dst_reg = dst_mcv.getReg().?; |
| 18185 | | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 26657 | for (elements, 0..) |elem, elem_i| { |
| 26658 | const elem_reg = try self.copyToTmpRegister(elem_ty, .{ .air_ref = elem }); |
| 26659 | const elem_lock = self.register_manager.lockRegAssumeUnused(elem_reg); |
| 26660 | defer self.register_manager.unlockReg(elem_lock); |
| 18186 | 26661 | |
| 18187 | | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryRegister( |
| 18188 | | mir_tag, |
| 18189 | | dst_alias, |
| 18190 | | if (lhs_mcv.isRegister()) |
| 18191 | | registerAlias(lhs_mcv.getReg().?, dst_abi_size) |
| 18192 | | else |
| 18193 | | dst_alias, |
| 18194 | | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 18195 | | select_mask_alias, |
| 18196 | | ) else try self.asmRegisterRegisterRegisterRegister( |
| 18197 | | mir_tag, |
| 18198 | | dst_alias, |
| 18199 | | if (lhs_mcv.isRegister()) |
| 18200 | | registerAlias(lhs_mcv.getReg().?, dst_abi_size) |
| 18201 | | else |
| 18202 | | dst_alias, |
| 18203 | | registerAlias(if (rhs_mcv.isRegister()) |
| 18204 | | rhs_mcv.getReg().? |
| 18205 | | else |
| 18206 | | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 18207 | | select_mask_alias, |
| 18208 | | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryRegister( |
| 18209 | | mir_tag, |
| 18210 | | dst_alias, |
| 18211 | | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 18212 | | select_mask_alias, |
| 18213 | | ) else try self.asmRegisterRegisterRegister( |
| 18214 | | mir_tag, |
| 18215 | | dst_alias, |
| 18216 | | registerAlias(if (rhs_mcv.isRegister()) |
| 18217 | | rhs_mcv.getReg().? |
| 18218 | | else |
| 18219 | | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 18220 | | select_mask_alias, |
| 18221 | | ); |
| 18222 | | break :result dst_mcv; |
| 18223 | | } |
| 26662 | try self.asmRegisterImmediate( |
| 26663 | .{ ._, .@"and" }, |
| 26664 | registerAlias(elem_reg, @min(result_size, 4)), |
| 26665 | .u(1), |
| 26666 | ); |
| 26667 | if (elem_i > 0) try self.asmRegisterImmediate( |
| 26668 | .{ ._l, .sh }, |
| 26669 | registerAlias(elem_reg, result_size), |
| 26670 | .u(@intCast(elem_i)), |
| 26671 | ); |
| 26672 | try self.asmRegisterRegister( |
| 26673 | .{ ._, .@"or" }, |
| 26674 | registerAlias(dst_reg, result_size), |
| 26675 | registerAlias(elem_reg, result_size), |
| 26676 | ); |
| 26677 | } |
| 26678 | break :result .{ .register = dst_reg }; |
| 26679 | } else { |
| 26680 | const frame_index = try self.allocFrameIndex(.initSpill(result_ty, zcu)); |
| 26681 | const elem_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 26682 | |
| 26683 | for (elements, 0..) |elem, elem_i| { |
| 26684 | const elem_mcv = try self.resolveInst(elem); |
| 26685 | const mat_elem_mcv = switch (elem_mcv) { |
| 26686 | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, |
| 26687 | else => elem_mcv, |
| 26688 | }; |
| 26689 | const elem_off: i32 = @intCast(elem_size * elem_i); |
| 26690 | try self.genSetMem( |
| 26691 | .{ .frame = frame_index }, |
| 26692 | elem_off, |
| 26693 | elem_ty, |
| 26694 | mat_elem_mcv, |
| 26695 | .{}, |
| 26696 | ); |
| 26697 | } |
| 26698 | if (result_ty.sentinel(zcu)) |sentinel| try self.genSetMem( |
| 26699 | .{ .frame = frame_index }, |
| 26700 | @intCast(elem_size * elements.len), |
| 26701 | elem_ty, |
| 26702 | try self.genTypedValue(sentinel), |
| 26703 | .{}, |
| 26704 | ); |
| 26705 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 26706 | } |
| 26707 | }, |
| 26708 | else => unreachable, |
| 26709 | } |
| 26710 | }; |
| 18224 | 26711 | |
| 18225 | | const lhs_mcv = try self.resolveInst(extra.a); |
| 18226 | | const rhs_mcv = try self.resolveInst(extra.b); |
| 26712 | if (elements.len <= Liveness.bpi - 1) { |
| 26713 | var buf: [Liveness.bpi - 1]Air.Inst.Ref = @splat(.none); |
| 26714 | @memcpy(buf[0..elements.len], elements); |
| 26715 | return self.finishAir(inst, result, buf); |
| 26716 | } |
| 26717 | var bt = self.liveness.iterateBigTomb(inst); |
| 26718 | for (elements) |elem| try self.feed(&bt, elem); |
| 26719 | return self.finishAirResult(inst, result); |
| 26720 | } |
| 18227 | 26721 | |
| 18228 | | const dst_mcv: MCValue = if (rhs_mcv.isRegister() and |
| 18229 | | self.reuseOperand(inst, extra.b, 1, rhs_mcv)) |
| 18230 | | rhs_mcv |
| 18231 | | else |
| 18232 | | try self.copyToRegisterWithInstTracking(inst, dst_ty, rhs_mcv); |
| 18233 | | const dst_reg = dst_mcv.getReg().?; |
| 18234 | | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 26722 | fn airUnionInit(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26723 | const pt = self.pt; |
| 26724 | const zcu = pt.zcu; |
| 26725 | const ip = &zcu.intern_pool; |
| 26726 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 26727 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 26728 | const result: MCValue = result: { |
| 26729 | const union_ty = self.typeOfIndex(inst); |
| 26730 | const layout = union_ty.unionGetLayout(zcu); |
| 18235 | 26731 | |
| 18236 | | const mask_reg = try self.copyToTmpRegister(select_mask_ty, select_mask_mcv); |
| 18237 | | const mask_alias = registerAlias(mask_reg, dst_abi_size); |
| 18238 | | const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg); |
| 18239 | | defer self.register_manager.unlockReg(mask_lock); |
| 26732 | const src_ty = self.typeOf(extra.init); |
| 26733 | const src_mcv = try self.resolveInst(extra.init); |
| 26734 | if (layout.tag_size == 0) { |
| 26735 | if (layout.abi_size <= src_ty.abiSize(zcu) and |
| 26736 | self.reuseOperand(inst, extra.init, 0, src_mcv)) break :result src_mcv; |
| 18240 | 26737 | |
| 18241 | | const mir_fixes: Mir.Inst.Fixes = if (elem_ty.isRuntimeFloat()) |
| 18242 | | switch (elem_ty.floatBits(self.target.*)) { |
| 18243 | | 16, 80, 128 => .p_, |
| 18244 | | 32 => ._ps, |
| 18245 | | 64 => ._pd, |
| 18246 | | else => unreachable, |
| 18247 | | } |
| 18248 | | else |
| 18249 | | .p_; |
| 18250 | | try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias); |
| 18251 | | if (lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 18252 | | .{ mir_fixes, .andn }, |
| 18253 | | mask_alias, |
| 18254 | | try lhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 18255 | | ) else try self.asmRegisterRegister( |
| 18256 | | .{ mir_fixes, .andn }, |
| 18257 | | mask_alias, |
| 18258 | | if (lhs_mcv.isRegister()) |
| 18259 | | lhs_mcv.getReg().? |
| 18260 | | else |
| 18261 | | try self.copyToTmpRegister(dst_ty, lhs_mcv), |
| 18262 | | ); |
| 18263 | | try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_alias, mask_alias); |
| 26738 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 26739 | try self.genCopy(src_ty, dst_mcv, src_mcv, .{}); |
| 18264 | 26740 | break :result dst_mcv; |
| 18265 | 26741 | } |
| 18266 | 26742 | |
| 18267 | | pshufb: { |
| 18268 | | if (max_abi_size > 16) break :pshufb; |
| 18269 | | if (!self.hasFeature(.ssse3)) break :pshufb; |
| 26743 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 18270 | 26744 | |
| 18271 | | const temp_regs = |
| 18272 | | try self.register_manager.allocRegs(2, .{ inst, null }, abi.RegisterClass.sse); |
| 18273 | | const temp_locks = self.register_manager.lockRegsAssumeUnused(2, temp_regs); |
| 18274 | | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 26745 | const loaded_union = zcu.typeToUnion(union_ty).?; |
| 26746 | const field_name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index]; |
| 26747 | const tag_ty: Type = .fromInterned(loaded_union.enum_tag_ty); |
| 26748 | const field_index = tag_ty.enumFieldIndex(field_name, zcu).?; |
| 26749 | const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index); |
| 26750 | const tag_int_val = try tag_val.intFromEnum(tag_ty, pt); |
| 26751 | const tag_int = tag_int_val.toUnsignedInt(zcu); |
| 26752 | const tag_off: i32 = @intCast(layout.tagOffset()); |
| 26753 | try self.genCopy( |
| 26754 | tag_ty, |
| 26755 | dst_mcv.address().offset(tag_off).deref(), |
| 26756 | .{ .immediate = tag_int }, |
| 26757 | .{}, |
| 26758 | ); |
| 18275 | 26759 | |
| 18276 | | const lhs_temp_alias = registerAlias(temp_regs[0], max_abi_size); |
| 18277 | | try self.genSetReg(temp_regs[0], lhs_ty, .{ .air_ref = extra.a }, .{}); |
| 26760 | const pl_off: i32 = @intCast(layout.payloadOffset()); |
| 26761 | try self.genCopy(src_ty, dst_mcv.address().offset(pl_off).deref(), src_mcv, .{}); |
| 18278 | 26762 | |
| 18279 | | const rhs_temp_alias = registerAlias(temp_regs[1], max_abi_size); |
| 18280 | | try self.genSetReg(temp_regs[1], rhs_ty, .{ .air_ref = extra.b }, .{}); |
| 26763 | break :result dst_mcv; |
| 26764 | }; |
| 26765 | return self.finishAir(inst, result, .{ extra.init, .none, .none }); |
| 26766 | } |
| 18281 | 26767 | |
| 18282 | | var lhs_mask_elems: [16]InternPool.Index = undefined; |
| 18283 | | for (lhs_mask_elems[0..max_abi_size], 0..) |*lhs_mask_elem, byte_index| { |
| 18284 | | const elem_index = byte_index / elem_abi_size; |
| 18285 | | lhs_mask_elem.* = try pt.intern(.{ .int = .{ |
| 18286 | | .ty = .u8_type, |
| 18287 | | .storage = .{ .u64 = if (elem_index >= mask_elems.len) 0b1_00_00000 else elem: { |
| 18288 | | const mask_elem = mask_elems[elem_index] orelse break :elem 0b1_00_00000; |
| 18289 | | if (mask_elem < 0) break :elem 0b1_00_00000; |
| 18290 | | const mask_elem_index: u31 = @intCast(mask_elem); |
| 18291 | | const byte_off: u32 = @intCast(byte_index % elem_abi_size); |
| 18292 | | break :elem @intCast(mask_elem_index * elem_abi_size + byte_off); |
| 18293 | | } }, |
| 18294 | | } }); |
| 18295 | | } |
| 18296 | | const lhs_mask_ty = try pt.vectorType(.{ .len = max_abi_size, .child = .u8_type }); |
| 18297 | | const lhs_mask_mcv = try self.genTypedValue(Value.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 18298 | | .ty = lhs_mask_ty.toIntern(), |
| 18299 | | .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] }, |
| 18300 | | } }))); |
| 18301 | | const lhs_mask_mem: Memory = .{ |
| 18302 | | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, lhs_mask_mcv.address()) }, |
| 18303 | | .mod = .{ .rm = .{ .size = Memory.Size.fromSize(@max(max_abi_size, 16)) } }, |
| 18304 | | }; |
| 18305 | | if (has_avx) try self.asmRegisterRegisterMemory( |
| 18306 | | .{ .vp_b, .shuf }, |
| 18307 | | lhs_temp_alias, |
| 18308 | | lhs_temp_alias, |
| 18309 | | lhs_mask_mem, |
| 18310 | | ) else try self.asmRegisterMemory( |
| 18311 | | .{ .p_b, .shuf }, |
| 18312 | | lhs_temp_alias, |
| 18313 | | lhs_mask_mem, |
| 18314 | | ); |
| 26768 | fn airPrefetch(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26769 | const prefetch = self.air.instructions.items(.data)[@intFromEnum(inst)].prefetch; |
| 26770 | return self.finishAir(inst, .unreach, .{ prefetch.ptr, .none, .none }); |
| 26771 | } |
| 18315 | 26772 | |
| 18316 | | var rhs_mask_elems: [16]InternPool.Index = undefined; |
| 18317 | | for (rhs_mask_elems[0..max_abi_size], 0..) |*rhs_mask_elem, byte_index| { |
| 18318 | | const elem_index = byte_index / elem_abi_size; |
| 18319 | | rhs_mask_elem.* = try pt.intern(.{ .int = .{ |
| 18320 | | .ty = .u8_type, |
| 18321 | | .storage = .{ .u64 = if (elem_index >= mask_elems.len) 0b1_00_00000 else elem: { |
| 18322 | | const mask_elem = mask_elems[elem_index] orelse break :elem 0b1_00_00000; |
| 18323 | | if (mask_elem >= 0) break :elem 0b1_00_00000; |
| 18324 | | const mask_elem_index: u31 = @intCast(~mask_elem); |
| 18325 | | const byte_off: u32 = @intCast(byte_index % elem_abi_size); |
| 18326 | | break :elem @intCast(mask_elem_index * elem_abi_size + byte_off); |
| 18327 | | } }, |
| 18328 | | } }); |
| 26773 | fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26774 | const pt = self.pt; |
| 26775 | const zcu = pt.zcu; |
| 26776 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 26777 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 26778 | const ty = self.typeOfIndex(inst); |
| 26779 | |
| 26780 | const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand }; |
| 26781 | const result = result: { |
| 26782 | if (switch (ty.scalarType(zcu).floatBits(self.target.*)) { |
| 26783 | 16, 80, 128 => true, |
| 26784 | 32, 64 => !self.hasFeature(.fma), |
| 26785 | else => unreachable, |
| 26786 | }) { |
| 26787 | if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement airMulAdd for {}", .{ |
| 26788 | ty.fmt(pt), |
| 26789 | }); |
| 26790 | |
| 26791 | var callee_buf: ["__fma?".len]u8 = undefined; |
| 26792 | break :result try self.genCall(.{ .lib = .{ |
| 26793 | .return_type = ty.toIntern(), |
| 26794 | .param_types = &.{ ty.toIntern(), ty.toIntern(), ty.toIntern() }, |
| 26795 | .callee = std.fmt.bufPrint(&callee_buf, "{s}fma{s}", .{ |
| 26796 | floatLibcAbiPrefix(ty), |
| 26797 | floatLibcAbiSuffix(ty), |
| 26798 | }) catch unreachable, |
| 26799 | } }, &.{ ty, ty, ty }, &.{ |
| 26800 | .{ .air_ref = extra.lhs }, .{ .air_ref = extra.rhs }, .{ .air_ref = pl_op.operand }, |
| 26801 | }, .{}); |
| 26802 | } |
| 26803 | |
| 26804 | var mcvs: [3]MCValue = undefined; |
| 26805 | var locks: [3]?RegisterManager.RegisterLock = @splat(null); |
| 26806 | defer for (locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 26807 | var order: [3]u2 = @splat(0); |
| 26808 | var unused: std.StaticBitSet(3) = .initFull(); |
| 26809 | for (ops, &mcvs, &locks, 0..) |op, *mcv, *lock, op_i| { |
| 26810 | const op_index: u2 = @intCast(op_i); |
| 26811 | mcv.* = try self.resolveInst(op); |
| 26812 | if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) { |
| 26813 | order[op_index] = 1; |
| 26814 | unused.unset(0); |
| 26815 | } else if (unused.isSet(2) and mcv.isBase()) { |
| 26816 | order[op_index] = 3; |
| 26817 | unused.unset(2); |
| 18329 | 26818 | } |
| 18330 | | const rhs_mask_ty = try pt.vectorType(.{ .len = max_abi_size, .child = .u8_type }); |
| 18331 | | const rhs_mask_mcv = try self.genTypedValue(Value.fromInterned(try pt.intern(.{ .aggregate = .{ |
| 18332 | | .ty = rhs_mask_ty.toIntern(), |
| 18333 | | .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] }, |
| 18334 | | } }))); |
| 18335 | | const rhs_mask_mem: Memory = .{ |
| 18336 | | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, rhs_mask_mcv.address()) }, |
| 18337 | | .mod = .{ .rm = .{ .size = Memory.Size.fromSize(@max(max_abi_size, 16)) } }, |
| 18338 | | }; |
| 18339 | | if (has_avx) try self.asmRegisterRegisterMemory( |
| 18340 | | .{ .vp_b, .shuf }, |
| 18341 | | rhs_temp_alias, |
| 18342 | | rhs_temp_alias, |
| 18343 | | rhs_mask_mem, |
| 18344 | | ) else try self.asmRegisterMemory( |
| 18345 | | .{ .p_b, .shuf }, |
| 18346 | | rhs_temp_alias, |
| 18347 | | rhs_mask_mem, |
| 18348 | | ); |
| 26819 | switch (mcv.*) { |
| 26820 | .register => |reg| lock.* = self.register_manager.lockReg(reg), |
| 26821 | else => {}, |
| 26822 | } |
| 26823 | } |
| 26824 | for (&order, &mcvs, &locks) |*mop_index, *mcv, *lock| { |
| 26825 | if (mop_index.* != 0) continue; |
| 26826 | mop_index.* = 1 + @as(u2, @intCast(unused.toggleFirstSet().?)); |
| 26827 | if (mop_index.* > 1 and mcv.isRegister()) continue; |
| 26828 | const reg = try self.copyToTmpRegister(ty, mcv.*); |
| 26829 | mcv.* = .{ .register = reg }; |
| 26830 | if (lock.*) |old_lock| self.register_manager.unlockReg(old_lock); |
| 26831 | lock.* = self.register_manager.lockRegAssumeUnused(reg); |
| 26832 | } |
| 18349 | 26833 | |
| 18350 | | if (has_avx) try self.asmRegisterRegisterRegister( |
| 18351 | | .{ switch (elem_ty.zigTypeTag(zcu)) { |
| 18352 | | else => break :result null, |
| 18353 | | .int => .vp_, |
| 18354 | | .float => switch (elem_ty.floatBits(self.target.*)) { |
| 18355 | | 32 => .v_ps, |
| 18356 | | 64 => .v_pd, |
| 18357 | | 16, 80, 128 => break :result null, |
| 26834 | const mir_tag = @as(?Mir.Inst.FixedTag, if (std.mem.eql(u2, &order, &.{ 1, 3, 2 }) or |
| 26835 | std.mem.eql(u2, &order, &.{ 3, 1, 2 })) |
| 26836 | switch (ty.zigTypeTag(zcu)) { |
| 26837 | .float => switch (ty.floatBits(self.target.*)) { |
| 26838 | 32 => .{ .v_ss, .fmadd132 }, |
| 26839 | 64 => .{ .v_sd, .fmadd132 }, |
| 26840 | 16, 80, 128 => null, |
| 26841 | else => unreachable, |
| 26842 | }, |
| 26843 | .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| 26844 | .float => switch (ty.childType(zcu).floatBits(self.target.*)) { |
| 26845 | 32 => switch (ty.vectorLen(zcu)) { |
| 26846 | 1 => .{ .v_ss, .fmadd132 }, |
| 26847 | 2...8 => .{ .v_ps, .fmadd132 }, |
| 26848 | else => null, |
| 26849 | }, |
| 26850 | 64 => switch (ty.vectorLen(zcu)) { |
| 26851 | 1 => .{ .v_sd, .fmadd132 }, |
| 26852 | 2...4 => .{ .v_pd, .fmadd132 }, |
| 26853 | else => null, |
| 26854 | }, |
| 26855 | 16, 80, 128 => null, |
| 26856 | else => unreachable, |
| 26857 | }, |
| 26858 | else => unreachable, |
| 26859 | }, |
| 26860 | else => unreachable, |
| 26861 | } |
| 26862 | else if (std.mem.eql(u2, &order, &.{ 2, 1, 3 }) or std.mem.eql(u2, &order, &.{ 1, 2, 3 })) |
| 26863 | switch (ty.zigTypeTag(zcu)) { |
| 26864 | .float => switch (ty.floatBits(self.target.*)) { |
| 26865 | 32 => .{ .v_ss, .fmadd213 }, |
| 26866 | 64 => .{ .v_sd, .fmadd213 }, |
| 26867 | 16, 80, 128 => null, |
| 26868 | else => unreachable, |
| 26869 | }, |
| 26870 | .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| 26871 | .float => switch (ty.childType(zcu).floatBits(self.target.*)) { |
| 26872 | 32 => switch (ty.vectorLen(zcu)) { |
| 26873 | 1 => .{ .v_ss, .fmadd213 }, |
| 26874 | 2...8 => .{ .v_ps, .fmadd213 }, |
| 26875 | else => null, |
| 26876 | }, |
| 26877 | 64 => switch (ty.vectorLen(zcu)) { |
| 26878 | 1 => .{ .v_sd, .fmadd213 }, |
| 26879 | 2...4 => .{ .v_pd, .fmadd213 }, |
| 26880 | else => null, |
| 26881 | }, |
| 26882 | 16, 80, 128 => null, |
| 18358 | 26883 | else => unreachable, |
| 18359 | 26884 | }, |
| 18360 | | }, .@"or" }, |
| 18361 | | lhs_temp_alias, |
| 18362 | | lhs_temp_alias, |
| 18363 | | rhs_temp_alias, |
| 18364 | | ) else try self.asmRegisterRegister( |
| 18365 | | .{ switch (elem_ty.zigTypeTag(zcu)) { |
| 18366 | | else => break :result null, |
| 18367 | | .int => .p_, |
| 18368 | | .float => switch (elem_ty.floatBits(self.target.*)) { |
| 18369 | | 32 => ._ps, |
| 18370 | | 64 => ._pd, |
| 18371 | | 16, 80, 128 => break :result null, |
| 26885 | else => unreachable, |
| 26886 | }, |
| 26887 | else => unreachable, |
| 26888 | } |
| 26889 | else if (std.mem.eql(u2, &order, &.{ 2, 3, 1 }) or std.mem.eql(u2, &order, &.{ 3, 2, 1 })) |
| 26890 | switch (ty.zigTypeTag(zcu)) { |
| 26891 | .float => switch (ty.floatBits(self.target.*)) { |
| 26892 | 32 => .{ .v_ss, .fmadd231 }, |
| 26893 | 64 => .{ .v_sd, .fmadd231 }, |
| 26894 | 16, 80, 128 => null, |
| 26895 | else => unreachable, |
| 26896 | }, |
| 26897 | .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| 26898 | .float => switch (ty.childType(zcu).floatBits(self.target.*)) { |
| 26899 | 32 => switch (ty.vectorLen(zcu)) { |
| 26900 | 1 => .{ .v_ss, .fmadd231 }, |
| 26901 | 2...8 => .{ .v_ps, .fmadd231 }, |
| 26902 | else => null, |
| 26903 | }, |
| 26904 | 64 => switch (ty.vectorLen(zcu)) { |
| 26905 | 1 => .{ .v_sd, .fmadd231 }, |
| 26906 | 2...4 => .{ .v_pd, .fmadd231 }, |
| 26907 | else => null, |
| 26908 | }, |
| 26909 | 16, 80, 128 => null, |
| 18372 | 26910 | else => unreachable, |
| 18373 | 26911 | }, |
| 18374 | | }, .@"or" }, |
| 18375 | | lhs_temp_alias, |
| 18376 | | rhs_temp_alias, |
| 18377 | | ); |
| 18378 | | break :result .{ .register = temp_regs[0] }; |
| 18379 | | } |
| 26912 | else => unreachable, |
| 26913 | }, |
| 26914 | else => unreachable, |
| 26915 | } |
| 26916 | else |
| 26917 | unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{ty.fmt(pt)}); |
| 18380 | 26918 | |
| 18381 | | break :result null; |
| 18382 | | }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{ |
| 18383 | | lhs_ty.fmt(pt), rhs_ty.fmt(pt), dst_ty.fmt(pt), |
| 18384 | | Value.fromInterned(extra.mask).fmtValue(pt), |
| 18385 | | }); |
| 18386 | | return self.finishAir(inst, result, .{ extra.a, extra.b, .none }); |
| 26919 | var mops: [3]MCValue = undefined; |
| 26920 | for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv; |
| 26921 | |
| 26922 | const abi_size: u32 = @intCast(ty.abiSize(zcu)); |
| 26923 | const mop1_reg = registerAlias(mops[0].getReg().?, abi_size); |
| 26924 | const mop2_reg = registerAlias(mops[1].getReg().?, abi_size); |
| 26925 | if (mops[2].isRegister()) try self.asmRegisterRegisterRegister( |
| 26926 | mir_tag, |
| 26927 | mop1_reg, |
| 26928 | mop2_reg, |
| 26929 | registerAlias(mops[2].getReg().?, abi_size), |
| 26930 | ) else try self.asmRegisterRegisterMemory( |
| 26931 | mir_tag, |
| 26932 | mop1_reg, |
| 26933 | mop2_reg, |
| 26934 | try mops[2].mem(self, .{ .size = .fromSize(abi_size) }), |
| 26935 | ); |
| 26936 | break :result mops[0]; |
| 26937 | }; |
| 26938 | return self.finishAir(inst, result, ops); |
| 18387 | 26939 | } |
| 18388 | 26940 | |
| 18389 | | fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| 26941 | fn airVaStart(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 18390 | 26942 | const pt = self.pt; |
| 18391 | 26943 | const zcu = pt.zcu; |
| 18392 | | const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce; |
| 26944 | const va_list_ty = self.air.instructions.items(.data)[@intFromEnum(inst)].ty; |
| 26945 | const ptr_anyopaque_ty = try pt.singleMutPtrType(.anyopaque); |
| 18393 | 26946 | |
| 18394 | | const result: MCValue = result: { |
| 18395 | | const operand_ty = self.typeOf(reduce.operand); |
| 18396 | | if (operand_ty.isVector(zcu) and operand_ty.childType(zcu).toIntern() == .bool_type) { |
| 26947 | const result: MCValue = switch (self.fn_type.fnCallingConvention(zcu)) { |
| 26948 | .x86_64_sysv => result: { |
| 26949 | const info = self.va_info.sysv; |
| 26950 | const dst_fi = try self.allocFrameIndex(.initSpill(va_list_ty, zcu)); |
| 26951 | var field_off: u31 = 0; |
| 26952 | // gp_offset: c_uint, |
| 26953 | try self.genSetMem( |
| 26954 | .{ .frame = dst_fi }, |
| 26955 | field_off, |
| 26956 | .c_uint, |
| 26957 | .{ .immediate = info.gp_count * 8 }, |
| 26958 | .{}, |
| 26959 | ); |
| 26960 | field_off += @intCast(Type.c_uint.abiSize(zcu)); |
| 26961 | // fp_offset: c_uint, |
| 26962 | try self.genSetMem( |
| 26963 | .{ .frame = dst_fi }, |
| 26964 | field_off, |
| 26965 | .c_uint, |
| 26966 | .{ .immediate = abi.SysV.c_abi_int_param_regs.len * 8 + info.fp_count * 16 }, |
| 26967 | .{}, |
| 26968 | ); |
| 26969 | field_off += @intCast(Type.c_uint.abiSize(zcu)); |
| 26970 | // overflow_arg_area: *anyopaque, |
| 26971 | try self.genSetMem( |
| 26972 | .{ .frame = dst_fi }, |
| 26973 | field_off, |
| 26974 | ptr_anyopaque_ty, |
| 26975 | .{ .lea_frame = info.overflow_arg_area }, |
| 26976 | .{}, |
| 26977 | ); |
| 26978 | field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu)); |
| 26979 | // reg_save_area: *anyopaque, |
| 26980 | try self.genSetMem( |
| 26981 | .{ .frame = dst_fi }, |
| 26982 | field_off, |
| 26983 | ptr_anyopaque_ty, |
| 26984 | .{ .lea_frame = info.reg_save_area }, |
| 26985 | .{}, |
| 26986 | ); |
| 26987 | field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu)); |
| 26988 | break :result .{ .load_frame = .{ .index = dst_fi } }; |
| 26989 | }, |
| 26990 | .x86_64_win => return self.fail("TODO implement c_va_start for Win64", .{}), |
| 26991 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 26992 | }; |
| 26993 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 26994 | } |
| 26995 | |
| 26996 | fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26997 | const pt = self.pt; |
| 26998 | const zcu = pt.zcu; |
| 26999 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 27000 | const ty = self.typeOfIndex(inst); |
| 27001 | const promote_ty = self.promoteVarArg(ty); |
| 27002 | const ptr_anyopaque_ty = try pt.singleMutPtrType(.anyopaque); |
| 27003 | const unused = self.liveness.isUnused(inst); |
| 27004 | |
| 27005 | const result: MCValue = switch (self.fn_type.fnCallingConvention(zcu)) { |
| 27006 | .x86_64_sysv => result: { |
| 18397 | 27007 | try self.spillEflagsIfOccupied(); |
| 18398 | 27008 | |
| 18399 | | const operand_mcv = try self.resolveInst(reduce.operand); |
| 18400 | | const mask_len = (math.cast(u6, operand_ty.vectorLen(zcu)) orelse |
| 18401 | | return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)})); |
| 18402 | | const mask = (@as(u64, 1) << mask_len) - 1; |
| 18403 | | const abi_size: u32 = @intCast(operand_ty.abiSize(zcu)); |
| 18404 | | switch (reduce.operation) { |
| 18405 | | .Or => { |
| 18406 | | if (operand_mcv.isMemory()) try self.asmMemoryImmediate( |
| 18407 | | .{ ._, .@"test" }, |
| 18408 | | try operand_mcv.mem(self, Memory.Size.fromSize(abi_size)), |
| 18409 | | Immediate.u(mask), |
| 18410 | | ) else { |
| 18411 | | const operand_reg = registerAlias(if (operand_mcv.isRegister()) |
| 18412 | | operand_mcv.getReg().? |
| 18413 | | else |
| 18414 | | try self.copyToTmpRegister(operand_ty, operand_mcv), abi_size); |
| 18415 | | if (mask_len < abi_size * 8) try self.asmRegisterImmediate( |
| 18416 | | .{ ._, .@"test" }, |
| 18417 | | operand_reg, |
| 18418 | | Immediate.u(mask), |
| 18419 | | ) else try self.asmRegisterRegister( |
| 18420 | | .{ ._, .@"test" }, |
| 18421 | | operand_reg, |
| 18422 | | operand_reg, |
| 18423 | | ); |
| 18424 | | } |
| 18425 | | break :result .{ .eflags = .nz }; |
| 27009 | const tmp_regs = |
| 27010 | try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp); |
| 27011 | const offset_reg = tmp_regs[0].to32(); |
| 27012 | const addr_reg = tmp_regs[1].to64(); |
| 27013 | const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs); |
| 27014 | defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); |
| 27015 | |
| 27016 | const promote_mcv = try self.allocTempRegOrMem(promote_ty, true); |
| 27017 | const promote_lock = switch (promote_mcv) { |
| 27018 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 27019 | else => null, |
| 27020 | }; |
| 27021 | defer if (promote_lock) |lock| self.register_manager.unlockReg(lock); |
| 27022 | |
| 27023 | const ptr_arg_list_reg = |
| 27024 | try self.copyToTmpRegister(self.typeOf(ty_op.operand), .{ .air_ref = ty_op.operand }); |
| 27025 | const ptr_arg_list_lock = self.register_manager.lockRegAssumeUnused(ptr_arg_list_reg); |
| 27026 | defer self.register_manager.unlockReg(ptr_arg_list_lock); |
| 27027 | |
| 27028 | const gp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 0 } }; |
| 27029 | const fp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 4 } }; |
| 27030 | const overflow_arg_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 8 } }; |
| 27031 | const reg_save_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 16 } }; |
| 27032 | |
| 27033 | const classes = std.mem.sliceTo(&abi.classifySystemV(promote_ty, zcu, self.target.*, .arg), .none); |
| 27034 | switch (classes[0]) { |
| 27035 | .integer => { |
| 27036 | assert(classes.len == 1); |
| 27037 | |
| 27038 | try self.genSetReg(offset_reg, .c_uint, gp_offset, .{}); |
| 27039 | try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, .u( |
| 27040 | abi.SysV.c_abi_int_param_regs.len * 8, |
| 27041 | )); |
| 27042 | const mem_reloc = try self.asmJccReloc(.ae, undefined); |
| 27043 | |
| 27044 | try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area, .{}); |
| 27045 | if (!unused) try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, .{ |
| 27046 | .base = .{ .reg = addr_reg }, |
| 27047 | .mod = .{ .rm = .{ |
| 27048 | .size = .qword, |
| 27049 | .index = offset_reg.to64(), |
| 27050 | } }, |
| 27051 | }); |
| 27052 | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, .{ |
| 27053 | .base = .{ .reg = offset_reg.to64() }, |
| 27054 | .mod = .{ .rm = .{ |
| 27055 | .size = .qword, |
| 27056 | .disp = 8, |
| 27057 | } }, |
| 27058 | }); |
| 27059 | try self.genCopy(.c_uint, gp_offset, .{ .register = offset_reg }, .{}); |
| 27060 | const done_reloc = try self.asmJmpReloc(undefined); |
| 27061 | |
| 27062 | self.performReloc(mem_reloc); |
| 27063 | try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area, .{}); |
| 27064 | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), .{ |
| 27065 | .base = .{ .reg = addr_reg }, |
| 27066 | .mod = .{ .rm = .{ |
| 27067 | .size = .qword, |
| 27068 | .disp = @intCast(@max(promote_ty.abiSize(zcu), 8)), |
| 27069 | } }, |
| 27070 | }); |
| 27071 | try self.genCopy( |
| 27072 | ptr_anyopaque_ty, |
| 27073 | overflow_arg_area, |
| 27074 | .{ .register = offset_reg.to64() }, |
| 27075 | .{}, |
| 27076 | ); |
| 27077 | |
| 27078 | self.performReloc(done_reloc); |
| 27079 | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ |
| 27080 | .indirect = .{ .reg = addr_reg }, |
| 27081 | }, .{}); |
| 18426 | 27082 | }, |
| 18427 | | .And => { |
| 18428 | | const tmp_reg = try self.copyToTmpRegister(operand_ty, operand_mcv); |
| 18429 | | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 18430 | | defer self.register_manager.unlockReg(tmp_lock); |
| 27083 | .sse => { |
| 27084 | assert(classes.len == 1); |
| 27085 | |
| 27086 | try self.genSetReg(offset_reg, .c_uint, fp_offset, .{}); |
| 27087 | try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, .u( |
| 27088 | abi.SysV.c_abi_int_param_regs.len * 8 + abi.SysV.c_abi_sse_param_regs.len * 16, |
| 27089 | )); |
| 27090 | const mem_reloc = try self.asmJccReloc(.ae, undefined); |
| 27091 | |
| 27092 | try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area, .{}); |
| 27093 | if (!unused) try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, .{ |
| 27094 | .base = .{ .reg = addr_reg }, |
| 27095 | .mod = .{ .rm = .{ |
| 27096 | .size = .qword, |
| 27097 | .index = offset_reg.to64(), |
| 27098 | } }, |
| 27099 | }); |
| 27100 | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, .{ |
| 27101 | .base = .{ .reg = offset_reg.to64() }, |
| 27102 | .mod = .{ .rm = .{ |
| 27103 | .size = .qword, |
| 27104 | .disp = 16, |
| 27105 | } }, |
| 27106 | }); |
| 27107 | try self.genCopy(.c_uint, fp_offset, .{ .register = offset_reg }, .{}); |
| 27108 | const done_reloc = try self.asmJmpReloc(undefined); |
| 18431 | 27109 | |
| 18432 | | try self.asmRegister(.{ ._, .not }, tmp_reg); |
| 18433 | | if (mask_len < abi_size * 8) |
| 18434 | | try self.asmRegisterImmediate(.{ ._, .@"test" }, tmp_reg, Immediate.u(mask)) |
| 18435 | | else |
| 18436 | | try self.asmRegisterRegister(.{ ._, .@"test" }, tmp_reg, tmp_reg); |
| 18437 | | break :result .{ .eflags = .z }; |
| 27110 | self.performReloc(mem_reloc); |
| 27111 | try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area, .{}); |
| 27112 | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), .{ |
| 27113 | .base = .{ .reg = addr_reg }, |
| 27114 | .mod = .{ .rm = .{ |
| 27115 | .size = .qword, |
| 27116 | .disp = @intCast(@max(promote_ty.abiSize(zcu), 8)), |
| 27117 | } }, |
| 27118 | }); |
| 27119 | try self.genCopy( |
| 27120 | ptr_anyopaque_ty, |
| 27121 | overflow_arg_area, |
| 27122 | .{ .register = offset_reg.to64() }, |
| 27123 | .{}, |
| 27124 | ); |
| 27125 | |
| 27126 | self.performReloc(done_reloc); |
| 27127 | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ |
| 27128 | .indirect = .{ .reg = addr_reg }, |
| 27129 | }, .{}); |
| 18438 | 27130 | }, |
| 18439 | | else => return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}), |
| 27131 | .memory => { |
| 27132 | assert(classes.len == 1); |
| 27133 | unreachable; |
| 27134 | }, |
| 27135 | else => return self.fail("TODO implement c_va_arg for {} on SysV", .{promote_ty.fmt(pt)}), |
| 18440 | 27136 | } |
| 18441 | | } |
| 18442 | | return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}); |
| 18443 | | }; |
| 18444 | | return self.finishAir(inst, result, .{ reduce.operand, .none, .none }); |
| 18445 | | } |
| 18446 | 27137 | |
| 18447 | | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 18448 | | const pt = self.pt; |
| 18449 | | const zcu = pt.zcu; |
| 18450 | | const result_ty = self.typeOfIndex(inst); |
| 18451 | | const len: usize = @intCast(result_ty.arrayLen(zcu)); |
| 18452 | | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 18453 | | const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]); |
| 18454 | | const result: MCValue = result: { |
| 18455 | | switch (result_ty.zigTypeTag(zcu)) { |
| 18456 | | .@"struct" => { |
| 18457 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(result_ty, zcu)); |
| 18458 | | if (result_ty.containerLayout(zcu) == .@"packed") { |
| 18459 | | const struct_obj = zcu.typeToStruct(result_ty).?; |
| 18460 | | try self.genInlineMemset( |
| 18461 | | .{ .lea_frame = .{ .index = frame_index } }, |
| 18462 | | .{ .immediate = 0 }, |
| 18463 | | .{ .immediate = result_ty.abiSize(zcu) }, |
| 18464 | | .{}, |
| 18465 | | ); |
| 18466 | | for (elements, 0..) |elem, elem_i_usize| { |
| 18467 | | const elem_i: u32 = @intCast(elem_i_usize); |
| 18468 | | if ((try result_ty.structFieldValueComptime(pt, elem_i)) != null) continue; |
| 27138 | if (unused) break :result .unreach; |
| 27139 | if (ty.toIntern() == promote_ty.toIntern()) break :result promote_mcv; |
| 18469 | 27140 | |
| 18470 | | const elem_ty = result_ty.fieldType(elem_i, zcu); |
| 18471 | | const elem_bit_size: u32 = @intCast(elem_ty.bitSize(zcu)); |
| 18472 | | if (elem_bit_size > 64) { |
| 18473 | | return self.fail( |
| 18474 | | "TODO airAggregateInit implement packed structs with large fields", |
| 18475 | | .{}, |
| 18476 | | ); |
| 18477 | | } |
| 18478 | | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 18479 | | const elem_abi_bits = elem_abi_size * 8; |
| 18480 | | const elem_off = pt.structPackedFieldBitOffset(struct_obj, elem_i); |
| 18481 | | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 18482 | | const elem_bit_off = elem_off % elem_abi_bits; |
| 18483 | | const elem_mcv = try self.resolveInst(elem); |
| 18484 | | const mat_elem_mcv = switch (elem_mcv) { |
| 18485 | | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, |
| 18486 | | else => elem_mcv, |
| 18487 | | }; |
| 18488 | | const elem_lock = switch (mat_elem_mcv) { |
| 18489 | | .register => |reg| self.register_manager.lockReg(reg), |
| 18490 | | .immediate => |imm| lock: { |
| 18491 | | if (imm == 0) continue; |
| 18492 | | break :lock null; |
| 18493 | | }, |
| 18494 | | else => null, |
| 18495 | | }; |
| 18496 | | defer if (elem_lock) |lock| self.register_manager.unlockReg(lock); |
| 27141 | if (!promote_ty.isRuntimeFloat()) { |
| 27142 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 27143 | try self.genCopy(ty, dst_mcv, promote_mcv, .{}); |
| 27144 | break :result dst_mcv; |
| 27145 | } |
| 18497 | 27146 | |
| 18498 | | const elem_extra_bits = self.regExtraBits(elem_ty); |
| 18499 | | { |
| 18500 | | const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv); |
| 18501 | | const temp_alias = registerAlias(temp_reg, elem_abi_size); |
| 18502 | | const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg); |
| 18503 | | defer self.register_manager.unlockReg(temp_lock); |
| 27147 | assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type); |
| 27148 | const dst_mcv = if (promote_mcv.isRegister()) |
| 27149 | promote_mcv |
| 27150 | else |
| 27151 | try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv); |
| 27152 | const dst_reg = dst_mcv.getReg().?.to128(); |
| 27153 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 27154 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 18504 | 27155 | |
| 18505 | | if (elem_bit_off < elem_extra_bits) { |
| 18506 | | try self.truncateRegister(elem_ty, temp_alias); |
| 18507 | | } |
| 18508 | | if (elem_bit_off > 0) try self.genShiftBinOpMir( |
| 18509 | | .{ ._l, .sh }, |
| 18510 | | elem_ty, |
| 18511 | | .{ .register = temp_alias }, |
| 18512 | | Type.u8, |
| 18513 | | .{ .immediate = elem_bit_off }, |
| 18514 | | ); |
| 18515 | | try self.genBinOpMir( |
| 18516 | | .{ ._, .@"or" }, |
| 18517 | | elem_ty, |
| 18518 | | .{ .load_frame = .{ .index = frame_index, .off = elem_byte_off } }, |
| 18519 | | .{ .register = temp_alias }, |
| 18520 | | ); |
| 18521 | | } |
| 18522 | | if (elem_bit_off > elem_extra_bits) { |
| 18523 | | const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv); |
| 18524 | | const temp_alias = registerAlias(temp_reg, elem_abi_size); |
| 18525 | | const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg); |
| 18526 | | defer self.register_manager.unlockReg(temp_lock); |
| 27156 | if (self.hasFeature(.avx)) if (promote_mcv.isBase()) try self.asmRegisterRegisterMemory( |
| 27157 | .{ .v_ss, .cvtsd2 }, |
| 27158 | dst_reg, |
| 27159 | dst_reg, |
| 27160 | try promote_mcv.mem(self, .{ .size = .qword }), |
| 27161 | ) else try self.asmRegisterRegisterRegister( |
| 27162 | .{ .v_ss, .cvtsd2 }, |
| 27163 | dst_reg, |
| 27164 | dst_reg, |
| 27165 | (if (promote_mcv.isRegister()) |
| 27166 | promote_mcv.getReg().? |
| 27167 | else |
| 27168 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| 27169 | ) else if (promote_mcv.isBase()) try self.asmRegisterMemory( |
| 27170 | .{ ._ss, .cvtsd2 }, |
| 27171 | dst_reg, |
| 27172 | try promote_mcv.mem(self, .{ .size = .qword }), |
| 27173 | ) else try self.asmRegisterRegister( |
| 27174 | .{ ._ss, .cvtsd2 }, |
| 27175 | dst_reg, |
| 27176 | (if (promote_mcv.isRegister()) |
| 27177 | promote_mcv.getReg().? |
| 27178 | else |
| 27179 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| 27180 | ); |
| 27181 | break :result promote_mcv; |
| 27182 | }, |
| 27183 | .x86_64_win => return self.fail("TODO implement c_va_arg for Win64", .{}), |
| 27184 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 27185 | }; |
| 27186 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 27187 | } |
| 18527 | 27188 | |
| 18528 | | if (elem_extra_bits > 0) { |
| 18529 | | try self.truncateRegister(elem_ty, temp_alias); |
| 18530 | | } |
| 18531 | | try self.genShiftBinOpMir( |
| 18532 | | .{ ._r, .sh }, |
| 18533 | | elem_ty, |
| 18534 | | .{ .register = temp_reg }, |
| 18535 | | Type.u8, |
| 18536 | | .{ .immediate = elem_abi_bits - elem_bit_off }, |
| 18537 | | ); |
| 18538 | | try self.genBinOpMir( |
| 18539 | | .{ ._, .@"or" }, |
| 18540 | | elem_ty, |
| 18541 | | .{ .load_frame = .{ |
| 18542 | | .index = frame_index, |
| 18543 | | .off = elem_byte_off + @as(i32, @intCast(elem_abi_size)), |
| 18544 | | } }, |
| 18545 | | .{ .register = temp_alias }, |
| 18546 | | ); |
| 18547 | | } |
| 18548 | | } |
| 18549 | | } else for (elements, 0..) |elem, elem_i| { |
| 18550 | | if ((try result_ty.structFieldValueComptime(pt, elem_i)) != null) continue; |
| 27189 | fn airVaCopy(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 27190 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 27191 | const ptr_va_list_ty = self.typeOf(ty_op.operand); |
| 18551 | 27192 | |
| 18552 | | const elem_ty = result_ty.fieldType(elem_i, zcu); |
| 18553 | | const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu)); |
| 18554 | | const elem_mcv = try self.resolveInst(elem); |
| 18555 | | const mat_elem_mcv = switch (elem_mcv) { |
| 18556 | | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, |
| 18557 | | else => elem_mcv, |
| 18558 | | }; |
| 18559 | | try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv, .{}); |
| 18560 | | } |
| 18561 | | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 18562 | | }, |
| 18563 | | .array, .vector => { |
| 18564 | | const elem_ty = result_ty.childType(zcu); |
| 18565 | | if (result_ty.isVector(zcu) and elem_ty.toIntern() == .bool_type) { |
| 18566 | | const result_size: u32 = @intCast(result_ty.abiSize(zcu)); |
| 18567 | | const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp); |
| 18568 | | try self.asmRegisterRegister( |
| 18569 | | .{ ._, .xor }, |
| 18570 | | registerAlias(dst_reg, @min(result_size, 4)), |
| 18571 | | registerAlias(dst_reg, @min(result_size, 4)), |
| 18572 | | ); |
| 27193 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 27194 | try self.load(dst_mcv, ptr_va_list_ty, .{ .air_ref = ty_op.operand }); |
| 27195 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 27196 | } |
| 18573 | 27197 | |
| 18574 | | for (elements, 0..) |elem, elem_i| { |
| 18575 | | const elem_reg = try self.copyToTmpRegister(elem_ty, .{ .air_ref = elem }); |
| 18576 | | const elem_lock = self.register_manager.lockRegAssumeUnused(elem_reg); |
| 18577 | | defer self.register_manager.unlockReg(elem_lock); |
| 27198 | fn airVaEnd(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 27199 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 27200 | return self.finishAir(inst, .unreach, .{ un_op, .none, .none }); |
| 27201 | } |
| 18578 | 27202 | |
| 18579 | | try self.asmRegisterImmediate( |
| 18580 | | .{ ._, .@"and" }, |
| 18581 | | registerAlias(elem_reg, @min(result_size, 4)), |
| 18582 | | Immediate.u(1), |
| 18583 | | ); |
| 18584 | | if (elem_i > 0) try self.asmRegisterImmediate( |
| 18585 | | .{ ._l, .sh }, |
| 18586 | | registerAlias(elem_reg, result_size), |
| 18587 | | Immediate.u(@intCast(elem_i)), |
| 18588 | | ); |
| 18589 | | try self.asmRegisterRegister( |
| 18590 | | .{ ._, .@"or" }, |
| 18591 | | registerAlias(dst_reg, result_size), |
| 18592 | | registerAlias(elem_reg, result_size), |
| 18593 | | ); |
| 18594 | | } |
| 18595 | | break :result .{ .register = dst_reg }; |
| 18596 | | } else { |
| 18597 | | const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(result_ty, zcu)); |
| 18598 | | const elem_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 27203 | fn resolveInst(self: *CodeGen, ref: Air.Inst.Ref) InnerError!MCValue { |
| 27204 | const zcu = self.pt.zcu; |
| 27205 | const ty = self.typeOf(ref); |
| 18599 | 27206 | |
| 18600 | | for (elements, 0..) |elem, elem_i| { |
| 18601 | | const elem_mcv = try self.resolveInst(elem); |
| 18602 | | const mat_elem_mcv = switch (elem_mcv) { |
| 18603 | | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, |
| 18604 | | else => elem_mcv, |
| 18605 | | }; |
| 18606 | | const elem_off: i32 = @intCast(elem_size * elem_i); |
| 18607 | | try self.genSetMem( |
| 18608 | | .{ .frame = frame_index }, |
| 18609 | | elem_off, |
| 18610 | | elem_ty, |
| 18611 | | mat_elem_mcv, |
| 27207 | // If the type has no codegen bits, no need to store it. |
| 27208 | if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return .none; |
| 27209 | |
| 27210 | const mcv = if (ref.toIndex()) |inst| mcv: { |
| 27211 | break :mcv self.inst_tracking.getPtr(inst).?.short; |
| 27212 | } else mcv: { |
| 27213 | const ip_index = ref.toInterned().?; |
| 27214 | const gop = try self.const_tracking.getOrPut(self.gpa, ip_index); |
| 27215 | if (!gop.found_existing) gop.value_ptr.* = .init(init: { |
| 27216 | const const_mcv = try self.genTypedValue(.fromInterned(ip_index)); |
| 27217 | switch (const_mcv) { |
| 27218 | .lea_tlv => |tlv_sym| switch (self.bin_file.tag) { |
| 27219 | .elf, .macho => { |
| 27220 | if (self.mod.pic) { |
| 27221 | try self.spillRegisters(&.{ .rdi, .rax }); |
| 27222 | } else { |
| 27223 | try self.spillRegisters(&.{.rax}); |
| 27224 | } |
| 27225 | const frame_index = try self.allocFrameIndex(.init(.{ |
| 27226 | .size = 8, |
| 27227 | .alignment = .@"8", |
| 27228 | })); |
| 27229 | try self.genSetMem( |
| 27230 | .{ .frame = frame_index }, |
| 27231 | 0, |
| 27232 | .usize, |
| 27233 | .{ .lea_symbol = .{ .sym_index = tlv_sym } }, |
| 18612 | 27234 | .{}, |
| 18613 | 27235 | ); |
| 18614 | | } |
| 18615 | | if (result_ty.sentinel(zcu)) |sentinel| try self.genSetMem( |
| 18616 | | .{ .frame = frame_index }, |
| 18617 | | @intCast(elem_size * elements.len), |
| 18618 | | elem_ty, |
| 18619 | | try self.genTypedValue(sentinel), |
| 18620 | | .{}, |
| 18621 | | ); |
| 18622 | | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 18623 | | } |
| 18624 | | }, |
| 18625 | | else => unreachable, |
| 18626 | | } |
| 27236 | break :init .{ .load_frame = .{ .index = frame_index } }; |
| 27237 | }, |
| 27238 | else => break :init const_mcv, |
| 27239 | }, |
| 27240 | else => break :init const_mcv, |
| 27241 | } |
| 27242 | }); |
| 27243 | break :mcv gop.value_ptr.short; |
| 18627 | 27244 | }; |
| 18628 | 27245 | |
| 18629 | | if (elements.len <= Liveness.bpi - 1) { |
| 18630 | | var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); |
| 18631 | | @memcpy(buf[0..elements.len], elements); |
| 18632 | | return self.finishAir(inst, result, buf); |
| 27246 | switch (mcv) { |
| 27247 | .none, .unreach, .dead => unreachable, |
| 27248 | else => return mcv, |
| 18633 | 27249 | } |
| 18634 | | var bt = self.liveness.iterateBigTomb(inst); |
| 18635 | | for (elements) |elem| try self.feed(&bt, elem); |
| 18636 | | return self.finishAirResult(inst, result); |
| 18637 | 27250 | } |
| 18638 | 27251 | |
| 18639 | | fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 18640 | | const pt = self.pt; |
| 18641 | | const zcu = pt.zcu; |
| 18642 | | const ip = &zcu.intern_pool; |
| 18643 | | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 18644 | | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 18645 | | const result: MCValue = result: { |
| 18646 | | const union_ty = self.typeOfIndex(inst); |
| 18647 | | const layout = union_ty.unionGetLayout(zcu); |
| 18648 | | |
| 18649 | | const src_ty = self.typeOf(extra.init); |
| 18650 | | const src_mcv = try self.resolveInst(extra.init); |
| 18651 | | if (layout.tag_size == 0) { |
| 18652 | | if (layout.abi_size <= src_ty.abiSize(zcu) and |
| 18653 | | self.reuseOperand(inst, extra.init, 0, src_mcv)) break :result src_mcv; |
| 18654 | | |
| 18655 | | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 18656 | | try self.genCopy(src_ty, dst_mcv, src_mcv, .{}); |
| 18657 | | break :result dst_mcv; |
| 18658 | | } |
| 18659 | | |
| 18660 | | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 18661 | | |
| 18662 | | const union_obj = zcu.typeToUnion(union_ty).?; |
| 18663 | | const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index]; |
| 18664 | | const tag_ty = Type.fromInterned(union_obj.enum_tag_ty); |
| 18665 | | const field_index = tag_ty.enumFieldIndex(field_name, zcu).?; |
| 18666 | | const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index); |
| 18667 | | const tag_int_val = try tag_val.intFromEnum(tag_ty, pt); |
| 18668 | | const tag_int = tag_int_val.toUnsignedInt(zcu); |
| 18669 | | const tag_off: i32 = @intCast(layout.tagOffset()); |
| 18670 | | try self.genCopy( |
| 18671 | | tag_ty, |
| 18672 | | dst_mcv.address().offset(tag_off).deref(), |
| 18673 | | .{ .immediate = tag_int }, |
| 18674 | | .{}, |
| 18675 | | ); |
| 27252 | fn getResolvedInstValue(self: *CodeGen, inst: Air.Inst.Index) *InstTracking { |
| 27253 | const tracking = self.inst_tracking.getPtr(inst).?; |
| 27254 | return switch (tracking.short) { |
| 27255 | .none, .unreach, .dead => unreachable, |
| 27256 | else => tracking, |
| 27257 | }; |
| 27258 | } |
| 18676 | 27259 | |
| 18677 | | const pl_off: i32 = @intCast(layout.payloadOffset()); |
| 18678 | | try self.genCopy(src_ty, dst_mcv.address().offset(pl_off).deref(), src_mcv, .{}); |
| 27260 | /// If the MCValue is an immediate, and it does not fit within this type, |
| 27261 | /// we put it in a register. |
| 27262 | /// A potential opportunity for future optimization here would be keeping track |
| 27263 | /// of the fact that the instruction is available both as an immediate |
| 27264 | /// and as a register. |
| 27265 | fn limitImmediateType(self: *CodeGen, operand: Air.Inst.Ref, comptime T: type) !MCValue { |
| 27266 | const mcv = try self.resolveInst(operand); |
| 27267 | const ti = @typeInfo(T).int; |
| 27268 | switch (mcv) { |
| 27269 | .immediate => |imm| { |
| 27270 | // This immediate is unsigned. |
| 27271 | const U = std.meta.Int(.unsigned, ti.bits - @intFromBool(ti.signedness == .signed)); |
| 27272 | if (imm >= std.math.maxInt(U)) { |
| 27273 | return MCValue{ .register = try self.copyToTmpRegister(.usize, mcv) }; |
| 27274 | } |
| 27275 | }, |
| 27276 | else => {}, |
| 27277 | } |
| 27278 | return mcv; |
| 27279 | } |
| 18679 | 27280 | |
| 18680 | | break :result dst_mcv; |
| 27281 | fn genTypedValue(self: *CodeGen, val: Value) InnerError!MCValue { |
| 27282 | const pt = self.pt; |
| 27283 | return switch (try codegen.genTypedValue(self.bin_file, pt, self.src_loc, val, self.target.*)) { |
| 27284 | .mcv => |mcv| switch (mcv) { |
| 27285 | .none => .none, |
| 27286 | .undef => .undef, |
| 27287 | .immediate => |imm| .{ .immediate = imm }, |
| 27288 | .memory => |addr| .{ .memory = addr }, |
| 27289 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym_index = sym_index } }, |
| 27290 | .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index } }, |
| 27291 | .load_direct => |sym_index| .{ .load_direct = sym_index }, |
| 27292 | .lea_direct => |sym_index| .{ .lea_direct = sym_index }, |
| 27293 | .load_got => |sym_index| .{ .lea_got = sym_index }, |
| 27294 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, |
| 27295 | }, |
| 27296 | .fail => |msg| return self.failMsg(msg), |
| 18681 | 27297 | }; |
| 18682 | | return self.finishAir(inst, result, .{ extra.init, .none, .none }); |
| 18683 | 27298 | } |
| 18684 | 27299 | |
| 18685 | | fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { |
| 18686 | | const prefetch = self.air.instructions.items(.data)[@intFromEnum(inst)].prefetch; |
| 18687 | | return self.finishAir(inst, .unreach, .{ prefetch.ptr, .none, .none }); |
| 18688 | | } |
| 27300 | const CallMCValues = struct { |
| 27301 | args: []MCValue, |
| 27302 | return_value: InstTracking, |
| 27303 | stack_byte_count: u31, |
| 27304 | stack_align: InternPool.Alignment, |
| 27305 | gp_count: u32, |
| 27306 | fp_count: u32, |
| 27307 | |
| 27308 | fn deinit(self: *CallMCValues, func: *CodeGen) void { |
| 27309 | func.gpa.free(self.args); |
| 27310 | self.* = undefined; |
| 27311 | } |
| 27312 | }; |
| 18689 | 27313 | |
| 18690 | | fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 27314 | /// Caller must call `CallMCValues.deinit`. |
| 27315 | fn resolveCallingConventionValues( |
| 27316 | self: *CodeGen, |
| 27317 | fn_info: InternPool.Key.FuncType, |
| 27318 | var_args: []const Type, |
| 27319 | stack_frame_base: FrameIndex, |
| 27320 | ) !CallMCValues { |
| 18691 | 27321 | const pt = self.pt; |
| 18692 | 27322 | const zcu = pt.zcu; |
| 18693 | | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 18694 | | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 18695 | | const ty = self.typeOfIndex(inst); |
| 27323 | const ip = &zcu.intern_pool; |
| 27324 | const cc = fn_info.cc; |
| 27325 | const param_types = try self.gpa.alloc(Type, fn_info.param_types.len + var_args.len); |
| 27326 | defer self.gpa.free(param_types); |
| 18696 | 27327 | |
| 18697 | | const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand }; |
| 18698 | | const result = result: { |
| 18699 | | if (switch (ty.scalarType(zcu).floatBits(self.target.*)) { |
| 18700 | | 16, 80, 128 => true, |
| 18701 | | 32, 64 => !self.hasFeature(.fma), |
| 18702 | | else => unreachable, |
| 18703 | | }) { |
| 18704 | | if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement airMulAdd for {}", .{ |
| 18705 | | ty.fmt(pt), |
| 18706 | | }); |
| 27328 | for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| |
| 27329 | dest.* = .fromInterned(src); |
| 27330 | for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| |
| 27331 | param_ty.* = self.promoteVarArg(arg_ty); |
| 18707 | 27332 | |
| 18708 | | var callee_buf: ["__fma?".len]u8 = undefined; |
| 18709 | | break :result try self.genCall(.{ .lib = .{ |
| 18710 | | .return_type = ty.toIntern(), |
| 18711 | | .param_types = &.{ ty.toIntern(), ty.toIntern(), ty.toIntern() }, |
| 18712 | | .callee = std.fmt.bufPrint(&callee_buf, "{s}fma{s}", .{ |
| 18713 | | floatLibcAbiPrefix(ty), |
| 18714 | | floatLibcAbiSuffix(ty), |
| 18715 | | }) catch unreachable, |
| 18716 | | } }, &.{ ty, ty, ty }, &.{ |
| 18717 | | .{ .air_ref = extra.lhs }, .{ .air_ref = extra.rhs }, .{ .air_ref = pl_op.operand }, |
| 18718 | | }); |
| 18719 | | } |
| 27333 | var result: CallMCValues = .{ |
| 27334 | .args = try self.gpa.alloc(MCValue, param_types.len), |
| 27335 | // These undefined values must be populated before returning from this function. |
| 27336 | .return_value = undefined, |
| 27337 | .stack_byte_count = 0, |
| 27338 | .stack_align = undefined, |
| 27339 | .gp_count = 0, |
| 27340 | .fp_count = 0, |
| 27341 | }; |
| 27342 | errdefer self.gpa.free(result.args); |
| 18720 | 27343 | |
| 18721 | | var mcvs: [3]MCValue = undefined; |
| 18722 | | var locks = [1]?RegisterManager.RegisterLock{null} ** 3; |
| 18723 | | defer for (locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 18724 | | var order = [1]u2{0} ** 3; |
| 18725 | | var unused = std.StaticBitSet(3).initFull(); |
| 18726 | | for (ops, &mcvs, &locks, 0..) |op, *mcv, *lock, op_i| { |
| 18727 | | const op_index: u2 = @intCast(op_i); |
| 18728 | | mcv.* = try self.resolveInst(op); |
| 18729 | | if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) { |
| 18730 | | order[op_index] = 1; |
| 18731 | | unused.unset(0); |
| 18732 | | } else if (unused.isSet(2) and mcv.isMemory()) { |
| 18733 | | order[op_index] = 3; |
| 18734 | | unused.unset(2); |
| 18735 | | } |
| 18736 | | switch (mcv.*) { |
| 18737 | | .register => |reg| lock.* = self.register_manager.lockReg(reg), |
| 18738 | | else => {}, |
| 27344 | const ret_ty: Type = .fromInterned(fn_info.return_type); |
| 27345 | switch (cc) { |
| 27346 | .naked => { |
| 27347 | assert(result.args.len == 0); |
| 27348 | result.return_value = .init(.unreach); |
| 27349 | result.stack_align = switch (self.target.cpu.arch) { |
| 27350 | else => unreachable, |
| 27351 | .x86 => .@"4", |
| 27352 | .x86_64 => .@"8", |
| 27353 | }; |
| 27354 | }, |
| 27355 | .x86_64_sysv, .x86_64_win => |cc_opts| { |
| 27356 | var ret_int_reg_i: u32 = 0; |
| 27357 | var ret_sse_reg_i: u32 = 0; |
| 27358 | var param_int_reg_i: u32 = 0; |
| 27359 | var param_sse_reg_i: u32 = 0; |
| 27360 | result.stack_align = .fromByteUnits(cc_opts.incoming_stack_alignment orelse 16); |
| 27361 | |
| 27362 | switch (cc) { |
| 27363 | .x86_64_sysv => {}, |
| 27364 | .x86_64_win => result.stack_byte_count += @intCast(4 * 8), |
| 27365 | else => unreachable, |
| 18739 | 27366 | } |
| 18740 | | } |
| 18741 | | for (&order, &mcvs, &locks) |*mop_index, *mcv, *lock| { |
| 18742 | | if (mop_index.* != 0) continue; |
| 18743 | | mop_index.* = 1 + @as(u2, @intCast(unused.toggleFirstSet().?)); |
| 18744 | | if (mop_index.* > 1 and mcv.isRegister()) continue; |
| 18745 | | const reg = try self.copyToTmpRegister(ty, mcv.*); |
| 18746 | | mcv.* = .{ .register = reg }; |
| 18747 | | if (lock.*) |old_lock| self.register_manager.unlockReg(old_lock); |
| 18748 | | lock.* = self.register_manager.lockRegAssumeUnused(reg); |
| 18749 | | } |
| 18750 | 27367 | |
| 18751 | | const mir_tag = @as(?Mir.Inst.FixedTag, if (mem.eql(u2, &order, &.{ 1, 3, 2 }) or |
| 18752 | | mem.eql(u2, &order, &.{ 3, 1, 2 })) |
| 18753 | | switch (ty.zigTypeTag(zcu)) { |
| 18754 | | .float => switch (ty.floatBits(self.target.*)) { |
| 18755 | | 32 => .{ .v_ss, .fmadd132 }, |
| 18756 | | 64 => .{ .v_sd, .fmadd132 }, |
| 18757 | | 16, 80, 128 => null, |
| 27368 | // Return values |
| 27369 | if (ret_ty.isNoReturn(zcu)) { |
| 27370 | result.return_value = .init(.unreach); |
| 27371 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 27372 | // TODO: is this even possible for C calling convention? |
| 27373 | result.return_value = .init(.none); |
| 27374 | } else { |
| 27375 | var ret_tracking: [4]InstTracking = undefined; |
| 27376 | var ret_tracking_i: usize = 0; |
| 27377 | |
| 27378 | const classes = switch (cc) { |
| 27379 | .x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, self.target.*, .ret), .none), |
| 27380 | .x86_64_win => &.{abi.classifyWindows(ret_ty, zcu)}, |
| 18758 | 27381 | else => unreachable, |
| 18759 | | }, |
| 18760 | | .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| 18761 | | .float => switch (ty.childType(zcu).floatBits(self.target.*)) { |
| 18762 | | 32 => switch (ty.vectorLen(zcu)) { |
| 18763 | | 1 => .{ .v_ss, .fmadd132 }, |
| 18764 | | 2...8 => .{ .v_ps, .fmadd132 }, |
| 18765 | | else => null, |
| 18766 | | }, |
| 18767 | | 64 => switch (ty.vectorLen(zcu)) { |
| 18768 | | 1 => .{ .v_sd, .fmadd132 }, |
| 18769 | | 2...4 => .{ .v_pd, .fmadd132 }, |
| 18770 | | else => null, |
| 18771 | | }, |
| 18772 | | 16, 80, 128 => null, |
| 18773 | | else => unreachable, |
| 27382 | }; |
| 27383 | for (classes) |class| switch (class) { |
| 27384 | .integer => { |
| 27385 | const ret_int_reg = registerAlias( |
| 27386 | abi.getCAbiIntReturnRegs(cc)[ret_int_reg_i], |
| 27387 | @intCast(@min(ret_ty.abiSize(zcu), 8)), |
| 27388 | ); |
| 27389 | ret_int_reg_i += 1; |
| 27390 | |
| 27391 | ret_tracking[ret_tracking_i] = .init(.{ .register = ret_int_reg }); |
| 27392 | ret_tracking_i += 1; |
| 27393 | }, |
| 27394 | .sse, .float, .float_combine, .win_i128 => { |
| 27395 | const ret_sse_regs = abi.getCAbiSseReturnRegs(cc); |
| 27396 | const abi_size: u32 = @intCast(ret_ty.abiSize(zcu)); |
| 27397 | const reg_size = @min(abi_size, self.vectorSize(.float)); |
| 27398 | var byte_offset: u32 = 0; |
| 27399 | while (byte_offset < abi_size) : (byte_offset += reg_size) { |
| 27400 | const ret_sse_reg = registerAlias(ret_sse_regs[ret_sse_reg_i], reg_size); |
| 27401 | ret_sse_reg_i += 1; |
| 27402 | |
| 27403 | ret_tracking[ret_tracking_i] = .init(.{ .register = ret_sse_reg }); |
| 27404 | ret_tracking_i += 1; |
| 27405 | } |
| 27406 | }, |
| 27407 | .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse), |
| 27408 | .x87 => { |
| 27409 | ret_tracking[ret_tracking_i] = .init(.{ .register = abi.getCAbiX87ReturnRegs(cc)[0] }); |
| 27410 | ret_tracking_i += 1; |
| 27411 | }, |
| 27412 | .x87up => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .x87), |
| 27413 | .complex_x87 => { |
| 27414 | ret_tracking[ret_tracking_i] = .init(.{ .register_pair = abi.getCAbiX87ReturnRegs(cc)[0..2].* }); |
| 27415 | ret_tracking_i += 1; |
| 18774 | 27416 | }, |
| 27417 | .memory => { |
| 27418 | const ret_int_reg = abi.getCAbiIntReturnRegs(cc)[ret_int_reg_i].to64(); |
| 27419 | ret_int_reg_i += 1; |
| 27420 | const ret_indirect_reg = abi.getCAbiIntParamRegs(cc)[param_int_reg_i]; |
| 27421 | param_int_reg_i += 1; |
| 27422 | |
| 27423 | ret_tracking[ret_tracking_i] = .{ |
| 27424 | .short = .{ .indirect = .{ .reg = ret_int_reg } }, |
| 27425 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 27426 | }; |
| 27427 | ret_tracking_i += 1; |
| 27428 | }, |
| 27429 | .none, .integer_per_element => unreachable, |
| 27430 | }; |
| 27431 | result.return_value = switch (ret_tracking_i) { |
| 18775 | 27432 | else => unreachable, |
| 18776 | | }, |
| 18777 | | else => unreachable, |
| 27433 | 1 => ret_tracking[0], |
| 27434 | 2 => .init(.{ .register_pair = .{ |
| 27435 | ret_tracking[0].short.register, |
| 27436 | ret_tracking[1].short.register, |
| 27437 | } }), |
| 27438 | 3 => .init(.{ .register_triple = .{ |
| 27439 | ret_tracking[0].short.register, |
| 27440 | ret_tracking[1].short.register, |
| 27441 | ret_tracking[2].short.register, |
| 27442 | } }), |
| 27443 | 4 => .init(.{ .register_quadruple = .{ |
| 27444 | ret_tracking[0].short.register, |
| 27445 | ret_tracking[1].short.register, |
| 27446 | ret_tracking[2].short.register, |
| 27447 | ret_tracking[3].short.register, |
| 27448 | } }), |
| 27449 | }; |
| 18778 | 27450 | } |
| 18779 | | else if (mem.eql(u2, &order, &.{ 2, 1, 3 }) or mem.eql(u2, &order, &.{ 1, 2, 3 })) |
| 18780 | | switch (ty.zigTypeTag(zcu)) { |
| 18781 | | .float => switch (ty.floatBits(self.target.*)) { |
| 18782 | | 32 => .{ .v_ss, .fmadd213 }, |
| 18783 | | 64 => .{ .v_sd, .fmadd213 }, |
| 18784 | | 16, 80, 128 => null, |
| 27451 | |
| 27452 | // Input params |
| 27453 | for (param_types, result.args) |ty, *arg| { |
| 27454 | assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); |
| 27455 | switch (cc) { |
| 27456 | .x86_64_sysv => {}, |
| 27457 | .x86_64_win => { |
| 27458 | param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i); |
| 27459 | param_sse_reg_i = param_int_reg_i; |
| 27460 | }, |
| 18785 | 27461 | else => unreachable, |
| 18786 | | }, |
| 18787 | | .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| 18788 | | .float => switch (ty.childType(zcu).floatBits(self.target.*)) { |
| 18789 | | 32 => switch (ty.vectorLen(zcu)) { |
| 18790 | | 1 => .{ .v_ss, .fmadd213 }, |
| 18791 | | 2...8 => .{ .v_ps, .fmadd213 }, |
| 18792 | | else => null, |
| 18793 | | }, |
| 18794 | | 64 => switch (ty.vectorLen(zcu)) { |
| 18795 | | 1 => .{ .v_sd, .fmadd213 }, |
| 18796 | | 2...4 => .{ .v_pd, .fmadd213 }, |
| 18797 | | else => null, |
| 27462 | } |
| 27463 | |
| 27464 | var arg_mcv: [4]MCValue = undefined; |
| 27465 | var arg_mcv_i: usize = 0; |
| 27466 | |
| 27467 | const classes = switch (cc) { |
| 27468 | .x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .arg), .none), |
| 27469 | .x86_64_win => &.{abi.classifyWindows(ty, zcu)}, |
| 27470 | else => unreachable, |
| 27471 | }; |
| 27472 | classes: for (classes) |class| switch (class) { |
| 27473 | .integer => { |
| 27474 | const param_int_regs = abi.getCAbiIntParamRegs(cc); |
| 27475 | if (param_int_reg_i >= param_int_regs.len) break; |
| 27476 | |
| 27477 | const param_int_reg = |
| 27478 | registerAlias(param_int_regs[param_int_reg_i], @intCast(@min(ty.abiSize(zcu), 8))); |
| 27479 | param_int_reg_i += 1; |
| 27480 | |
| 27481 | arg_mcv[arg_mcv_i] = .{ .register = param_int_reg }; |
| 27482 | arg_mcv_i += 1; |
| 27483 | }, |
| 27484 | .sse, .float, .float_combine => { |
| 27485 | const param_sse_regs = abi.getCAbiSseParamRegs(cc); |
| 27486 | const abi_size: u32 = @intCast(ty.abiSize(zcu)); |
| 27487 | const reg_size = @min(abi_size, self.vectorSize(.float)); |
| 27488 | var byte_offset: u32 = 0; |
| 27489 | while (byte_offset < abi_size) : (byte_offset += reg_size) { |
| 27490 | if (param_sse_reg_i >= param_sse_regs.len) break :classes; |
| 27491 | |
| 27492 | const param_sse_reg = registerAlias(param_sse_regs[param_sse_reg_i], reg_size); |
| 27493 | param_sse_reg_i += 1; |
| 27494 | |
| 27495 | arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg }; |
| 27496 | arg_mcv_i += 1; |
| 27497 | } |
| 27498 | }, |
| 27499 | .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse), |
| 27500 | .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (cc) { |
| 27501 | .x86_64_sysv => switch (class) { |
| 27502 | .x87, .x87up, .complex_x87, .memory => break, |
| 27503 | else => unreachable, |
| 18798 | 27504 | }, |
| 18799 | | 16, 80, 128 => null, |
| 27505 | .x86_64_win => if (ty.abiSize(zcu) > 8) { |
| 27506 | const param_int_reg = abi.getCAbiIntParamRegs(cc)[param_int_reg_i].to64(); |
| 27507 | param_int_reg_i += 1; |
| 27508 | |
| 27509 | arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } }; |
| 27510 | arg_mcv_i += 1; |
| 27511 | } else break, |
| 18800 | 27512 | else => unreachable, |
| 18801 | 27513 | }, |
| 18802 | | else => unreachable, |
| 18803 | | }, |
| 18804 | | else => unreachable, |
| 27514 | .none => unreachable, |
| 27515 | .integer_per_element => { |
| 27516 | const param_int_regs_len: u32 = |
| 27517 | @intCast(abi.getCAbiIntParamRegs(cc).len); |
| 27518 | const remaining_param_int_regs: u3 = |
| 27519 | @intCast(param_int_regs_len - param_int_reg_i); |
| 27520 | param_int_reg_i = param_int_regs_len; |
| 27521 | |
| 27522 | const frame_elem_align = 8; |
| 27523 | const frame_elems_len = ty.vectorLen(zcu) - remaining_param_int_regs; |
| 27524 | const frame_elem_size = std.mem.alignForward( |
| 27525 | u64, |
| 27526 | ty.childType(zcu).abiSize(zcu), |
| 27527 | frame_elem_align, |
| 27528 | ); |
| 27529 | const frame_size: u31 = @intCast(frame_elems_len * frame_elem_size); |
| 27530 | |
| 27531 | result.stack_byte_count = |
| 27532 | std.mem.alignForward(u31, result.stack_byte_count, frame_elem_align); |
| 27533 | arg_mcv[arg_mcv_i] = .{ .elementwise_regs_then_frame = .{ |
| 27534 | .regs = remaining_param_int_regs, |
| 27535 | .frame_off = @intCast(result.stack_byte_count), |
| 27536 | .frame_index = stack_frame_base, |
| 27537 | } }; |
| 27538 | arg_mcv_i += 1; |
| 27539 | result.stack_byte_count += frame_size; |
| 27540 | }, |
| 27541 | } else { |
| 27542 | arg.* = switch (arg_mcv_i) { |
| 27543 | else => unreachable, |
| 27544 | 1 => arg_mcv[0], |
| 27545 | 2 => .{ .register_pair = .{ |
| 27546 | arg_mcv[0].register, |
| 27547 | arg_mcv[1].register, |
| 27548 | } }, |
| 27549 | 3 => .{ .register_triple = .{ |
| 27550 | arg_mcv[0].register, |
| 27551 | arg_mcv[1].register, |
| 27552 | arg_mcv[2].register, |
| 27553 | } }, |
| 27554 | 4 => .{ .register_quadruple = .{ |
| 27555 | arg_mcv[0].register, |
| 27556 | arg_mcv[1].register, |
| 27557 | arg_mcv[2].register, |
| 27558 | arg_mcv[3].register, |
| 27559 | } }, |
| 27560 | }; |
| 27561 | continue; |
| 27562 | } |
| 27563 | |
| 27564 | const param_align = ty.abiAlignment(zcu).max(.@"8"); |
| 27565 | result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count)); |
| 27566 | result.stack_align = result.stack_align.max(param_align); |
| 27567 | arg.* = .{ .load_frame = .{ |
| 27568 | .index = stack_frame_base, |
| 27569 | .off = result.stack_byte_count, |
| 27570 | } }; |
| 27571 | result.stack_byte_count += @intCast(ty.abiSize(zcu)); |
| 18805 | 27572 | } |
| 18806 | | else if (mem.eql(u2, &order, &.{ 2, 3, 1 }) or mem.eql(u2, &order, &.{ 3, 2, 1 })) |
| 18807 | | switch (ty.zigTypeTag(zcu)) { |
| 18808 | | .float => switch (ty.floatBits(self.target.*)) { |
| 18809 | | 32 => .{ .v_ss, .fmadd231 }, |
| 18810 | | 64 => .{ .v_sd, .fmadd231 }, |
| 18811 | | 16, 80, 128 => null, |
| 18812 | | else => unreachable, |
| 18813 | | }, |
| 18814 | | .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| 18815 | | .float => switch (ty.childType(zcu).floatBits(self.target.*)) { |
| 18816 | | 32 => switch (ty.vectorLen(zcu)) { |
| 18817 | | 1 => .{ .v_ss, .fmadd231 }, |
| 18818 | | 2...8 => .{ .v_ps, .fmadd231 }, |
| 18819 | | else => null, |
| 18820 | | }, |
| 18821 | | 64 => switch (ty.vectorLen(zcu)) { |
| 18822 | | 1 => .{ .v_sd, .fmadd231 }, |
| 18823 | | 2...4 => .{ .v_pd, .fmadd231 }, |
| 18824 | | else => null, |
| 18825 | | }, |
| 18826 | | 16, 80, 128 => null, |
| 27573 | assert(param_int_reg_i <= 6); |
| 27574 | result.gp_count = param_int_reg_i; |
| 27575 | assert(param_sse_reg_i <= 16); |
| 27576 | result.fp_count = param_sse_reg_i; |
| 27577 | }, |
| 27578 | .auto => { |
| 27579 | result.stack_align = abi.zigcc.stack_align orelse .fromByteUnits(self.vectorSize(.float)); |
| 27580 | |
| 27581 | var param_gpr = abi.getCAbiIntParamRegs(cc); |
| 27582 | var param_x87 = abi.getCAbiX87ParamRegs(cc); |
| 27583 | var param_sse = abi.getCAbiSseParamRegs(cc); |
| 27584 | |
| 27585 | // Return values |
| 27586 | result.return_value = if (ret_ty.isNoReturn(zcu)) |
| 27587 | .init(.unreach) |
| 27588 | else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) |
| 27589 | .init(.none) |
| 27590 | else return_value: { |
| 27591 | const ret_gpr = abi.getCAbiIntReturnRegs(cc); |
| 27592 | const ret_size: u31 = @intCast(ret_ty.abiSize(zcu)); |
| 27593 | if (abi.zigcc.return_in_regs) switch (self.regClassForType(ret_ty)) { |
| 27594 | .general_purpose => if (ret_size <= @as(u4, switch (self.target.cpu.arch) { |
| 27595 | else => unreachable, |
| 27596 | .x86 => 4, |
| 27597 | .x86_64 => 8, |
| 27598 | })) |
| 27599 | break :return_value .init(.{ .register = registerAlias(ret_gpr[0], ret_size) }) |
| 27600 | else if (ret_gpr.len >= 2 and ret_ty.isSliceAtRuntime(zcu)) |
| 27601 | break :return_value .init(.{ .register_pair = ret_gpr[0..2].* }), |
| 27602 | .segment, .mmx, .ip => unreachable, |
| 27603 | .x87 => break :return_value .init(.{ .register = .st0 }), |
| 27604 | .sse => if (ret_size <= self.vectorSize(.float)) break :return_value .init(.{ |
| 27605 | .register = registerAlias(abi.getCAbiSseReturnRegs(cc)[0], @max(ret_size, 16)), |
| 27606 | }), |
| 27607 | }; |
| 27608 | const ret_indirect_reg = param_gpr[0]; |
| 27609 | param_gpr = param_gpr[1..]; |
| 27610 | break :return_value .{ |
| 27611 | .short = .{ .indirect = .{ .reg = ret_gpr[0] } }, |
| 27612 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 27613 | }; |
| 27614 | }; |
| 27615 | |
| 27616 | // Input params |
| 27617 | for (param_types, result.args) |param_ty, *arg| { |
| 27618 | if (!param_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 27619 | arg.* = .none; |
| 27620 | continue; |
| 27621 | } |
| 27622 | const param_size: u31 = @intCast(param_ty.abiSize(zcu)); |
| 27623 | if (abi.zigcc.params_in_regs) switch (self.regClassForType(param_ty)) { |
| 27624 | .general_purpose => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (self.target.cpu.arch) { |
| 18827 | 27625 | else => unreachable, |
| 27626 | .x86 => 4, |
| 27627 | .x86_64 => 8, |
| 27628 | })) { |
| 27629 | arg.* = .{ .register = registerAlias(param_gpr[0], param_size) }; |
| 27630 | param_gpr = param_gpr[1..]; |
| 27631 | continue; |
| 27632 | } else if (param_gpr.len >= 2 and param_ty.isSliceAtRuntime(zcu)) { |
| 27633 | arg.* = .{ .register_pair = param_gpr[0..2].* }; |
| 27634 | param_gpr = param_gpr[2..]; |
| 27635 | continue; |
| 18828 | 27636 | }, |
| 18829 | | else => unreachable, |
| 18830 | | }, |
| 18831 | | else => unreachable, |
| 27637 | .segment, .mmx, .ip => unreachable, |
| 27638 | .x87 => if (param_x87.len >= 1) { |
| 27639 | arg.* = .{ .register = param_x87[0] }; |
| 27640 | param_x87 = param_x87[1..]; |
| 27641 | continue; |
| 27642 | }, |
| 27643 | .sse => if (param_sse.len >= 1 and param_size <= self.vectorSize(.float)) { |
| 27644 | arg.* = .{ |
| 27645 | .register = registerAlias(param_sse[0], @max(param_size, 16)), |
| 27646 | }; |
| 27647 | param_sse = param_sse[1..]; |
| 27648 | continue; |
| 27649 | }, |
| 27650 | }; |
| 27651 | const param_align = param_ty.abiAlignment(zcu); |
| 27652 | result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count)); |
| 27653 | result.stack_align = result.stack_align.max(param_align); |
| 27654 | arg.* = .{ .load_frame = .{ |
| 27655 | .index = stack_frame_base, |
| 27656 | .off = result.stack_byte_count, |
| 27657 | } }; |
| 27658 | result.stack_byte_count += param_size; |
| 18832 | 27659 | } |
| 18833 | | else |
| 18834 | | unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{ty.fmt(pt)}); |
| 27660 | }, |
| 27661 | else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}), |
| 27662 | } |
| 18835 | 27663 | |
| 18836 | | var mops: [3]MCValue = undefined; |
| 18837 | | for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv; |
| 27664 | result.stack_byte_count = @intCast(result.stack_align.forward(result.stack_byte_count)); |
| 27665 | return result; |
| 27666 | } |
| 18838 | 27667 | |
| 18839 | | const abi_size: u32 = @intCast(ty.abiSize(zcu)); |
| 18840 | | const mop1_reg = registerAlias(mops[0].getReg().?, abi_size); |
| 18841 | | const mop2_reg = registerAlias(mops[1].getReg().?, abi_size); |
| 18842 | | if (mops[2].isRegister()) try self.asmRegisterRegisterRegister( |
| 18843 | | mir_tag, |
| 18844 | | mop1_reg, |
| 18845 | | mop2_reg, |
| 18846 | | registerAlias(mops[2].getReg().?, abi_size), |
| 18847 | | ) else try self.asmRegisterRegisterMemory( |
| 18848 | | mir_tag, |
| 18849 | | mop1_reg, |
| 18850 | | mop2_reg, |
| 18851 | | try mops[2].mem(self, Memory.Size.fromSize(abi_size)), |
| 18852 | | ); |
| 18853 | | break :result mops[0]; |
| 27668 | fn fail(self: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 27669 | @branchHint(.cold); |
| 27670 | const zcu = self.pt.zcu; |
| 27671 | switch (self.owner) { |
| 27672 | .nav_index => |i| return zcu.codegenFail(i, format, args), |
| 27673 | .lazy_sym => |s| return zcu.codegenFailType(s.ty, format, args), |
| 27674 | } |
| 27675 | return error.CodegenFail; |
| 27676 | } |
| 27677 | |
| 27678 | fn failMsg(self: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } { |
| 27679 | @branchHint(.cold); |
| 27680 | const zcu = self.pt.zcu; |
| 27681 | switch (self.owner) { |
| 27682 | .nav_index => |i| return zcu.codegenFailMsg(i, msg), |
| 27683 | .lazy_sym => |s| return zcu.codegenFailTypeMsg(s.ty, msg), |
| 27684 | } |
| 27685 | return error.CodegenFail; |
| 27686 | } |
| 27687 | |
| 27688 | fn parseRegName(name: []const u8) ?Register { |
| 27689 | if (@hasDecl(Register, "parseRegName")) { |
| 27690 | return Register.parseRegName(name); |
| 27691 | } |
| 27692 | return std.meta.stringToEnum(Register, name); |
| 27693 | } |
| 27694 | |
| 27695 | /// Returns register wide enough to hold at least `size_bytes`. |
| 27696 | fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 27697 | return switch (reg.class()) { |
| 27698 | .general_purpose => if (size_bytes == 0) |
| 27699 | unreachable // should be comptime-known |
| 27700 | else if (size_bytes <= 1) |
| 27701 | reg.to8() |
| 27702 | else if (size_bytes <= 2) |
| 27703 | reg.to16() |
| 27704 | else if (size_bytes <= 4) |
| 27705 | reg.to32() |
| 27706 | else if (size_bytes <= 8) |
| 27707 | reg.to64() |
| 27708 | else |
| 27709 | unreachable, |
| 27710 | .segment => if (size_bytes <= 2) |
| 27711 | reg |
| 27712 | else |
| 27713 | unreachable, |
| 27714 | .x87 => if (size_bytes >= 10 and size_bytes <= 16) |
| 27715 | reg |
| 27716 | else |
| 27717 | unreachable, |
| 27718 | .mmx => if (size_bytes <= 8) |
| 27719 | reg |
| 27720 | else |
| 27721 | unreachable, |
| 27722 | .sse => if (size_bytes <= 16) |
| 27723 | reg.to128() |
| 27724 | else if (size_bytes <= 32) |
| 27725 | reg.to256() |
| 27726 | else |
| 27727 | unreachable, |
| 27728 | .ip => if (size_bytes <= 2) |
| 27729 | .ip |
| 27730 | else if (size_bytes <= 4) |
| 27731 | .eip |
| 27732 | else if (size_bytes <= 8) |
| 27733 | .rip |
| 27734 | else |
| 27735 | unreachable, |
| 27736 | }; |
| 27737 | } |
| 27738 | |
| 27739 | fn memSize(self: *CodeGen, ty: Type) Memory.Size { |
| 27740 | const zcu = self.pt.zcu; |
| 27741 | return switch (ty.zigTypeTag(zcu)) { |
| 27742 | .float => .fromBitSize(ty.floatBits(self.target.*)), |
| 27743 | else => .fromSize(@intCast(ty.abiSize(zcu))), |
| 18854 | 27744 | }; |
| 18855 | | return self.finishAir(inst, result, ops); |
| 18856 | 27745 | } |
| 18857 | 27746 | |
| 18858 | | fn airVaStart(self: *Self, inst: Air.Inst.Index) !void { |
| 27747 | fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Type { |
| 18859 | 27748 | const pt = self.pt; |
| 18860 | 27749 | const zcu = pt.zcu; |
| 18861 | | const va_list_ty = self.air.instructions.items(.data)[@intFromEnum(inst)].ty; |
| 18862 | | const ptr_anyopaque_ty = try pt.singleMutPtrType(Type.anyopaque); |
| 18863 | | |
| 18864 | | const result: MCValue = switch (abi.resolveCallingConvention( |
| 18865 | | self.fn_type.fnCallingConvention(zcu), |
| 18866 | | self.target.*, |
| 18867 | | )) { |
| 18868 | | .x86_64_sysv => result: { |
| 18869 | | const info = self.va_info.sysv; |
| 18870 | | const dst_fi = try self.allocFrameIndex(FrameAlloc.initSpill(va_list_ty, zcu)); |
| 18871 | | var field_off: u31 = 0; |
| 18872 | | // gp_offset: c_uint, |
| 18873 | | try self.genSetMem( |
| 18874 | | .{ .frame = dst_fi }, |
| 18875 | | field_off, |
| 18876 | | Type.c_uint, |
| 18877 | | .{ .immediate = info.gp_count * 8 }, |
| 18878 | | .{}, |
| 18879 | | ); |
| 18880 | | field_off += @intCast(Type.c_uint.abiSize(zcu)); |
| 18881 | | // fp_offset: c_uint, |
| 18882 | | try self.genSetMem( |
| 18883 | | .{ .frame = dst_fi }, |
| 18884 | | field_off, |
| 18885 | | Type.c_uint, |
| 18886 | | .{ .immediate = abi.SysV.c_abi_int_param_regs.len * 8 + info.fp_count * 16 }, |
| 18887 | | .{}, |
| 18888 | | ); |
| 18889 | | field_off += @intCast(Type.c_uint.abiSize(zcu)); |
| 18890 | | // overflow_arg_area: *anyopaque, |
| 18891 | | try self.genSetMem( |
| 18892 | | .{ .frame = dst_fi }, |
| 18893 | | field_off, |
| 18894 | | ptr_anyopaque_ty, |
| 18895 | | .{ .lea_frame = info.overflow_arg_area }, |
| 18896 | | .{}, |
| 18897 | | ); |
| 18898 | | field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu)); |
| 18899 | | // reg_save_area: *anyopaque, |
| 18900 | | try self.genSetMem( |
| 18901 | | .{ .frame = dst_fi }, |
| 18902 | | field_off, |
| 18903 | | ptr_anyopaque_ty, |
| 18904 | | .{ .lea_frame = info.reg_save_area }, |
| 18905 | | .{}, |
| 18906 | | ); |
| 18907 | | field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu)); |
| 18908 | | break :result .{ .load_frame = .{ .index = dst_fi } }; |
| 18909 | | }, |
| 18910 | | .x86_64_win => return self.fail("TODO implement c_va_start for Win64", .{}), |
| 18911 | | else => unreachable, |
| 27750 | var parts: [parts_len]Type = undefined; |
| 27751 | if (ty.isVector(zcu)) if (std.math.divExact(u32, ty.vectorLen(zcu), parts_len)) |vec_len| return .{ |
| 27752 | try pt.vectorType(.{ .len = vec_len, .child = ty.scalarType(zcu).toIntern() }), |
| 27753 | } ** parts_len else |err| switch (err) { |
| 27754 | error.DivisionByZero => unreachable, |
| 27755 | error.UnexpectedRemainder => {}, |
| 18912 | 27756 | }; |
| 18913 | | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 27757 | const classes = std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none); |
| 27758 | if (classes.len == parts_len) for (&parts, classes, 0..) |*part, class, part_i| { |
| 27759 | part.* = switch (class) { |
| 27760 | .integer => if (part_i < parts_len - 1) |
| 27761 | .u64 |
| 27762 | else part: { |
| 27763 | const elem_size = ty.abiAlignment(zcu).minStrict(.@"8").toByteUnits().?; |
| 27764 | const elem_ty = try pt.intType(.unsigned, @intCast(elem_size * 8)); |
| 27765 | break :part switch (@divExact(ty.abiSize(zcu) - part_i * 8, elem_size)) { |
| 27766 | 1 => elem_ty, |
| 27767 | else => |array_len| try pt.arrayType(.{ .len = array_len, .child = elem_ty.toIntern() }), |
| 27768 | }; |
| 27769 | }, |
| 27770 | .float => .f32, |
| 27771 | .float_combine => try pt.arrayType(.{ .len = 2, .child = .f32_type }), |
| 27772 | .sse => .f64, |
| 27773 | else => break, |
| 27774 | }; |
| 27775 | } else { |
| 27776 | var part_sizes: u64 = 0; |
| 27777 | for (parts) |part| part_sizes += part.abiSize(zcu); |
| 27778 | if (part_sizes == ty.abiSize(zcu)) return parts; |
| 27779 | }; |
| 27780 | return self.fail("TODO implement splitType({d}, {})", .{ parts_len, ty.fmt(pt) }); |
| 18914 | 27781 | } |
| 18915 | 27782 | |
| 18916 | | fn airVaArg(self: *Self, inst: Air.Inst.Index) !void { |
| 27783 | /// Truncates the value in the register in place. |
| 27784 | /// Clobbers any remaining bits. |
| 27785 | fn truncateRegister(self: *CodeGen, ty: Type, reg: Register) !void { |
| 18917 | 27786 | const pt = self.pt; |
| 18918 | 27787 | const zcu = pt.zcu; |
| 18919 | | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 18920 | | const ty = self.typeOfIndex(inst); |
| 18921 | | const promote_ty = self.promoteVarArg(ty); |
| 18922 | | const ptr_anyopaque_ty = try pt.singleMutPtrType(Type.anyopaque); |
| 18923 | | const unused = self.liveness.isUnused(inst); |
| 18924 | | |
| 18925 | | const result: MCValue = switch (abi.resolveCallingConvention( |
| 18926 | | self.fn_type.fnCallingConvention(zcu), |
| 18927 | | self.target.*, |
| 18928 | | )) { |
| 18929 | | .x86_64_sysv => result: { |
| 18930 | | try self.spillEflagsIfOccupied(); |
| 18931 | | |
| 18932 | | const tmp_regs = |
| 18933 | | try self.register_manager.allocRegs(2, .{null} ** 2, abi.RegisterClass.gp); |
| 18934 | | const offset_reg = tmp_regs[0].to32(); |
| 18935 | | const addr_reg = tmp_regs[1].to64(); |
| 18936 | | const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs); |
| 18937 | | defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock); |
| 18938 | | |
| 18939 | | const promote_mcv = try self.allocTempRegOrMem(promote_ty, true); |
| 18940 | | const promote_lock = switch (promote_mcv) { |
| 18941 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 18942 | | else => null, |
| 18943 | | }; |
| 18944 | | defer if (promote_lock) |lock| self.register_manager.unlockReg(lock); |
| 18945 | | |
| 18946 | | const ptr_arg_list_reg = |
| 18947 | | try self.copyToTmpRegister(self.typeOf(ty_op.operand), .{ .air_ref = ty_op.operand }); |
| 18948 | | const ptr_arg_list_lock = self.register_manager.lockRegAssumeUnused(ptr_arg_list_reg); |
| 18949 | | defer self.register_manager.unlockReg(ptr_arg_list_lock); |
| 18950 | | |
| 18951 | | const gp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 0 } }; |
| 18952 | | const fp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 4 } }; |
| 18953 | | const overflow_arg_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 8 } }; |
| 18954 | | const reg_save_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 16 } }; |
| 18955 | | |
| 18956 | | const classes = mem.sliceTo(&abi.classifySystemV(promote_ty, zcu, self.target.*, .arg), .none); |
| 18957 | | switch (classes[0]) { |
| 18958 | | .integer => { |
| 18959 | | assert(classes.len == 1); |
| 18960 | | |
| 18961 | | try self.genSetReg(offset_reg, Type.c_uint, gp_offset, .{}); |
| 18962 | | try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, Immediate.u( |
| 18963 | | abi.SysV.c_abi_int_param_regs.len * 8, |
| 18964 | | )); |
| 18965 | | const mem_reloc = try self.asmJccReloc(.ae, undefined); |
| 18966 | | |
| 18967 | | try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area, .{}); |
| 18968 | | if (!unused) try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, .{ |
| 18969 | | .base = .{ .reg = addr_reg }, |
| 18970 | | .mod = .{ .rm = .{ |
| 18971 | | .size = .qword, |
| 18972 | | .index = offset_reg.to64(), |
| 18973 | | } }, |
| 18974 | | }); |
| 18975 | | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, .{ |
| 18976 | | .base = .{ .reg = offset_reg.to64() }, |
| 18977 | | .mod = .{ .rm = .{ |
| 18978 | | .size = .qword, |
| 18979 | | .disp = 8, |
| 18980 | | } }, |
| 18981 | | }); |
| 18982 | | try self.genCopy(Type.c_uint, gp_offset, .{ .register = offset_reg }, .{}); |
| 18983 | | const done_reloc = try self.asmJmpReloc(undefined); |
| 27788 | const int_info: InternPool.Key.IntType = if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else .{ |
| 27789 | .signedness = .unsigned, |
| 27790 | .bits = @intCast(ty.bitSize(zcu)), |
| 27791 | }; |
| 27792 | const shift = std.math.cast(u6, 64 - int_info.bits % 64) orelse return; |
| 27793 | try self.spillEflagsIfOccupied(); |
| 27794 | switch (int_info.signedness) { |
| 27795 | .signed => { |
| 27796 | try self.genShiftBinOpMir(.{ ._l, .sa }, .isize, .{ .register = reg }, .u8, .{ .immediate = shift }); |
| 27797 | try self.genShiftBinOpMir(.{ ._r, .sa }, .isize, .{ .register = reg }, .u8, .{ .immediate = shift }); |
| 27798 | }, |
| 27799 | .unsigned => { |
| 27800 | const mask = ~@as(u64, 0) >> shift; |
| 27801 | if (int_info.bits <= 32) { |
| 27802 | try self.genBinOpMir(.{ ._, .@"and" }, .u32, .{ .register = reg }, .{ .immediate = mask }); |
| 27803 | } else { |
| 27804 | const tmp_reg = try self.copyToTmpRegister(.usize, .{ .immediate = mask }); |
| 27805 | try self.genBinOpMir(.{ ._, .@"and" }, .usize, .{ .register = reg }, .{ .register = tmp_reg }); |
| 27806 | } |
| 27807 | }, |
| 27808 | } |
| 27809 | } |
| 18984 | 27810 | |
| 18985 | | self.performReloc(mem_reloc); |
| 18986 | | try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area, .{}); |
| 18987 | | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), .{ |
| 18988 | | .base = .{ .reg = addr_reg }, |
| 18989 | | .mod = .{ .rm = .{ |
| 18990 | | .size = .qword, |
| 18991 | | .disp = @intCast(@max(promote_ty.abiSize(zcu), 8)), |
| 18992 | | } }, |
| 18993 | | }); |
| 18994 | | try self.genCopy( |
| 18995 | | ptr_anyopaque_ty, |
| 18996 | | overflow_arg_area, |
| 18997 | | .{ .register = offset_reg.to64() }, |
| 18998 | | .{}, |
| 18999 | | ); |
| 27811 | fn regBitSize(self: *CodeGen, ty: Type) u64 { |
| 27812 | const zcu = self.pt.zcu; |
| 27813 | const abi_size = ty.abiSize(zcu); |
| 27814 | return switch (ty.zigTypeTag(zcu)) { |
| 27815 | else => switch (abi_size) { |
| 27816 | 1 => 8, |
| 27817 | 2 => 16, |
| 27818 | 3...4 => 32, |
| 27819 | 5...8 => 64, |
| 27820 | else => unreachable, |
| 27821 | }, |
| 27822 | .float => switch (abi_size) { |
| 27823 | 1...16 => 128, |
| 27824 | 17...32 => 256, |
| 27825 | else => unreachable, |
| 27826 | }, |
| 27827 | }; |
| 27828 | } |
| 19000 | 27829 | |
| 19001 | | self.performReloc(done_reloc); |
| 19002 | | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ |
| 19003 | | .indirect = .{ .reg = addr_reg }, |
| 19004 | | }, .{}); |
| 19005 | | }, |
| 19006 | | .sse => { |
| 19007 | | assert(classes.len == 1); |
| 27830 | fn regExtraBits(self: *CodeGen, ty: Type) u64 { |
| 27831 | return self.regBitSize(ty) - ty.bitSize(self.pt.zcu); |
| 27832 | } |
| 19008 | 27833 | |
| 19009 | | try self.genSetReg(offset_reg, Type.c_uint, fp_offset, .{}); |
| 19010 | | try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, Immediate.u( |
| 19011 | | abi.SysV.c_abi_int_param_regs.len * 8 + abi.SysV.c_abi_sse_param_regs.len * 16, |
| 19012 | | )); |
| 19013 | | const mem_reloc = try self.asmJccReloc(.ae, undefined); |
| 27834 | fn hasFeature(cg: *CodeGen, feature: std.Target.x86.Feature) bool { |
| 27835 | return switch (feature) { |
| 27836 | .@"64bit" => switch (cg.target.cpu.arch) { |
| 27837 | else => unreachable, |
| 27838 | .x86 => false, |
| 27839 | .x86_64 => true, |
| 27840 | }, |
| 27841 | .false_deps_getmant, |
| 27842 | .false_deps_lzcnt_tzcnt, |
| 27843 | .false_deps_mulc, |
| 27844 | .false_deps_mullq, |
| 27845 | .false_deps_perm, |
| 27846 | .false_deps_popcnt, |
| 27847 | .false_deps_range, |
| 27848 | .slow_3ops_lea, |
| 27849 | .slow_incdec, |
| 27850 | .slow_lea, |
| 27851 | .slow_pmaddwd, |
| 27852 | .slow_pmulld, |
| 27853 | .slow_shld, |
| 27854 | .slow_two_mem_ops, |
| 27855 | .slow_unaligned_mem_16, |
| 27856 | .slow_unaligned_mem_32, |
| 27857 | => switch (cg.mod.optimize_mode) { |
| 27858 | .Debug, .ReleaseSafe, .ReleaseFast => null, |
| 27859 | .ReleaseSmall => false, |
| 27860 | }, |
| 27861 | .fast_11bytenop, |
| 27862 | .fast_15bytenop, |
| 27863 | .fast_7bytenop, |
| 27864 | .fast_bextr, |
| 27865 | .fast_dpwssd, |
| 27866 | .fast_gather, |
| 27867 | .fast_hops, |
| 27868 | .fast_imm16, |
| 27869 | .fast_lzcnt, |
| 27870 | .fast_movbe, |
| 27871 | .fast_scalar_fsqrt, |
| 27872 | .fast_scalar_shift_masks, |
| 27873 | .fast_shld_rotate, |
| 27874 | .fast_variable_crosslane_shuffle, |
| 27875 | .fast_variable_perlane_shuffle, |
| 27876 | .fast_vector_fsqrt, |
| 27877 | .fast_vector_shift_masks, |
| 27878 | => switch (cg.mod.optimize_mode) { |
| 27879 | .Debug, .ReleaseSafe, .ReleaseFast => null, |
| 27880 | .ReleaseSmall => true, |
| 27881 | }, |
| 27882 | .mmx => false, |
| 27883 | else => null, |
| 27884 | } orelse std.Target.x86.featureSetHas(cg.target.cpu.features, feature); |
| 27885 | } |
| 19014 | 27886 | |
| 19015 | | try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area, .{}); |
| 19016 | | if (!unused) try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, .{ |
| 19017 | | .base = .{ .reg = addr_reg }, |
| 19018 | | .mod = .{ .rm = .{ |
| 19019 | | .size = .qword, |
| 19020 | | .index = offset_reg.to64(), |
| 19021 | | } }, |
| 19022 | | }); |
| 19023 | | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, .{ |
| 19024 | | .base = .{ .reg = offset_reg.to64() }, |
| 19025 | | .mod = .{ .rm = .{ |
| 19026 | | .size = .qword, |
| 19027 | | .disp = 16, |
| 19028 | | } }, |
| 19029 | | }); |
| 19030 | | try self.genCopy(Type.c_uint, fp_offset, .{ .register = offset_reg }, .{}); |
| 19031 | | const done_reloc = try self.asmJmpReloc(undefined); |
| 27887 | fn typeOf(self: *CodeGen, inst: Air.Inst.Ref) Type { |
| 27888 | const pt = self.pt; |
| 27889 | const zcu = pt.zcu; |
| 27890 | return self.air.typeOf(inst, &zcu.intern_pool); |
| 27891 | } |
| 19032 | 27892 | |
| 19033 | | self.performReloc(mem_reloc); |
| 19034 | | try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area, .{}); |
| 19035 | | try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), .{ |
| 19036 | | .base = .{ .reg = addr_reg }, |
| 19037 | | .mod = .{ .rm = .{ |
| 19038 | | .size = .qword, |
| 19039 | | .disp = @intCast(@max(promote_ty.abiSize(zcu), 8)), |
| 19040 | | } }, |
| 19041 | | }); |
| 19042 | | try self.genCopy( |
| 19043 | | ptr_anyopaque_ty, |
| 19044 | | overflow_arg_area, |
| 19045 | | .{ .register = offset_reg.to64() }, |
| 19046 | | .{}, |
| 19047 | | ); |
| 27893 | fn typeOfIndex(self: *CodeGen, inst: Air.Inst.Index) Type { |
| 27894 | const pt = self.pt; |
| 27895 | const zcu = pt.zcu; |
| 27896 | const temp: Temp = .{ .index = inst }; |
| 27897 | return switch (temp.unwrap(self)) { |
| 27898 | .ref => switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) { |
| 27899 | .loop_switch_br => self.typeOf(self.air.unwrapSwitch(inst).operand), |
| 27900 | else => self.air.typeOfIndex(inst, &zcu.intern_pool), |
| 27901 | }, |
| 27902 | .temp => temp.typeOf(self), |
| 27903 | }; |
| 27904 | } |
| 19048 | 27905 | |
| 19049 | | self.performReloc(done_reloc); |
| 19050 | | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ |
| 19051 | | .indirect = .{ .reg = addr_reg }, |
| 19052 | | }, .{}); |
| 19053 | | }, |
| 19054 | | .memory => { |
| 19055 | | assert(classes.len == 1); |
| 19056 | | unreachable; |
| 19057 | | }, |
| 19058 | | else => return self.fail("TODO implement c_va_arg for {} on SysV", .{ |
| 19059 | | promote_ty.fmt(pt), |
| 19060 | | }), |
| 19061 | | } |
| 27906 | fn intCompilerRtAbiName(int_bits: u32) u8 { |
| 27907 | return switch (int_bits) { |
| 27908 | 1...32 => 's', |
| 27909 | 33...64 => 'd', |
| 27910 | 65...128 => 't', |
| 27911 | else => unreachable, |
| 27912 | }; |
| 27913 | } |
| 19062 | 27914 | |
| 19063 | | if (unused) break :result .unreach; |
| 19064 | | if (ty.toIntern() == promote_ty.toIntern()) break :result promote_mcv; |
| 27915 | fn floatCompilerRtAbiName(float_bits: u32) u8 { |
| 27916 | return switch (float_bits) { |
| 27917 | 16 => 'h', |
| 27918 | 32 => 's', |
| 27919 | 64 => 'd', |
| 27920 | 80 => 'x', |
| 27921 | 128 => 't', |
| 27922 | else => unreachable, |
| 27923 | }; |
| 27924 | } |
| 19065 | 27925 | |
| 19066 | | if (!promote_ty.isRuntimeFloat()) { |
| 19067 | | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 19068 | | try self.genCopy(ty, dst_mcv, promote_mcv, .{}); |
| 19069 | | break :result dst_mcv; |
| 19070 | | } |
| 27926 | fn floatCompilerRtAbiType(self: *CodeGen, ty: Type, other_ty: Type) Type { |
| 27927 | if (ty.toIntern() == .f16_type and |
| 27928 | (other_ty.toIntern() == .f32_type or other_ty.toIntern() == .f64_type) and |
| 27929 | self.target.isDarwin()) return .u16; |
| 27930 | return ty; |
| 27931 | } |
| 19071 | 27932 | |
| 19072 | | assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type); |
| 19073 | | const dst_mcv = if (promote_mcv.isRegister()) |
| 19074 | | promote_mcv |
| 19075 | | else |
| 19076 | | try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv); |
| 19077 | | const dst_reg = dst_mcv.getReg().?.to128(); |
| 19078 | | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 19079 | | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 27933 | fn floatLibcAbiPrefix(ty: Type) []const u8 { |
| 27934 | return switch (ty.toIntern()) { |
| 27935 | .f16_type, .f80_type => "__", |
| 27936 | .f32_type, .f64_type, .f128_type, .c_longdouble_type => "", |
| 27937 | else => unreachable, |
| 27938 | }; |
| 27939 | } |
| 19080 | 27940 | |
| 19081 | | if (self.hasFeature(.avx)) if (promote_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 19082 | | .{ .v_ss, .cvtsd2 }, |
| 19083 | | dst_reg, |
| 19084 | | dst_reg, |
| 19085 | | try promote_mcv.mem(self, .qword), |
| 19086 | | ) else try self.asmRegisterRegisterRegister( |
| 19087 | | .{ .v_ss, .cvtsd2 }, |
| 19088 | | dst_reg, |
| 19089 | | dst_reg, |
| 19090 | | (if (promote_mcv.isRegister()) |
| 19091 | | promote_mcv.getReg().? |
| 19092 | | else |
| 19093 | | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| 19094 | | ) else if (promote_mcv.isMemory()) try self.asmRegisterMemory( |
| 19095 | | .{ ._ss, .cvtsd2 }, |
| 19096 | | dst_reg, |
| 19097 | | try promote_mcv.mem(self, .qword), |
| 19098 | | ) else try self.asmRegisterRegister( |
| 19099 | | .{ ._ss, .cvtsd2 }, |
| 19100 | | dst_reg, |
| 19101 | | (if (promote_mcv.isRegister()) |
| 19102 | | promote_mcv.getReg().? |
| 19103 | | else |
| 19104 | | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), |
| 19105 | | ); |
| 19106 | | break :result promote_mcv; |
| 19107 | | }, |
| 19108 | | .x86_64_win => return self.fail("TODO implement c_va_arg for Win64", .{}), |
| 27941 | fn floatLibcAbiSuffix(ty: Type) []const u8 { |
| 27942 | return switch (ty.toIntern()) { |
| 27943 | .f16_type => "h", |
| 27944 | .f32_type => "f", |
| 27945 | .f64_type => "", |
| 27946 | .f80_type => "x", |
| 27947 | .f128_type => "q", |
| 27948 | .c_longdouble_type => "l", |
| 19109 | 27949 | else => unreachable, |
| 19110 | 27950 | }; |
| 19111 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 19112 | 27951 | } |
| 19113 | 27952 | |
| 19114 | | fn airVaCopy(self: *Self, inst: Air.Inst.Index) !void { |
| 19115 | | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 19116 | | const ptr_va_list_ty = self.typeOf(ty_op.operand); |
| 27953 | fn promoteInt(self: *CodeGen, ty: Type) Type { |
| 27954 | const pt = self.pt; |
| 27955 | const zcu = pt.zcu; |
| 27956 | const int_info: InternPool.Key.IntType = switch (ty.toIntern()) { |
| 27957 | .bool_type => .{ .signedness = .unsigned, .bits = 1 }, |
| 27958 | else => if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else return ty, |
| 27959 | }; |
| 27960 | for ([_]Type{ |
| 27961 | .c_int, .c_uint, |
| 27962 | .c_long, .c_ulong, |
| 27963 | .c_longlong, .c_ulonglong, |
| 27964 | }) |promote_ty| { |
| 27965 | const promote_info = promote_ty.intInfo(zcu); |
| 27966 | if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue; |
| 27967 | if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and |
| 27968 | promote_info.signedness == .signed) <= promote_info.bits) return promote_ty; |
| 27969 | } |
| 27970 | return ty; |
| 27971 | } |
| 19117 | 27972 | |
| 19118 | | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 19119 | | try self.load(dst_mcv, ptr_va_list_ty, .{ .air_ref = ty_op.operand }); |
| 19120 | | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 27973 | fn promoteVarArg(self: *CodeGen, ty: Type) Type { |
| 27974 | if (!ty.isRuntimeFloat()) return self.promoteInt(ty); |
| 27975 | switch (ty.floatBits(self.target.*)) { |
| 27976 | 32, 64 => return .f64, |
| 27977 | else => |float_bits| { |
| 27978 | assert(float_bits == self.target.cTypeBitSize(.longdouble)); |
| 27979 | return .c_longdouble; |
| 27980 | }, |
| 27981 | } |
| 19121 | 27982 | } |
| 19122 | 27983 | |
| 19123 | | fn airVaEnd(self: *Self, inst: Air.Inst.Index) !void { |
| 19124 | | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 19125 | | return self.finishAir(inst, .unreach, .{ un_op, .none, .none }); |
| 27984 | fn intInfo(ty: Type, cg: *CodeGen) ?std.builtin.Type.Int { |
| 27985 | const zcu = cg.pt.zcu; |
| 27986 | const ip = &zcu.intern_pool; |
| 27987 | var ty_index = ty.ip_index; |
| 27988 | while (true) switch (ip.indexToKey(ty_index)) { |
| 27989 | .int_type => |int_type| return int_type, |
| 27990 | .ptr_type => |ptr_type| return switch (ptr_type.flags.size) { |
| 27991 | .one, .many, .c => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() }, |
| 27992 | .slice => null, |
| 27993 | }, |
| 27994 | .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBitsIgnoreComptime(zcu)) |
| 27995 | .{ .signedness = .unsigned, .bits = 1 } |
| 27996 | else switch (ip.indexToKey(opt_child)) { |
| 27997 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 27998 | .one, .many => switch (ptr_type.flags.is_allowzero) { |
| 27999 | false => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() }, |
| 28000 | true => null, |
| 28001 | }, |
| 28002 | .slice, .c => null, |
| 28003 | }, |
| 28004 | else => null, |
| 28005 | }, |
| 28006 | .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type) |
| 28007 | .hasRuntimeBitsIgnoreComptime(zcu)) .{ .signedness = .unsigned, .bits = zcu.errorSetBits() } else null, |
| 28008 | .simple_type => |simple_type| return switch (simple_type) { |
| 28009 | .bool => .{ .signedness = .unsigned, .bits = 1 }, |
| 28010 | .anyerror => .{ .signedness = .unsigned, .bits = zcu.errorSetBits() }, |
| 28011 | .isize => .{ .signedness = .signed, .bits = cg.target.ptrBitWidth() }, |
| 28012 | .usize => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() }, |
| 28013 | .c_char => .{ .signedness = cg.target.charSignedness(), .bits = cg.target.cTypeBitSize(.char) }, |
| 28014 | .c_short => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.short) }, |
| 28015 | .c_ushort => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.short) }, |
| 28016 | .c_int => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.int) }, |
| 28017 | .c_uint => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.int) }, |
| 28018 | .c_long => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.long) }, |
| 28019 | .c_ulong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.long) }, |
| 28020 | .c_longlong => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.longlong) }, |
| 28021 | .c_ulonglong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.longlong) }, |
| 28022 | .f16, .f32, .f64, .f80, .f128, .c_longdouble => null, |
| 28023 | .anyopaque, |
| 28024 | .void, |
| 28025 | .type, |
| 28026 | .comptime_int, |
| 28027 | .comptime_float, |
| 28028 | .noreturn, |
| 28029 | .null, |
| 28030 | .undefined, |
| 28031 | .enum_literal, |
| 28032 | .adhoc_inferred_error_set, |
| 28033 | .generic_poison, |
| 28034 | => unreachable, |
| 28035 | }, |
| 28036 | .struct_type => { |
| 28037 | const loaded_struct = ip.loadStructType(ty_index); |
| 28038 | switch (loaded_struct.layout) { |
| 28039 | .auto, .@"extern" => return null, |
| 28040 | .@"packed" => ty_index = loaded_struct.backingIntTypeUnordered(ip), |
| 28041 | } |
| 28042 | }, |
| 28043 | .union_type => return switch (ip.loadUnionType(ty_index).flagsUnordered(ip).layout) { |
| 28044 | .auto, .@"extern" => null, |
| 28045 | .@"packed" => .{ .signedness = .unsigned, .bits = @intCast(ty.bitSize(zcu)) }, |
| 28046 | }, |
| 28047 | .enum_type => ty_index = ip.loadEnumType(ty_index).tag_ty, |
| 28048 | .error_set_type, .inferred_error_set_type => return .{ .signedness = .unsigned, .bits = zcu.errorSetBits() }, |
| 28049 | else => return null, |
| 28050 | }; |
| 19126 | 28051 | } |
| 19127 | 28052 | |
| 19128 | | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |
| 19129 | | const zcu = self.pt.zcu; |
| 19130 | | const ty = self.typeOf(ref); |
| 28053 | const Temp = struct { |
| 28054 | index: Air.Inst.Index, |
| 19131 | 28055 | |
| 19132 | | // If the type has no codegen bits, no need to store it. |
| 19133 | | if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return .none; |
| 28056 | fn unwrap(temp: Temp, cg: *CodeGen) union(enum) { |
| 28057 | ref: Air.Inst.Ref, |
| 28058 | temp: Index, |
| 28059 | } { |
| 28060 | switch (temp.index.unwrap()) { |
| 28061 | .ref => |ref| return .{ .ref = ref }, |
| 28062 | .target => |target_index| { |
| 28063 | const temp_index: Index = @enumFromInt(target_index); |
| 28064 | assert(temp_index.isValid(cg)); |
| 28065 | return .{ .temp = temp_index }; |
| 28066 | }, |
| 28067 | } |
| 28068 | } |
| 19134 | 28069 | |
| 19135 | | const mcv = if (ref.toIndex()) |inst| mcv: { |
| 19136 | | break :mcv self.inst_tracking.getPtr(inst).?.short; |
| 19137 | | } else mcv: { |
| 19138 | | const ip_index = ref.toInterned().?; |
| 19139 | | const gop = try self.const_tracking.getOrPut(self.gpa, ip_index); |
| 19140 | | if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(init: { |
| 19141 | | const const_mcv = try self.genTypedValue(Value.fromInterned(ip_index)); |
| 19142 | | switch (const_mcv) { |
| 19143 | | .lea_tlv => |tlv_sym| switch (self.bin_file.tag) { |
| 19144 | | .elf, .macho => { |
| 19145 | | if (self.mod.pic) { |
| 19146 | | try self.spillRegisters(&.{ .rdi, .rax }); |
| 19147 | | } else { |
| 19148 | | try self.spillRegisters(&.{.rax}); |
| 28070 | fn typeOf(temp: Temp, cg: *CodeGen) Type { |
| 28071 | return switch (temp.unwrap(cg)) { |
| 28072 | .ref => |ref| cg.typeOf(ref), |
| 28073 | .temp => |temp_index| temp_index.typeOf(cg), |
| 28074 | }; |
| 28075 | } |
| 28076 | |
| 28077 | fn isMut(temp: Temp, cg: *CodeGen) bool { |
| 28078 | return switch (temp.unwrap(cg)) { |
| 28079 | .ref => false, |
| 28080 | .temp => |temp_index| switch (temp_index.tracking(cg).short) { |
| 28081 | .none, |
| 28082 | .unreach, |
| 28083 | .dead, |
| 28084 | .undef, |
| 28085 | .immediate, |
| 28086 | .eflags, |
| 28087 | .register_offset, |
| 28088 | .register_mask, |
| 28089 | .memory, |
| 28090 | .load_symbol, |
| 28091 | .lea_symbol, |
| 28092 | .indirect, |
| 28093 | .load_direct, |
| 28094 | .lea_direct, |
| 28095 | .load_got, |
| 28096 | .lea_got, |
| 28097 | .load_tlv, |
| 28098 | .lea_tlv, |
| 28099 | .lea_frame, |
| 28100 | .elementwise_regs_then_frame, |
| 28101 | .reserved_frame, |
| 28102 | .air_ref, |
| 28103 | => false, |
| 28104 | .register, |
| 28105 | .register_pair, |
| 28106 | .register_triple, |
| 28107 | .register_quadruple, |
| 28108 | .register_overflow, |
| 28109 | => true, |
| 28110 | .load_frame => |frame_addr| !frame_addr.index.isNamed(), |
| 28111 | }, |
| 28112 | }; |
| 28113 | } |
| 28114 | |
| 28115 | fn tracking(temp: Temp, cg: *CodeGen) InstTracking { |
| 28116 | return cg.inst_tracking.get(temp.index).?; |
| 28117 | } |
| 28118 | |
| 28119 | fn getOffset(temp: Temp, off: i32, cg: *CodeGen) !Temp { |
| 28120 | const new_temp_index = cg.next_temp_index; |
| 28121 | cg.temp_type[@intFromEnum(new_temp_index)] = .usize; |
| 28122 | cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1); |
| 28123 | switch (temp.tracking(cg).short) { |
| 28124 | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28125 | .register => |reg| { |
| 28126 | const new_reg = |
| 28127 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28128 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28129 | try cg.asmRegisterMemory(.{ ._, .lea }, new_reg.to64(), .{ |
| 28130 | .base = .{ .reg = reg.to64() }, |
| 28131 | .mod = .{ .rm = .{ |
| 28132 | .size = .qword, |
| 28133 | .disp = off, |
| 28134 | } }, |
| 28135 | }); |
| 28136 | }, |
| 28137 | .register_offset => |reg_off| { |
| 28138 | const new_reg = |
| 28139 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28140 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28141 | try cg.asmRegisterMemory(.{ ._, .lea }, new_reg.to64(), .{ |
| 28142 | .base = .{ .reg = reg_off.reg.to64() }, |
| 28143 | .mod = .{ .rm = .{ |
| 28144 | .size = .qword, |
| 28145 | .disp = reg_off.off + off, |
| 28146 | } }, |
| 28147 | }); |
| 28148 | }, |
| 28149 | .lea_symbol => |sym_off| new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = .{ |
| 28150 | .sym_index = sym_off.sym_index, |
| 28151 | .off = sym_off.off + off, |
| 28152 | } }), |
| 28153 | .load_frame => |frame_addr| { |
| 28154 | const new_reg = |
| 28155 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28156 | new_temp_index.tracking(cg).* = .init(.{ .register_offset = .{ |
| 28157 | .reg = new_reg, |
| 28158 | .off = off, |
| 28159 | } }); |
| 28160 | try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ |
| 28161 | .base = .{ .frame = frame_addr.index }, |
| 28162 | .mod = .{ .rm = .{ |
| 28163 | .size = .qword, |
| 28164 | .disp = frame_addr.off, |
| 28165 | } }, |
| 28166 | }); |
| 28167 | }, |
| 28168 | .lea_frame => |frame_addr| new_temp_index.tracking(cg).* = .init(.{ .lea_frame = .{ |
| 28169 | .index = frame_addr.index, |
| 28170 | .off = frame_addr.off + off, |
| 28171 | } }), |
| 28172 | } |
| 28173 | return .{ .index = new_temp_index.toIndex() }; |
| 28174 | } |
| 28175 | |
| 28176 | fn toOffset(temp: *Temp, off: i32, cg: *CodeGen) !void { |
| 28177 | if (off == 0) return; |
| 28178 | switch (temp.unwrap(cg)) { |
| 28179 | .ref => {}, |
| 28180 | .temp => |temp_index| { |
| 28181 | const temp_tracking = temp_index.tracking(cg); |
| 28182 | switch (temp_tracking.short) { |
| 28183 | else => {}, |
| 28184 | .register => |reg| { |
| 28185 | try cg.freeValue(temp_tracking.long); |
| 28186 | temp_tracking.* = .init(.{ .register_offset = .{ |
| 28187 | .reg = reg, |
| 28188 | .off = off, |
| 28189 | } }); |
| 28190 | return; |
| 28191 | }, |
| 28192 | .register_offset => |reg_off| { |
| 28193 | try cg.freeValue(temp_tracking.long); |
| 28194 | temp_tracking.* = .init(.{ .register_offset = .{ |
| 28195 | .reg = reg_off.reg, |
| 28196 | .off = reg_off.off + off, |
| 28197 | } }); |
| 28198 | return; |
| 28199 | }, |
| 28200 | .lea_symbol => |sym_off| { |
| 28201 | assert(std.meta.eql(temp_tracking.long.lea_symbol, sym_off)); |
| 28202 | temp_tracking.* = .init(.{ .lea_symbol = .{ |
| 28203 | .sym_index = sym_off.sym_index, |
| 28204 | .off = sym_off.off + off, |
| 28205 | } }); |
| 28206 | return; |
| 28207 | }, |
| 28208 | .lea_frame => |frame_addr| { |
| 28209 | assert(std.meta.eql(temp_tracking.long.lea_frame, frame_addr)); |
| 28210 | temp_tracking.* = .init(.{ .lea_frame = .{ |
| 28211 | .index = frame_addr.index, |
| 28212 | .off = frame_addr.off + off, |
| 28213 | } }); |
| 28214 | return; |
| 28215 | }, |
| 28216 | } |
| 28217 | }, |
| 28218 | } |
| 28219 | const new_temp = try temp.getOffset(off, cg); |
| 28220 | try temp.die(cg); |
| 28221 | temp.* = new_temp; |
| 28222 | } |
| 28223 | |
| 28224 | fn getLimb(temp: Temp, limb_ty: Type, limb_index: u28, cg: *CodeGen) !Temp { |
| 28225 | const new_temp_index = cg.next_temp_index; |
| 28226 | cg.temp_type[@intFromEnum(new_temp_index)] = limb_ty; |
| 28227 | switch (temp.tracking(cg).short) { |
| 28228 | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28229 | .immediate => |imm| { |
| 28230 | assert(limb_index == 0); |
| 28231 | new_temp_index.tracking(cg).* = .init(.{ .immediate = imm }); |
| 28232 | }, |
| 28233 | .register => |reg| { |
| 28234 | assert(limb_index == 0); |
| 28235 | const new_reg = |
| 28236 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28237 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28238 | try cg.asmRegisterRegister(.{ ._, .mov }, new_reg.to64(), reg.to64()); |
| 28239 | }, |
| 28240 | .register_pair => |regs| { |
| 28241 | const new_reg = |
| 28242 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28243 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28244 | try cg.asmRegisterRegister(.{ ._, .mov }, new_reg.to64(), regs[limb_index].to64()); |
| 28245 | }, |
| 28246 | .register_offset => |reg_off| { |
| 28247 | assert(limb_index == 0); |
| 28248 | const new_reg = |
| 28249 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28250 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28251 | try cg.asmRegisterMemory(.{ ._, .lea }, new_reg.to64(), .{ |
| 28252 | .base = .{ .reg = reg_off.reg.to64() }, |
| 28253 | .mod = .{ .rm = .{ |
| 28254 | .size = .qword, |
| 28255 | .disp = reg_off.off + @as(u31, limb_index) * 8, |
| 28256 | } }, |
| 28257 | }); |
| 28258 | }, |
| 28259 | .load_symbol => |sym_off| { |
| 28260 | const new_reg = |
| 28261 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28262 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28263 | try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ |
| 28264 | .base = .{ .reloc = sym_off.sym_index }, |
| 28265 | .mod = .{ .rm = .{ |
| 28266 | .size = .qword, |
| 28267 | .disp = sym_off.off + @as(u31, limb_index) * 8, |
| 28268 | } }, |
| 28269 | }); |
| 28270 | }, |
| 28271 | .lea_symbol => |sym_off| { |
| 28272 | assert(limb_index == 0); |
| 28273 | new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off }); |
| 28274 | }, |
| 28275 | .load_frame => |frame_addr| { |
| 28276 | const new_reg = |
| 28277 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28278 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28279 | try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ |
| 28280 | .base = .{ .frame = frame_addr.index }, |
| 28281 | .mod = .{ .rm = .{ |
| 28282 | .size = .qword, |
| 28283 | .disp = frame_addr.off + @as(u31, limb_index) * 8, |
| 28284 | } }, |
| 28285 | }); |
| 28286 | }, |
| 28287 | .lea_frame => |frame_addr| { |
| 28288 | assert(limb_index == 0); |
| 28289 | new_temp_index.tracking(cg).* = .init(.{ .lea_frame = frame_addr }); |
| 28290 | }, |
| 28291 | } |
| 28292 | cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1); |
| 28293 | return .{ .index = new_temp_index.toIndex() }; |
| 28294 | } |
| 28295 | |
| 28296 | fn toLimb(temp: *Temp, limb_ty: Type, limb_index: u28, cg: *CodeGen) !void { |
| 28297 | switch (temp.unwrap(cg)) { |
| 28298 | .ref => {}, |
| 28299 | .temp => |temp_index| { |
| 28300 | const temp_tracking = temp_index.tracking(cg); |
| 28301 | switch (temp_tracking.short) { |
| 28302 | else => {}, |
| 28303 | .register, .lea_symbol, .lea_frame => { |
| 28304 | assert(limb_index == 0); |
| 28305 | cg.temp_type[@intFromEnum(temp_index)] = limb_ty; |
| 28306 | return; |
| 28307 | }, |
| 28308 | .register_pair => |regs| { |
| 28309 | switch (temp_tracking.long) { |
| 28310 | .none, .reserved_frame => {}, |
| 28311 | else => temp_tracking.long = |
| 28312 | temp_tracking.long.address().offset(@as(u31, limb_index) * 8).deref(), |
| 19149 | 28313 | } |
| 19150 | | const frame_index = try self.allocFrameIndex(FrameAlloc.init(.{ |
| 19151 | | .size = 8, |
| 19152 | | .alignment = .@"8", |
| 19153 | | })); |
| 19154 | | try self.genSetMem( |
| 19155 | | .{ .frame = frame_index }, |
| 19156 | | 0, |
| 19157 | | Type.usize, |
| 19158 | | .{ .lea_symbol = .{ .sym_index = tlv_sym } }, |
| 19159 | | .{}, |
| 19160 | | ); |
| 19161 | | break :init .{ .load_frame = .{ .index = frame_index } }; |
| 28314 | for (regs, 0..) |reg, reg_index| if (reg_index != limb_index) |
| 28315 | cg.register_manager.freeReg(reg); |
| 28316 | temp_tracking.* = .init(.{ .register = regs[limb_index] }); |
| 28317 | cg.temp_type[@intFromEnum(temp_index)] = limb_ty; |
| 28318 | return; |
| 19162 | 28319 | }, |
| 19163 | | else => break :init const_mcv, |
| 19164 | | }, |
| 19165 | | else => break :init const_mcv, |
| 19166 | | } |
| 19167 | | }); |
| 19168 | | break :mcv gop.value_ptr.short; |
| 19169 | | }; |
| 28320 | .load_symbol => |sym_off| { |
| 28321 | assert(std.meta.eql(temp_tracking.long.load_symbol, sym_off)); |
| 28322 | temp_tracking.* = .init(.{ .load_symbol = .{ |
| 28323 | .sym_index = sym_off.sym_index, |
| 28324 | .off = sym_off.off + @as(u31, limb_index) * 8, |
| 28325 | } }); |
| 28326 | cg.temp_type[@intFromEnum(temp_index)] = limb_ty; |
| 28327 | return; |
| 28328 | }, |
| 28329 | .load_frame => |frame_addr| if (!frame_addr.index.isNamed()) { |
| 28330 | assert(std.meta.eql(temp_tracking.long.load_frame, frame_addr)); |
| 28331 | temp_tracking.* = .init(.{ .load_frame = .{ |
| 28332 | .index = frame_addr.index, |
| 28333 | .off = frame_addr.off + @as(u31, limb_index) * 8, |
| 28334 | } }); |
| 28335 | cg.temp_type[@intFromEnum(temp_index)] = limb_ty; |
| 28336 | return; |
| 28337 | }, |
| 28338 | } |
| 28339 | }, |
| 28340 | } |
| 28341 | const new_temp = try temp.getLimb(limb_ty, limb_index, cg); |
| 28342 | try temp.die(cg); |
| 28343 | temp.* = new_temp; |
| 28344 | } |
| 19170 | 28345 | |
| 19171 | | switch (mcv) { |
| 19172 | | .none, .unreach, .dead => unreachable, |
| 19173 | | else => return mcv, |
| 28346 | fn toSlicePtr(temp: *Temp, cg: *CodeGen) !void { |
| 28347 | const temp_ty = temp.typeOf(cg); |
| 28348 | if (temp_ty.isSlice(cg.pt.zcu)) try temp.toLimb(temp_ty.slicePtrFieldType(cg.pt.zcu), 0, cg); |
| 28349 | } |
| 28350 | |
| 28351 | fn toSliceLen(temp: *Temp, cg: *CodeGen) !void { |
| 28352 | try temp.toLimb(.usize, 1, cg); |
| 19174 | 28353 | } |
| 19175 | | } |
| 19176 | 28354 | |
| 19177 | | fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking { |
| 19178 | | const tracking = self.inst_tracking.getPtr(inst).?; |
| 19179 | | return switch (tracking.short) { |
| 19180 | | .none, .unreach, .dead => unreachable, |
| 19181 | | else => tracking, |
| 19182 | | }; |
| 19183 | | } |
| 28355 | fn toReg(temp: *Temp, new_reg: Register, cg: *CodeGen) !bool { |
| 28356 | const val, const ty = val_ty: switch (temp.unwrap(cg)) { |
| 28357 | .ref => |ref| .{ temp.tracking(cg).short, cg.typeOf(ref) }, |
| 28358 | .temp => |temp_index| { |
| 28359 | const temp_tracking = temp_index.tracking(cg); |
| 28360 | if (temp_tracking.short == .register and |
| 28361 | temp_tracking.short.register == new_reg) return false; |
| 28362 | break :val_ty .{ temp_tracking.short, temp_index.typeOf(cg) }; |
| 28363 | }, |
| 28364 | }; |
| 28365 | const new_temp_index = cg.next_temp_index; |
| 28366 | try cg.register_manager.getReg(new_reg, new_temp_index.toIndex()); |
| 28367 | cg.temp_type[@intFromEnum(new_temp_index)] = ty; |
| 28368 | try cg.genSetReg(new_reg, ty, val, .{}); |
| 28369 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28370 | try temp.die(cg); |
| 28371 | cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1); |
| 28372 | temp.* = .{ .index = new_temp_index.toIndex() }; |
| 28373 | return true; |
| 28374 | } |
| 19184 | 28375 | |
| 19185 | | /// If the MCValue is an immediate, and it does not fit within this type, |
| 19186 | | /// we put it in a register. |
| 19187 | | /// A potential opportunity for future optimization here would be keeping track |
| 19188 | | /// of the fact that the instruction is available both as an immediate |
| 19189 | | /// and as a register. |
| 19190 | | fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCValue { |
| 19191 | | const mcv = try self.resolveInst(operand); |
| 19192 | | const ti = @typeInfo(T).int; |
| 19193 | | switch (mcv) { |
| 19194 | | .immediate => |imm| { |
| 19195 | | // This immediate is unsigned. |
| 19196 | | const U = std.meta.Int(.unsigned, ti.bits - @intFromBool(ti.signedness == .signed)); |
| 19197 | | if (imm >= math.maxInt(U)) { |
| 19198 | | return MCValue{ .register = try self.copyToTmpRegister(Type.usize, mcv) }; |
| 19199 | | } |
| 19200 | | }, |
| 19201 | | else => {}, |
| 28376 | fn toRegClass(temp: *Temp, mut: bool, rc: Register.Class, cg: *CodeGen) !bool { |
| 28377 | const val = temp.tracking(cg).short; |
| 28378 | if (!mut or temp.isMut(cg)) switch (val) { |
| 28379 | else => {}, |
| 28380 | .register => |reg| if (reg.class() == rc) return false, |
| 28381 | .register_offset => |reg_off| if (reg_off.reg.class() == rc and reg_off.off == 0) return false, |
| 28382 | }; |
| 28383 | const ty = temp.typeOf(cg); |
| 28384 | const new_temp_index = cg.next_temp_index; |
| 28385 | cg.temp_type[@intFromEnum(new_temp_index)] = ty; |
| 28386 | const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), regSetForRegClass(rc)); |
| 28387 | try cg.genSetReg(new_reg, ty, val, .{}); |
| 28388 | new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); |
| 28389 | try temp.die(cg); |
| 28390 | cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1); |
| 28391 | temp.* = .{ .index = new_temp_index.toIndex() }; |
| 28392 | return true; |
| 19202 | 28393 | } |
| 19203 | | return mcv; |
| 19204 | | } |
| 19205 | 28394 | |
| 19206 | | fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 19207 | | const pt = self.pt; |
| 19208 | | return switch (try codegen.genTypedValue(self.bin_file, pt, self.src_loc, val, self.target.*)) { |
| 19209 | | .mcv => |mcv| switch (mcv) { |
| 19210 | | .none => .none, |
| 19211 | | .undef => .undef, |
| 19212 | | .immediate => |imm| .{ .immediate = imm }, |
| 19213 | | .memory => |addr| .{ .memory = addr }, |
| 19214 | | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym_index = sym_index } }, |
| 19215 | | .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index } }, |
| 19216 | | .load_direct => |sym_index| .{ .load_direct = sym_index }, |
| 19217 | | .lea_direct => |sym_index| .{ .lea_direct = sym_index }, |
| 19218 | | .load_got => |sym_index| .{ .lea_got = sym_index }, |
| 19219 | | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, |
| 19220 | | }, |
| 19221 | | .fail => |msg| return self.failMsg(msg), |
| 19222 | | }; |
| 19223 | | } |
| 28395 | fn toPair(first_temp: *Temp, second_temp: *Temp, cg: *CodeGen) !void { |
| 28396 | while (true) for ([_]*Temp{ first_temp, second_temp }) |part_temp| { |
| 28397 | if (try part_temp.toRegClass(true, .general_purpose, cg)) break; |
| 28398 | } else break; |
| 28399 | const first_temp_tracking = first_temp.unwrap(cg).temp.tracking(cg); |
| 28400 | const second_temp_tracking = second_temp.unwrap(cg).temp.tracking(cg); |
| 28401 | const result: MCValue = .{ .register_pair = .{ |
| 28402 | first_temp_tracking.short.register, |
| 28403 | second_temp_tracking.short.register, |
| 28404 | } }; |
| 28405 | const result_temp_index = cg.next_temp_index; |
| 28406 | const result_temp: Temp = .{ .index = result_temp_index.toIndex() }; |
| 28407 | assert(cg.reuseTemp(result_temp.index, first_temp.index, first_temp_tracking)); |
| 28408 | assert(cg.reuseTemp(result_temp.index, second_temp.index, second_temp_tracking)); |
| 28409 | cg.temp_type[@intFromEnum(result_temp_index)] = .slice_const_u8; |
| 28410 | result_temp_index.tracking(cg).* = .init(result); |
| 28411 | first_temp.* = result_temp; |
| 28412 | } |
| 19224 | 28413 | |
| 19225 | | const CallMCValues = struct { |
| 19226 | | args: []MCValue, |
| 19227 | | return_value: InstTracking, |
| 19228 | | stack_byte_count: u31, |
| 19229 | | stack_align: Alignment, |
| 19230 | | gp_count: u32, |
| 19231 | | fp_count: u32, |
| 28414 | fn asMask(temp: Temp, info: MaskInfo, cg: *CodeGen) void { |
| 28415 | assert(info.scalar != .none); |
| 28416 | const mcv = &temp.unwrap(cg).temp.tracking(cg).short; |
| 28417 | const reg = mcv.register; |
| 28418 | mcv.* = .{ .register_mask = .{ .reg = reg, .info = info } }; |
| 28419 | } |
| 19232 | 28420 | |
| 19233 | | fn deinit(self: *CallMCValues, func: *Self) void { |
| 19234 | | func.gpa.free(self.args); |
| 19235 | | self.* = undefined; |
| 28421 | fn toLea(temp: *Temp, cg: *CodeGen) !bool { |
| 28422 | switch (temp.tracking(cg).short) { |
| 28423 | .none, |
| 28424 | .unreach, |
| 28425 | .dead, |
| 28426 | .undef, |
| 28427 | .eflags, |
| 28428 | .register_pair, |
| 28429 | .register_triple, |
| 28430 | .register_quadruple, |
| 28431 | .register_overflow, |
| 28432 | .register_mask, |
| 28433 | .elementwise_regs_then_frame, |
| 28434 | .reserved_frame, |
| 28435 | .air_ref, |
| 28436 | => unreachable, // not a valid pointer |
| 28437 | .immediate, |
| 28438 | .register, |
| 28439 | .register_offset, |
| 28440 | .lea_direct, |
| 28441 | .lea_got, |
| 28442 | .lea_tlv, |
| 28443 | .lea_frame, |
| 28444 | => return false, |
| 28445 | .memory, |
| 28446 | .indirect, |
| 28447 | .load_symbol, |
| 28448 | .load_direct, |
| 28449 | .load_got, |
| 28450 | .load_tlv, |
| 28451 | .load_frame, |
| 28452 | => return temp.toRegClass(true, .general_purpose, cg), |
| 28453 | .lea_symbol => |sym_off| { |
| 28454 | const off = sym_off.off; |
| 28455 | if (off == 0) return false; |
| 28456 | try temp.toOffset(-off, cg); |
| 28457 | while (try temp.toRegClass(true, .general_purpose, cg)) {} |
| 28458 | try temp.toOffset(off, cg); |
| 28459 | return true; |
| 28460 | }, |
| 28461 | } |
| 19236 | 28462 | } |
| 19237 | | }; |
| 19238 | 28463 | |
| 19239 | | /// Caller must call `CallMCValues.deinit`. |
| 19240 | | fn resolveCallingConventionValues( |
| 19241 | | self: *Self, |
| 19242 | | fn_info: InternPool.Key.FuncType, |
| 19243 | | var_args: []const Type, |
| 19244 | | stack_frame_base: FrameIndex, |
| 19245 | | ) !CallMCValues { |
| 19246 | | const pt = self.pt; |
| 19247 | | const zcu = pt.zcu; |
| 19248 | | const ip = &zcu.intern_pool; |
| 19249 | | const cc = fn_info.cc; |
| 19250 | | const param_types = try self.gpa.alloc(Type, fn_info.param_types.len + var_args.len); |
| 19251 | | defer self.gpa.free(param_types); |
| 28464 | fn toMemory(temp: *Temp, cg: *CodeGen) !bool { |
| 28465 | const temp_tracking = temp.tracking(cg); |
| 28466 | if (temp_tracking.short.isMemory()) return false; |
| 28467 | const new_temp_index = cg.next_temp_index; |
| 28468 | const ty = temp.typeOf(cg); |
| 28469 | cg.temp_type[@intFromEnum(new_temp_index)] = ty; |
| 28470 | const new_frame_index = try cg.allocFrameIndex(.initSpill(ty, cg.pt.zcu)); |
| 28471 | try cg.genSetMem(.{ .frame = new_frame_index }, 0, ty, temp_tracking.short, .{}); |
| 28472 | new_temp_index.tracking(cg).* = .init(.{ .load_frame = .{ .index = new_frame_index } }); |
| 28473 | try temp.die(cg); |
| 28474 | cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1); |
| 28475 | temp.* = .{ .index = new_temp_index.toIndex() }; |
| 28476 | return true; |
| 28477 | } |
| 19252 | 28478 | |
| 19253 | | for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| { |
| 19254 | | dest.* = Type.fromInterned(src); |
| 28479 | // hack around linker relocation bugs |
| 28480 | fn toBase(temp: *Temp, cg: *CodeGen) !bool { |
| 28481 | const temp_tracking = temp.tracking(cg); |
| 28482 | if (temp_tracking.short.isBase()) return false; |
| 28483 | if (try temp.toMemory(cg)) return true; |
| 28484 | const new_temp_index = cg.next_temp_index; |
| 28485 | cg.temp_type[@intFromEnum(new_temp_index)] = temp.typeOf(cg); |
| 28486 | const new_reg = |
| 28487 | try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); |
| 28488 | try cg.genSetReg(new_reg, .usize, temp_tracking.short.address(), .{}); |
| 28489 | new_temp_index.tracking(cg).* = .init(.{ .indirect = .{ .reg = new_reg } }); |
| 28490 | try temp.die(cg); |
| 28491 | cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1); |
| 28492 | temp.* = .{ .index = new_temp_index.toIndex() }; |
| 28493 | return true; |
| 19255 | 28494 | } |
| 19256 | | for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| |
| 19257 | | param_ty.* = self.promoteVarArg(arg_ty); |
| 19258 | 28495 | |
| 19259 | | var result: CallMCValues = .{ |
| 19260 | | .args = try self.gpa.alloc(MCValue, param_types.len), |
| 19261 | | // These undefined values must be populated before returning from this function. |
| 19262 | | .return_value = undefined, |
| 19263 | | .stack_byte_count = 0, |
| 19264 | | .stack_align = undefined, |
| 19265 | | .gp_count = 0, |
| 19266 | | .fp_count = 0, |
| 28496 | const AccessOptions = struct { |
| 28497 | disp: i32 = 0, |
| 28498 | safe: bool = false, |
| 19267 | 28499 | }; |
| 19268 | | errdefer self.gpa.free(result.args); |
| 19269 | | |
| 19270 | | const ret_ty = Type.fromInterned(fn_info.return_type); |
| 19271 | 28500 | |
| 19272 | | const resolved_cc = abi.resolveCallingConvention(cc, self.target.*); |
| 19273 | | switch (cc) { |
| 19274 | | .naked => { |
| 19275 | | assert(result.args.len == 0); |
| 19276 | | result.return_value = InstTracking.init(.unreach); |
| 19277 | | result.stack_align = .@"8"; |
| 19278 | | }, |
| 19279 | | .x86_64_sysv, .x86_64_win => |cc_opts| { |
| 19280 | | var ret_int_reg_i: u32 = 0; |
| 19281 | | var ret_sse_reg_i: u32 = 0; |
| 19282 | | var param_int_reg_i: u32 = 0; |
| 19283 | | var param_sse_reg_i: u32 = 0; |
| 19284 | | result.stack_align = .fromByteUnits(cc_opts.incoming_stack_alignment orelse 16); |
| 28501 | fn load(ptr: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp { |
| 28502 | const val = try cg.tempAlloc(val_ty); |
| 28503 | try ptr.toOffset(opts.disp, cg); |
| 28504 | while (try ptr.toLea(cg)) {} |
| 28505 | const val_mcv = val.tracking(cg).short; |
| 28506 | switch (val_mcv) { |
| 28507 | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28508 | .register => |val_reg| try ptr.loadReg(val_ty, registerAlias( |
| 28509 | val_reg, |
| 28510 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28511 | ), cg), |
| 28512 | inline .register_pair, |
| 28513 | .register_triple, |
| 28514 | .register_quadruple, |
| 28515 | => |val_regs| for (val_regs) |val_reg| { |
| 28516 | try ptr.loadReg(val_ty, val_reg, cg); |
| 28517 | try ptr.toOffset(@divExact(val_reg.bitSize(), 8), cg); |
| 28518 | while (try ptr.toLea(cg)) {} |
| 28519 | }, |
| 28520 | .register_offset => |val_reg_off| switch (val_reg_off.off) { |
| 28521 | 0 => try ptr.loadReg(val_ty, registerAlias( |
| 28522 | val_reg_off.reg, |
| 28523 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28524 | ), cg), |
| 28525 | else => unreachable, |
| 28526 | }, |
| 28527 | .memory, .indirect, .load_frame, .load_symbol => { |
| 28528 | var val_ptr = try cg.tempInit(.usize, val_mcv.address()); |
| 28529 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28530 | try val_ptr.memcpy(ptr, &len, cg); |
| 28531 | try val_ptr.die(cg); |
| 28532 | try len.die(cg); |
| 28533 | }, |
| 28534 | } |
| 28535 | return val; |
| 28536 | } |
| 19285 | 28537 | |
| 19286 | | switch (resolved_cc) { |
| 19287 | | .x86_64_sysv => {}, |
| 19288 | | .x86_64_win => { |
| 19289 | | // Align the stack to 16bytes before allocating shadow stack space (if any). |
| 19290 | | result.stack_byte_count += @intCast(4 * Type.usize.abiSize(zcu)); |
| 28538 | fn store(ptr: *Temp, val: *Temp, opts: AccessOptions, cg: *CodeGen) !void { |
| 28539 | const val_ty = val.typeOf(cg); |
| 28540 | try ptr.toOffset(opts.disp, cg); |
| 28541 | while (try ptr.toLea(cg)) {} |
| 28542 | val_to_gpr: while (true) : (while (try ptr.toLea(cg) or |
| 28543 | try val.toRegClass(false, .general_purpose, cg)) |
| 28544 | {}) { |
| 28545 | const val_mcv = val.tracking(cg).short; |
| 28546 | switch (val_mcv) { |
| 28547 | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28548 | .undef => if (opts.safe) { |
| 28549 | var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa }); |
| 28550 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28551 | try ptr.memset(&pat, &len, cg); |
| 28552 | try pat.die(cg); |
| 28553 | try len.die(cg); |
| 28554 | }, |
| 28555 | .immediate => |val_imm| { |
| 28556 | const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31| |
| 28557 | .u(val_uimm31) |
| 28558 | else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32| |
| 28559 | .s(val_simm32) |
| 28560 | else |
| 28561 | continue :val_to_gpr; |
| 28562 | // hack around linker relocation bugs |
| 28563 | switch (ptr.tracking(cg).short) { |
| 28564 | else => {}, |
| 28565 | .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, |
| 28566 | } |
| 28567 | try cg.asmMemoryImmediate( |
| 28568 | .{ ._, .mov }, |
| 28569 | try ptr.tracking(cg).short.deref().mem(cg, .{ |
| 28570 | .size = cg.memSize(val_ty), |
| 28571 | }), |
| 28572 | val_op, |
| 28573 | ); |
| 28574 | }, |
| 28575 | .eflags => |cc| { |
| 28576 | // hack around linker relocation bugs |
| 28577 | switch (ptr.tracking(cg).short) { |
| 28578 | else => {}, |
| 28579 | .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, |
| 28580 | } |
| 28581 | try cg.asmSetccMemory( |
| 28582 | cc, |
| 28583 | try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }), |
| 28584 | ); |
| 28585 | }, |
| 28586 | .register => |val_reg| try ptr.storeRegs(val_ty, &.{registerAlias( |
| 28587 | val_reg, |
| 28588 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28589 | )}, cg), |
| 28590 | inline .register_pair, |
| 28591 | .register_triple, |
| 28592 | .register_quadruple, |
| 28593 | => |val_regs| try ptr.storeRegs(val_ty, &val_regs, cg), |
| 28594 | .register_offset => |val_reg_off| switch (val_reg_off.off) { |
| 28595 | 0 => try ptr.storeRegs(val_ty, &.{registerAlias( |
| 28596 | val_reg_off.reg, |
| 28597 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28598 | )}, cg), |
| 28599 | else => continue :val_to_gpr, |
| 28600 | }, |
| 28601 | .register_overflow => |val_reg_ov| { |
| 28602 | const ip = &cg.pt.zcu.intern_pool; |
| 28603 | const first_ty: Type = .fromInterned(first_ty: switch (ip.indexToKey(val_ty.toIntern())) { |
| 28604 | .tuple_type => |tuple_type| { |
| 28605 | const tuple_field_types = tuple_type.types.get(ip); |
| 28606 | assert(tuple_field_types.len == 2 and tuple_field_types[1] == .u1_type); |
| 28607 | break :first_ty tuple_field_types[0]; |
| 28608 | }, |
| 28609 | .opt_type => |opt_child| { |
| 28610 | assert(!val_ty.optionalReprIsPayload(cg.pt.zcu)); |
| 28611 | break :first_ty opt_child; |
| 28612 | }, |
| 28613 | else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }), |
| 28614 | }); |
| 28615 | const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu)); |
| 28616 | try ptr.storeRegs(first_ty, &.{registerAlias(val_reg_ov.reg, first_size)}, cg); |
| 28617 | try ptr.toOffset(first_size, cg); |
| 28618 | try cg.asmSetccMemory( |
| 28619 | val_reg_ov.eflags, |
| 28620 | try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }), |
| 28621 | ); |
| 28622 | }, |
| 28623 | .lea_frame, .lea_symbol => continue :val_to_gpr, |
| 28624 | .memory, .indirect, .load_frame, .load_symbol => { |
| 28625 | var val_ptr = try cg.tempInit(.usize, val_mcv.address()); |
| 28626 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28627 | try ptr.memcpy(&val_ptr, &len, cg); |
| 28628 | try val_ptr.die(cg); |
| 28629 | try len.die(cg); |
| 19291 | 28630 | }, |
| 19292 | | else => unreachable, |
| 19293 | 28631 | } |
| 28632 | break; |
| 28633 | } |
| 28634 | } |
| 19294 | 28635 | |
| 19295 | | // Return values |
| 19296 | | if (ret_ty.zigTypeTag(zcu) == .noreturn) { |
| 19297 | | result.return_value = InstTracking.init(.unreach); |
| 19298 | | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 19299 | | // TODO: is this even possible for C calling convention? |
| 19300 | | result.return_value = InstTracking.init(.none); |
| 19301 | | } else { |
| 19302 | | var ret_tracking: [2]InstTracking = undefined; |
| 19303 | | var ret_tracking_i: usize = 0; |
| 28636 | fn read(src: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp { |
| 28637 | var val = try cg.tempAlloc(val_ty); |
| 28638 | while (try src.toBase(cg)) {} |
| 28639 | const val_mcv = val.tracking(cg).short; |
| 28640 | switch (val_mcv) { |
| 28641 | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28642 | .register => |val_reg| try src.readReg(opts.disp, val_ty, registerAlias( |
| 28643 | val_reg, |
| 28644 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28645 | ), cg), |
| 28646 | inline .register_pair, .register_triple, .register_quadruple => |val_regs| { |
| 28647 | var disp = opts.disp; |
| 28648 | for (val_regs) |val_reg| { |
| 28649 | try src.readReg(disp, val_ty, val_reg, cg); |
| 28650 | disp += @divExact(val_reg.bitSize(), 8); |
| 28651 | } |
| 28652 | }, |
| 28653 | .register_offset => |val_reg_off| switch (val_reg_off.off) { |
| 28654 | 0 => try src.readReg(opts.disp, val_ty, registerAlias( |
| 28655 | val_reg_off.reg, |
| 28656 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28657 | ), cg), |
| 28658 | else => unreachable, |
| 28659 | }, |
| 28660 | .memory, .indirect, .load_frame, .load_symbol => { |
| 28661 | var val_ptr = try cg.tempInit(.usize, val_mcv.address()); |
| 28662 | var src_ptr = |
| 28663 | try cg.tempInit(.usize, src.tracking(cg).short.address().offset(opts.disp)); |
| 28664 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28665 | try val_ptr.memcpy(&src_ptr, &len, cg); |
| 28666 | try val_ptr.die(cg); |
| 28667 | try src_ptr.die(cg); |
| 28668 | try len.die(cg); |
| 28669 | }, |
| 28670 | } |
| 28671 | return val; |
| 28672 | } |
| 19304 | 28673 | |
| 19305 | | const classes = switch (resolved_cc) { |
| 19306 | | .x86_64_sysv => mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, self.target.*, .ret), .none), |
| 19307 | | .x86_64_win => &.{abi.classifyWindows(ret_ty, zcu)}, |
| 19308 | | else => unreachable, |
| 19309 | | }; |
| 19310 | | for (classes) |class| switch (class) { |
| 19311 | | .integer => { |
| 19312 | | const ret_int_reg = registerAlias( |
| 19313 | | abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i], |
| 19314 | | @intCast(@min(ret_ty.abiSize(zcu), 8)), |
| 19315 | | ); |
| 19316 | | ret_int_reg_i += 1; |
| 28674 | fn write(dst: *Temp, val: *Temp, opts: AccessOptions, cg: *CodeGen) !void { |
| 28675 | const val_ty = val.typeOf(cg); |
| 28676 | while (try dst.toBase(cg)) {} |
| 28677 | val_to_gpr: while (true) : (while (try dst.toBase(cg) or |
| 28678 | try val.toRegClass(false, .general_purpose, cg)) |
| 28679 | {}) { |
| 28680 | const val_mcv = val.tracking(cg).short; |
| 28681 | switch (val_mcv) { |
| 28682 | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28683 | .undef => if (opts.safe) { |
| 28684 | var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp)); |
| 28685 | var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa }); |
| 28686 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28687 | try dst_ptr.memset(&pat, &len, cg); |
| 28688 | try dst_ptr.die(cg); |
| 28689 | try pat.die(cg); |
| 28690 | try len.die(cg); |
| 28691 | }, |
| 28692 | .immediate => |val_imm| { |
| 28693 | const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31| |
| 28694 | .u(val_uimm31) |
| 28695 | else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32| |
| 28696 | .s(val_simm32) |
| 28697 | else |
| 28698 | continue :val_to_gpr; |
| 28699 | try cg.asmMemoryImmediate( |
| 28700 | .{ ._, .mov }, |
| 28701 | try dst.tracking(cg).short.mem(cg, .{ |
| 28702 | .size = cg.memSize(val_ty), |
| 28703 | .disp = opts.disp, |
| 28704 | }), |
| 28705 | val_op, |
| 28706 | ); |
| 28707 | }, |
| 28708 | .eflags => |cc| try cg.asmSetccMemory( |
| 28709 | cc, |
| 28710 | try dst.tracking(cg).short.mem(cg, .{ |
| 28711 | .size = .byte, |
| 28712 | .disp = opts.disp, |
| 28713 | }), |
| 28714 | ), |
| 28715 | .register => |val_reg| try dst.writeRegs(opts.disp, val_ty, &.{registerAlias( |
| 28716 | val_reg, |
| 28717 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28718 | )}, cg), |
| 28719 | inline .register_pair, |
| 28720 | .register_triple, |
| 28721 | .register_quadruple, |
| 28722 | => |val_regs| try dst.writeRegs(opts.disp, val_ty, &val_regs, cg), |
| 28723 | .register_offset => |val_reg_off| switch (val_reg_off.off) { |
| 28724 | 0 => try dst.writeRegs(opts.disp, val_ty, &.{registerAlias( |
| 28725 | val_reg_off.reg, |
| 28726 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28727 | )}, cg), |
| 28728 | else => continue :val_to_gpr, |
| 28729 | }, |
| 28730 | .register_overflow => |val_reg_ov| { |
| 28731 | const ip = &cg.pt.zcu.intern_pool; |
| 28732 | const first_ty: Type = .fromInterned(first_ty: switch (ip.indexToKey(val_ty.toIntern())) { |
| 28733 | .tuple_type => |tuple_type| { |
| 28734 | const tuple_field_types = tuple_type.types.get(ip); |
| 28735 | assert(tuple_field_types.len == 2 and tuple_field_types[1] == .u1_type); |
| 28736 | break :first_ty tuple_field_types[0]; |
| 28737 | }, |
| 28738 | .opt_type => |opt_child| { |
| 28739 | assert(!val_ty.optionalReprIsPayload(cg.pt.zcu)); |
| 28740 | break :first_ty opt_child; |
| 28741 | }, |
| 28742 | else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }), |
| 28743 | }); |
| 28744 | const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu)); |
| 28745 | try dst.writeRegs(opts.disp, first_ty, &.{registerAlias(val_reg_ov.reg, first_size)}, cg); |
| 28746 | try cg.asmSetccMemory( |
| 28747 | val_reg_ov.eflags, |
| 28748 | try dst.tracking(cg).short.mem(cg, .{ |
| 28749 | .size = .byte, |
| 28750 | .disp = opts.disp + first_size, |
| 28751 | }), |
| 28752 | ); |
| 28753 | }, |
| 28754 | .lea_frame, .lea_symbol => continue :val_to_gpr, |
| 28755 | .memory, .indirect, .load_frame, .load_symbol => { |
| 28756 | var dst_ptr = |
| 28757 | try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp)); |
| 28758 | var val_ptr = try cg.tempInit(.usize, val_mcv.address()); |
| 28759 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28760 | try dst_ptr.memcpy(&val_ptr, &len, cg); |
| 28761 | try dst_ptr.die(cg); |
| 28762 | try val_ptr.die(cg); |
| 28763 | try len.die(cg); |
| 28764 | }, |
| 28765 | } |
| 28766 | break; |
| 28767 | } |
| 28768 | } |
| 19317 | 28769 | |
| 19318 | | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg }); |
| 19319 | | ret_tracking_i += 1; |
| 19320 | | }, |
| 19321 | | .sse, .float, .float_combine, .win_i128 => { |
| 19322 | | const ret_sse_reg = registerAlias( |
| 19323 | | abi.getCAbiSseReturnRegs(resolved_cc)[ret_sse_reg_i], |
| 19324 | | @intCast(ret_ty.abiSize(zcu)), |
| 19325 | | ); |
| 19326 | | ret_sse_reg_i += 1; |
| 28770 | fn loadReg(ptr: *Temp, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void { |
| 28771 | const dst_rc = dst_reg.class(); |
| 28772 | const strat = try cg.moveStrategy(dst_ty, dst_rc, false); |
| 28773 | // hack around linker relocation bugs |
| 28774 | switch (ptr.tracking(cg).short) { |
| 28775 | else => {}, |
| 28776 | .lea_symbol => |sym_off| if (dst_rc != .general_purpose or sym_off.off != 0) |
| 28777 | while (try ptr.toRegClass(false, .general_purpose, cg)) {}, |
| 28778 | } |
| 28779 | try strat.read(cg, dst_reg, try ptr.tracking(cg).short.deref().mem(cg, .{ |
| 28780 | .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())), |
| 28781 | })); |
| 28782 | } |
| 19327 | 28783 | |
| 19328 | | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_sse_reg }); |
| 19329 | | ret_tracking_i += 1; |
| 19330 | | }, |
| 19331 | | .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse), |
| 19332 | | .x87 => { |
| 19333 | | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = .st0 }); |
| 19334 | | ret_tracking_i += 1; |
| 19335 | | }, |
| 19336 | | .x87up => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .x87), |
| 19337 | | .complex_x87 => { |
| 19338 | | ret_tracking[ret_tracking_i] = |
| 19339 | | InstTracking.init(.{ .register_pair = .{ .st0, .st1 } }); |
| 19340 | | ret_tracking_i += 1; |
| 19341 | | }, |
| 19342 | | .memory => { |
| 19343 | | const ret_int_reg = abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i].to64(); |
| 19344 | | ret_int_reg_i += 1; |
| 19345 | | const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i]; |
| 19346 | | param_int_reg_i += 1; |
| 28784 | fn storeRegs(ptr: *Temp, src_ty: Type, src_regs: []const Register, cg: *CodeGen) !void { |
| 28785 | var part_disp: u31 = 0; |
| 28786 | var deferred_disp: u31 = 0; |
| 28787 | var src_abi_size: u32 = @intCast(src_ty.abiSize(cg.pt.zcu)); |
| 28788 | for (src_regs) |src_reg| { |
| 28789 | const src_rc = src_reg.class(); |
| 28790 | const part_bit_size = @min(8 * src_abi_size, src_reg.bitSize()); |
| 28791 | const part_size = @divExact(part_bit_size, 8); |
| 28792 | if (src_rc == .x87 or std.math.isPowerOfTwo(part_size)) { |
| 28793 | // hack around linker relocation bugs |
| 28794 | switch (ptr.tracking(cg).short) { |
| 28795 | else => {}, |
| 28796 | .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, |
| 28797 | } |
| 28798 | const strat = try cg.moveStrategy(src_ty, src_rc, false); |
| 28799 | try strat.write(cg, try ptr.tracking(cg).short.deref().mem(cg, .{ |
| 28800 | .size = .fromBitSize(part_bit_size), |
| 28801 | .disp = part_disp, |
| 28802 | }), registerAlias(src_reg, part_size)); |
| 28803 | } else { |
| 28804 | const frame_size = std.math.ceilPowerOfTwoAssert(u32, part_size); |
| 28805 | const frame_index = try cg.allocFrameIndex(.init(.{ |
| 28806 | .size = frame_size, |
| 28807 | .alignment = .fromNonzeroByteUnits(frame_size), |
| 28808 | })); |
| 28809 | const strat = try cg.moveStrategy(src_ty, src_rc, true); |
| 28810 | try strat.write(cg, .{ |
| 28811 | .base = .{ .frame = frame_index }, |
| 28812 | .mod = .{ .rm = .{ .size = .fromSize(frame_size) } }, |
| 28813 | }, registerAlias(src_reg, frame_size)); |
| 28814 | try ptr.toOffset(deferred_disp, cg); |
| 28815 | deferred_disp = 0; |
| 28816 | var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } }); |
| 28817 | var len = try cg.tempInit(.usize, .{ .immediate = src_abi_size }); |
| 28818 | try ptr.memcpy(&src_ptr, &len, cg); |
| 28819 | try src_ptr.die(cg); |
| 28820 | try len.die(cg); |
| 28821 | } |
| 28822 | part_disp += part_size; |
| 28823 | deferred_disp += part_size; |
| 28824 | src_abi_size -= part_size; |
| 28825 | } |
| 28826 | } |
| 19347 | 28827 | |
| 19348 | | ret_tracking[ret_tracking_i] = .{ |
| 19349 | | .short = .{ .indirect = .{ .reg = ret_int_reg } }, |
| 19350 | | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 19351 | | }; |
| 19352 | | ret_tracking_i += 1; |
| 19353 | | }, |
| 19354 | | .none, .integer_per_element => unreachable, |
| 19355 | | }; |
| 19356 | | result.return_value = switch (ret_tracking_i) { |
| 19357 | | else => unreachable, |
| 19358 | | 1 => ret_tracking[0], |
| 19359 | | 2 => InstTracking.init(.{ .register_pair = .{ |
| 19360 | | ret_tracking[0].short.register, ret_tracking[1].short.register, |
| 19361 | | } }), |
| 19362 | | }; |
| 28828 | fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void { |
| 28829 | const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false); |
| 28830 | try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{ |
| 28831 | .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())), |
| 28832 | .disp = disp, |
| 28833 | })); |
| 28834 | } |
| 28835 | |
| 28836 | fn writeRegs(dst: Temp, disp: i32, src_ty: Type, src_regs: []const Register, cg: *CodeGen) !void { |
| 28837 | var part_disp = disp; |
| 28838 | var src_abi_size: u32 = @intCast(src_ty.abiSize(cg.pt.zcu)); |
| 28839 | for (src_regs) |src_reg| { |
| 28840 | const src_rc = src_reg.class(); |
| 28841 | const part_bit_size = @min(8 * src_abi_size, src_reg.bitSize()); |
| 28842 | const part_size = @divExact(part_bit_size, 8); |
| 28843 | if (src_rc == .x87 or std.math.isPowerOfTwo(part_size)) { |
| 28844 | const strat = try cg.moveStrategy(src_ty, src_rc, false); |
| 28845 | try strat.write(cg, try dst.tracking(cg).short.mem(cg, .{ |
| 28846 | .size = .fromBitSize(part_bit_size), |
| 28847 | .disp = part_disp, |
| 28848 | }), registerAlias(src_reg, part_size)); |
| 28849 | } else { |
| 28850 | const frame_size = std.math.ceilPowerOfTwoAssert(u32, part_size); |
| 28851 | const frame_index = try cg.allocFrameIndex(.init(.{ |
| 28852 | .size = frame_size, |
| 28853 | .alignment = .fromNonzeroByteUnits(frame_size), |
| 28854 | })); |
| 28855 | const strat = try cg.moveStrategy(src_ty, src_rc, true); |
| 28856 | try strat.write(cg, .{ |
| 28857 | .base = .{ .frame = frame_index }, |
| 28858 | .mod = .{ .rm = .{ .size = .fromSize(frame_size) } }, |
| 28859 | }, registerAlias(src_reg, frame_size)); |
| 28860 | var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address()); |
| 28861 | try dst_ptr.toOffset(part_disp, cg); |
| 28862 | var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } }); |
| 28863 | var len = try cg.tempInit(.usize, .{ .immediate = src_abi_size }); |
| 28864 | try dst_ptr.memcpy(&src_ptr, &len, cg); |
| 28865 | try dst_ptr.die(cg); |
| 28866 | try src_ptr.die(cg); |
| 28867 | try len.die(cg); |
| 19363 | 28868 | } |
| 28869 | part_disp += part_size; |
| 28870 | src_abi_size -= part_size; |
| 28871 | } |
| 28872 | } |
| 19364 | 28873 | |
| 19365 | | // Input params |
| 19366 | | for (param_types, result.args) |ty, *arg| { |
| 19367 | | assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); |
| 19368 | | switch (resolved_cc) { |
| 19369 | | .x86_64_sysv => {}, |
| 19370 | | .x86_64_win => { |
| 19371 | | param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i); |
| 19372 | | param_sse_reg_i = param_int_reg_i; |
| 19373 | | }, |
| 19374 | | else => unreachable, |
| 19375 | | } |
| 28874 | fn memcpy(dst: *Temp, src: *Temp, len: *Temp, cg: *CodeGen) !void { |
| 28875 | while (true) for ([_]*Temp{ dst, src, len }, [_]Register{ .rdi, .rsi, .rcx }) |temp, reg| { |
| 28876 | if (try temp.toReg(reg, cg)) break; |
| 28877 | } else break; |
| 28878 | try cg.asmOpOnly(.{ .@"rep _sb", .mov }); |
| 28879 | } |
| 19376 | 28880 | |
| 19377 | | var arg_mcv: [2]MCValue = undefined; |
| 19378 | | var arg_mcv_i: usize = 0; |
| 28881 | fn memset(dst: *Temp, val: *Temp, len: *Temp, cg: *CodeGen) !void { |
| 28882 | while (true) for ([_]*Temp{ dst, val, len }, [_]Register{ .rdi, .rax, .rcx }) |temp, reg| { |
| 28883 | if (try temp.toReg(reg, cg)) break; |
| 28884 | } else break; |
| 28885 | try cg.asmOpOnly(.{ .@"rep _sb", .sto }); |
| 28886 | } |
| 19379 | 28887 | |
| 19380 | | const classes = switch (resolved_cc) { |
| 19381 | | .x86_64_sysv => mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .arg), .none), |
| 19382 | | .x86_64_win => &.{abi.classifyWindows(ty, zcu)}, |
| 19383 | | else => unreachable, |
| 19384 | | }; |
| 19385 | | for (classes) |class| switch (class) { |
| 19386 | | .integer => { |
| 19387 | | const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 19388 | | if (param_int_reg_i >= param_int_regs.len) break; |
| 28888 | fn moveTo(temp: Temp, inst: Air.Inst.Index, cg: *CodeGen) !void { |
| 28889 | if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) { |
| 28890 | .ref => { |
| 28891 | const result = try cg.allocRegOrMem(inst, true); |
| 28892 | try cg.genCopy(cg.typeOfIndex(inst), result, temp.tracking(cg).short, .{}); |
| 28893 | tracking_log.debug("{} => {} (birth)", .{ inst, result }); |
| 28894 | cg.inst_tracking.putAssumeCapacityNoClobber(inst, .init(result)); |
| 28895 | }, |
| 28896 | .temp => |temp_index| { |
| 28897 | const temp_tracking = temp_index.tracking(cg); |
| 28898 | tracking_log.debug("{} => {} (birth)", .{ inst, temp_tracking.short }); |
| 28899 | cg.inst_tracking.putAssumeCapacityNoClobber(inst, temp_tracking.*); |
| 28900 | assert(cg.reuseTemp(inst, temp_index.toIndex(), temp_tracking)); |
| 28901 | }, |
| 28902 | } |
| 28903 | } |
| 19389 | 28904 | |
| 19390 | | const param_int_reg = registerAlias( |
| 19391 | | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i], |
| 19392 | | @intCast(@min(ty.abiSize(zcu), 8)), |
| 19393 | | ); |
| 19394 | | param_int_reg_i += 1; |
| 28905 | fn die(temp: Temp, cg: *CodeGen) !void { |
| 28906 | switch (temp.unwrap(cg)) { |
| 28907 | .ref => {}, |
| 28908 | .temp => |temp_index| try temp_index.tracking(cg).die(cg, temp_index.toIndex()), |
| 28909 | } |
| 28910 | } |
| 19395 | 28911 | |
| 19396 | | arg_mcv[arg_mcv_i] = .{ .register = param_int_reg }; |
| 19397 | | arg_mcv_i += 1; |
| 19398 | | }, |
| 19399 | | .sse, .float, .float_combine => { |
| 19400 | | const param_sse_regs = abi.getCAbiSseParamRegs(resolved_cc); |
| 19401 | | if (param_sse_reg_i >= param_sse_regs.len) break; |
| 28912 | const Index = enum(u4) { |
| 28913 | _, |
| 19402 | 28914 | |
| 19403 | | const param_sse_reg = registerAlias( |
| 19404 | | abi.getCAbiSseParamRegs(resolved_cc)[param_sse_reg_i], |
| 19405 | | @intCast(ty.abiSize(zcu)), |
| 19406 | | ); |
| 19407 | | param_sse_reg_i += 1; |
| 28915 | fn toIndex(index: Index) Air.Inst.Index { |
| 28916 | return .fromTargetIndex(@intFromEnum(index)); |
| 28917 | } |
| 19408 | 28918 | |
| 19409 | | arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg }; |
| 19410 | | arg_mcv_i += 1; |
| 19411 | | }, |
| 19412 | | .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse), |
| 19413 | | .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) { |
| 19414 | | .x86_64_sysv => switch (class) { |
| 19415 | | .x87, .x87up, .complex_x87, .memory => break, |
| 19416 | | else => unreachable, |
| 19417 | | }, |
| 19418 | | .x86_64_win => if (ty.abiSize(zcu) > 8) { |
| 19419 | | const param_int_reg = |
| 19420 | | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64(); |
| 19421 | | param_int_reg_i += 1; |
| 28919 | fn fromIndex(index: Air.Inst.Index) Index { |
| 28920 | return @enumFromInt(index.toTargetIndex()); |
| 28921 | } |
| 19422 | 28922 | |
| 19423 | | arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } }; |
| 19424 | | arg_mcv_i += 1; |
| 19425 | | } else break, |
| 19426 | | else => unreachable, |
| 19427 | | }, |
| 19428 | | .none => unreachable, |
| 19429 | | .integer_per_element => { |
| 19430 | | const param_int_regs_len: u32 = |
| 19431 | | @intCast(abi.getCAbiIntParamRegs(resolved_cc).len); |
| 19432 | | const remaining_param_int_regs: u3 = |
| 19433 | | @intCast(param_int_regs_len - param_int_reg_i); |
| 19434 | | param_int_reg_i = param_int_regs_len; |
| 28923 | fn tracking(index: Index, cg: *CodeGen) *InstTracking { |
| 28924 | return &cg.inst_tracking.values()[@intFromEnum(index)]; |
| 28925 | } |
| 19435 | 28926 | |
| 19436 | | const frame_elem_align = 8; |
| 19437 | | const frame_elems_len = ty.vectorLen(zcu) - remaining_param_int_regs; |
| 19438 | | const frame_elem_size = mem.alignForward( |
| 19439 | | u64, |
| 19440 | | ty.childType(zcu).abiSize(zcu), |
| 19441 | | frame_elem_align, |
| 19442 | | ); |
| 19443 | | const frame_size: u31 = @intCast(frame_elems_len * frame_elem_size); |
| 28927 | fn isValid(index: Index, cg: *CodeGen) bool { |
| 28928 | return index.tracking(cg).short != .dead; |
| 28929 | } |
| 19444 | 28930 | |
| 19445 | | result.stack_byte_count = |
| 19446 | | mem.alignForward(u31, result.stack_byte_count, frame_elem_align); |
| 19447 | | arg_mcv[arg_mcv_i] = .{ .elementwise_regs_then_frame = .{ |
| 19448 | | .regs = remaining_param_int_regs, |
| 19449 | | .frame_off = @intCast(result.stack_byte_count), |
| 19450 | | .frame_index = stack_frame_base, |
| 19451 | | } }; |
| 19452 | | arg_mcv_i += 1; |
| 19453 | | result.stack_byte_count += frame_size; |
| 19454 | | }, |
| 19455 | | } else { |
| 19456 | | arg.* = switch (arg_mcv_i) { |
| 19457 | | else => unreachable, |
| 19458 | | 1 => arg_mcv[0], |
| 19459 | | 2 => .{ .register_pair = .{ arg_mcv[0].register, arg_mcv[1].register } }, |
| 19460 | | }; |
| 19461 | | continue; |
| 19462 | | } |
| 28931 | fn typeOf(index: Index, cg: *CodeGen) Type { |
| 28932 | assert(index.isValid(cg)); |
| 28933 | return cg.temp_type[@intFromEnum(index)]; |
| 28934 | } |
| 19463 | 28935 | |
| 19464 | | const param_size: u31 = @intCast(ty.abiSize(zcu)); |
| 19465 | | const param_align = ty.abiAlignment(zcu).max(.@"8"); |
| 19466 | | result.stack_byte_count = mem.alignForward( |
| 19467 | | u31, |
| 19468 | | result.stack_byte_count, |
| 19469 | | @intCast(param_align.toByteUnits().?), |
| 19470 | | ); |
| 19471 | | result.stack_align = result.stack_align.max(param_align); |
| 19472 | | arg.* = .{ .load_frame = .{ |
| 19473 | | .index = stack_frame_base, |
| 19474 | | .off = result.stack_byte_count, |
| 19475 | | } }; |
| 19476 | | result.stack_byte_count += param_size; |
| 28936 | const max = std.math.maxInt(@typeInfo(Index).@"enum".tag_type); |
| 28937 | const Set = std.StaticBitSet(max); |
| 28938 | const SafetySet = if (std.debug.runtime_safety) Set else struct { |
| 28939 | inline fn initEmpty() @This() { |
| 28940 | return .{}; |
| 19477 | 28941 | } |
| 19478 | | assert(param_int_reg_i <= 6); |
| 19479 | | result.gp_count = param_int_reg_i; |
| 19480 | | assert(param_sse_reg_i <= 16); |
| 19481 | | result.fp_count = param_sse_reg_i; |
| 19482 | | }, |
| 19483 | | .auto => { |
| 19484 | | result.stack_align = .@"16"; |
| 19485 | 28942 | |
| 19486 | | // Return values |
| 19487 | | if (ret_ty.zigTypeTag(zcu) == .noreturn) { |
| 19488 | | result.return_value = InstTracking.init(.unreach); |
| 19489 | | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 19490 | | result.return_value = InstTracking.init(.none); |
| 19491 | | } else { |
| 19492 | | const ret_reg = abi.getCAbiIntReturnRegs(resolved_cc)[0]; |
| 19493 | | const ret_ty_size: u31 = @intCast(ret_ty.abiSize(zcu)); |
| 19494 | | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { |
| 19495 | | const aliased_reg = registerAlias(ret_reg, ret_ty_size); |
| 19496 | | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; |
| 19497 | | } else { |
| 19498 | | const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[0]; |
| 19499 | | result.return_value = .{ |
| 19500 | | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| 19501 | | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 19502 | | }; |
| 19503 | | } |
| 28943 | inline fn isSet(_: @This(), index: usize) bool { |
| 28944 | assert(index < max); |
| 28945 | return true; |
| 19504 | 28946 | } |
| 19505 | 28947 | |
| 19506 | | // Input params |
| 19507 | | for (param_types, result.args) |ty, *arg| { |
| 19508 | | if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 19509 | | arg.* = .none; |
| 19510 | | continue; |
| 19511 | | } |
| 19512 | | const param_size: u31 = @intCast(ty.abiSize(zcu)); |
| 19513 | | const param_align = ty.abiAlignment(zcu); |
| 19514 | | result.stack_byte_count = mem.alignForward( |
| 19515 | | u31, |
| 19516 | | result.stack_byte_count, |
| 19517 | | @intCast(param_align.toByteUnits().?), |
| 19518 | | ); |
| 19519 | | result.stack_align = result.stack_align.max(param_align); |
| 19520 | | arg.* = .{ .load_frame = .{ |
| 19521 | | .index = stack_frame_base, |
| 19522 | | .off = result.stack_byte_count, |
| 19523 | | } }; |
| 19524 | | result.stack_byte_count += param_size; |
| 28948 | inline fn set(_: @This(), index: usize) void { |
| 28949 | assert(index < max); |
| 28950 | } |
| 28951 | |
| 28952 | inline fn eql(_: @This(), _: @This()) bool { |
| 28953 | return true; |
| 28954 | } |
| 28955 | }; |
| 28956 | }; |
| 28957 | }; |
| 28958 | |
| 28959 | fn resetTemps(cg: *CodeGen) void { |
| 28960 | for (0..@intFromEnum(cg.next_temp_index)) |temp_index| { |
| 28961 | const temp: Temp.Index = @enumFromInt(temp_index); |
| 28962 | assert(!temp.isValid(cg)); |
| 28963 | cg.temp_type[temp_index] = undefined; |
| 28964 | } |
| 28965 | cg.next_temp_index = @enumFromInt(0); |
| 28966 | } |
| 28967 | |
| 28968 | fn reuseTemp( |
| 28969 | cg: *CodeGen, |
| 28970 | new_inst: Air.Inst.Index, |
| 28971 | old_inst: Air.Inst.Index, |
| 28972 | tracking: *InstTracking, |
| 28973 | ) bool { |
| 28974 | switch (tracking.short) { |
| 28975 | .register, |
| 28976 | .register_pair, |
| 28977 | .register_offset, |
| 28978 | .register_overflow, |
| 28979 | .register_mask, |
| 28980 | .indirect, |
| 28981 | => for (tracking.short.getRegs()) |tracked_reg| { |
| 28982 | if (RegisterManager.indexOfRegIntoTracked(tracked_reg)) |tracked_index| { |
| 28983 | cg.register_manager.registers[tracked_index] = new_inst; |
| 19525 | 28984 | } |
| 19526 | 28985 | }, |
| 19527 | | else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}), |
| 28986 | .load_frame => |frame_addr| if (frame_addr.index.isNamed()) return false, |
| 28987 | else => {}, |
| 28988 | } |
| 28989 | switch (tracking.short) { |
| 28990 | .eflags, .register_overflow => cg.eflags_inst = new_inst, |
| 28991 | else => {}, |
| 19528 | 28992 | } |
| 28993 | tracking.reuse(cg, new_inst, old_inst); |
| 28994 | return true; |
| 28995 | } |
| 19529 | 28996 | |
| 19530 | | result.stack_byte_count = @intCast(result.stack_align.forward(result.stack_byte_count)); |
| 19531 | | return result; |
| 28997 | fn tempAlloc(cg: *CodeGen, ty: Type) !Temp { |
| 28998 | const temp_index = cg.next_temp_index; |
| 28999 | temp_index.tracking(cg).* = .init( |
| 29000 | try cg.allocRegOrMemAdvanced(ty, temp_index.toIndex(), true), |
| 29001 | ); |
| 29002 | cg.temp_type[@intFromEnum(temp_index)] = ty; |
| 29003 | cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1); |
| 29004 | return .{ .index = temp_index.toIndex() }; |
| 19532 | 29005 | } |
| 19533 | 29006 | |
| 19534 | | fn fail(self: *Self, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 19535 | | @branchHint(.cold); |
| 19536 | | const zcu = self.pt.zcu; |
| 19537 | | switch (self.owner) { |
| 19538 | | .nav_index => |i| return zcu.codegenFail(i, format, args), |
| 19539 | | .lazy_sym => |s| return zcu.codegenFailType(s.ty, format, args), |
| 19540 | | } |
| 19541 | | return error.CodegenFail; |
| 29007 | fn tempAllocReg(cg: *CodeGen, ty: Type, rs: RegisterManager.RegisterBitSet) !Temp { |
| 29008 | const temp_index = cg.next_temp_index; |
| 29009 | temp_index.tracking(cg).* = .init( |
| 29010 | .{ .register = try cg.register_manager.allocReg(temp_index.toIndex(), rs) }, |
| 29011 | ); |
| 29012 | cg.temp_type[@intFromEnum(temp_index)] = ty; |
| 29013 | cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1); |
| 29014 | return .{ .index = temp_index.toIndex() }; |
| 19542 | 29015 | } |
| 19543 | 29016 | |
| 19544 | | fn failMsg(self: *Self, msg: *ErrorMsg) error{ OutOfMemory, CodegenFail } { |
| 19545 | | @branchHint(.cold); |
| 19546 | | const zcu = self.pt.zcu; |
| 19547 | | switch (self.owner) { |
| 19548 | | .nav_index => |i| return zcu.codegenFailMsg(i, msg), |
| 19549 | | .lazy_sym => |s| return zcu.codegenFailTypeMsg(s.ty, msg), |
| 19550 | | } |
| 19551 | | return error.CodegenFail; |
| 29017 | fn tempAllocRegPair(cg: *CodeGen, ty: Type, rs: RegisterManager.RegisterBitSet) !Temp { |
| 29018 | const temp_index = cg.next_temp_index; |
| 29019 | temp_index.tracking(cg).* = .init( |
| 29020 | .{ .register_pair = try cg.register_manager.allocRegs(2, temp_index.toIndex(), rs) }, |
| 29021 | ); |
| 29022 | cg.temp_type[@intFromEnum(temp_index)] = ty; |
| 29023 | cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1); |
| 29024 | return .{ .index = temp_index.toIndex() }; |
| 19552 | 29025 | } |
| 19553 | 29026 | |
| 19554 | | fn parseRegName(name: []const u8) ?Register { |
| 19555 | | if (@hasDecl(Register, "parseRegName")) { |
| 19556 | | return Register.parseRegName(name); |
| 29027 | fn tempAllocMem(cg: *CodeGen, ty: Type) !Temp { |
| 29028 | const temp_index = cg.next_temp_index; |
| 29029 | temp_index.tracking(cg).* = .init( |
| 29030 | try cg.allocRegOrMemAdvanced(ty, temp_index.toIndex(), false), |
| 29031 | ); |
| 29032 | cg.temp_type[@intFromEnum(temp_index)] = ty; |
| 29033 | cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1); |
| 29034 | return .{ .index = temp_index.toIndex() }; |
| 29035 | } |
| 29036 | |
| 29037 | fn tempInit(cg: *CodeGen, ty: Type, value: MCValue) !Temp { |
| 29038 | const temp_index = cg.next_temp_index; |
| 29039 | temp_index.tracking(cg).* = .init(value); |
| 29040 | cg.temp_type[@intFromEnum(temp_index)] = ty; |
| 29041 | try cg.getValue(value, temp_index.toIndex()); |
| 29042 | cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1); |
| 29043 | return .{ .index = temp_index.toIndex() }; |
| 29044 | } |
| 29045 | |
| 29046 | fn tempFromValue(cg: *CodeGen, value: Value) !Temp { |
| 29047 | return cg.tempInit(value.typeOf(cg.pt.zcu), try cg.genTypedValue(value)); |
| 29048 | } |
| 29049 | |
| 29050 | fn tempFromOperand( |
| 29051 | cg: *CodeGen, |
| 29052 | inst: Air.Inst.Index, |
| 29053 | op_index: Liveness.OperandInt, |
| 29054 | op_ref: Air.Inst.Ref, |
| 29055 | ignore_death: bool, |
| 29056 | ) !Temp { |
| 29057 | const zcu = cg.pt.zcu; |
| 29058 | const ip = &zcu.intern_pool; |
| 29059 | |
| 29060 | if (ignore_death or !cg.liveness.operandDies(inst, op_index)) { |
| 29061 | if (op_ref.toIndex()) |op_inst| return .{ .index = op_inst }; |
| 29062 | const val = op_ref.toInterned().?; |
| 29063 | const gop = try cg.const_tracking.getOrPut(cg.gpa, val); |
| 29064 | if (!gop.found_existing) gop.value_ptr.* = .init(init: { |
| 29065 | const const_mcv = try cg.genTypedValue(.fromInterned(val)); |
| 29066 | switch (const_mcv) { |
| 29067 | .lea_tlv => |tlv_sym| switch (cg.bin_file.tag) { |
| 29068 | .elf, .macho => { |
| 29069 | if (cg.mod.pic) { |
| 29070 | try cg.spillRegisters(&.{ .rdi, .rax }); |
| 29071 | } else { |
| 29072 | try cg.spillRegisters(&.{.rax}); |
| 29073 | } |
| 29074 | const frame_index = try cg.allocFrameIndex(.init(.{ |
| 29075 | .size = 8, |
| 29076 | .alignment = .@"8", |
| 29077 | })); |
| 29078 | try cg.genSetMem( |
| 29079 | .{ .frame = frame_index }, |
| 29080 | 0, |
| 29081 | .usize, |
| 29082 | .{ .lea_symbol = .{ .sym_index = tlv_sym } }, |
| 29083 | .{}, |
| 29084 | ); |
| 29085 | break :init .{ .load_frame = .{ .index = frame_index } }; |
| 29086 | }, |
| 29087 | else => break :init const_mcv, |
| 29088 | }, |
| 29089 | else => break :init const_mcv, |
| 29090 | } |
| 29091 | }); |
| 29092 | return cg.tempInit(.fromInterned(ip.typeOf(val)), gop.value_ptr.short); |
| 19557 | 29093 | } |
| 19558 | | return std.meta.stringToEnum(Register, name); |
| 29094 | |
| 29095 | const temp_index = cg.next_temp_index; |
| 29096 | const temp: Temp = .{ .index = temp_index.toIndex() }; |
| 29097 | const op_inst = op_ref.toIndex().?; |
| 29098 | const tracking = cg.getResolvedInstValue(op_inst); |
| 29099 | temp_index.tracking(cg).* = tracking.*; |
| 29100 | if (!cg.reuseTemp(temp.index, op_inst, tracking)) return .{ .index = op_ref.toIndex().? }; |
| 29101 | cg.temp_type[@intFromEnum(temp_index)] = cg.typeOf(op_ref); |
| 29102 | cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1); |
| 29103 | return temp; |
| 29104 | } |
| 29105 | |
| 29106 | inline fn tempsFromOperands(cg: *CodeGen, inst: Air.Inst.Index, op_refs: anytype) ![op_refs.len]Temp { |
| 29107 | var temps: [op_refs.len]Temp = undefined; |
| 29108 | inline for (&temps, 0.., op_refs) |*temp, op_index, op_ref| { |
| 29109 | temp.* = try cg.tempFromOperand(inst, op_index, op_ref, inline for (0..op_index) |prev_op_index| { |
| 29110 | if (op_ref == op_refs[prev_op_index]) break true; |
| 29111 | } else false); |
| 29112 | } |
| 29113 | return temps; |
| 19559 | 29114 | } |
| 19560 | 29115 | |
| 19561 | | /// Returns register wide enough to hold at least `size_bytes`. |
| 19562 | | fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 19563 | | return switch (reg.class()) { |
| 19564 | | .general_purpose => if (size_bytes == 0) |
| 19565 | | unreachable // should be comptime-known |
| 19566 | | else if (size_bytes <= 1) |
| 19567 | | reg.to8() |
| 19568 | | else if (size_bytes <= 2) |
| 19569 | | reg.to16() |
| 19570 | | else if (size_bytes <= 4) |
| 19571 | | reg.to32() |
| 19572 | | else if (size_bytes <= 8) |
| 19573 | | reg.to64() |
| 19574 | | else |
| 19575 | | unreachable, |
| 19576 | | .segment => if (size_bytes <= 2) |
| 19577 | | reg |
| 19578 | | else |
| 19579 | | unreachable, |
| 19580 | | .x87 => if (size_bytes == 16) |
| 19581 | | reg |
| 19582 | | else |
| 19583 | | unreachable, |
| 19584 | | .mmx => if (size_bytes <= 8) |
| 19585 | | reg |
| 19586 | | else |
| 19587 | | unreachable, |
| 19588 | | .sse => if (size_bytes <= 16) |
| 19589 | | reg.to128() |
| 19590 | | else if (size_bytes <= 32) |
| 19591 | | reg.to256() |
| 19592 | | else |
| 19593 | | unreachable, |
| 19594 | | .ip => if (size_bytes <= 2) |
| 19595 | | .ip |
| 19596 | | else if (size_bytes <= 4) |
| 19597 | | .eip |
| 19598 | | else if (size_bytes <= 8) |
| 19599 | | .rip |
| 19600 | | else |
| 19601 | | unreachable, |
| 29116 | const Operand = union(enum) { |
| 29117 | none, |
| 29118 | reg: Register, |
| 29119 | mem: Memory, |
| 29120 | imm: Immediate, |
| 29121 | inst: Mir.Inst.Index, |
| 29122 | }; |
| 29123 | |
| 29124 | const Select = struct { |
| 29125 | cg: *CodeGen, |
| 29126 | temps: [@intFromEnum(Select.Operand.Ref.none)]Temp, |
| 29127 | labels: [@intFromEnum(Label._)]struct { |
| 29128 | backward: ?Mir.Inst.Index, |
| 29129 | forward: [1]?Mir.Inst.Index, |
| 29130 | }, |
| 29131 | |
| 29132 | fn emitLabel(s: *Select, label_index: Label) void { |
| 29133 | if (label_index == ._) return; |
| 29134 | const label = &s.labels[@intFromEnum(label_index)]; |
| 29135 | for (&label.forward) |*reloc| { |
| 29136 | if (reloc.*) |r| s.cg.performReloc(r); |
| 29137 | reloc.* = null; |
| 29138 | } |
| 29139 | label.backward = @intCast(s.cg.mir_instructions.len); |
| 29140 | } |
| 29141 | |
| 29142 | fn emit(s: *Select, inst: Instruction) !void { |
| 29143 | s.emitLabel(inst[0]); |
| 29144 | const mir_tag: Mir.Inst.FixedTag = .{ inst[1], inst[2] }; |
| 29145 | var mir_ops: [4]CodeGen.Operand = undefined; |
| 29146 | inline for (&mir_ops, 3..) |*mir_op, inst_index| mir_op.* = try inst[inst_index].lower(s); |
| 29147 | s.cg.asmOps(mir_tag, mir_ops) catch |err| switch (err) { |
| 29148 | error.InvalidInstruction => { |
| 29149 | const fixes = @tagName(mir_tag[0]); |
| 29150 | const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?; |
| 29151 | return s.cg.fail( |
| 29152 | "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", |
| 29153 | .{ |
| 29154 | fixes[0..fixes_blank], |
| 29155 | @tagName(mir_tag[1]), |
| 29156 | fixes[fixes_blank + 1 ..], |
| 29157 | @tagName(mir_ops[0]), |
| 29158 | @tagName(mir_ops[1]), |
| 29159 | @tagName(mir_ops[2]), |
| 29160 | @tagName(mir_ops[3]), |
| 29161 | }, |
| 29162 | ); |
| 29163 | }, |
| 29164 | else => |e| return e, |
| 29165 | }; |
| 29166 | } |
| 29167 | |
| 29168 | const Case = struct { |
| 29169 | required_features: [4]?std.Target.x86.Feature = @splat(null), |
| 29170 | dst_constraints: [@intFromEnum(Select.Operand.Ref.src0) - @intFromEnum(Select.Operand.Ref.dst0)]Constraint = @splat(.any), |
| 29171 | src_constraints: [@intFromEnum(Select.Operand.Ref.none) - @intFromEnum(Select.Operand.Ref.src0)]Constraint = @splat(.any), |
| 29172 | patterns: []const Select.Pattern, |
| 29173 | extra_temps: [@intFromEnum(Select.Operand.Ref.dst0) - @intFromEnum(Select.Operand.Ref.tmp0)]TempSpec = @splat(.unused), |
| 29174 | dst_temps: [@intFromEnum(Select.Operand.Ref.src0) - @intFromEnum(Select.Operand.Ref.dst0)]TempSpec.Kind = @splat(.unused), |
| 29175 | clobbers: struct { eflags: bool = false } = .{}, |
| 29176 | each: union(enum) { |
| 29177 | once: []const Instruction, |
| 29178 | }, |
| 19602 | 29179 | }; |
| 19603 | | } |
| 19604 | 29180 | |
| 19605 | | fn memSize(self: *Self, ty: Type) Memory.Size { |
| 19606 | | const pt = self.pt; |
| 19607 | | const zcu = pt.zcu; |
| 19608 | | return switch (ty.zigTypeTag(zcu)) { |
| 19609 | | .float => Memory.Size.fromBitSize(ty.floatBits(self.target.*)), |
| 19610 | | else => Memory.Size.fromSize(@intCast(ty.abiSize(zcu))), |
| 29181 | const Constraint = union(enum) { |
| 29182 | any, |
| 29183 | any_bool_vec, |
| 29184 | any_int, |
| 29185 | any_signed_int, |
| 29186 | any_float, |
| 29187 | po2_any, |
| 29188 | bool_vec: Memory.Size, |
| 29189 | vec: Memory.Size, |
| 29190 | signed_int_vec: Memory.Size, |
| 29191 | signed_int_or_full_vec: Memory.Size, |
| 29192 | unsigned_int_vec: Memory.Size, |
| 29193 | size: Memory.Size, |
| 29194 | multiple_size: Memory.Size, |
| 29195 | int: Memory.Size, |
| 29196 | scalar_int: Memory.Size, |
| 29197 | scalar_signed_int: Memory.Size, |
| 29198 | scalar_unsigned_int: Memory.Size, |
| 29199 | scalar_remainder_int: struct { of: Memory.Size, is: Memory.Size }, |
| 29200 | exact_int: u16, |
| 29201 | exact_signed_int: u16, |
| 29202 | exact_unsigned_int: u16, |
| 29203 | signed_or_exact_int: Memory.Size, |
| 29204 | unsigned_or_exact_int: Memory.Size, |
| 29205 | po2_int: Memory.Size, |
| 29206 | signed_po2_int: Memory.Size, |
| 29207 | unsigned_po2_or_exact_int: Memory.Size, |
| 29208 | remainder_int: struct { of: Memory.Size, is: Memory.Size }, |
| 29209 | exact_remainder_int: struct { of: Memory.Size, is: Memory.Size }, |
| 29210 | signed_or_exact_remainder_int: struct { of: Memory.Size, is: Memory.Size }, |
| 29211 | unsigned_or_exact_remainder_int: struct { of: Memory.Size, is: Memory.Size }, |
| 29212 | signed_int: Memory.Size, |
| 29213 | unsigned_int: Memory.Size, |
| 29214 | elem_size_is: u8, |
| 29215 | po2_elem_size, |
| 29216 | elem_int: Memory.Size, |
| 29217 | |
| 29218 | fn accepts(constraint: Constraint, ty: Type, cg: *CodeGen) bool { |
| 29219 | const zcu = cg.pt.zcu; |
| 29220 | return switch (constraint) { |
| 29221 | .any => true, |
| 29222 | .any_bool_vec => ty.isVector(zcu) and ty.childType(zcu).toIntern() == .bool_type, |
| 29223 | .any_int => intInfo(ty, cg) != null, |
| 29224 | .any_signed_int => if (intInfo(ty, cg)) |int_info| int_info.signedness == .signed else false, |
| 29225 | .any_float => ty.isRuntimeFloat(), |
| 29226 | .po2_any => std.math.isPowerOfTwo(ty.abiSize(zcu)), |
| 29227 | .bool_vec => |size| ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and |
| 29228 | size.bitSize(cg.target) >= ty.vectorLen(zcu), |
| 29229 | .vec => |size| ty.isVector(zcu) and ty.scalarType(zcu).toIntern() != .bool_type and |
| 29230 | size.bitSize(cg.target) >= ty.abiSize(zcu), |
| 29231 | .signed_int_vec => |size| ty.isVector(zcu) and size.bitSize(cg.target) >= 8 * ty.abiSize(zcu) and |
| 29232 | if (intInfo(ty.childType(zcu), cg)) |int_info| int_info.signedness == .signed else false, |
| 29233 | .signed_int_or_full_vec => |size| ty.isVector(zcu) and size.bitSize(cg.target) >= 8 * ty.abiSize(zcu) and |
| 29234 | if (intInfo(ty.childType(zcu), cg)) |int_info| switch (int_info.signedness) { |
| 29235 | .signed => true, |
| 29236 | .unsigned => int_info.bits >= 8 and std.math.isPowerOfTwo(int_info.bits), |
| 29237 | } else false, |
| 29238 | .unsigned_int_vec => |size| ty.isVector(zcu) and size.bitSize(cg.target) >= 8 * ty.abiSize(zcu) and |
| 29239 | if (intInfo(ty.childType(zcu), cg)) |int_info| int_info.signedness == .unsigned else false, |
| 29240 | .size => |size| size.bitSize(cg.target) >= 8 * ty.abiSize(zcu), |
| 29241 | .multiple_size => |size| size.bitSize(cg.target) % 8 * ty.abiSize(zcu) == 0, |
| 29242 | .int => |size| if (intInfo(ty, cg)) |int_info| size.bitSize(cg.target) >= int_info.bits else false, |
| 29243 | .scalar_int => |size| if (intInfo(ty.scalarType(zcu), cg)) |int_info| |
| 29244 | size.bitSize(cg.target) >= int_info.bits |
| 29245 | else |
| 29246 | false, |
| 29247 | .scalar_signed_int => |size| if (intInfo(ty.scalarType(zcu), cg)) |int_info| switch (int_info.signedness) { |
| 29248 | .signed => size.bitSize(cg.target) >= int_info.bits, |
| 29249 | .unsigned => false, |
| 29250 | } else false, |
| 29251 | .scalar_unsigned_int => |size| if (intInfo(ty.scalarType(zcu), cg)) |int_info| switch (int_info.signedness) { |
| 29252 | .signed => false, |
| 29253 | .unsigned => size.bitSize(cg.target) >= int_info.bits, |
| 29254 | } else false, |
| 29255 | .scalar_remainder_int => |of_is| if (intInfo(ty.scalarType(zcu), cg)) |int_info| |
| 29256 | of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1 |
| 29257 | else |
| 29258 | false, |
| 29259 | .exact_int => |bit_size| if (intInfo(ty, cg)) |int_info| bit_size == int_info.bits else false, |
| 29260 | .exact_signed_int => |bit_size| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29261 | .signed => bit_size == int_info.bits, |
| 29262 | .unsigned => false, |
| 29263 | } else false, |
| 29264 | .exact_unsigned_int => |bit_size| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29265 | .signed => false, |
| 29266 | .unsigned => bit_size == int_info.bits, |
| 29267 | } else false, |
| 29268 | .signed_or_exact_int => |size| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29269 | .signed => size.bitSize(cg.target) >= int_info.bits, |
| 29270 | .unsigned => size.bitSize(cg.target) == int_info.bits, |
| 29271 | } else false, |
| 29272 | .unsigned_or_exact_int => |size| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29273 | .signed => size.bitSize(cg.target) == int_info.bits, |
| 29274 | .unsigned => size.bitSize(cg.target) >= int_info.bits, |
| 29275 | } else false, |
| 29276 | .po2_int => |size| if (intInfo(ty, cg)) |int_info| |
| 29277 | std.math.isPowerOfTwo(int_info.bits) and size.bitSize(cg.target) >= int_info.bits |
| 29278 | else |
| 29279 | false, |
| 29280 | .signed_po2_int => |size| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29281 | .signed => std.math.isPowerOfTwo(int_info.bits) and size.bitSize(cg.target) >= int_info.bits, |
| 29282 | .unsigned => false, |
| 29283 | } else false, |
| 29284 | .unsigned_po2_or_exact_int => |size| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29285 | .signed => size.bitSize(cg.target) == int_info.bits, |
| 29286 | .unsigned => std.math.isPowerOfTwo(int_info.bits) and size.bitSize(cg.target) >= int_info.bits, |
| 29287 | } else false, |
| 29288 | .remainder_int => |of_is| if (intInfo(ty, cg)) |int_info| |
| 29289 | of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1 |
| 29290 | else |
| 29291 | false, |
| 29292 | .exact_remainder_int => |of_is| if (intInfo(ty, cg)) |int_info| |
| 29293 | of_is.is.bitSize(cg.target) == (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1 |
| 29294 | else |
| 29295 | false, |
| 29296 | .signed_or_exact_remainder_int => |of_is| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29297 | .signed => of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1, |
| 29298 | .unsigned => of_is.is.bitSize(cg.target) == (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1, |
| 29299 | } else false, |
| 29300 | .unsigned_or_exact_remainder_int => |of_is| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29301 | .signed => of_is.is.bitSize(cg.target) == (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1, |
| 29302 | .unsigned => of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1, |
| 29303 | } else false, |
| 29304 | .signed_int => |size| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29305 | .signed => size.bitSize(cg.target) >= int_info.bits, |
| 29306 | .unsigned => false, |
| 29307 | } else false, |
| 29308 | .unsigned_int => |size| if (intInfo(ty, cg)) |int_info| switch (int_info.signedness) { |
| 29309 | .signed => false, |
| 29310 | .unsigned => size.bitSize(cg.target) >= int_info.bits, |
| 29311 | } else false, |
| 29312 | .elem_size_is => |size| size == ty.elemType2(zcu).abiSize(zcu), |
| 29313 | .po2_elem_size => std.math.isPowerOfTwo(ty.elemType2(zcu).abiSize(zcu)), |
| 29314 | .elem_int => |size| if (intInfo(ty.elemType2(zcu), cg)) |elem_int_info| |
| 29315 | size.bitSize(cg.target) >= elem_int_info.bits |
| 29316 | else |
| 29317 | false, |
| 29318 | }; |
| 29319 | } |
| 29320 | }; |
| 29321 | |
| 29322 | const Pattern = struct { |
| 29323 | src: [2]Src, |
| 29324 | commute: struct { u8, u8 } = .{ 0, 0 }, |
| 29325 | |
| 29326 | const Src = enum { |
| 29327 | none, |
| 29328 | any, |
| 29329 | imm8, |
| 29330 | imm16, |
| 29331 | imm32, |
| 29332 | simm32, |
| 29333 | mem, |
| 29334 | to_mem, |
| 29335 | mut_mem, |
| 29336 | to_mut_mem, |
| 29337 | gpr, |
| 29338 | to_gpr, |
| 29339 | mut_gpr, |
| 29340 | to_mut_gpr, |
| 29341 | mm, |
| 29342 | to_mm, |
| 29343 | mut_mm, |
| 29344 | to_mut_mm, |
| 29345 | xmm, |
| 29346 | to_xmm, |
| 29347 | mut_xmm, |
| 29348 | to_mut_xmm, |
| 29349 | ymm, |
| 29350 | to_ymm, |
| 29351 | mut_ymm, |
| 29352 | to_mut_ymm, |
| 29353 | |
| 29354 | fn matches(src: Src, temp: Temp, cg: *CodeGen) bool { |
| 29355 | return switch (src) { |
| 29356 | .none => unreachable, |
| 29357 | .any => true, |
| 29358 | .imm8 => switch (temp.tracking(cg).short) { |
| 29359 | .immediate => |imm| std.math.cast(u8, imm) != null, |
| 29360 | else => false, |
| 29361 | }, |
| 29362 | .imm16 => switch (temp.tracking(cg).short) { |
| 29363 | .immediate => |imm| std.math.cast(u16, imm) != null, |
| 29364 | else => false, |
| 29365 | }, |
| 29366 | .imm32 => switch (temp.tracking(cg).short) { |
| 29367 | .immediate => |imm| std.math.cast(u32, imm) != null, |
| 29368 | else => false, |
| 29369 | }, |
| 29370 | .simm32 => switch (temp.tracking(cg).short) { |
| 29371 | .immediate => |imm| std.math.cast(i32, @as(i64, @bitCast(imm))) != null, |
| 29372 | else => false, |
| 29373 | }, |
| 29374 | .mem => temp.tracking(cg).short.isMemory(), |
| 29375 | .to_mem, .to_mut_mem => true, |
| 29376 | .mut_mem => temp.isMut(cg) and temp.tracking(cg).short.isMemory(), |
| 29377 | .gpr => temp.typeOf(cg).abiSize(cg.pt.zcu) <= 8 and switch (temp.tracking(cg).short) { |
| 29378 | .register => |reg| reg.class() == .general_purpose, |
| 29379 | .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and reg_off.off == 0, |
| 29380 | else => false, |
| 29381 | }, |
| 29382 | .mut_gpr => temp.isMut(cg) and temp.typeOf(cg).abiSize(cg.pt.zcu) <= 8 and switch (temp.tracking(cg).short) { |
| 29383 | .register => |reg| reg.class() == .general_purpose, |
| 29384 | .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and reg_off.off == 0, |
| 29385 | else => false, |
| 29386 | }, |
| 29387 | .to_gpr, .to_mut_gpr => temp.typeOf(cg).abiSize(cg.pt.zcu) <= 8, |
| 29388 | .mm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 8 and switch (temp.tracking(cg).short) { |
| 29389 | .register => |reg| reg.class() == .mmx, |
| 29390 | .register_offset => |reg_off| reg_off.reg.class() == .mmx and reg_off.off == 0, |
| 29391 | else => false, |
| 29392 | }, |
| 29393 | .mut_mm => temp.isMut(cg) and temp.typeOf(cg).abiSize(cg.pt.zcu) == 8 and switch (temp.tracking(cg).short) { |
| 29394 | .register => |reg| reg.class() == .mmx, |
| 29395 | .register_offset => |reg_off| reg_off.reg.class() == .mmx and reg_off.off == 0, |
| 29396 | else => false, |
| 29397 | }, |
| 29398 | .to_mm, .to_mut_mm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 8, |
| 29399 | .xmm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 16 and switch (temp.tracking(cg).short) { |
| 29400 | .register => |reg| reg.class() == .sse, |
| 29401 | .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0, |
| 29402 | else => false, |
| 29403 | }, |
| 29404 | .mut_xmm => temp.isMut(cg) and temp.typeOf(cg).abiSize(cg.pt.zcu) == 16 and switch (temp.tracking(cg).short) { |
| 29405 | .register => |reg| reg.class() == .sse, |
| 29406 | .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0, |
| 29407 | else => false, |
| 29408 | }, |
| 29409 | .to_xmm, .to_mut_xmm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 16, |
| 29410 | .ymm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 32 and switch (temp.tracking(cg).short) { |
| 29411 | .register => |reg| reg.class() == .sse, |
| 29412 | .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0, |
| 29413 | else => false, |
| 29414 | }, |
| 29415 | .mut_ymm => temp.isMut(cg) and temp.typeOf(cg).abiSize(cg.pt.zcu) == 32 and switch (temp.tracking(cg).short) { |
| 29416 | .register => |reg| reg.class() == .sse, |
| 29417 | .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0, |
| 29418 | else => false, |
| 29419 | }, |
| 29420 | .to_ymm, .to_mut_ymm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 32, |
| 29421 | }; |
| 29422 | } |
| 29423 | |
| 29424 | fn convert(src: Src, temp: *Temp, cg: *CodeGen) !bool { |
| 29425 | return switch (src) { |
| 29426 | .none => unreachable, |
| 29427 | .any, .imm8, .imm16, .imm32, .simm32 => false, |
| 29428 | .mem, .to_mem, .mut_mem, .to_mut_mem => try temp.toBase(cg), |
| 29429 | .gpr, .to_gpr => try temp.toRegClass(false, .general_purpose, cg), |
| 29430 | .mut_gpr, .to_mut_gpr => try temp.toRegClass(true, .general_purpose, cg), |
| 29431 | .mm, .to_mm => try temp.toRegClass(false, .mmx, cg), |
| 29432 | .mut_mm, .to_mut_mm => try temp.toRegClass(true, .mmx, cg), |
| 29433 | .xmm, .to_xmm, .ymm, .to_ymm => try temp.toRegClass(false, .sse, cg), |
| 29434 | .mut_xmm, .to_mut_xmm, .mut_ymm, .to_mut_ymm => try temp.toRegClass(true, .sse, cg), |
| 29435 | }; |
| 29436 | } |
| 29437 | }; |
| 19611 | 29438 | }; |
| 19612 | | } |
| 19613 | 29439 | |
| 19614 | | fn splitType(self: *Self, ty: Type) ![2]Type { |
| 19615 | | const pt = self.pt; |
| 19616 | | const zcu = pt.zcu; |
| 19617 | | const classes = mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none); |
| 19618 | | var parts: [2]Type = undefined; |
| 19619 | | if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| { |
| 19620 | | part.* = switch (class) { |
| 19621 | | .integer => switch (part_i) { |
| 19622 | | 0 => Type.u64, |
| 19623 | | 1 => part: { |
| 19624 | | const elem_size = ty.abiAlignment(zcu).minStrict(.@"8").toByteUnits().?; |
| 19625 | | const elem_ty = try pt.intType(.unsigned, @intCast(elem_size * 8)); |
| 19626 | | break :part switch (@divExact(ty.abiSize(zcu) - 8, elem_size)) { |
| 19627 | | 1 => elem_ty, |
| 19628 | | else => |len| try pt.arrayType(.{ .len = len, .child = elem_ty.toIntern() }), |
| 29440 | const TempSpec = struct { |
| 29441 | type: Type = .noreturn, |
| 29442 | kind: Kind, |
| 29443 | |
| 29444 | const unused: TempSpec = .{ .kind = .unused }; |
| 29445 | |
| 29446 | const Kind = union(enum) { |
| 29447 | unused, |
| 29448 | any, |
| 29449 | cc: Condition, |
| 29450 | reg: Register, |
| 29451 | rc: Register.Class, |
| 29452 | rc_mask: struct { rc: Register.Class, info: MaskInfo }, |
| 29453 | mem, |
| 29454 | smin_mem: Select.Operand.Ref, |
| 29455 | smax_mem: Select.Operand.Ref, |
| 29456 | umin_mem: Select.Operand.Ref, |
| 29457 | umax_mem: Select.Operand.Ref, |
| 29458 | ref: Select.Operand.Ref, |
| 29459 | ref_mask: struct { ref: Select.Operand.Ref, info: MaskInfo }, |
| 29460 | |
| 29461 | fn finish(kind: Kind, temp: Temp, s: *const Select) void { |
| 29462 | switch (kind) { |
| 29463 | else => {}, |
| 29464 | inline .rc_mask, .ref_mask => |mask| temp.asMask(mask.info, s.cg), |
| 29465 | } |
| 29466 | } |
| 29467 | }; |
| 29468 | |
| 29469 | fn create(spec: TempSpec, s: *Select) !?Temp { |
| 29470 | const cg = s.cg; |
| 29471 | return switch (spec.kind) { |
| 29472 | .unused => null, |
| 29473 | .any => try cg.tempAlloc(spec.type), |
| 29474 | .cc => |cc| try cg.tempInit(spec.type, .{ .eflags = cc }), |
| 29475 | .reg => |reg| try cg.tempInit(spec.type, .{ .register = reg }), |
| 29476 | .rc => |rc| try cg.tempAllocReg(spec.type, regSetForRegClass(rc)), |
| 29477 | .rc_mask => |rc_mask| try cg.tempAllocReg(spec.type, regSetForRegClass(rc_mask.rc)), |
| 29478 | .mem => try cg.tempAllocMem(spec.type), |
| 29479 | .smin_mem, .smax_mem, .umin_mem, .umax_mem => |ty_ref| { |
| 29480 | const pt = cg.pt; |
| 29481 | const zcu = pt.zcu; |
| 29482 | const ip = &zcu.intern_pool; |
| 29483 | const ty = ty_ref.deref(s).typeOf(s.cg); |
| 29484 | const vector_len, const scalar_ty: Type = switch (ip.indexToKey(ty.toIntern())) { |
| 29485 | else => .{ null, ty }, |
| 29486 | .vector_type => |vector_type| .{ vector_type.len, .fromInterned(vector_type.child) }, |
| 19629 | 29487 | }; |
| 29488 | const res_scalar_ty, const res_scalar_val: Value = res_scalar: switch (scalar_ty.toIntern()) { |
| 29489 | .bool_type => .{ |
| 29490 | scalar_ty, |
| 29491 | .fromInterned(switch (spec.kind) { |
| 29492 | else => unreachable, |
| 29493 | .smin_mem, .umax_mem => .bool_true, |
| 29494 | .smax_mem, .umin_mem => .bool_false, |
| 29495 | }), |
| 29496 | }, |
| 29497 | else => { |
| 29498 | const scalar_info = intInfo(scalar_ty, cg).?; |
| 29499 | const scalar_int_ty = try pt.intType(scalar_info.signedness, scalar_info.bits); |
| 29500 | if (scalar_info.bits <= 64) { |
| 29501 | const int_val: i64 = switch (spec.kind) { |
| 29502 | else => unreachable, |
| 29503 | .smin_mem => std.math.minInt(i64), |
| 29504 | .smax_mem => std.math.maxInt(i64), |
| 29505 | .umin_mem => 0, |
| 29506 | .umax_mem => -1, |
| 29507 | }; |
| 29508 | const shift: u6 = @intCast(64 - scalar_info.bits); |
| 29509 | break :res_scalar .{ scalar_int_ty, switch (scalar_info.signedness) { |
| 29510 | .signed => try pt.intValue_i64(scalar_int_ty, int_val >> shift), |
| 29511 | .unsigned => try pt.intValue_u64(scalar_int_ty, @as(u64, @bitCast(int_val)) >> shift), |
| 29512 | } }; |
| 29513 | } |
| 29514 | var big_int: std.math.big.int.Managed = try .init(cg.gpa); |
| 29515 | defer big_int.deinit(); |
| 29516 | try big_int.setTwosCompIntLimit(switch (spec.kind) { |
| 29517 | else => unreachable, |
| 29518 | .smin_mem, .umin_mem => .min, |
| 29519 | .smax_mem, .umax_mem => .max, |
| 29520 | }, switch (spec.kind) { |
| 29521 | else => unreachable, |
| 29522 | .smin_mem, .smax_mem => .signed, |
| 29523 | .umin_mem, .umax_mem => .unsigned, |
| 29524 | }, scalar_info.bits); |
| 29525 | try big_int.truncate(&big_int, scalar_info.signedness, scalar_info.bits); |
| 29526 | break :res_scalar .{ scalar_int_ty, try pt.intValue_big(scalar_int_ty, big_int.toConst()) }; |
| 29527 | }, |
| 29528 | }; |
| 29529 | const res_val: Value = if (vector_len) |len| .fromInterned(try pt.intern(.{ .aggregate = .{ |
| 29530 | .ty = (try pt.vectorType(.{ |
| 29531 | .len = len, |
| 29532 | .child = res_scalar_ty.toIntern(), |
| 29533 | })).toIntern(), |
| 29534 | .storage = .{ .repeated_elem = res_scalar_val.toIntern() }, |
| 29535 | } })) else res_scalar_val; |
| 29536 | return try cg.tempFromValue(res_val); |
| 19630 | 29537 | }, |
| 19631 | | else => unreachable, |
| 29538 | .ref => |ref| ref.deref(s), |
| 29539 | .ref_mask => |ref_mask| ref_mask.ref.deref(s), |
| 29540 | }; |
| 29541 | } |
| 29542 | }; |
| 29543 | |
| 29544 | const Instruction = struct { |
| 29545 | Label, |
| 29546 | Mir.Inst.Fixes, |
| 29547 | Mir.Inst.Tag, |
| 29548 | Select.Operand, |
| 29549 | Select.Operand, |
| 29550 | Select.Operand, |
| 29551 | Select.Operand, |
| 29552 | }; |
| 29553 | const Label = enum { @"0:", @"1:", @"_" }; |
| 29554 | const Operand = struct { |
| 29555 | tag: Tag, |
| 29556 | base: Ref.Sized = .none, |
| 29557 | index: packed struct(u6) { |
| 29558 | ref: Ref, |
| 29559 | scale: Memory.Scale, |
| 29560 | } = .{ .ref = .none, .scale = .@"1" }, |
| 29561 | adjust: Adjust = .none, |
| 29562 | imm: i32 = 0, |
| 29563 | |
| 29564 | const Tag = enum { |
| 29565 | none, |
| 29566 | backward_label, |
| 29567 | forward_label, |
| 29568 | ref, |
| 29569 | simm, |
| 29570 | uimm, |
| 29571 | lea, |
| 29572 | mem, |
| 29573 | }; |
| 29574 | const Adjust = packed struct(u8) { |
| 29575 | factor: i2, |
| 29576 | scale: Memory.Scale, |
| 29577 | amount: enum(u4) { |
| 29578 | none, |
| 29579 | ptr_size, |
| 29580 | ptr_bit_size, |
| 29581 | size, |
| 29582 | src0_size, |
| 29583 | bit_size, |
| 29584 | src0_bit_size, |
| 29585 | len, |
| 29586 | elem_limbs, |
| 29587 | src0_elem_size, |
| 29588 | src0_elem_size_times_src1, |
| 29589 | log2_src0_elem_size, |
| 29590 | smin, |
| 29591 | smax, |
| 29592 | umax, |
| 19632 | 29593 | }, |
| 19633 | | .float => Type.f32, |
| 19634 | | .float_combine => try pt.arrayType(.{ .len = 2, .child = .f32_type }), |
| 19635 | | .sse => Type.f64, |
| 19636 | | else => break, |
| 29594 | |
| 29595 | const none: Adjust = .{ .factor = 0, .scale = .@"1", .amount = .none }; |
| 29596 | const sub_ptr_size: Adjust = .{ .factor = -1, .scale = .@"1", .amount = .ptr_size }; |
| 29597 | const add_ptr_bit_size: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .ptr_bit_size }; |
| 29598 | const add_size: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .size }; |
| 29599 | const sub_size: Adjust = .{ .factor = -1, .scale = .@"1", .amount = .size }; |
| 29600 | const add_src0_size: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .src0_size }; |
| 29601 | const sub_src0_size: Adjust = .{ .factor = -1, .scale = .@"1", .amount = .src0_size }; |
| 29602 | const add_2_bit_size: Adjust = .{ .factor = 1, .scale = .@"2", .amount = .bit_size }; |
| 29603 | const add_bit_size: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .bit_size }; |
| 29604 | const sub_bit_size: Adjust = .{ .factor = -1, .scale = .@"1", .amount = .bit_size }; |
| 29605 | const add_src0_bit_size: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .src0_bit_size }; |
| 29606 | const sub_src0_bit_size: Adjust = .{ .factor = -1, .scale = .@"1", .amount = .src0_bit_size }; |
| 29607 | const add_8_len: Adjust = .{ .factor = 1, .scale = .@"8", .amount = .len }; |
| 29608 | const add_4_len: Adjust = .{ .factor = 1, .scale = .@"4", .amount = .len }; |
| 29609 | const add_3_len: Adjust = .{ .factor = 1, .scale = .@"3", .amount = .len }; |
| 29610 | const add_2_len: Adjust = .{ .factor = 1, .scale = .@"2", .amount = .len }; |
| 29611 | const add_len: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .len }; |
| 29612 | const sub_len: Adjust = .{ .factor = -1, .scale = .@"1", .amount = .len }; |
| 29613 | const add_src0_elem_size: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .src0_elem_size }; |
| 29614 | const add_2_src0_elem_size: Adjust = .{ .factor = 1, .scale = .@"2", .amount = .src0_elem_size }; |
| 29615 | const add_4_src0_elem_size: Adjust = .{ .factor = 1, .scale = .@"4", .amount = .src0_elem_size }; |
| 29616 | const add_8_src0_elem_size: Adjust = .{ .factor = 1, .scale = .@"8", .amount = .src0_elem_size }; |
| 29617 | const sub_src0_elem_size: Adjust = .{ .factor = -1, .scale = .@"1", .amount = .src0_elem_size }; |
| 29618 | const add_src0_elem_size_times_src1: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .src0_elem_size_times_src1 }; |
| 29619 | const sub_src0_elem_size_times_src1: Adjust = .{ .factor = -1, .scale = .@"1", .amount = .src0_elem_size_times_src1 }; |
| 29620 | const add_log2_src0_elem_size: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .log2_src0_elem_size }; |
| 29621 | const add_elem_limbs: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .elem_limbs }; |
| 29622 | const add_umax: Adjust = .{ .factor = 1, .scale = .@"1", .amount = .umax }; |
| 19637 | 29623 | }; |
| 19638 | | } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts; |
| 19639 | | return self.fail("TODO implement splitType for {}", .{ty.fmt(pt)}); |
| 19640 | | } |
| 29624 | const Ref = enum(u4) { |
| 29625 | tmp0, |
| 29626 | tmp1, |
| 29627 | tmp2, |
| 29628 | tmp3, |
| 29629 | tmp4, |
| 29630 | tmp5, |
| 29631 | dst0, |
| 29632 | src0, |
| 29633 | src1, |
| 29634 | none, |
| 19641 | 29635 | |
| 19642 | | /// Truncates the value in the register in place. |
| 19643 | | /// Clobbers any remaining bits. |
| 19644 | | fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 19645 | | const pt = self.pt; |
| 19646 | | const zcu = pt.zcu; |
| 19647 | | const int_info = if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else std.builtin.Type.Int{ |
| 19648 | | .signedness = .unsigned, |
| 19649 | | .bits = @intCast(ty.bitSize(zcu)), |
| 19650 | | }; |
| 19651 | | const shift = math.cast(u6, 64 - int_info.bits % 64) orelse return; |
| 19652 | | try self.spillEflagsIfOccupied(); |
| 19653 | | switch (int_info.signedness) { |
| 19654 | | .signed => { |
| 19655 | | try self.genShiftBinOpMir( |
| 19656 | | .{ ._l, .sa }, |
| 19657 | | Type.isize, |
| 19658 | | .{ .register = reg }, |
| 19659 | | Type.u8, |
| 19660 | | .{ .immediate = shift }, |
| 19661 | | ); |
| 19662 | | try self.genShiftBinOpMir( |
| 19663 | | .{ ._r, .sa }, |
| 19664 | | Type.isize, |
| 19665 | | .{ .register = reg }, |
| 19666 | | Type.u8, |
| 19667 | | .{ .immediate = shift }, |
| 19668 | | ); |
| 19669 | | }, |
| 19670 | | .unsigned => { |
| 19671 | | const mask = ~@as(u64, 0) >> shift; |
| 19672 | | if (int_info.bits <= 32) { |
| 19673 | | try self.genBinOpMir( |
| 19674 | | .{ ._, .@"and" }, |
| 19675 | | Type.u32, |
| 19676 | | .{ .register = reg }, |
| 19677 | | .{ .immediate = mask }, |
| 19678 | | ); |
| 19679 | | } else { |
| 19680 | | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); |
| 19681 | | try self.genBinOpMir( |
| 19682 | | .{ ._, .@"and" }, |
| 19683 | | Type.usize, |
| 19684 | | .{ .register = reg }, |
| 19685 | | .{ .register = tmp_reg }, |
| 19686 | | ); |
| 19687 | | } |
| 19688 | | }, |
| 19689 | | } |
| 19690 | | } |
| 29636 | const Sized = packed struct(u8) { |
| 29637 | ref: Ref, |
| 29638 | size: Memory.Size, |
| 29639 | |
| 29640 | const none: Sized = .{ .ref = .none, .size = .none }; |
| 29641 | |
| 29642 | const tmp0: Sized = .{ .ref = .tmp0, .size = .none }; |
| 29643 | const tmp0b: Sized = .{ .ref = .tmp0, .size = .byte }; |
| 29644 | const tmp0w: Sized = .{ .ref = .tmp0, .size = .word }; |
| 29645 | const tmp0d: Sized = .{ .ref = .tmp0, .size = .dword }; |
| 29646 | const tmp0p: Sized = .{ .ref = .tmp0, .size = .ptr }; |
| 29647 | const tmp0q: Sized = .{ .ref = .tmp0, .size = .qword }; |
| 29648 | const tmp0x: Sized = .{ .ref = .tmp0, .size = .xword }; |
| 29649 | const tmp0y: Sized = .{ .ref = .tmp0, .size = .yword }; |
| 29650 | |
| 29651 | const tmp1: Sized = .{ .ref = .tmp1, .size = .none }; |
| 29652 | const tmp1b: Sized = .{ .ref = .tmp1, .size = .byte }; |
| 29653 | const tmp1w: Sized = .{ .ref = .tmp1, .size = .word }; |
| 29654 | const tmp1d: Sized = .{ .ref = .tmp1, .size = .dword }; |
| 29655 | const tmp1p: Sized = .{ .ref = .tmp1, .size = .ptr }; |
| 29656 | const tmp1q: Sized = .{ .ref = .tmp1, .size = .qword }; |
| 29657 | const tmp1x: Sized = .{ .ref = .tmp1, .size = .xword }; |
| 29658 | const tmp1y: Sized = .{ .ref = .tmp1, .size = .yword }; |
| 29659 | |
| 29660 | const tmp2: Sized = .{ .ref = .tmp2, .size = .none }; |
| 29661 | const tmp2b: Sized = .{ .ref = .tmp2, .size = .byte }; |
| 29662 | const tmp2w: Sized = .{ .ref = .tmp2, .size = .word }; |
| 29663 | const tmp2d: Sized = .{ .ref = .tmp2, .size = .dword }; |
| 29664 | const tmp2p: Sized = .{ .ref = .tmp2, .size = .ptr }; |
| 29665 | const tmp2q: Sized = .{ .ref = .tmp2, .size = .qword }; |
| 29666 | const tmp2x: Sized = .{ .ref = .tmp2, .size = .xword }; |
| 29667 | const tmp2y: Sized = .{ .ref = .tmp2, .size = .yword }; |
| 29668 | |
| 29669 | const tmp3: Sized = .{ .ref = .tmp3, .size = .none }; |
| 29670 | const tmp3b: Sized = .{ .ref = .tmp3, .size = .byte }; |
| 29671 | const tmp3w: Sized = .{ .ref = .tmp3, .size = .word }; |
| 29672 | const tmp3d: Sized = .{ .ref = .tmp3, .size = .dword }; |
| 29673 | const tmp3p: Sized = .{ .ref = .tmp3, .size = .ptr }; |
| 29674 | const tmp3q: Sized = .{ .ref = .tmp3, .size = .qword }; |
| 29675 | const tmp3x: Sized = .{ .ref = .tmp3, .size = .xword }; |
| 29676 | const tmp3y: Sized = .{ .ref = .tmp3, .size = .yword }; |
| 29677 | |
| 29678 | const tmp4: Sized = .{ .ref = .tmp4, .size = .none }; |
| 29679 | const tmp4b: Sized = .{ .ref = .tmp4, .size = .byte }; |
| 29680 | const tmp4w: Sized = .{ .ref = .tmp4, .size = .word }; |
| 29681 | const tmp4d: Sized = .{ .ref = .tmp4, .size = .dword }; |
| 29682 | const tmp4p: Sized = .{ .ref = .tmp4, .size = .ptr }; |
| 29683 | const tmp4q: Sized = .{ .ref = .tmp4, .size = .qword }; |
| 29684 | const tmp4x: Sized = .{ .ref = .tmp4, .size = .xword }; |
| 29685 | const tmp4y: Sized = .{ .ref = .tmp4, .size = .yword }; |
| 29686 | |
| 29687 | const tmp5: Sized = .{ .ref = .tmp5, .size = .none }; |
| 29688 | const tmp5b: Sized = .{ .ref = .tmp5, .size = .byte }; |
| 29689 | const tmp5w: Sized = .{ .ref = .tmp5, .size = .word }; |
| 29690 | const tmp5d: Sized = .{ .ref = .tmp5, .size = .dword }; |
| 29691 | const tmp5p: Sized = .{ .ref = .tmp5, .size = .ptr }; |
| 29692 | const tmp5q: Sized = .{ .ref = .tmp5, .size = .qword }; |
| 29693 | const tmp5x: Sized = .{ .ref = .tmp5, .size = .xword }; |
| 29694 | const tmp5y: Sized = .{ .ref = .tmp5, .size = .yword }; |
| 29695 | |
| 29696 | const dst0: Sized = .{ .ref = .dst0, .size = .none }; |
| 29697 | const dst0b: Sized = .{ .ref = .dst0, .size = .byte }; |
| 29698 | const dst0w: Sized = .{ .ref = .dst0, .size = .word }; |
| 29699 | const dst0d: Sized = .{ .ref = .dst0, .size = .dword }; |
| 29700 | const dst0p: Sized = .{ .ref = .dst0, .size = .ptr }; |
| 29701 | const dst0q: Sized = .{ .ref = .dst0, .size = .qword }; |
| 29702 | const dst0x: Sized = .{ .ref = .dst0, .size = .xword }; |
| 29703 | const dst0y: Sized = .{ .ref = .dst0, .size = .yword }; |
| 29704 | |
| 29705 | const src0: Sized = .{ .ref = .src0, .size = .none }; |
| 29706 | const src0b: Sized = .{ .ref = .src0, .size = .byte }; |
| 29707 | const src0w: Sized = .{ .ref = .src0, .size = .word }; |
| 29708 | const src0d: Sized = .{ .ref = .src0, .size = .dword }; |
| 29709 | const src0p: Sized = .{ .ref = .src0, .size = .ptr }; |
| 29710 | const src0q: Sized = .{ .ref = .src0, .size = .qword }; |
| 29711 | const src0x: Sized = .{ .ref = .src0, .size = .xword }; |
| 29712 | const src0y: Sized = .{ .ref = .src0, .size = .yword }; |
| 29713 | |
| 29714 | const src1: Sized = .{ .ref = .src1, .size = .none }; |
| 29715 | const src1b: Sized = .{ .ref = .src1, .size = .byte }; |
| 29716 | const src1w: Sized = .{ .ref = .src1, .size = .word }; |
| 29717 | const src1d: Sized = .{ .ref = .src1, .size = .dword }; |
| 29718 | const src1p: Sized = .{ .ref = .src1, .size = .ptr }; |
| 29719 | const src1q: Sized = .{ .ref = .src1, .size = .qword }; |
| 29720 | const src1x: Sized = .{ .ref = .src1, .size = .xword }; |
| 29721 | const src1y: Sized = .{ .ref = .src1, .size = .yword }; |
| 29722 | }; |
| 19691 | 29723 | |
| 19692 | | fn regBitSize(self: *Self, ty: Type) u64 { |
| 19693 | | const pt = self.pt; |
| 19694 | | const zcu = pt.zcu; |
| 19695 | | const abi_size = ty.abiSize(zcu); |
| 19696 | | return switch (ty.zigTypeTag(zcu)) { |
| 19697 | | else => switch (abi_size) { |
| 19698 | | 1 => 8, |
| 19699 | | 2 => 16, |
| 19700 | | 3...4 => 32, |
| 19701 | | 5...8 => 64, |
| 19702 | | else => unreachable, |
| 19703 | | }, |
| 19704 | | .float => switch (abi_size) { |
| 19705 | | 1...16 => 128, |
| 19706 | | 17...32 => 256, |
| 19707 | | else => unreachable, |
| 19708 | | }, |
| 19709 | | }; |
| 19710 | | } |
| 29724 | fn deref(ref: Ref, s: *const Select) Temp { |
| 29725 | return s.temps[@intFromEnum(ref)]; |
| 29726 | } |
| 29727 | }; |
| 19711 | 29728 | |
| 19712 | | fn regExtraBits(self: *Self, ty: Type) u64 { |
| 19713 | | return self.regBitSize(ty) - ty.bitSize(self.pt.zcu); |
| 19714 | | } |
| 29729 | const @"_": Select.Operand = .{ .tag = .none }; |
| 29730 | |
| 29731 | const @"0b": Select.Operand = .{ .tag = .backward_label, .base = .{ .ref = .tmp0, .size = .none } }; |
| 29732 | const @"0f": Select.Operand = .{ .tag = .forward_label, .base = .{ .ref = .tmp0, .size = .none } }; |
| 29733 | const @"1b": Select.Operand = .{ .tag = .backward_label, .base = .{ .ref = .tmp1, .size = .none } }; |
| 29734 | const @"1f": Select.Operand = .{ .tag = .forward_label, .base = .{ .ref = .tmp1, .size = .none } }; |
| 29735 | |
| 29736 | const tmp0b: Select.Operand = .{ .tag = .ref, .base = .tmp0b }; |
| 29737 | const tmp0w: Select.Operand = .{ .tag = .ref, .base = .tmp0w }; |
| 29738 | const tmp0d: Select.Operand = .{ .tag = .ref, .base = .tmp0d }; |
| 29739 | const tmp0p: Select.Operand = .{ .tag = .ref, .base = .tmp0p }; |
| 29740 | const tmp0q: Select.Operand = .{ .tag = .ref, .base = .tmp0q }; |
| 29741 | const tmp0x: Select.Operand = .{ .tag = .ref, .base = .tmp0x }; |
| 29742 | const tmp0y: Select.Operand = .{ .tag = .ref, .base = .tmp0y }; |
| 29743 | |
| 29744 | const tmp1b: Select.Operand = .{ .tag = .ref, .base = .tmp1b }; |
| 29745 | const tmp1w: Select.Operand = .{ .tag = .ref, .base = .tmp1w }; |
| 29746 | const tmp1d: Select.Operand = .{ .tag = .ref, .base = .tmp1d }; |
| 29747 | const tmp1p: Select.Operand = .{ .tag = .ref, .base = .tmp1p }; |
| 29748 | const tmp1q: Select.Operand = .{ .tag = .ref, .base = .tmp1q }; |
| 29749 | const tmp1x: Select.Operand = .{ .tag = .ref, .base = .tmp1x }; |
| 29750 | const tmp1y: Select.Operand = .{ .tag = .ref, .base = .tmp1y }; |
| 29751 | |
| 29752 | const tmp2b: Select.Operand = .{ .tag = .ref, .base = .tmp2b }; |
| 29753 | const tmp2w: Select.Operand = .{ .tag = .ref, .base = .tmp2w }; |
| 29754 | const tmp2d: Select.Operand = .{ .tag = .ref, .base = .tmp2d }; |
| 29755 | const tmp2p: Select.Operand = .{ .tag = .ref, .base = .tmp2p }; |
| 29756 | const tmp2q: Select.Operand = .{ .tag = .ref, .base = .tmp2q }; |
| 29757 | const tmp2x: Select.Operand = .{ .tag = .ref, .base = .tmp2x }; |
| 29758 | const tmp2y: Select.Operand = .{ .tag = .ref, .base = .tmp2y }; |
| 29759 | |
| 29760 | const tmp3b: Select.Operand = .{ .tag = .ref, .base = .tmp3b }; |
| 29761 | const tmp3w: Select.Operand = .{ .tag = .ref, .base = .tmp3w }; |
| 29762 | const tmp3d: Select.Operand = .{ .tag = .ref, .base = .tmp3d }; |
| 29763 | const tmp3p: Select.Operand = .{ .tag = .ref, .base = .tmp3p }; |
| 29764 | const tmp3q: Select.Operand = .{ .tag = .ref, .base = .tmp3q }; |
| 29765 | const tmp3x: Select.Operand = .{ .tag = .ref, .base = .tmp3x }; |
| 29766 | const tmp3y: Select.Operand = .{ .tag = .ref, .base = .tmp3y }; |
| 29767 | |
| 29768 | const tmp4b: Select.Operand = .{ .tag = .ref, .base = .tmp4b }; |
| 29769 | const tmp4w: Select.Operand = .{ .tag = .ref, .base = .tmp4w }; |
| 29770 | const tmp4d: Select.Operand = .{ .tag = .ref, .base = .tmp4d }; |
| 29771 | const tmp4p: Select.Operand = .{ .tag = .ref, .base = .tmp4p }; |
| 29772 | const tmp4q: Select.Operand = .{ .tag = .ref, .base = .tmp4q }; |
| 29773 | const tmp4x: Select.Operand = .{ .tag = .ref, .base = .tmp4x }; |
| 29774 | const tmp4y: Select.Operand = .{ .tag = .ref, .base = .tmp4y }; |
| 29775 | |
| 29776 | const tmp5b: Select.Operand = .{ .tag = .ref, .base = .tmp5b }; |
| 29777 | const tmp5w: Select.Operand = .{ .tag = .ref, .base = .tmp5w }; |
| 29778 | const tmp5d: Select.Operand = .{ .tag = .ref, .base = .tmp5d }; |
| 29779 | const tmp5p: Select.Operand = .{ .tag = .ref, .base = .tmp5p }; |
| 29780 | const tmp5q: Select.Operand = .{ .tag = .ref, .base = .tmp5q }; |
| 29781 | const tmp5x: Select.Operand = .{ .tag = .ref, .base = .tmp5x }; |
| 29782 | const tmp5y: Select.Operand = .{ .tag = .ref, .base = .tmp5y }; |
| 29783 | |
| 29784 | const dst0b: Select.Operand = .{ .tag = .ref, .base = .dst0b }; |
| 29785 | const dst0w: Select.Operand = .{ .tag = .ref, .base = .dst0w }; |
| 29786 | const dst0d: Select.Operand = .{ .tag = .ref, .base = .dst0d }; |
| 29787 | const dst0p: Select.Operand = .{ .tag = .ref, .base = .dst0p }; |
| 29788 | const dst0q: Select.Operand = .{ .tag = .ref, .base = .dst0q }; |
| 29789 | const dst0x: Select.Operand = .{ .tag = .ref, .base = .dst0x }; |
| 29790 | const dst0y: Select.Operand = .{ .tag = .ref, .base = .dst0y }; |
| 29791 | |
| 29792 | const src0b: Select.Operand = .{ .tag = .ref, .base = .src0b }; |
| 29793 | const src0w: Select.Operand = .{ .tag = .ref, .base = .src0w }; |
| 29794 | const src0d: Select.Operand = .{ .tag = .ref, .base = .src0d }; |
| 29795 | const src0p: Select.Operand = .{ .tag = .ref, .base = .src0p }; |
| 29796 | const src0q: Select.Operand = .{ .tag = .ref, .base = .src0q }; |
| 29797 | const src0x: Select.Operand = .{ .tag = .ref, .base = .src0x }; |
| 29798 | const src0y: Select.Operand = .{ .tag = .ref, .base = .src0y }; |
| 29799 | |
| 29800 | const src1b: Select.Operand = .{ .tag = .ref, .base = .src1b }; |
| 29801 | const src1w: Select.Operand = .{ .tag = .ref, .base = .src1w }; |
| 29802 | const src1d: Select.Operand = .{ .tag = .ref, .base = .src1d }; |
| 29803 | const src1p: Select.Operand = .{ .tag = .ref, .base = .src1p }; |
| 29804 | const src1q: Select.Operand = .{ .tag = .ref, .base = .src1q }; |
| 29805 | const src1x: Select.Operand = .{ .tag = .ref, .base = .src1x }; |
| 29806 | const src1y: Select.Operand = .{ .tag = .ref, .base = .src1y }; |
| 29807 | |
| 29808 | fn si(imm: i32) Select.Operand { |
| 29809 | return .{ .tag = .simm, .imm = imm }; |
| 29810 | } |
| 29811 | fn sa(base: Ref.Sized, adjust: Adjust) Select.Operand { |
| 29812 | return .{ .tag = .simm, .base = base, .adjust = adjust }; |
| 29813 | } |
| 29814 | fn sia(imm: i32, base: Ref.Sized, adjust: Adjust) Select.Operand { |
| 29815 | return .{ .tag = .simm, .base = base, .adjust = adjust, .imm = imm }; |
| 29816 | } |
| 29817 | fn ui(imm: i32) Select.Operand { |
| 29818 | return .{ .tag = .uimm, .imm = imm }; |
| 29819 | } |
| 29820 | fn ua(base: Ref.Sized, adjust: Adjust) Select.Operand { |
| 29821 | return .{ .tag = .uimm, .base = base, .adjust = adjust }; |
| 29822 | } |
| 29823 | fn uia(imm: i32, base: Ref.Sized, adjust: Adjust) Select.Operand { |
| 29824 | return .{ .tag = .uimm, .base = base, .adjust = adjust, .imm = imm }; |
| 29825 | } |
| 19715 | 29826 | |
| 19716 | | fn hasFeature(self: *Self, feature: Target.x86.Feature) bool { |
| 19717 | | return Target.x86.featureSetHas(self.target.cpu.features, feature); |
| 19718 | | } |
| 19719 | | fn hasAnyFeatures(self: *Self, features: anytype) bool { |
| 19720 | | return Target.x86.featureSetHasAny(self.target.cpu.features, features); |
| 19721 | | } |
| 19722 | | fn hasAllFeatures(self: *Self, features: anytype) bool { |
| 19723 | | return Target.x86.featureSetHasAll(self.target.cpu.features, features); |
| 19724 | | } |
| 29827 | fn lea(size: Memory.Size, base: Ref) Select.Operand { |
| 29828 | return .{ |
| 29829 | .tag = .lea, |
| 29830 | .base = .{ .ref = base, .size = size }, |
| 29831 | }; |
| 29832 | } |
| 29833 | fn leaa(size: Memory.Size, base: Ref, adjust: Adjust) Select.Operand { |
| 29834 | return .{ |
| 29835 | .tag = .lea, |
| 29836 | .base = .{ .ref = base, .size = size }, |
| 29837 | .adjust = adjust, |
| 29838 | }; |
| 29839 | } |
| 29840 | fn lead(size: Memory.Size, base: Ref, disp: i32) Select.Operand { |
| 29841 | return .{ |
| 29842 | .tag = .lea, |
| 29843 | .base = .{ .ref = base, .size = size }, |
| 29844 | .imm = disp, |
| 29845 | }; |
| 29846 | } |
| 29847 | fn leai(size: Memory.Size, base: Ref, index: Ref) Select.Operand { |
| 29848 | return .{ |
| 29849 | .tag = .lea, |
| 29850 | .base = .{ .ref = base, .size = size }, |
| 29851 | .index = .{ .ref = index, .scale = .@"1" }, |
| 29852 | }; |
| 29853 | } |
| 29854 | fn leaia(size: Memory.Size, base: Ref, index: Ref, adjust: Adjust) Select.Operand { |
| 29855 | return .{ |
| 29856 | .tag = .lea, |
| 29857 | .base = .{ .ref = base, .size = size }, |
| 29858 | .index = .{ .ref = index, .scale = .@"1" }, |
| 29859 | .adjust = adjust, |
| 29860 | }; |
| 29861 | } |
| 29862 | fn leaid(size: Memory.Size, base: Ref, index: Ref, disp: i32) Select.Operand { |
| 29863 | return .{ |
| 29864 | .tag = .lea, |
| 29865 | .base = .{ .ref = base, .size = size }, |
| 29866 | .index = .{ .ref = index, .scale = .@"1" }, |
| 29867 | .imm = disp, |
| 29868 | }; |
| 29869 | } |
| 29870 | fn leasi(size: Memory.Size, base: Ref, scale: Memory.Scale, index: Ref) Select.Operand { |
| 29871 | return .{ |
| 29872 | .tag = .lea, |
| 29873 | .base = .{ .ref = base, .size = size }, |
| 29874 | .index = .{ .ref = index, .scale = scale }, |
| 29875 | }; |
| 29876 | } |
| 29877 | fn leasid(size: Memory.Size, base: Ref, scale: Memory.Scale, index: Ref, disp: i32) Select.Operand { |
| 29878 | return .{ |
| 29879 | .tag = .lea, |
| 29880 | .base = .{ .ref = base, .size = size }, |
| 29881 | .index = .{ .ref = index, .scale = scale }, |
| 29882 | .imm = disp, |
| 29883 | }; |
| 29884 | } |
| 29885 | fn leasiad(size: Memory.Size, base: Ref, scale: Memory.Scale, index: Ref, adjust: Adjust, disp: i32) Select.Operand { |
| 29886 | return .{ |
| 29887 | .tag = .lea, |
| 29888 | .base = .{ .ref = base, .size = size }, |
| 29889 | .index = .{ .ref = index, .scale = scale }, |
| 29890 | .adjust = adjust, |
| 29891 | .imm = disp, |
| 29892 | }; |
| 29893 | } |
| 19725 | 29894 | |
| 19726 | | fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { |
| 19727 | | const pt = self.pt; |
| 19728 | | const zcu = pt.zcu; |
| 19729 | | return self.air.typeOf(inst, &zcu.intern_pool); |
| 19730 | | } |
| 29895 | fn mem(base: Ref.Sized) Select.Operand { |
| 29896 | return .{ |
| 29897 | .tag = .mem, |
| 29898 | .base = base, |
| 29899 | }; |
| 29900 | } |
| 29901 | fn memd(base: Ref.Sized, disp: i32) Select.Operand { |
| 29902 | return .{ |
| 29903 | .tag = .mem, |
| 29904 | .base = base, |
| 29905 | .imm = disp, |
| 29906 | }; |
| 29907 | } |
| 29908 | fn mema(base: Ref.Sized, adjust: Adjust) Select.Operand { |
| 29909 | return .{ |
| 29910 | .tag = .mem, |
| 29911 | .base = base, |
| 29912 | .adjust = adjust, |
| 29913 | }; |
| 29914 | } |
| 29915 | fn memad(base: Ref.Sized, adjust: Adjust, disp: i32) Select.Operand { |
| 29916 | return .{ |
| 29917 | .tag = .mem, |
| 29918 | .base = base, |
| 29919 | .adjust = adjust, |
| 29920 | .imm = disp, |
| 29921 | }; |
| 29922 | } |
| 29923 | fn memi(base: Ref.Sized, index: Ref) Select.Operand { |
| 29924 | return .{ |
| 29925 | .tag = .mem, |
| 29926 | .base = base, |
| 29927 | .index = .{ .ref = index, .scale = .@"1" }, |
| 29928 | }; |
| 29929 | } |
| 29930 | fn memia(base: Ref.Sized, index: Ref, adjust: Adjust) Select.Operand { |
| 29931 | return .{ |
| 29932 | .tag = .mem, |
| 29933 | .base = base, |
| 29934 | .index = .{ .ref = index, .scale = .@"1" }, |
| 29935 | .adjust = adjust, |
| 29936 | }; |
| 29937 | } |
| 29938 | fn memiad(base: Ref.Sized, index: Ref, adjust: Adjust, disp: i32) Select.Operand { |
| 29939 | return .{ |
| 29940 | .tag = .mem, |
| 29941 | .base = base, |
| 29942 | .index = .{ .ref = index, .scale = .@"1" }, |
| 29943 | .adjust = adjust, |
| 29944 | .imm = disp, |
| 29945 | }; |
| 29946 | } |
| 29947 | fn memid(base: Ref.Sized, index: Ref, disp: i32) Select.Operand { |
| 29948 | return .{ |
| 29949 | .tag = .mem, |
| 29950 | .base = base, |
| 29951 | .index = .{ .ref = index, .scale = .@"1" }, |
| 29952 | .imm = disp, |
| 29953 | }; |
| 29954 | } |
| 29955 | fn memsi(base: Ref.Sized, scale: Memory.Scale, index: Ref) Select.Operand { |
| 29956 | return .{ |
| 29957 | .tag = .mem, |
| 29958 | .base = base, |
| 29959 | .index = .{ .ref = index, .scale = scale }, |
| 29960 | }; |
| 29961 | } |
| 29962 | fn memsia(base: Ref.Sized, scale: Memory.Scale, index: Ref, adjust: Adjust) Select.Operand { |
| 29963 | return .{ |
| 29964 | .tag = .mem, |
| 29965 | .base = base, |
| 29966 | .index = .{ .ref = index, .scale = scale }, |
| 29967 | .adjust = adjust, |
| 29968 | }; |
| 29969 | } |
| 29970 | fn memsid(base: Ref.Sized, scale: Memory.Scale, index: Ref, disp: i32) Select.Operand { |
| 29971 | return .{ |
| 29972 | .tag = .mem, |
| 29973 | .base = base, |
| 29974 | .index = .{ .ref = index, .scale = scale }, |
| 29975 | .imm = disp, |
| 29976 | }; |
| 29977 | } |
| 29978 | fn memsiad(base: Ref.Sized, scale: Memory.Scale, index: Ref, adjust: Adjust, disp: i32) Select.Operand { |
| 29979 | return .{ |
| 29980 | .tag = .mem, |
| 29981 | .base = base, |
| 29982 | .index = .{ .ref = index, .scale = scale }, |
| 29983 | .adjust = adjust, |
| 29984 | .imm = disp, |
| 29985 | }; |
| 29986 | } |
| 19731 | 29987 | |
| 19732 | | fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { |
| 19733 | | const pt = self.pt; |
| 19734 | | const zcu = pt.zcu; |
| 19735 | | return switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) { |
| 19736 | | .loop_switch_br => self.typeOf(self.air.unwrapSwitch(inst).operand), |
| 19737 | | else => self.air.typeOfIndex(inst, &zcu.intern_pool), |
| 19738 | | }; |
| 19739 | | } |
| 29988 | fn adjustedImm(op: Select.Operand, comptime SignedImm: type, s: *const Select) SignedImm { |
| 29989 | const UnsignedImm = @Type(.{ |
| 29990 | .int = .{ .signedness = .unsigned, .bits = @typeInfo(SignedImm).int.bits }, |
| 29991 | }); |
| 29992 | return @as(i5, op.adjust.factor) * op.adjust.scale.toFactor() * @as(SignedImm, switch (op.adjust.amount) { |
| 29993 | .none => 0, |
| 29994 | .ptr_size => @divExact(s.cg.target.ptrBitWidth(), 8), |
| 29995 | .ptr_bit_size => s.cg.target.ptrBitWidth(), |
| 29996 | .size => @intCast(op.base.ref.deref(s).typeOf(s.cg).abiSize(s.cg.pt.zcu)), |
| 29997 | .src0_size => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).abiSize(s.cg.pt.zcu)), |
| 29998 | .bit_size => @intCast(op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu)), |
| 29999 | .src0_bit_size => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu)), |
| 30000 | .len => @intCast(op.base.ref.deref(s).typeOf(s.cg).vectorLen(s.cg.pt.zcu)), |
| 30001 | .elem_limbs => @intCast(@divExact( |
| 30002 | op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu), |
| 30003 | @divExact(op.base.size.bitSize(s.cg.target), 8), |
| 30004 | )), |
| 30005 | .src0_elem_size => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), |
| 30006 | .src0_elem_size_times_src1 => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * |
| 30007 | Select.Operand.Ref.src1.deref(s).tracking(s.cg).short.immediate), |
| 30008 | .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))), |
| 30009 | .smin => @as(SignedImm, std.math.minInt(SignedImm)) >> @truncate( |
| 30010 | -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu), |
| 30011 | ), |
| 30012 | .smax => @as(SignedImm, std.math.maxInt(SignedImm)) >> @truncate( |
| 30013 | -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu), |
| 30014 | ), |
| 30015 | .umax => @bitCast(@as(UnsignedImm, std.math.maxInt(UnsignedImm)) >> @truncate( |
| 30016 | -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu), |
| 30017 | )), |
| 30018 | }) + op.imm; |
| 30019 | } |
| 19740 | 30020 | |
| 19741 | | fn intCompilerRtAbiName(int_bits: u32) u8 { |
| 19742 | | return switch (int_bits) { |
| 19743 | | 1...32 => 's', |
| 19744 | | 33...64 => 'd', |
| 19745 | | 65...128 => 't', |
| 19746 | | else => unreachable, |
| 30021 | fn lower(op: Select.Operand, s: *Select) !CodeGen.Operand { |
| 30022 | return switch (op.tag) { |
| 30023 | .none => .none, |
| 30024 | .backward_label => .{ .inst = s.labels[@intFromEnum(op.base.ref)].backward.? }, |
| 30025 | .forward_label => for (&s.labels[@intFromEnum(op.base.ref)].forward) |*label| { |
| 30026 | if (label.*) |_| continue; |
| 30027 | label.* = @intCast(s.cg.mir_instructions.len); |
| 30028 | break .{ .inst = undefined }; |
| 30029 | } else unreachable, |
| 30030 | .ref => switch (op.base.ref.deref(s).tracking(s.cg).short) { |
| 30031 | .immediate => |imm| .{ .imm = switch (op.base.size) { |
| 30032 | .byte => if (std.math.cast(i8, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u8, @intCast(imm))), |
| 30033 | .word => if (std.math.cast(i16, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u16, @intCast(imm))), |
| 30034 | .dword => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u32, @intCast(imm))), |
| 30035 | .qword => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(imm), |
| 30036 | else => unreachable, |
| 30037 | } }, |
| 30038 | else => |mcv| .{ .mem = try mcv.mem(s.cg, .{ .size = op.base.size }) }, |
| 30039 | .register => |reg| .{ .reg = registerAlias(reg, @intCast(@divExact(op.base.size.bitSize(s.cg.target), 8))) }, |
| 30040 | }, |
| 30041 | .simm => .{ .imm = .s(op.adjustedImm(i32, s)) }, |
| 30042 | .uimm => .{ .imm = .u(@bitCast(op.adjustedImm(i64, s))) }, |
| 30043 | .lea => .{ .mem = .{ |
| 30044 | .base = .{ .reg = registerAlias(op.base.ref.deref(s).tracking(s.cg).short.register, @divExact(s.cg.target.ptrBitWidth(), 8)) }, |
| 30045 | .mod = .{ .rm = .{ |
| 30046 | .size = op.base.size, |
| 30047 | .index = switch (op.index.ref) { |
| 30048 | else => |ref| registerAlias(ref.deref(s).tracking(s.cg).short.register, @divExact(s.cg.target.ptrBitWidth(), 8)), |
| 30049 | .none => .none, |
| 30050 | }, |
| 30051 | .scale = op.index.scale, |
| 30052 | .disp = op.adjustedImm(i32, s), |
| 30053 | } }, |
| 30054 | } }, |
| 30055 | .mem => .{ .mem = try op.base.ref.deref(s).tracking(s.cg).short.mem(s.cg, .{ |
| 30056 | .size = op.base.size, |
| 30057 | .index = switch (op.index.ref) { |
| 30058 | else => |ref| registerAlias(ref.deref(s).tracking(s.cg).short.register, @divExact(s.cg.target.ptrBitWidth(), 8)), |
| 30059 | .none => .none, |
| 30060 | }, |
| 30061 | .scale = op.index.scale, |
| 30062 | .disp = op.adjustedImm(i32, s), |
| 30063 | }) }, |
| 30064 | }; |
| 30065 | } |
| 19747 | 30066 | }; |
| 19748 | | } |
| 30067 | }; |
| 30068 | fn select( |
| 30069 | cg: *CodeGen, |
| 30070 | dst_temps: []Temp, |
| 30071 | dst_tys: []const Type, |
| 30072 | src_temps: []Temp, |
| 30073 | cases: []const Select.Case, |
| 30074 | ) !void { |
| 30075 | cases: for (cases) |case| { |
| 30076 | for (case.required_features) |required_feature| if (required_feature) |feature| if (!cg.hasFeature(feature)) continue :cases; |
| 30077 | for (case.dst_constraints[0..dst_temps.len], dst_tys) |dst_constraint, dst_ty| if (!dst_constraint.accepts(dst_ty, cg)) continue :cases; |
| 30078 | for (case.src_constraints[0..src_temps.len], src_temps) |src_constraint, src_temp| if (!src_constraint.accepts(src_temp.typeOf(cg), cg)) continue :cases; |
| 30079 | if (std.debug.runtime_safety) { |
| 30080 | for (case.dst_constraints[dst_temps.len..]) |dst_constraint| assert(dst_constraint == .any); |
| 30081 | for (case.src_constraints[src_temps.len..]) |src_constraint| assert(src_constraint == .any); |
| 30082 | } |
| 30083 | patterns: for (case.patterns) |pattern| { |
| 30084 | for (pattern.src[0..src_temps.len], src_temps) |src_pattern, src_temp| if (!src_pattern.matches(src_temp, cg)) continue :patterns; |
| 30085 | if (std.debug.runtime_safety) for (pattern.src[src_temps.len..]) |src_pattern| assert(src_pattern == .none); |
| 30086 | |
| 30087 | var s: Select = .{ |
| 30088 | .cg = cg, |
| 30089 | .temps = undefined, |
| 30090 | .labels = @splat(.{ .forward = @splat(null), .backward = null }), |
| 30091 | }; |
| 30092 | const tmp_slots = s.temps[@intFromEnum(Select.Operand.Ref.tmp0)..@intFromEnum(Select.Operand.Ref.dst0)]; |
| 30093 | const dst_slots = s.temps[@intFromEnum(Select.Operand.Ref.dst0)..@intFromEnum(Select.Operand.Ref.src0)]; |
| 30094 | const src_slots = s.temps[@intFromEnum(Select.Operand.Ref.src0)..@intFromEnum(Select.Operand.Ref.none)]; |
| 19749 | 30095 | |
| 19750 | | fn floatCompilerRtAbiName(float_bits: u32) u8 { |
| 19751 | | return switch (float_bits) { |
| 19752 | | 16 => 'h', |
| 19753 | | 32 => 's', |
| 19754 | | 64 => 'd', |
| 19755 | | 80 => 'x', |
| 19756 | | 128 => 't', |
| 19757 | | else => unreachable, |
| 19758 | | }; |
| 19759 | | } |
| 30096 | @memcpy(src_slots[0..src_temps.len], src_temps); |
| 30097 | std.mem.swap(Temp, &src_slots[pattern.commute[0]], &src_slots[pattern.commute[1]]); |
| 30098 | for (tmp_slots, case.extra_temps) |*slot, spec| slot.* = try spec.create(&s) orelse continue; |
| 19760 | 30099 | |
| 19761 | | fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type { |
| 19762 | | if (ty.toIntern() == .f16_type and |
| 19763 | | (other_ty.toIntern() == .f32_type or other_ty.toIntern() == .f64_type) and |
| 19764 | | self.target.isDarwin()) return Type.u16; |
| 19765 | | return ty; |
| 19766 | | } |
| 30100 | while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| { |
| 30101 | if (try src_pattern.convert(src_temp, cg)) break; |
| 30102 | } else break; |
| 30103 | @memcpy(src_slots[0..src_temps.len], src_temps); |
| 30104 | std.mem.swap(Temp, &src_slots[pattern.commute[0]], &src_slots[pattern.commute[1]]); |
| 19767 | 30105 | |
| 19768 | | fn floatLibcAbiPrefix(ty: Type) []const u8 { |
| 19769 | | return switch (ty.toIntern()) { |
| 19770 | | .f16_type, .f80_type => "__", |
| 19771 | | .f32_type, .f64_type, .f128_type, .c_longdouble_type => "", |
| 19772 | | else => unreachable, |
| 19773 | | }; |
| 19774 | | } |
| 30106 | if (case.clobbers.eflags or case.each != .once) try cg.spillEflagsIfOccupied(); |
| 19775 | 30107 | |
| 19776 | | fn floatLibcAbiSuffix(ty: Type) []const u8 { |
| 19777 | | return switch (ty.toIntern()) { |
| 19778 | | .f16_type => "h", |
| 19779 | | .f32_type => "f", |
| 19780 | | .f64_type => "", |
| 19781 | | .f80_type => "x", |
| 19782 | | .f128_type => "q", |
| 19783 | | .c_longdouble_type => "l", |
| 19784 | | else => unreachable, |
| 19785 | | }; |
| 19786 | | } |
| 30108 | for (dst_temps, dst_tys, case.dst_temps[0..dst_temps.len]) |*dst_temp, dst_ty, dst_kind| |
| 30109 | dst_temp.* = (try Select.TempSpec.create(.{ .type = dst_ty, .kind = dst_kind }, &s)).?; |
| 30110 | @memcpy(dst_slots[0..dst_temps.len], dst_temps); |
| 19787 | 30111 | |
| 19788 | | fn promoteInt(self: *Self, ty: Type) Type { |
| 19789 | | const pt = self.pt; |
| 19790 | | const zcu = pt.zcu; |
| 19791 | | const int_info: InternPool.Key.IntType = switch (ty.toIntern()) { |
| 19792 | | .bool_type => .{ .signedness = .unsigned, .bits = 1 }, |
| 19793 | | else => if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else return ty, |
| 19794 | | }; |
| 19795 | | for ([_]Type{ |
| 19796 | | Type.c_int, Type.c_uint, |
| 19797 | | Type.c_long, Type.c_ulong, |
| 19798 | | Type.c_longlong, Type.c_ulonglong, |
| 19799 | | }) |promote_ty| { |
| 19800 | | const promote_info = promote_ty.intInfo(zcu); |
| 19801 | | if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue; |
| 19802 | | if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and |
| 19803 | | promote_info.signedness == .signed) <= promote_info.bits) return promote_ty; |
| 19804 | | } |
| 19805 | | return ty; |
| 19806 | | } |
| 30112 | switch (case.each) { |
| 30113 | .once => |body| { |
| 30114 | for (body) |inst| try s.emit(inst); |
| 30115 | s.emitLabel(.@"0:"); |
| 30116 | }, |
| 30117 | } |
| 19807 | 30118 | |
| 19808 | | fn promoteVarArg(self: *Self, ty: Type) Type { |
| 19809 | | if (!ty.isRuntimeFloat()) return self.promoteInt(ty); |
| 19810 | | switch (ty.floatBits(self.target.*)) { |
| 19811 | | 32, 64 => return Type.f64, |
| 19812 | | else => |float_bits| { |
| 19813 | | assert(float_bits == self.target.cTypeBitSize(.longdouble)); |
| 19814 | | return Type.c_longdouble; |
| 19815 | | }, |
| 30119 | for (dst_temps, case.dst_temps[0..dst_temps.len]) |dst_temp, dst_kind| dst_kind.finish(dst_temp, &s); |
| 30120 | for (case.extra_temps, tmp_slots) |spec, temp| if (spec.kind != .unused) try temp.die(cg); |
| 30121 | return; |
| 30122 | } |
| 19816 | 30123 | } |
| 30124 | return error.SelectFailed; |
| 19817 | 30125 | } |