| ... | @@ -22,6 +22,8 @@ const DW = std.dwarf; | ... | @@ -22,6 +22,8 @@ const DW = std.dwarf; |
| 22 | const leb128 = std.leb; | 22 | const leb128 = std.leb; |
| 23 | const log = std.log.scoped(.riscv_codegen); | 23 | const log = std.log.scoped(.riscv_codegen); |
| 24 | const tracking_log = std.log.scoped(.tracking); | 24 | const tracking_log = std.log.scoped(.tracking); |
| | 25 | const verbose_tracking_log = std.log.scoped(.verbose_tracking); |
| | 26 | const wip_mir_log = std.log.scoped(.wip_mir); |
| 25 | const build_options = @import("build_options"); | 27 | const build_options = @import("build_options"); |
| 26 | const codegen = @import("../../codegen.zig"); | 28 | const codegen = @import("../../codegen.zig"); |
| 27 | const Alignment = InternPool.Alignment; | 29 | const Alignment = InternPool.Alignment; |
| ... | @@ -32,6 +34,8 @@ const DebugInfoOutput = codegen.DebugInfoOutput; | ... | @@ -32,6 +34,8 @@ const DebugInfoOutput = codegen.DebugInfoOutput; |
| 32 | | 34 | |
| 33 | const bits = @import("bits.zig"); | 35 | const bits = @import("bits.zig"); |
| 34 | const abi = @import("abi.zig"); | 36 | const abi = @import("abi.zig"); |
| | 37 | const Lower = @import("Lower.zig"); |
| | 38 | |
| 35 | const Register = bits.Register; | 39 | const Register = bits.Register; |
| 36 | const Immediate = bits.Immediate; | 40 | const Immediate = bits.Immediate; |
| 37 | const Memory = bits.Memory; | 41 | const Memory = bits.Memory; |
| ... | @@ -158,6 +162,14 @@ const MCValue = union(enum) { | ... | @@ -158,6 +162,14 @@ const MCValue = union(enum) { |
| 158 | }; | 162 | }; |
| 159 | } | 163 | } |
| 160 | | 164 | |
| | 165 | fn isRegister(mcv: MCValue) bool { |
| | 166 | return switch (mcv) { |
| | 167 | .register => true, |
| | 168 | .register_offset => |reg_off| return reg_off.off == 0, |
| | 169 | else => false, |
| | 170 | }; |
| | 171 | } |
| | 172 | |
| 161 | fn isMutable(mcv: MCValue) bool { | 173 | fn isMutable(mcv: MCValue) bool { |
| 162 | return switch (mcv) { | 174 | return switch (mcv) { |
| 163 | .none => unreachable, | 175 | .none => unreachable, |
| ... | @@ -289,6 +301,7 @@ const Branch = struct { | ... | @@ -289,6 +301,7 @@ const Branch = struct { |
| 289 | | 301 | |
| 290 | const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking); | 302 | const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking); |
| 291 | const ConstTrackingMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, InstTracking); | 303 | const ConstTrackingMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, InstTracking); |
| | 304 | |
| 292 | const InstTracking = struct { | 305 | const InstTracking = struct { |
| 293 | long: MCValue, | 306 | long: MCValue, |
| 294 | short: MCValue, | 307 | short: MCValue, |
| ... | @@ -317,33 +330,37 @@ const InstTracking = struct { | ... | @@ -317,33 +330,37 @@ const InstTracking = struct { |
| 317 | }, .short = result }; | 330 | }, .short = result }; |
| 318 | } | 331 | } |
| 319 | | 332 | |
| 320 | fn getReg(func: InstTracking) ?Register { | 333 | fn getReg(inst_tracking: InstTracking) ?Register { |
| 321 | return func.short.getReg(); | 334 | return inst_tracking.short.getReg(); |
| 322 | } | 335 | } |
| 323 | | 336 | |
| 324 | fn getRegs(func: *const InstTracking) []const Register { | 337 | fn getRegs(inst_tracking: *const InstTracking) []const Register { |
| 325 | return func.short.getRegs(); | 338 | return inst_tracking.short.getRegs(); |
| 326 | } | 339 | } |
| 327 | | 340 | |
| 328 | fn spill(func: *InstTracking, function: *Func, inst: Air.Inst.Index) !void { | 341 | fn spill(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void { |
| 329 | if (std.meta.eql(func.long, func.short)) return; // Already spilled | 342 | if (std.meta.eql(inst_tracking.long, inst_tracking.short)) return; // Already spilled |
| 330 | // Allocate or reuse frame index | 343 | // Allocate or reuse frame index |
| 331 | switch (func.long) { | 344 | switch (inst_tracking.long) { |
| 332 | .none => func.long = try function.allocRegOrMem(inst, false), | 345 | .none => inst_tracking.long = try function.allocRegOrMem( |
| | 346 | function.typeOfIndex(inst), |
| | 347 | inst, |
| | 348 | false, |
| | 349 | ), |
| 333 | .load_frame => {}, | 350 | .load_frame => {}, |
| 334 | .reserved_frame => |index| func.long = .{ .load_frame = .{ .index = index } }, | 351 | .reserved_frame => |index| inst_tracking.long = .{ .load_frame = .{ .index = index } }, |
| 335 | else => unreachable, | 352 | else => unreachable, |
| 336 | } | 353 | } |
| 337 | tracking_log.debug("spill %{d} from {} to {}", .{ inst, func.short, func.long }); | 354 | tracking_log.debug("spill %{d} from {} to {}", .{ inst, inst_tracking.short, inst_tracking.long }); |
| 338 | try function.genCopy(function.typeOfIndex(inst), func.long, func.short); | 355 | try function.genCopy(function.typeOfIndex(inst), inst_tracking.long, inst_tracking.short); |
| 339 | } | 356 | } |
| 340 | | 357 | |
| 341 | fn reuseFrame(func: *InstTracking) void { | 358 | fn reuseFrame(inst_tracking: *InstTracking) void { |
| 342 | switch (func.long) { | 359 | switch (inst_tracking.long) { |
| 343 | .reserved_frame => |index| func.long = .{ .load_frame = .{ .index = index } }, | 360 | .reserved_frame => |index| inst_tracking.long = .{ .load_frame = .{ .index = index } }, |
| 344 | else => {}, | 361 | else => {}, |
| 345 | } | 362 | } |
| 346 | func.short = switch (func.long) { | 363 | inst_tracking.short = switch (inst_tracking.long) { |
| 347 | .none, | 364 | .none, |
| 348 | .unreach, | 365 | .unreach, |
| 349 | .undef, | 366 | .undef, |
| ... | @@ -353,7 +370,7 @@ const InstTracking = struct { | ... | @@ -353,7 +370,7 @@ const InstTracking = struct { |
| 353 | .lea_frame, | 370 | .lea_frame, |
| 354 | .load_symbol, | 371 | .load_symbol, |
| 355 | .lea_symbol, | 372 | .lea_symbol, |
| 356 | => func.long, | 373 | => inst_tracking.long, |
| 357 | .dead, | 374 | .dead, |
| 358 | .register, | 375 | .register, |
| 359 | .register_pair, | 376 | .register_pair, |
| ... | @@ -365,14 +382,14 @@ const InstTracking = struct { | ... | @@ -365,14 +382,14 @@ const InstTracking = struct { |
| 365 | }; | 382 | }; |
| 366 | } | 383 | } |
| 367 | | 384 | |
| 368 | fn trackSpill(func: *InstTracking, function: *Func, inst: Air.Inst.Index) !void { | 385 | fn trackSpill(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void { |
| 369 | try function.freeValue(func.short); | 386 | try function.freeValue(inst_tracking.short); |
| 370 | func.reuseFrame(); | 387 | inst_tracking.reuseFrame(); |
| 371 | tracking_log.debug("%{d} => {} (spilled)", .{ inst, func.* }); | 388 | tracking_log.debug("%{d} => {} (spilled)", .{ inst, inst_tracking.* }); |
| 372 | } | 389 | } |
| 373 | | 390 | |
| 374 | fn verifyMaterialize(func: InstTracking, target: InstTracking) void { | 391 | fn verifyMaterialize(inst_tracking: InstTracking, target: InstTracking) void { |
| 375 | switch (func.long) { | 392 | switch (inst_tracking.long) { |
| 376 | .none, | 393 | .none, |
| 377 | .unreach, | 394 | .unreach, |
| 378 | .undef, | 395 | .undef, |
| ... | @@ -381,7 +398,7 @@ const InstTracking = struct { | ... | @@ -381,7 +398,7 @@ const InstTracking = struct { |
| 381 | .lea_frame, | 398 | .lea_frame, |
| 382 | .load_symbol, | 399 | .load_symbol, |
| 383 | .lea_symbol, | 400 | .lea_symbol, |
| 384 | => assert(std.meta.eql(func.long, target.long)), | 401 | => assert(std.meta.eql(inst_tracking.long, target.long)), |
| 385 | .load_frame, | 402 | .load_frame, |
| 386 | .reserved_frame, | 403 | .reserved_frame, |
| 387 | => switch (target.long) { | 404 | => switch (target.long) { |
| ... | @@ -402,73 +419,73 @@ const InstTracking = struct { | ... | @@ -402,73 +419,73 @@ const InstTracking = struct { |
| 402 | } | 419 | } |
| 403 | | 420 | |
| 404 | fn materialize( | 421 | fn materialize( |
| 405 | func: *InstTracking, | 422 | inst_tracking: *InstTracking, |
| 406 | function: *Func, | 423 | function: *Func, |
| 407 | inst: Air.Inst.Index, | 424 | inst: Air.Inst.Index, |
| 408 | target: InstTracking, | 425 | target: InstTracking, |
| 409 | ) !void { | 426 | ) !void { |
| 410 | func.verifyMaterialize(target); | 427 | inst_tracking.verifyMaterialize(target); |
| 411 | try func.materializeUnsafe(function, inst, target); | 428 | try inst_tracking.materializeUnsafe(function, inst, target); |
| 412 | } | 429 | } |
| 413 | | 430 | |
| 414 | fn materializeUnsafe( | 431 | fn materializeUnsafe( |
| 415 | func: InstTracking, | 432 | inst_tracking: InstTracking, |
| 416 | function: *Func, | 433 | function: *Func, |
| 417 | inst: Air.Inst.Index, | 434 | inst: Air.Inst.Index, |
| 418 | target: InstTracking, | 435 | target: InstTracking, |
| 419 | ) !void { | 436 | ) !void { |
| 420 | const ty = function.typeOfIndex(inst); | 437 | const ty = function.typeOfIndex(inst); |
| 421 | if ((func.long == .none or func.long == .reserved_frame) and target.long == .load_frame) | 438 | if ((inst_tracking.long == .none or inst_tracking.long == .reserved_frame) and target.long == .load_frame) |
| 422 | try function.genCopy(ty, target.long, func.short); | 439 | try function.genCopy(ty, target.long, inst_tracking.short); |
| 423 | try function.genCopy(ty, target.short, func.short); | 440 | try function.genCopy(ty, target.short, inst_tracking.short); |
| 424 | } | 441 | } |
| 425 | | 442 | |
| 426 | fn trackMaterialize(func: *InstTracking, inst: Air.Inst.Index, target: InstTracking) void { | 443 | fn trackMaterialize(inst_tracking: *InstTracking, inst: Air.Inst.Index, target: InstTracking) void { |
| 427 | func.verifyMaterialize(target); | 444 | inst_tracking.verifyMaterialize(target); |
| 428 | // Don't clobber reserved frame indices | 445 | // Don't clobber reserved frame indices |
| 429 | func.long = if (target.long == .none) switch (func.long) { | 446 | inst_tracking.long = if (target.long == .none) switch (inst_tracking.long) { |
| 430 | .load_frame => |addr| .{ .reserved_frame = addr.index }, | 447 | .load_frame => |addr| .{ .reserved_frame = addr.index }, |
| 431 | .reserved_frame => func.long, | 448 | .reserved_frame => inst_tracking.long, |
| 432 | else => target.long, | 449 | else => target.long, |
| 433 | } else target.long; | 450 | } else target.long; |
| 434 | func.short = target.short; | 451 | inst_tracking.short = target.short; |
| 435 | tracking_log.debug("%{d} => {} (materialize)", .{ inst, func.* }); | 452 | tracking_log.debug("%{d} => {} (materialize)", .{ inst, inst_tracking.* }); |
| 436 | } | 453 | } |
| 437 | | 454 | |
| 438 | fn resurrect(func: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void { | 455 | fn resurrect(inst_tracking: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void { |
| 439 | switch (func.short) { | 456 | switch (inst_tracking.short) { |
| 440 | .dead => |die_generation| if (die_generation >= scope_generation) { | 457 | .dead => |die_generation| if (die_generation >= scope_generation) { |
| 441 | func.reuseFrame(); | 458 | inst_tracking.reuseFrame(); |
| 442 | tracking_log.debug("%{d} => {} (resurrect)", .{ inst, func.* }); | 459 | tracking_log.debug("%{d} => {} (resurrect)", .{ inst, inst_tracking.* }); |
| 443 | }, | 460 | }, |
| 444 | else => {}, | 461 | else => {}, |
| 445 | } | 462 | } |
| 446 | } | 463 | } |
| 447 | | 464 | |
| 448 | fn die(func: *InstTracking, function: *Func, inst: Air.Inst.Index) !void { | 465 | fn die(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void { |
| 449 | if (func.short == .dead) return; | 466 | if (inst_tracking.short == .dead) return; |
| 450 | try function.freeValue(func.short); | 467 | try function.freeValue(inst_tracking.short); |
| 451 | func.short = .{ .dead = function.scope_generation }; | 468 | inst_tracking.short = .{ .dead = function.scope_generation }; |
| 452 | tracking_log.debug("%{d} => {} (death)", .{ inst, func.* }); | 469 | tracking_log.debug("%{d} => {} (death)", .{ inst, inst_tracking.* }); |
| 453 | } | 470 | } |
| 454 | | 471 | |
| 455 | fn reuse( | 472 | fn reuse( |
| 456 | func: *InstTracking, | 473 | inst_tracking: *InstTracking, |
| 457 | function: *Func, | 474 | function: *Func, |
| 458 | new_inst: ?Air.Inst.Index, | 475 | new_inst: ?Air.Inst.Index, |
| 459 | old_inst: Air.Inst.Index, | 476 | old_inst: Air.Inst.Index, |
| 460 | ) void { | 477 | ) void { |
| 461 | func.short = .{ .dead = function.scope_generation }; | 478 | inst_tracking.short = .{ .dead = function.scope_generation }; |
| 462 | if (new_inst) |inst| | 479 | if (new_inst) |inst| |
| 463 | tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, func.*, old_inst }) | 480 | tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, inst_tracking.*, old_inst }) |
| 464 | else | 481 | else |
| 465 | tracking_log.debug("tmp => {} (reuse %{d})", .{ func.*, old_inst }); | 482 | tracking_log.debug("tmp => {} (reuse %{d})", .{ inst_tracking.*, old_inst }); |
| 466 | } | 483 | } |
| 467 | | 484 | |
| 468 | fn liveOut(func: *InstTracking, function: *Func, inst: Air.Inst.Index) void { | 485 | fn liveOut(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) void { |
| 469 | for (func.getRegs()) |reg| { | 486 | for (inst_tracking.getRegs()) |reg| { |
| 470 | if (function.register_manager.isRegFree(reg)) { | 487 | if (function.register_manager.isRegFree(reg)) { |
| 471 | tracking_log.debug("%{d} => {} (live-out)", .{ inst, func.* }); | 488 | tracking_log.debug("%{d} => {} (live-out)", .{ inst, inst_tracking.* }); |
| 472 | continue; | 489 | continue; |
| 473 | } | 490 | } |
| 474 | | 491 | |
| ... | @@ -495,18 +512,18 @@ const InstTracking = struct { | ... | @@ -495,18 +512,18 @@ const InstTracking = struct { |
| 495 | // Perform side-effects of freeValue manually. | 512 | // Perform side-effects of freeValue manually. |
| 496 | function.register_manager.freeReg(reg); | 513 | function.register_manager.freeReg(reg); |
| 497 | | 514 | |
| 498 | tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, func.*, tracked_inst }); | 515 | tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, inst_tracking.*, tracked_inst }); |
| 499 | } | 516 | } |
| 500 | } | 517 | } |
| 501 | | 518 | |
| 502 | pub fn format( | 519 | pub fn format( |
| 503 | func: InstTracking, | 520 | inst_tracking: InstTracking, |
| 504 | comptime _: []const u8, | 521 | comptime _: []const u8, |
| 505 | _: std.fmt.FormatOptions, | 522 | _: std.fmt.FormatOptions, |
| 506 | writer: anytype, | 523 | writer: anytype, |
| 507 | ) @TypeOf(writer).Error!void { | 524 | ) @TypeOf(writer).Error!void { |
| 508 | if (!std.meta.eql(func.long, func.short)) try writer.print("|{}| ", .{func.long}); | 525 | if (!std.meta.eql(inst_tracking.long, inst_tracking.short)) try writer.print("|{}| ", .{inst_tracking.long}); |
| 509 | try writer.print("{}", .{func.short}); | 526 | try writer.print("{}", .{inst_tracking.short}); |
| 510 | } | 527 | } |
| 511 | }; | 528 | }; |
| 512 | | 529 | |
| ... | @@ -741,6 +758,8 @@ pub fn generate( | ... | @@ -741,6 +758,8 @@ pub fn generate( |
| 741 | function.mir_extra.deinit(gpa); | 758 | function.mir_extra.deinit(gpa); |
| 742 | } | 759 | } |
| 743 | | 760 | |
| | 761 | wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)}); |
| | 762 | |
| 744 | try function.frame_allocs.resize(gpa, FrameIndex.named_count); | 763 | try function.frame_allocs.resize(gpa, FrameIndex.named_count); |
| 745 | function.frame_allocs.set( | 764 | function.frame_allocs.set( |
| 746 | @intFromEnum(FrameIndex.stack_frame), | 765 | @intFromEnum(FrameIndex.stack_frame), |
| ... | @@ -846,13 +865,133 @@ pub fn generate( | ... | @@ -846,13 +865,133 @@ pub fn generate( |
| 846 | } | 865 | } |
| 847 | } | 866 | } |
| 848 | | 867 | |
| | 868 | const FormatWipMirData = struct { |
| | 869 | func: *Func, |
| | 870 | inst: Mir.Inst.Index, |
| | 871 | }; |
| | 872 | fn formatWipMir( |
| | 873 | data: FormatWipMirData, |
| | 874 | comptime _: []const u8, |
| | 875 | _: std.fmt.FormatOptions, |
| | 876 | writer: anytype, |
| | 877 | ) @TypeOf(writer).Error!void { |
| | 878 | const comp = data.func.bin_file.comp; |
| | 879 | const mod = comp.root_mod; |
| | 880 | var lower = Lower{ |
| | 881 | .bin_file = data.func.bin_file, |
| | 882 | .allocator = data.func.gpa, |
| | 883 | .mir = .{ |
| | 884 | .instructions = data.func.mir_instructions.slice(), |
| | 885 | .extra = data.func.mir_extra.items, |
| | 886 | .frame_locs = data.func.frame_locs.slice(), |
| | 887 | }, |
| | 888 | .cc = .Unspecified, |
| | 889 | .src_loc = data.func.src_loc, |
| | 890 | .output_mode = comp.config.output_mode, |
| | 891 | .link_mode = comp.config.link_mode, |
| | 892 | .pic = mod.pic, |
| | 893 | }; |
| | 894 | var first = true; |
| | 895 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { |
| | 896 | error.LowerFail => { |
| | 897 | defer { |
| | 898 | lower.err_msg.?.deinit(data.func.gpa); |
| | 899 | lower.err_msg = null; |
| | 900 | } |
| | 901 | try writer.writeAll(lower.err_msg.?.msg); |
| | 902 | return; |
| | 903 | }, |
| | 904 | error.OutOfMemory, error.InvalidInstruction => |e| { |
| | 905 | try writer.writeAll(switch (e) { |
| | 906 | error.OutOfMemory => "Out of memory", |
| | 907 | error.InvalidInstruction => "CodeGen failed to find a viable instruction.", |
| | 908 | }); |
| | 909 | return; |
| | 910 | }, |
| | 911 | else => |e| return e, |
| | 912 | }).insts) |lowered_inst| { |
| | 913 | if (!first) try writer.writeAll("\ndebug(wip_mir): "); |
| | 914 | try writer.print(" | {}", .{lowered_inst}); |
| | 915 | first = false; |
| | 916 | } |
| | 917 | } |
| | 918 | fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) { |
| | 919 | return .{ .data = .{ .func = func, .inst = inst } }; |
| | 920 | } |
| | 921 | |
| | 922 | const FormatDeclData = struct { |
| | 923 | mod: *Module, |
| | 924 | decl_index: InternPool.DeclIndex, |
| | 925 | }; |
| | 926 | fn formatDecl( |
| | 927 | data: FormatDeclData, |
| | 928 | comptime _: []const u8, |
| | 929 | _: std.fmt.FormatOptions, |
| | 930 | writer: anytype, |
| | 931 | ) @TypeOf(writer).Error!void { |
| | 932 | try data.mod.declPtr(data.decl_index).renderFullyQualifiedName(data.mod, writer); |
| | 933 | } |
| | 934 | fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) { |
| | 935 | return .{ .data = .{ |
| | 936 | .mod = func.bin_file.comp.module.?, |
| | 937 | .decl_index = decl_index, |
| | 938 | } }; |
| | 939 | } |
| | 940 | |
| | 941 | const FormatAirData = struct { |
| | 942 | func: *Func, |
| | 943 | inst: Air.Inst.Index, |
| | 944 | }; |
| | 945 | fn formatAir( |
| | 946 | data: FormatAirData, |
| | 947 | comptime _: []const u8, |
| | 948 | _: std.fmt.FormatOptions, |
| | 949 | writer: anytype, |
| | 950 | ) @TypeOf(writer).Error!void { |
| | 951 | @import("../../print_air.zig").dumpInst( |
| | 952 | data.inst, |
| | 953 | data.func.bin_file.comp.module.?, |
| | 954 | data.func.air, |
| | 955 | data.func.liveness, |
| | 956 | ); |
| | 957 | } |
| | 958 | fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { |
| | 959 | return .{ .data = .{ .func = func, .inst = inst } }; |
| | 960 | } |
| | 961 | |
| | 962 | const FormatTrackingData = struct { |
| | 963 | func: *Func, |
| | 964 | }; |
| | 965 | fn formatTracking( |
| | 966 | data: FormatTrackingData, |
| | 967 | comptime _: []const u8, |
| | 968 | _: std.fmt.FormatOptions, |
| | 969 | writer: anytype, |
| | 970 | ) @TypeOf(writer).Error!void { |
| | 971 | var it = data.func.inst_tracking.iterator(); |
| | 972 | while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* }); |
| | 973 | } |
| | 974 | fn fmtTracking(func: *Func) std.fmt.Formatter(formatTracking) { |
| | 975 | return .{ .data = .{ .func = func } }; |
| | 976 | } |
| | 977 | |
| 849 | fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | 978 | fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 850 | const gpa = func.gpa; | 979 | const gpa = func.gpa; |
| 851 | | | |
| 852 | try func.mir_instructions.ensureUnusedCapacity(gpa, 1); | 980 | try func.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| 853 | | | |
| 854 | const result_index: Mir.Inst.Index = @intCast(func.mir_instructions.len); | 981 | const result_index: Mir.Inst.Index = @intCast(func.mir_instructions.len); |
| 855 | func.mir_instructions.appendAssumeCapacity(inst); | 982 | func.mir_instructions.appendAssumeCapacity(inst); |
| | 983 | if (inst.tag != .pseudo or switch (inst.ops) { |
| | 984 | else => true, |
| | 985 | .pseudo_dbg_prologue_end, |
| | 986 | .pseudo_dbg_line_column, |
| | 987 | .pseudo_dbg_epilogue_begin, |
| | 988 | .pseudo_store_rm, |
| | 989 | .pseudo_load_rm, |
| | 990 | .pseudo_lea_rm, |
| | 991 | .pseudo_mv, |
| | 992 | .pseudo_dead, |
| | 993 | => false, |
| | 994 | }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)}) else wip_mir_log.debug(" | uses-mem", .{}); |
| 856 | return result_index; | 995 | return result_index; |
| 857 | } | 996 | } |
| 858 | | 997 | |
| ... | @@ -979,7 +1118,7 @@ fn gen(func: *Func) !void { | ... | @@ -979,7 +1118,7 @@ fn gen(func: *Func) !void { |
| 979 | .r = .ra, | 1118 | .r = .ra, |
| 980 | .m = .{ | 1119 | .m = .{ |
| 981 | .base = .{ .frame = .ret_addr }, | 1120 | .base = .{ .frame = .ret_addr }, |
| 982 | .mod = .{ .rm = .{ .size = .dword } }, | 1121 | .mod = .{ .size = .dword, .unsigned = false }, |
| 983 | }, | 1122 | }, |
| 984 | } }, | 1123 | } }, |
| 985 | }); | 1124 | }); |
| ... | @@ -990,7 +1129,7 @@ fn gen(func: *Func) !void { | ... | @@ -990,7 +1129,7 @@ fn gen(func: *Func) !void { |
| 990 | .r = .ra, | 1129 | .r = .ra, |
| 991 | .m = .{ | 1130 | .m = .{ |
| 992 | .base = .{ .frame = .ret_addr }, | 1131 | .base = .{ .frame = .ret_addr }, |
| 993 | .mod = .{ .rm = .{ .size = .dword } }, | 1132 | .mod = .{ .size = .dword, .unsigned = false }, |
| 994 | }, | 1133 | }, |
| 995 | } }, | 1134 | } }, |
| 996 | }); | 1135 | }); |
| ... | @@ -1001,7 +1140,7 @@ fn gen(func: *Func) !void { | ... | @@ -1001,7 +1140,7 @@ fn gen(func: *Func) !void { |
| 1001 | .r = .s0, | 1140 | .r = .s0, |
| 1002 | .m = .{ | 1141 | .m = .{ |
| 1003 | .base = .{ .frame = .base_ptr }, | 1142 | .base = .{ .frame = .base_ptr }, |
| 1004 | .mod = .{ .rm = .{ .size = .dword } }, | 1143 | .mod = .{ .size = .dword, .unsigned = false }, |
| 1005 | }, | 1144 | }, |
| 1006 | } }, | 1145 | } }, |
| 1007 | }); | 1146 | }); |
| ... | @@ -1012,7 +1151,7 @@ fn gen(func: *Func) !void { | ... | @@ -1012,7 +1151,7 @@ fn gen(func: *Func) !void { |
| 1012 | .r = .s0, | 1151 | .r = .s0, |
| 1013 | .m = .{ | 1152 | .m = .{ |
| 1014 | .base = .{ .frame = .base_ptr }, | 1153 | .base = .{ .frame = .base_ptr }, |
| 1015 | .mod = .{ .rm = .{ .size = .dword } }, | 1154 | .mod = .{ .size = .dword, .unsigned = false }, |
| 1016 | }, | 1155 | }, |
| 1017 | } }, | 1156 | } }, |
| 1018 | }); | 1157 | }); |
| ... | @@ -1072,36 +1211,47 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1072,36 +1211,47 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1072 | | 1211 | |
| 1073 | for (body) |inst| { | 1212 | for (body) |inst| { |
| 1074 | if (func.liveness.isUnused(inst) and !func.air.mustLower(inst, ip)) continue; | 1213 | if (func.liveness.isUnused(inst) and !func.air.mustLower(inst, ip)) continue; |
| | 1214 | wip_mir_log.debug("{}", .{func.fmtAir(inst)}); |
| | 1215 | verbose_tracking_log.debug("{}", .{func.fmtTracking()}); |
| 1075 | | 1216 | |
| 1076 | const old_air_bookkeeping = func.air_bookkeeping; | 1217 | const old_air_bookkeeping = func.air_bookkeeping; |
| 1077 | try func.inst_tracking.ensureUnusedCapacity(func.gpa, 1); | 1218 | try func.inst_tracking.ensureUnusedCapacity(func.gpa, 1); |
| 1078 | switch (air_tags[@intFromEnum(inst)]) { | 1219 | const tag: Air.Inst.Tag = air_tags[@intFromEnum(inst)]; |
| | 1220 | switch (tag) { |
| 1079 | // zig fmt: off | 1221 | // zig fmt: off |
| 1080 | .ptr_add => try func.airPtrArithmetic(inst, .ptr_add), | 1222 | .add, |
| 1081 | .ptr_sub => try func.airPtrArithmetic(inst, .ptr_sub), | 1223 | .add_wrap, |
| | 1224 | .sub, |
| | 1225 | .sub_wrap, |
| 1082 | | 1226 | |
| 1083 | .add => try func.airBinOp(inst, .add), | 1227 | .mul, |
| 1084 | .sub => try func.airBinOp(inst, .sub), | 1228 | .mul_wrap, |
| | 1229 | .div_trunc, |
| 1085 | | 1230 | |
| 1086 | .add_safe, | 1231 | .shl, .shl_exact, |
| 1087 | .sub_safe, | 1232 | .shr, .shr_exact, |
| 1088 | .mul_safe, | | |
| 1089 | => return func.fail("TODO implement safety_checked_instructions", .{}), | | |
| 1090 | | 1233 | |
| 1091 | .add_wrap => try func.airAddWrap(inst), | 1234 | .bool_and, |
| 1092 | .add_sat => try func.airAddSat(inst), | 1235 | .bool_or, |
| 1093 | .sub_wrap => try func.airSubWrap(inst), | 1236 | .bit_and, |
| 1094 | .sub_sat => try func.airSubSat(inst), | 1237 | .bit_or, |
| 1095 | .mul => try func.airMul(inst), | 1238 | |
| 1096 | .mul_wrap => try func.airMulWrap(inst), | 1239 | .xor, |
| 1097 | .mul_sat => try func.airMulSat(inst), | 1240 | |
| 1098 | .rem => try func.airRem(inst), | 1241 | .min, |
| 1099 | .mod => try func.airMod(inst), | 1242 | .max, |
| 1100 | .shl, .shl_exact => try func.airShl(inst), | 1243 | => try func.airBinOp(inst, tag), |
| 1101 | .shl_sat => try func.airShlSat(inst), | 1244 | |
| 1102 | .min => try func.airMinMax(inst, .min), | 1245 | |
| 1103 | .max => try func.airMinMax(inst, .max), | 1246 | .ptr_add, |
| 1104 | .slice => try func.airSlice(inst), | 1247 | .ptr_sub => try func.airPtrArithmetic(inst, tag), |
| | 1248 | |
| | 1249 | .rem, |
| | 1250 | .mod, |
| | 1251 | .div_float, |
| | 1252 | .div_floor, |
| | 1253 | .div_exact, |
| | 1254 | => return func.fail("TODO: {s}", .{@tagName(tag)}), |
| 1105 | | 1255 | |
| 1106 | .sqrt, | 1256 | .sqrt, |
| 1107 | .sin, | 1257 | .sin, |
| ... | @@ -1124,24 +1274,33 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1124,24 +1274,33 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1124 | .mul_with_overflow => try func.airMulWithOverflow(inst), | 1274 | .mul_with_overflow => try func.airMulWithOverflow(inst), |
| 1125 | .shl_with_overflow => try func.airShlWithOverflow(inst), | 1275 | .shl_with_overflow => try func.airShlWithOverflow(inst), |
| 1126 | | 1276 | |
| 1127 | .div_float, .div_trunc, .div_floor, .div_exact => try func.airDiv(inst), | | |
| 1128 | | 1277 | |
| 1129 | .cmp_lt => try func.airCmp(inst), | 1278 | .add_sat => try func.airAddSat(inst), |
| 1130 | .cmp_lte => try func.airCmp(inst), | 1279 | .sub_sat => try func.airSubSat(inst), |
| 1131 | .cmp_eq => try func.airCmp(inst), | 1280 | .mul_sat => try func.airMulSat(inst), |
| 1132 | .cmp_gte => try func.airCmp(inst), | 1281 | .shl_sat => try func.airShlSat(inst), |
| 1133 | .cmp_gt => try func.airCmp(inst), | 1282 | |
| 1134 | .cmp_neq => try func.airCmp(inst), | 1283 | .add_safe, |
| | 1284 | .sub_safe, |
| | 1285 | .mul_safe, |
| | 1286 | => return func.fail("TODO implement safety_checked_instructions", .{}), |
| | 1287 | |
| | 1288 | .cmp_lt, |
| | 1289 | .cmp_lte, |
| | 1290 | .cmp_eq, |
| | 1291 | .cmp_gte, |
| | 1292 | .cmp_gt, |
| | 1293 | .cmp_neq, |
| | 1294 | => try func.airCmp(inst, tag), |
| 1135 | | 1295 | |
| 1136 | .cmp_vector => try func.airCmpVector(inst), | 1296 | .cmp_vector => try func.airCmpVector(inst), |
| 1137 | .cmp_lt_errors_len => try func.airCmpLtErrorsLen(inst), | 1297 | .cmp_lt_errors_len => try func.airCmpLtErrorsLen(inst), |
| 1138 | | 1298 | |
| 1139 | .bool_and => try func.airBoolOp(inst), | 1299 | .slice => try func.airSlice(inst), |
| 1140 | .bool_or => try func.airBoolOp(inst), | 1300 | .array_to_slice => try func.airArrayToSlice(inst), |
| 1141 | .bit_and => try func.airBitAnd(inst), | 1301 | |
| 1142 | .bit_or => try func.airBitOr(inst), | 1302 | .slice_ptr => try func.airSlicePtr(inst), |
| 1143 | .xor => try func.airXor(inst), | 1303 | .slice_len => try func.airSliceLen(inst), |
| 1144 | .shr, .shr_exact => try func.airShr(inst), | | |
| 1145 | | 1304 | |
| 1146 | .alloc => try func.airAlloc(inst), | 1305 | .alloc => try func.airAlloc(inst), |
| 1147 | .ret_ptr => try func.airRetPtr(inst), | 1306 | .ret_ptr => try func.airRetPtr(inst), |
| ... | @@ -1181,7 +1340,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1181,7 +1340,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1181 | .store_safe => try func.airStore(inst, true), | 1340 | .store_safe => try func.airStore(inst, true), |
| 1182 | .struct_field_ptr=> try func.airStructFieldPtr(inst), | 1341 | .struct_field_ptr=> try func.airStructFieldPtr(inst), |
| 1183 | .struct_field_val=> try func.airStructFieldVal(inst), | 1342 | .struct_field_val=> try func.airStructFieldVal(inst), |
| 1184 | .array_to_slice => try func.airArrayToSlice(inst), | | |
| 1185 | .float_from_int => try func.airFloatFromInt(inst), | 1343 | .float_from_int => try func.airFloatFromInt(inst), |
| 1186 | .int_from_float => try func.airIntFromFloat(inst), | 1344 | .int_from_float => try func.airIntFromFloat(inst), |
| 1187 | .cmpxchg_strong => try func.airCmpxchg(inst), | 1345 | .cmpxchg_strong => try func.airCmpxchg(inst), |
| ... | @@ -1229,7 +1387,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1229,7 +1387,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1229 | .atomic_store_monotonic => try func.airAtomicStore(inst, .monotonic), | 1387 | .atomic_store_monotonic => try func.airAtomicStore(inst, .monotonic), |
| 1230 | .atomic_store_release => try func.airAtomicStore(inst, .release), | 1388 | .atomic_store_release => try func.airAtomicStore(inst, .release), |
| 1231 | .atomic_store_seq_cst => try func.airAtomicStore(inst, .seq_cst), | 1389 | .atomic_store_seq_cst => try func.airAtomicStore(inst, .seq_cst), |
| 1232 | | | |
| 1233 | .struct_field_ptr_index_0 => try func.airStructFieldPtrIndex(inst, 0), | 1390 | .struct_field_ptr_index_0 => try func.airStructFieldPtrIndex(inst, 0), |
| 1234 | .struct_field_ptr_index_1 => try func.airStructFieldPtrIndex(inst, 1), | 1391 | .struct_field_ptr_index_1 => try func.airStructFieldPtrIndex(inst, 1), |
| 1235 | .struct_field_ptr_index_2 => try func.airStructFieldPtrIndex(inst, 2), | 1392 | .struct_field_ptr_index_2 => try func.airStructFieldPtrIndex(inst, 2), |
| ... | @@ -1238,15 +1395,15 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1238,15 +1395,15 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1238 | .field_parent_ptr => try func.airFieldParentPtr(inst), | 1395 | .field_parent_ptr => try func.airFieldParentPtr(inst), |
| 1239 | | 1396 | |
| 1240 | .switch_br => try func.airSwitchBr(inst), | 1397 | .switch_br => try func.airSwitchBr(inst), |
| 1241 | .slice_ptr => try func.airSlicePtr(inst), | | |
| 1242 | .slice_len => try func.airSliceLen(inst), | | |
| 1243 | | 1398 | |
| 1244 | .ptr_slice_len_ptr => try func.airPtrSliceLenPtr(inst), | 1399 | .ptr_slice_len_ptr => try func.airPtrSliceLenPtr(inst), |
| 1245 | .ptr_slice_ptr_ptr => try func.airPtrSlicePtrPtr(inst), | 1400 | .ptr_slice_ptr_ptr => try func.airPtrSlicePtrPtr(inst), |
| 1246 | | 1401 | |
| 1247 | .array_elem_val => try func.airArrayElemVal(inst), | 1402 | .array_elem_val => try func.airArrayElemVal(inst), |
| | 1403 | |
| 1248 | .slice_elem_val => try func.airSliceElemVal(inst), | 1404 | .slice_elem_val => try func.airSliceElemVal(inst), |
| 1249 | .slice_elem_ptr => try func.airSliceElemPtr(inst), | 1405 | .slice_elem_ptr => try func.airSliceElemPtr(inst), |
| | 1406 | |
| 1250 | .ptr_elem_val => try func.airPtrElemVal(inst), | 1407 | .ptr_elem_val => try func.airPtrElemVal(inst), |
| 1251 | .ptr_elem_ptr => try func.airPtrElemPtr(inst), | 1408 | .ptr_elem_ptr => try func.airPtrElemPtr(inst), |
| 1252 | | 1409 | |
| ... | @@ -1330,6 +1487,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1330,6 +1487,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1330 | } | 1487 | } |
| 1331 | } | 1488 | } |
| 1332 | } | 1489 | } |
| | 1490 | verbose_tracking_log.debug("{}", .{func.fmtTracking()}); |
| 1333 | } | 1491 | } |
| 1334 | | 1492 | |
| 1335 | fn getValue(func: *Func, value: MCValue, inst: ?Air.Inst.Index) !void { | 1493 | fn getValue(func: *Func, value: MCValue, inst: ?Air.Inst.Index) !void { |
| ... | @@ -1563,7 +1721,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { | ... | @@ -1563,7 +1721,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { |
| 1563 | .i_type = .{ | 1721 | .i_type = .{ |
| 1564 | .rd = reg, | 1722 | .rd = reg, |
| 1565 | .rs1 = reg, | 1723 | .rs1 = reg, |
| 1566 | .imm12 = Immediate.s(shift), | 1724 | .imm12 = Immediate.u(shift), |
| 1567 | }, | 1725 | }, |
| 1568 | }, | 1726 | }, |
| 1569 | }); | 1727 | }); |
| ... | @@ -1574,25 +1732,49 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { | ... | @@ -1574,25 +1732,49 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { |
| 1574 | .i_type = .{ | 1732 | .i_type = .{ |
| 1575 | .rd = reg, | 1733 | .rd = reg, |
| 1576 | .rs1 = reg, | 1734 | .rs1 = reg, |
| 1577 | .imm12 = Immediate.s(shift), | 1735 | .imm12 = Immediate.u(shift), |
| 1578 | }, | 1736 | }, |
| 1579 | }, | 1737 | }, |
| 1580 | }); | 1738 | }); |
| 1581 | }, | 1739 | }, |
| 1582 | .unsigned => { | 1740 | .unsigned => { |
| 1583 | const mask = ~@as(u64, 0) >> shift; | 1741 | const mask = ~@as(u64, 0) >> shift; |
| 1584 | const tmp_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = mask }); | 1742 | if (mask < 256) { |
| 1585 | _ = try func.addInst(.{ | 1743 | _ = try func.addInst(.{ |
| 1586 | .tag = .@"and", | 1744 | .tag = .andi, |
| 1587 | .ops = .rrr, | 1745 | .ops = .rri, |
| 1588 | .data = .{ | 1746 | .data = .{ |
| 1589 | .r_type = .{ | 1747 | .i_type = .{ |
| 1590 | .rd = reg, | 1748 | .rd = reg, |
| 1591 | .rs1 = reg, | 1749 | .rs1 = reg, |
| 1592 | .rs2 = tmp_reg, | 1750 | .imm12 = Immediate.u(@intCast(mask)), |
| | 1751 | }, |
| 1593 | }, | 1752 | }, |
| 1594 | }, | 1753 | }); |
| 1595 | }); | 1754 | } else { |
| | 1755 | _ = try func.addInst(.{ |
| | 1756 | .tag = .slli, |
| | 1757 | .ops = .rri, |
| | 1758 | .data = .{ |
| | 1759 | .i_type = .{ |
| | 1760 | .rd = reg, |
| | 1761 | .rs1 = reg, |
| | 1762 | .imm12 = Immediate.u(shift), |
| | 1763 | }, |
| | 1764 | }, |
| | 1765 | }); |
| | 1766 | _ = try func.addInst(.{ |
| | 1767 | .tag = .srli, |
| | 1768 | .ops = .rri, |
| | 1769 | .data = .{ |
| | 1770 | .i_type = .{ |
| | 1771 | .rd = reg, |
| | 1772 | .rs1 = reg, |
| | 1773 | .imm12 = Immediate.u(shift), |
| | 1774 | }, |
| | 1775 | }, |
| | 1776 | }); |
| | 1777 | } |
| 1596 | }, | 1778 | }, |
| 1597 | } | 1779 | } |
| 1598 | } | 1780 | } |
| ... | @@ -1673,9 +1855,8 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { | ... | @@ -1673,9 +1855,8 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { |
| 1673 | }; | 1855 | }; |
| 1674 | } | 1856 | } |
| 1675 | | 1857 | |
| 1676 | fn allocRegOrMem(func: *Func, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | 1858 | fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1677 | const zcu = func.bin_file.comp.module.?; | 1859 | const zcu = func.bin_file.comp.module.?; |
| 1678 | const elem_ty = func.typeOfIndex(inst); | | |
| 1679 | | 1860 | |
| 1680 | const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse { | 1861 | const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse { |
| 1681 | return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)}); | 1862 | return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)}); |
| ... | @@ -1714,66 +1895,15 @@ fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, Regis | ... | @@ -1714,66 +1895,15 @@ fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, Regis |
| 1714 | return .{ reg, lock }; | 1895 | return .{ reg, lock }; |
| 1715 | } | 1896 | } |
| 1716 | | 1897 | |
| 1717 | const PromoteOptions = struct { | | |
| 1718 | /// zeroes out the register before loading in the operand | | |
| 1719 | /// | | |
| 1720 | /// if the operand is already a register, it will truncate with 0 | | |
| 1721 | zero: bool = false, | | |
| 1722 | }; | | |
| 1723 | | | |
| 1724 | /// Similar to `allocReg` but will copy the MCValue into the Register unless `operand` is already | 1898 | /// Similar to `allocReg` but will copy the MCValue into the Register unless `operand` is already |
| 1725 | /// a register, in which case it will return a possible lock to that register. | 1899 | /// a register, in which case it will return a possible lock to that register. |
| 1726 | fn promoteReg(func: *Func, ty: Type, operand: MCValue, options: PromoteOptions) !struct { Register, ?RegisterLock } { | 1900 | fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?RegisterLock } { |
| 1727 | const zcu = func.bin_file.comp.module.?; | | |
| 1728 | const bit_size = ty.bitSize(zcu); | | |
| 1729 | | | |
| 1730 | if (operand == .register) { | 1901 | if (operand == .register) { |
| 1731 | const op_reg = operand.register; | 1902 | const op_reg = operand.register; |
| 1732 | if (options.zero and op_reg.class() == .int) { | | |
| 1733 | // we make sure to emit the truncate manually because binOp will call this function | | |
| 1734 | // and it could cause an infinite loop | | |
| 1735 | | | |
| 1736 | _ = try func.addInst(.{ | | |
| 1737 | .tag = .slli, | | |
| 1738 | .ops = .rri, | | |
| 1739 | .data = .{ | | |
| 1740 | .i_type = .{ | | |
| 1741 | .imm12 = Immediate.u(64 - bit_size), | | |
| 1742 | .rd = op_reg, | | |
| 1743 | .rs1 = op_reg, | | |
| 1744 | }, | | |
| 1745 | }, | | |
| 1746 | }); | | |
| 1747 | | | |
| 1748 | _ = try func.addInst(.{ | | |
| 1749 | .tag = .srli, | | |
| 1750 | .ops = .rri, | | |
| 1751 | .data = .{ | | |
| 1752 | .i_type = .{ | | |
| 1753 | .imm12 = Immediate.u(64 - bit_size), | | |
| 1754 | .rd = op_reg, | | |
| 1755 | .rs1 = op_reg, | | |
| 1756 | }, | | |
| 1757 | }, | | |
| 1758 | }); | | |
| 1759 | } | | |
| 1760 | | | |
| 1761 | return .{ op_reg, func.register_manager.lockReg(operand.register) }; | 1903 | return .{ op_reg, func.register_manager.lockReg(operand.register) }; |
| 1762 | } | 1904 | } |
| 1763 | | 1905 | |
| 1764 | const reg, const lock = try func.allocReg(func.typeRegClass(ty)); | 1906 | const reg, const lock = try func.allocReg(func.typeRegClass(ty)); |
| 1765 | | | |
| 1766 | if (options.zero and reg.class() == .int) { | | |
| 1767 | _ = try func.addInst(.{ | | |
| 1768 | .tag = .pseudo, | | |
| 1769 | .ops = .pseudo_mv, | | |
| 1770 | .data = .{ .rr = .{ | | |
| 1771 | .rd = reg, | | |
| 1772 | .rs = .zero, | | |
| 1773 | } }, | | |
| 1774 | }); | | |
| 1775 | } | | |
| 1776 | | | |
| 1777 | try func.genSetReg(ty, reg, operand); | 1907 | try func.genSetReg(ty, reg, operand); |
| 1778 | return .{ reg, lock }; | 1908 | return .{ reg, lock }; |
| 1779 | } | 1909 | } |
| ... | @@ -1793,14 +1923,19 @@ fn elemOffset(func: *Func, index_ty: Type, index: MCValue, elem_size: u64) !Regi | ... | @@ -1793,14 +1923,19 @@ fn elemOffset(func: *Func, index_ty: Type, index: MCValue, elem_size: u64) !Regi |
| 1793 | const lock = func.register_manager.lockRegAssumeUnused(reg); | 1923 | const lock = func.register_manager.lockRegAssumeUnused(reg); |
| 1794 | defer func.register_manager.unlockReg(lock); | 1924 | defer func.register_manager.unlockReg(lock); |
| 1795 | | 1925 | |
| 1796 | const result = try func.binOp( | 1926 | const result_reg, const result_lock = try func.allocReg(.int); |
| | 1927 | defer func.register_manager.unlockReg(result_lock); |
| | 1928 | |
| | 1929 | try func.genBinOp( |
| 1797 | .mul, | 1930 | .mul, |
| 1798 | .{ .register = reg }, | 1931 | .{ .register = reg }, |
| 1799 | index_ty, | 1932 | index_ty, |
| 1800 | .{ .immediate = elem_size }, | 1933 | .{ .immediate = elem_size }, |
| 1801 | index_ty, | 1934 | index_ty, |
| | 1935 | result_reg, |
| 1802 | ); | 1936 | ); |
| 1803 | break :blk result.register; | 1937 | |
| | 1938 | break :blk result_reg; |
| 1804 | }, | 1939 | }, |
| 1805 | } | 1940 | } |
| 1806 | }; | 1941 | }; |
| ... | @@ -1892,7 +2027,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -1892,7 +2027,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void { |
| 1892 | math.divCeil(u16, dst_int_info.bits, 64) catch unreachable == | 2027 | math.divCeil(u16, dst_int_info.bits, 64) catch unreachable == |
| 1893 | math.divCeil(u32, src_storage_bits, 64) catch unreachable and | 2028 | math.divCeil(u32, src_storage_bits, 64) catch unreachable and |
| 1894 | func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { | 2029 | func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { |
| 1895 | const dst_mcv = try func.allocRegOrMem(inst, true); | 2030 | const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true); |
| 1896 | try func.genCopy(min_ty, dst_mcv, src_mcv); | 2031 | try func.genCopy(min_ty, dst_mcv, src_mcv); |
| 1897 | break :dst dst_mcv; | 2032 | break :dst dst_mcv; |
| 1898 | }; | 2033 | }; |
| ... | @@ -1904,7 +2039,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -1904,7 +2039,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void { |
| 1904 | break :result null; // TODO | 2039 | break :result null; // TODO |
| 1905 | | 2040 | |
| 1906 | break :result dst_mcv; | 2041 | break :result dst_mcv; |
| 1907 | } orelse return func.fail("TODO implement airIntCast from {} to {}", .{ | 2042 | } orelse return func.fail("TODO: implement airIntCast from {} to {}", .{ |
| 1908 | src_ty.fmt(zcu), dst_ty.fmt(zcu), | 2043 | src_ty.fmt(zcu), dst_ty.fmt(zcu), |
| 1909 | }); | 2044 | }); |
| 1910 | | 2045 | |
| ... | @@ -1948,7 +2083,7 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -1948,7 +2083,7 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { |
| 1948 | if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register) | 2083 | if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register) |
| 1949 | operand.register | 2084 | operand.register |
| 1950 | else | 2085 | else |
| 1951 | (try func.allocRegOrMem(inst, true)).register; | 2086 | (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register; |
| 1952 | | 2087 | |
| 1953 | _ = try func.addInst(.{ | 2088 | _ = try func.addInst(.{ |
| 1954 | .tag = .pseudo, | 2089 | .tag = .pseudo, |
| ... | @@ -1970,106 +2105,6 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -1970,106 +2105,6 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { |
| 1970 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2105 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1971 | } | 2106 | } |
| 1972 | | 2107 | |
| 1973 | fn airMinMax( | | |
| 1974 | func: *Func, | | |
| 1975 | inst: Air.Inst.Index, | | |
| 1976 | comptime tag: enum { | | |
| 1977 | max, | | |
| 1978 | min, | | |
| 1979 | }, | | |
| 1980 | ) !void { | | |
| 1981 | const zcu = func.bin_file.comp.module.?; | | |
| 1982 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | | |
| 1983 | | | |
| 1984 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | | |
| 1985 | const lhs = try func.resolveInst(bin_op.lhs); | | |
| 1986 | const rhs = try func.resolveInst(bin_op.rhs); | | |
| 1987 | const lhs_ty = func.typeOf(bin_op.lhs); | | |
| 1988 | const rhs_ty = func.typeOf(bin_op.rhs); | | |
| 1989 | | | |
| 1990 | const int_info = lhs_ty.intInfo(zcu); | | |
| 1991 | | | |
| 1992 | if (int_info.bits > 64) return func.fail("TODO: > 64 bit @min", .{}); | | |
| 1993 | | | |
| 1994 | const lhs_reg, const lhs_lock = blk: { | | |
| 1995 | if (lhs == .register) break :blk .{ lhs.register, func.register_manager.lockReg(lhs.register) }; | | |
| 1996 | | | |
| 1997 | const lhs_reg, const lhs_lock = try func.allocReg(.int); | | |
| 1998 | try func.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 1999 | break :blk .{ lhs_reg, lhs_lock }; | | |
| 2000 | }; | | |
| 2001 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2002 | | | |
| 2003 | const rhs_reg, const rhs_lock = blk: { | | |
| 2004 | if (rhs == .register) break :blk .{ rhs.register, func.register_manager.lockReg(rhs.register) }; | | |
| 2005 | | | |
| 2006 | const rhs_reg, const rhs_lock = try func.allocReg(.int); | | |
| 2007 | try func.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 2008 | break :blk .{ rhs_reg, rhs_lock }; | | |
| 2009 | }; | | |
| 2010 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2011 | | | |
| 2012 | const mask_reg, const mask_lock = try func.allocReg(.int); | | |
| 2013 | defer func.register_manager.unlockReg(mask_lock); | | |
| 2014 | | | |
| 2015 | const result_reg, const result_lock = try func.allocReg(.int); | | |
| 2016 | defer func.register_manager.unlockReg(result_lock); | | |
| 2017 | | | |
| 2018 | _ = try func.addInst(.{ | | |
| 2019 | .tag = if (int_info.signedness == .unsigned) .sltu else .slt, | | |
| 2020 | .ops = .rrr, | | |
| 2021 | .data = .{ .r_type = .{ | | |
| 2022 | .rd = mask_reg, | | |
| 2023 | .rs1 = lhs_reg, | | |
| 2024 | .rs2 = rhs_reg, | | |
| 2025 | } }, | | |
| 2026 | }); | | |
| 2027 | | | |
| 2028 | _ = try func.addInst(.{ | | |
| 2029 | .tag = .sub, | | |
| 2030 | .ops = .rrr, | | |
| 2031 | .data = .{ .r_type = .{ | | |
| 2032 | .rd = mask_reg, | | |
| 2033 | .rs1 = .zero, | | |
| 2034 | .rs2 = mask_reg, | | |
| 2035 | } }, | | |
| 2036 | }); | | |
| 2037 | | | |
| 2038 | _ = try func.addInst(.{ | | |
| 2039 | .tag = .xor, | | |
| 2040 | .ops = .rrr, | | |
| 2041 | .data = .{ .r_type = .{ | | |
| 2042 | .rd = result_reg, | | |
| 2043 | .rs1 = lhs_reg, | | |
| 2044 | .rs2 = rhs_reg, | | |
| 2045 | } }, | | |
| 2046 | }); | | |
| 2047 | | | |
| 2048 | _ = try func.addInst(.{ | | |
| 2049 | .tag = .@"and", | | |
| 2050 | .ops = .rrr, | | |
| 2051 | .data = .{ .r_type = .{ | | |
| 2052 | .rd = mask_reg, | | |
| 2053 | .rs1 = result_reg, | | |
| 2054 | .rs2 = mask_reg, | | |
| 2055 | } }, | | |
| 2056 | }); | | |
| 2057 | | | |
| 2058 | _ = try func.addInst(.{ | | |
| 2059 | .tag = .xor, | | |
| 2060 | .ops = .rrr, | | |
| 2061 | .data = .{ .r_type = .{ | | |
| 2062 | .rd = result_reg, | | |
| 2063 | .rs1 = if (tag == .min) rhs_reg else lhs_reg, | | |
| 2064 | .rs2 = mask_reg, | | |
| 2065 | } }, | | |
| 2066 | }); | | |
| 2067 | | | |
| 2068 | break :result .{ .register = result_reg }; | | |
| 2069 | }; | | |
| 2070 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2071 | } | | |
| 2072 | | | |
| 2073 | fn airSlice(func: *Func, inst: Air.Inst.Index) !void { | 2108 | fn airSlice(func: *Func, inst: Air.Inst.Index) !void { |
| 2074 | const zcu = func.bin_file.comp.module.?; | 2109 | const zcu = func.bin_file.comp.module.?; |
| 2075 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 2110 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | @@ -2094,417 +2129,487 @@ fn airSlice(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2094,417 +2129,487 @@ fn airSlice(func: *Func, inst: Air.Inst.Index) !void { |
| 2094 | } | 2129 | } |
| 2095 | | 2130 | |
| 2096 | fn airBinOp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 2131 | fn airBinOp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| | 2132 | const zcu = func.bin_file.comp.module.?; |
| 2097 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2133 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2098 | const lhs = try func.resolveInst(bin_op.lhs); | 2134 | const dst_mcv = try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 2099 | const rhs = try func.resolveInst(bin_op.rhs); | | |
| 2100 | const lhs_ty = func.typeOf(bin_op.lhs); | | |
| 2101 | const rhs_ty = func.typeOf(bin_op.rhs); | | |
| 2102 | | 2135 | |
| 2103 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2136 | const dst_ty = func.typeOfIndex(inst); |
| 2104 | break :result try func.binOp(tag, lhs, lhs_ty, rhs, rhs_ty); | 2137 | if (dst_ty.isAbiInt(zcu)) { |
| 2105 | }; | 2138 | const abi_size: u32 = @intCast(dst_ty.abiSize(zcu)); |
| 2106 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2139 | const bit_size: u32 = @intCast(dst_ty.bitSize(zcu)); |
| | 2140 | if (abi_size * 8 > bit_size) { |
| | 2141 | const dst_lock = switch (dst_mcv) { |
| | 2142 | .register => |dst_reg| func.register_manager.lockRegAssumeUnused(dst_reg), |
| | 2143 | else => null, |
| | 2144 | }; |
| | 2145 | defer if (dst_lock) |lock| func.register_manager.unlockReg(lock); |
| | 2146 | |
| | 2147 | if (dst_mcv.isRegister()) { |
| | 2148 | try func.truncateRegister(dst_ty, dst_mcv.getReg().?); |
| | 2149 | } else { |
| | 2150 | const tmp_reg, const tmp_lock = try func.allocReg(.int); |
| | 2151 | defer func.register_manager.unlockReg(tmp_lock); |
| | 2152 | |
| | 2153 | const hi_ty = try zcu.intType(.unsigned, @intCast((dst_ty.bitSize(zcu) - 1) % 64 + 1)); |
| | 2154 | const hi_mcv = dst_mcv.address().offset(@intCast(bit_size / 64 * 8)).deref(); |
| | 2155 | try func.genSetReg(hi_ty, tmp_reg, hi_mcv); |
| | 2156 | try func.truncateRegister(dst_ty, tmp_reg); |
| | 2157 | try func.genCopy(hi_ty, hi_mcv, .{ .register = tmp_reg }); |
| | 2158 | } |
| | 2159 | } |
| | 2160 | } |
| | 2161 | |
| | 2162 | return func.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2107 | } | 2163 | } |
| 2108 | | 2164 | |
| 2109 | fn binOp( | 2165 | fn binOp( |
| | 2166 | func: *Func, |
| | 2167 | maybe_inst: ?Air.Inst.Index, |
| | 2168 | air_tag: Air.Inst.Tag, |
| | 2169 | lhs_air: Air.Inst.Ref, |
| | 2170 | rhs_air: Air.Inst.Ref, |
| | 2171 | ) !MCValue { |
| | 2172 | _ = maybe_inst; |
| | 2173 | const zcu = func.bin_file.comp.module.?; |
| | 2174 | const lhs_ty = func.typeOf(lhs_air); |
| | 2175 | const rhs_ty = func.typeOf(rhs_air); |
| | 2176 | |
| | 2177 | if (lhs_ty.isRuntimeFloat()) libcall: { |
| | 2178 | const float_bits = lhs_ty.floatBits(func.target.*); |
| | 2179 | const type_needs_libcall = switch (float_bits) { |
| | 2180 | 16 => true, |
| | 2181 | 32, 64 => false, |
| | 2182 | 80, 128 => true, |
| | 2183 | else => unreachable, |
| | 2184 | }; |
| | 2185 | switch (air_tag) { |
| | 2186 | .rem, .mod => {}, |
| | 2187 | else => if (!type_needs_libcall) break :libcall, |
| | 2188 | } |
| | 2189 | return func.fail("binOp libcall runtime-float ops", .{}); |
| | 2190 | } |
| | 2191 | |
| | 2192 | if (lhs_ty.bitSize(zcu) > 64) return func.fail("TODO: binOp >= 64 bits", .{}); |
| | 2193 | |
| | 2194 | const lhs_mcv = try func.resolveInst(lhs_air); |
| | 2195 | const rhs_mcv = try func.resolveInst(rhs_air); |
| | 2196 | |
| | 2197 | const class_for_dst_ty: abi.RegisterClass = switch (air_tag) { |
| | 2198 | // will always return int register no matter the input |
| | 2199 | .cmp_eq, |
| | 2200 | .cmp_neq, |
| | 2201 | .cmp_lt, |
| | 2202 | .cmp_lte, |
| | 2203 | .cmp_gt, |
| | 2204 | .cmp_gte, |
| | 2205 | => .int, |
| | 2206 | |
| | 2207 | else => func.typeRegClass(lhs_ty), |
| | 2208 | }; |
| | 2209 | |
| | 2210 | const dst_reg, const dst_lock = try func.allocReg(class_for_dst_ty); |
| | 2211 | defer func.register_manager.unlockReg(dst_lock); |
| | 2212 | |
| | 2213 | try func.genBinOp( |
| | 2214 | air_tag, |
| | 2215 | lhs_mcv, |
| | 2216 | lhs_ty, |
| | 2217 | rhs_mcv, |
| | 2218 | rhs_ty, |
| | 2219 | dst_reg, |
| | 2220 | ); |
| | 2221 | |
| | 2222 | return .{ .register = dst_reg }; |
| | 2223 | } |
| | 2224 | |
| | 2225 | /// Does the same thing as binOp however is meant to be used internally to the backend. |
| | 2226 | /// |
| | 2227 | /// The `dst_reg` argument is meant to be caller-locked. Asserts that the binOp result can be |
| | 2228 | /// fit into the register. |
| | 2229 | /// |
| | 2230 | /// Assumes that the `dst_reg` class is correct. |
| | 2231 | fn genBinOp( |
| 2110 | func: *Func, | 2232 | func: *Func, |
| 2111 | tag: Air.Inst.Tag, | 2233 | tag: Air.Inst.Tag, |
| 2112 | lhs: MCValue, | 2234 | lhs_mcv: MCValue, |
| 2113 | lhs_ty: Type, | 2235 | lhs_ty: Type, |
| 2114 | rhs: MCValue, | 2236 | rhs_mcv: MCValue, |
| 2115 | rhs_ty: Type, | 2237 | rhs_ty: Type, |
| 2116 | ) InnerError!MCValue { | 2238 | dst_reg: Register, |
| | 2239 | ) !void { |
| 2117 | const zcu = func.bin_file.comp.module.?; | 2240 | const zcu = func.bin_file.comp.module.?; |
| | 2241 | const bit_size = lhs_ty.bitSize(zcu); |
| | 2242 | assert(bit_size <= 64); |
| | 2243 | |
| | 2244 | const is_unsigned = lhs_ty.isUnsignedInt(zcu); |
| | 2245 | |
| | 2246 | const lhs_reg, const maybe_lhs_lock = try func.promoteReg(lhs_ty, lhs_mcv); |
| | 2247 | const rhs_reg, const maybe_rhs_lock = try func.promoteReg(rhs_ty, rhs_mcv); |
| | 2248 | |
| | 2249 | defer if (maybe_lhs_lock) |lock| func.register_manager.unlockReg(lock); |
| | 2250 | defer if (maybe_rhs_lock) |lock| func.register_manager.unlockReg(lock); |
| 2118 | | 2251 | |
| 2119 | switch (tag) { | 2252 | switch (tag) { |
| 2120 | // Arithmetic operations on integers and floats | | |
| 2121 | .add, | 2253 | .add, |
| | 2254 | .add_wrap, |
| 2122 | .sub, | 2255 | .sub, |
| | 2256 | .sub_wrap, |
| 2123 | .mul, | 2257 | .mul, |
| 2124 | .div_float, | 2258 | .mul_wrap, |
| 2125 | .cmp_eq, | | |
| 2126 | .cmp_neq, | | |
| 2127 | .cmp_gt, | | |
| 2128 | .cmp_gte, | | |
| 2129 | .cmp_lt, | | |
| 2130 | .cmp_lte, | | |
| 2131 | => { | 2259 | => { |
| 2132 | assert(lhs_ty.eql(rhs_ty, zcu)); | 2260 | if (!math.isPowerOfTwo(bit_size)) |
| 2133 | switch (lhs_ty.zigTypeTag(zcu)) { | 2261 | return func.fail( |
| 2134 | .Float => { | 2262 | "TODO: genBinOp {s} non-pow 2, found {}", |
| 2135 | const float_bits = lhs_ty.floatBits(zcu.getTarget()); | 2263 | .{ @tagName(tag), bit_size }, |
| 2136 | const float_reg_bits: u32 = if (func.hasFeature(.d)) 64 else 32; | 2264 | ); |
| 2137 | if (float_bits <= float_reg_bits) { | | |
| 2138 | return func.binOpFloat(tag, lhs, lhs_ty, rhs, rhs_ty); | | |
| 2139 | } else { | | |
| 2140 | return func.fail("TODO: binary operations for floats with bits > {d}", .{float_reg_bits}); | | |
| 2141 | } | | |
| 2142 | }, | | |
| 2143 | .Vector => return func.fail("TODO binary operations on vectors", .{}), | | |
| 2144 | .Int, .Enum, .ErrorSet => { | | |
| 2145 | const int_info = lhs_ty.intInfo(zcu); | | |
| 2146 | if (int_info.bits <= 64) { | | |
| 2147 | return func.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty); | | |
| 2148 | } else { | | |
| 2149 | return func.fail("TODO binary operations on int with bits > 64", .{}); | | |
| 2150 | } | | |
| 2151 | }, | | |
| 2152 | else => |x| return func.fail("TOOD: binOp {s}", .{@tagName(x)}), | | |
| 2153 | } | | |
| 2154 | }, | | |
| 2155 | | 2265 | |
| 2156 | .ptr_add, | | |
| 2157 | .ptr_sub, | | |
| 2158 | => { | | |
| 2159 | switch (lhs_ty.zigTypeTag(zcu)) { | 2266 | switch (lhs_ty.zigTypeTag(zcu)) { |
| 2160 | .Pointer => { | 2267 | .Int => { |
| 2161 | const ptr_ty = lhs_ty; | 2268 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2162 | const elem_ty = switch (ptr_ty.ptrSize(zcu)) { | 2269 | .add, .add_wrap => switch (bit_size) { |
| 2163 | .One => ptr_ty.childType(zcu).childType(zcu), // ptr to array, so get array element type | 2270 | 8, 16, 64 => .add, |
| 2164 | else => ptr_ty.childType(zcu), | 2271 | 32 => .addw, |
| 2165 | }; | | |
| 2166 | const elem_size = elem_ty.abiSize(zcu); | | |
| 2167 | | | |
| 2168 | if (elem_size == 1) { | | |
| 2169 | const base_tag: Air.Inst.Tag = switch (tag) { | | |
| 2170 | .ptr_add => .add, | | |
| 2171 | .ptr_sub => .sub, | | |
| 2172 | else => unreachable, | 2272 | else => unreachable, |
| 2173 | }; | 2273 | }, |
| | 2274 | .sub, .sub_wrap => switch (bit_size) { |
| | 2275 | 8, 16, 32 => .subw, |
| | 2276 | 64 => .sub, |
| | 2277 | else => unreachable, |
| | 2278 | }, |
| | 2279 | .mul, .mul_wrap => switch (bit_size) { |
| | 2280 | 8, 16, 64 => .mul, |
| | 2281 | 32 => .mulw, |
| | 2282 | else => unreachable, |
| | 2283 | }, |
| | 2284 | else => unreachable, |
| | 2285 | }; |
| 2174 | | 2286 | |
| 2175 | return try func.binOpRegister(base_tag, lhs, lhs_ty, rhs, rhs_ty); | 2287 | _ = try func.addInst(.{ |
| 2176 | } else { | 2288 | .tag = mir_tag, |
| 2177 | const offset = try func.binOp( | 2289 | .ops = .rrr, |
| 2178 | .mul, | 2290 | .data = .{ |
| 2179 | rhs, | 2291 | .r_type = .{ |
| 2180 | Type.usize, | 2292 | .rd = dst_reg, |
| 2181 | .{ .immediate = elem_size }, | 2293 | .rs1 = lhs_reg, |
| 2182 | Type.usize, | 2294 | .rs2 = rhs_reg, |
| 2183 | ); | 2295 | }, |
| | 2296 | }, |
| | 2297 | }); |
| 2184 | | 2298 | |
| 2185 | const addr = try func.binOp( | 2299 | // truncate when the instruction is larger than the bit size. |
| 2186 | tag, | 2300 | switch (bit_size) { |
| 2187 | lhs, | 2301 | 8, 16 => try func.truncateRegister(lhs_ty, dst_reg), |
| 2188 | Type.manyptr_u8, | 2302 | 32 => {}, // addw/subw affects the first 32-bits |
| 2189 | offset, | 2303 | 64 => {}, // add/sub affects the entire register |
| 2190 | Type.usize, | 2304 | else => unreachable, |
| 2191 | ); | | |
| 2192 | return addr; | | |
| 2193 | } | 2305 | } |
| 2194 | }, | 2306 | }, |
| 2195 | else => unreachable, | 2307 | .Float => { |
| 2196 | } | 2308 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2197 | }, | 2309 | .add => switch (bit_size) { |
| | 2310 | 32 => .fadds, |
| | 2311 | 64 => .faddd, |
| | 2312 | else => unreachable, |
| | 2313 | }, |
| | 2314 | .sub => switch (bit_size) { |
| | 2315 | 32 => .fsubs, |
| | 2316 | 64 => .fsubd, |
| | 2317 | else => unreachable, |
| | 2318 | }, |
| | 2319 | .mul => switch (bit_size) { |
| | 2320 | 32 => .fmuls, |
| | 2321 | 64 => .fmuld, |
| | 2322 | else => unreachable, |
| | 2323 | }, |
| | 2324 | else => unreachable, |
| | 2325 | }; |
| 2198 | | 2326 | |
| 2199 | // These instructions have unsymteric bit sizes on RHS and LHS. | 2327 | _ = try func.addInst(.{ |
| 2200 | .shr, | 2328 | .tag = mir_tag, |
| 2201 | .shl, | 2329 | .ops = .rrr, |
| 2202 | => { | 2330 | .data = .{ |
| 2203 | switch (lhs_ty.zigTypeTag(zcu)) { | 2331 | .r_type = .{ |
| 2204 | .Float => return func.fail("TODO binary operations on floats", .{}), | 2332 | .rd = dst_reg, |
| 2205 | .Vector => return func.fail("TODO binary operations on vectors", .{}), | 2333 | .rs1 = lhs_reg, |
| 2206 | .Int => { | 2334 | .rs2 = rhs_reg, |
| 2207 | const int_info = lhs_ty.intInfo(zcu); | 2335 | }, |
| 2208 | if (int_info.bits <= 64) { | 2336 | }, |
| 2209 | return func.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty); | 2337 | }); |
| 2210 | } else { | | |
| 2211 | return func.fail("TODO binary operations on int with bits > 64", .{}); | | |
| 2212 | } | | |
| 2213 | }, | 2338 | }, |
| 2214 | else => unreachable, | 2339 | else => unreachable, |
| 2215 | } | 2340 | } |
| 2216 | }, | 2341 | }, |
| 2217 | else => return func.fail("TODO binOp {}", .{tag}), | | |
| 2218 | } | | |
| 2219 | } | | |
| 2220 | | | |
| 2221 | fn binOpRegister( | | |
| 2222 | func: *Func, | | |
| 2223 | tag: Air.Inst.Tag, | | |
| 2224 | lhs: MCValue, | | |
| 2225 | lhs_ty: Type, | | |
| 2226 | rhs: MCValue, | | |
| 2227 | rhs_ty: Type, | | |
| 2228 | ) !MCValue { | | |
| 2229 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{ .zero = true }); | | |
| 2230 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2231 | | | |
| 2232 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{ .zero = true }); | | |
| 2233 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2234 | | 2342 | |
| 2235 | const dest_reg, const dest_lock = try func.allocReg(.int); | 2343 | .ptr_add, |
| 2236 | defer func.register_manager.unlockReg(dest_lock); | 2344 | .ptr_sub, |
| 2237 | | 2345 | => { |
| 2238 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 2346 | const tmp_reg = try func.copyToTmpRegister(rhs_ty, .{ .register = rhs_reg }); |
| 2239 | .add => .add, | 2347 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| 2240 | .sub => .sub, | 2348 | const tmp_lock = func.register_manager.lockRegAssumeUnused(tmp_reg); |
| 2241 | .mul => .mul, | 2349 | defer func.register_manager.unlockReg(tmp_lock); |
| 2242 | | 2350 | |
| 2243 | .shl => .sllw, | 2351 | // RISC-V has no immediate mul, so we copy the size to a temporary register |
| 2244 | .shr => .srlw, | 2352 | const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu); |
| 2245 | | 2353 | const elem_size_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = elem_size }); |
| 2246 | .cmp_eq, | 2354 | |
| 2247 | .cmp_neq, | 2355 | try func.genBinOp( |
| 2248 | .cmp_gt, | 2356 | .mul, |
| 2249 | .cmp_gte, | 2357 | tmp_mcv, |
| 2250 | .cmp_lt, | 2358 | rhs_ty, |
| 2251 | .cmp_lte, | 2359 | .{ .register = elem_size_reg }, |
| 2252 | => .pseudo, | 2360 | Type.usize, |
| | 2361 | tmp_reg, |
| | 2362 | ); |
| 2253 | | 2363 | |
| 2254 | else => return func.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), | 2364 | try func.genBinOp( |
| 2255 | }; | 2365 | switch (tag) { |
| | 2366 | .ptr_add => .add, |
| | 2367 | .ptr_sub => .sub, |
| | 2368 | else => unreachable, |
| | 2369 | }, |
| | 2370 | lhs_mcv, |
| | 2371 | Type.usize, // we know it's a pointer, so it'll be usize. |
| | 2372 | tmp_mcv, |
| | 2373 | Type.usize, |
| | 2374 | dst_reg, |
| | 2375 | ); |
| | 2376 | }, |
| 2256 | | 2377 | |
| 2257 | switch (mir_tag) { | 2378 | .bit_and, |
| 2258 | .add, | 2379 | .bit_or, |
| 2259 | .sub, | 2380 | .bool_and, |
| 2260 | .mul, | 2381 | .bool_or, |
| 2261 | .sllw, | | |
| 2262 | .srlw, | | |
| 2263 | => { | 2382 | => { |
| 2264 | _ = try func.addInst(.{ | 2383 | _ = try func.addInst(.{ |
| 2265 | .tag = mir_tag, | 2384 | .tag = switch (tag) { |
| | 2385 | .bit_and, .bool_and => .@"and", |
| | 2386 | .bit_or, .bool_or => .@"or", |
| | 2387 | else => unreachable, |
| | 2388 | }, |
| 2266 | .ops = .rrr, | 2389 | .ops = .rrr, |
| 2267 | .data = .{ | 2390 | .data = .{ |
| 2268 | .r_type = .{ | 2391 | .r_type = .{ |
| 2269 | .rd = dest_reg, | 2392 | .rd = dst_reg, |
| 2270 | .rs1 = lhs_reg, | 2393 | .rs1 = lhs_reg, |
| 2271 | .rs2 = rhs_reg, | 2394 | .rs2 = rhs_reg, |
| 2272 | }, | 2395 | }, |
| 2273 | }, | 2396 | }, |
| 2274 | }); | 2397 | }); |
| | 2398 | |
| | 2399 | switch (tag) { |
| | 2400 | .bool_and, |
| | 2401 | .bool_or, |
| | 2402 | => try func.truncateRegister(Type.bool, dst_reg), |
| | 2403 | else => {}, |
| | 2404 | } |
| 2275 | }, | 2405 | }, |
| 2276 | | 2406 | |
| 2277 | .pseudo => { | 2407 | .div_trunc, |
| 2278 | const pseudo_op = switch (tag) { | 2408 | => { |
| 2279 | .cmp_eq, | 2409 | if (!math.isPowerOfTwo(bit_size)) |
| 2280 | .cmp_neq, | 2410 | return func.fail( |
| 2281 | .cmp_gt, | 2411 | "TODO: genBinOp {s} non-pow 2, found {}", |
| 2282 | .cmp_gte, | 2412 | .{ @tagName(tag), bit_size }, |
| 2283 | .cmp_lt, | 2413 | ); |
| 2284 | .cmp_lte, | 2414 | |
| 2285 | => .pseudo_compare, | 2415 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| | 2416 | .div_trunc => switch (bit_size) { |
| | 2417 | 8, 16, 32 => if (is_unsigned) .divuw else .divw, |
| | 2418 | 64 => if (is_unsigned) .divu else .div, |
| | 2419 | else => unreachable, |
| | 2420 | }, |
| 2286 | else => unreachable, | 2421 | else => unreachable, |
| 2287 | }; | 2422 | }; |
| 2288 | | 2423 | |
| 2289 | _ = try func.addInst(.{ | 2424 | _ = try func.addInst(.{ |
| 2290 | .tag = .pseudo, | 2425 | .tag = mir_tag, |
| 2291 | .ops = pseudo_op, | 2426 | .ops = .rrr, |
| 2292 | .data = .{ | 2427 | .data = .{ |
| 2293 | .compare = .{ | 2428 | .r_type = .{ |
| 2294 | .rd = dest_reg, | 2429 | .rd = dst_reg, |
| 2295 | .rs1 = lhs_reg, | 2430 | .rs1 = lhs_reg, |
| 2296 | .rs2 = rhs_reg, | 2431 | .rs2 = rhs_reg, |
| 2297 | .op = switch (tag) { | | |
| 2298 | .cmp_eq => .eq, | | |
| 2299 | .cmp_neq => .neq, | | |
| 2300 | .cmp_gt => .gt, | | |
| 2301 | .cmp_gte => .gte, | | |
| 2302 | .cmp_lt => .lt, | | |
| 2303 | .cmp_lte => .lte, | | |
| 2304 | else => unreachable, | | |
| 2305 | }, | | |
| 2306 | .size = func.memSize(lhs_ty), | | |
| 2307 | }, | 2432 | }, |
| 2308 | }, | 2433 | }, |
| 2309 | }); | 2434 | }); |
| 2310 | }, | | |
| 2311 | | | |
| 2312 | else => unreachable, | | |
| 2313 | } | | |
| 2314 | | | |
| 2315 | return MCValue{ .register = dest_reg }; | | |
| 2316 | } | | |
| 2317 | | | |
| 2318 | fn binOpFloat( | | |
| 2319 | func: *Func, | | |
| 2320 | tag: Air.Inst.Tag, | | |
| 2321 | lhs: MCValue, | | |
| 2322 | lhs_ty: Type, | | |
| 2323 | rhs: MCValue, | | |
| 2324 | rhs_ty: Type, | | |
| 2325 | ) !MCValue { | | |
| 2326 | const zcu = func.bin_file.comp.module.?; | | |
| 2327 | const float_bits = lhs_ty.floatBits(zcu.getTarget()); | | |
| 2328 | | | |
| 2329 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{}); | | |
| 2330 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2331 | | | |
| 2332 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{}); | | |
| 2333 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2334 | | | |
| 2335 | const mir_tag: Mir.Inst.Tag = switch (tag) { | | |
| 2336 | .add => if (float_bits == 32) .fadds else .faddd, | | |
| 2337 | .sub => if (float_bits == 32) .fsubs else .fsubd, | | |
| 2338 | .mul => if (float_bits == 32) .fmuls else .fmuld, | | |
| 2339 | .div_float => if (float_bits == 32) .fdivs else .fdivd, | | |
| 2340 | | 2435 | |
| 2341 | .cmp_eq, | 2436 | if (!is_unsigned) { |
| 2342 | .cmp_neq, | 2437 | // truncate when the instruction is larger than the bit size. |
| 2343 | .cmp_gt, | 2438 | switch (bit_size) { |
| 2344 | .cmp_gte, | 2439 | 8, 16 => try func.truncateRegister(lhs_ty, dst_reg), |
| 2345 | .cmp_lt, | 2440 | 32 => {}, // divw affects the first 32-bits |
| 2346 | .cmp_lte, | 2441 | 64 => {}, // div affects the entire register |
| 2347 | => .pseudo, | 2442 | else => unreachable, |
| 2348 | | 2443 | } |
| 2349 | else => return func.fail("TODO: binOpFloat mir_tag {s}", .{@tagName(tag)}), | 2444 | } |
| 2350 | }; | 2445 | }, |
| 2351 | | 2446 | |
| 2352 | const return_class: abi.RegisterClass = switch (tag) { | 2447 | .shr, |
| 2353 | .add, | 2448 | .shr_exact, |
| 2354 | .sub, | 2449 | .shl, |
| 2355 | .mul, | 2450 | .shl_exact, |
| 2356 | .div_float, | 2451 | => { |
| 2357 | => .float, | 2452 | if (!math.isPowerOfTwo(bit_size)) |
| | 2453 | return func.fail( |
| | 2454 | "TODO: genBinOp {s} non-pow 2, found {}", |
| | 2455 | .{ @tagName(tag), bit_size }, |
| | 2456 | ); |
| 2358 | | 2457 | |
| 2359 | .cmp_eq, | 2458 | // it's important that the shift amount is exact |
| 2360 | .cmp_neq, | 2459 | try func.truncateRegister(rhs_ty, rhs_reg); |
| 2361 | .cmp_gt, | | |
| 2362 | .cmp_gte, | | |
| 2363 | .cmp_lt, | | |
| 2364 | .cmp_lte, | | |
| 2365 | => .int, | | |
| 2366 | else => unreachable, | | |
| 2367 | }; | | |
| 2368 | | 2460 | |
| 2369 | const dest_reg, const dest_lock = try func.allocReg(return_class); | 2461 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2370 | defer func.register_manager.unlockReg(dest_lock); | 2462 | .shl, .shl_exact => switch (bit_size) { |
| | 2463 | 8, 16, 64 => .sll, |
| | 2464 | 32 => .sllw, |
| | 2465 | else => unreachable, |
| | 2466 | }, |
| | 2467 | .shr, .shr_exact => switch (bit_size) { |
| | 2468 | 8, 16, 64 => .srl, |
| | 2469 | 32 => .srlw, |
| | 2470 | else => unreachable, |
| | 2471 | }, |
| | 2472 | else => unreachable, |
| | 2473 | }; |
| 2371 | | 2474 | |
| 2372 | switch (tag) { | | |
| 2373 | .add, | | |
| 2374 | .sub, | | |
| 2375 | .mul, | | |
| 2376 | .div_float, | | |
| 2377 | => { | | |
| 2378 | _ = try func.addInst(.{ | 2475 | _ = try func.addInst(.{ |
| 2379 | .tag = mir_tag, | 2476 | .tag = mir_tag, |
| 2380 | .ops = .rrr, | 2477 | .ops = .rrr, |
| 2381 | .data = .{ .r_type = .{ | 2478 | .data = .{ .r_type = .{ |
| 2382 | .rd = dest_reg, | 2479 | .rd = dst_reg, |
| 2383 | .rs1 = lhs_reg, | 2480 | .rs1 = lhs_reg, |
| 2384 | .rs2 = rhs_reg, | 2481 | .rs2 = rhs_reg, |
| 2385 | } }, | 2482 | } }, |
| 2386 | }); | 2483 | }); |
| | 2484 | |
| | 2485 | switch (bit_size) { |
| | 2486 | 8, 16 => try func.truncateRegister(lhs_ty, dst_reg), |
| | 2487 | 32 => {}, |
| | 2488 | 64 => {}, |
| | 2489 | else => unreachable, |
| | 2490 | } |
| 2387 | }, | 2491 | }, |
| 2388 | | 2492 | |
| | 2493 | // TODO: move the isel logic out of lower and into here. |
| 2389 | .cmp_eq, | 2494 | .cmp_eq, |
| 2390 | .cmp_neq, | 2495 | .cmp_neq, |
| 2391 | .cmp_gt, | | |
| 2392 | .cmp_gte, | | |
| 2393 | .cmp_lt, | 2496 | .cmp_lt, |
| 2394 | .cmp_lte, | 2497 | .cmp_lte, |
| | 2498 | .cmp_gt, |
| | 2499 | .cmp_gte, |
| 2395 | => { | 2500 | => { |
| 2396 | _ = try func.addInst(.{ | 2501 | _ = try func.addInst(.{ |
| 2397 | .tag = .pseudo, | 2502 | .tag = .pseudo, |
| 2398 | .ops = .pseudo_compare, | 2503 | .ops = .pseudo_compare, |
| 2399 | .data = .{ | 2504 | .data = .{ |
| 2400 | .compare = .{ | 2505 | .compare = .{ |
| 2401 | .rd = dest_reg, | | |
| 2402 | .rs1 = lhs_reg, | | |
| 2403 | .rs2 = rhs_reg, | | |
| 2404 | .op = switch (tag) { | 2506 | .op = switch (tag) { |
| 2405 | .cmp_eq => .eq, | 2507 | .cmp_eq => .eq, |
| 2406 | .cmp_neq => .neq, | 2508 | .cmp_neq => .neq, |
| 2407 | .cmp_gt => .gt, | | |
| 2408 | .cmp_gte => .gte, | | |
| 2409 | .cmp_lt => .lt, | 2509 | .cmp_lt => .lt, |
| 2410 | .cmp_lte => .lte, | 2510 | .cmp_lte => .lte, |
| | 2511 | .cmp_gt => .gt, |
| | 2512 | .cmp_gte => .gte, |
| 2411 | else => unreachable, | 2513 | else => unreachable, |
| 2412 | }, | 2514 | }, |
| 2413 | .size = func.memSize(lhs_ty), | 2515 | .rd = dst_reg, |
| | 2516 | .rs1 = lhs_reg, |
| | 2517 | .rs2 = rhs_reg, |
| | 2518 | .ty = lhs_ty, |
| 2414 | }, | 2519 | }, |
| 2415 | }, | 2520 | }, |
| 2416 | }); | 2521 | }); |
| 2417 | }, | 2522 | }, |
| 2418 | | 2523 | |
| 2419 | else => unreachable, | 2524 | // A branchless @min/@max sequence. |
| 2420 | } | 2525 | // |
| 2421 | | 2526 | // Assume that a0 and a1 are the lhs and rhs respectively. |
| 2422 | return MCValue{ .register = dest_reg }; | 2527 | // Also assume that a2 is the destination register. |
| 2423 | } | 2528 | // |
| 2424 | | 2529 | // Algorithm: |
| 2425 | fn airPtrArithmetic(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 2530 | // slt s0, a0, a1 |
| 2426 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 2531 | // sub s0, zero, s0 |
| 2427 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; | 2532 | // xor a2, a0, a1 |
| 2428 | const lhs = try func.resolveInst(bin_op.lhs); | 2533 | // and s0, a2, s0 |
| 2429 | const rhs = try func.resolveInst(bin_op.rhs); | 2534 | // xor a2, a0, s0 # a0 is @min, a1 is @max |
| 2430 | const lhs_ty = func.typeOf(bin_op.lhs); | 2535 | // |
| 2431 | const rhs_ty = func.typeOf(bin_op.rhs); | 2536 | // "slt s0, a0, a1" will set s0 to 1 if a0 is less than a1, and 1 otherwise. |
| 2432 | | 2537 | // |
| 2433 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2538 | // "sub s0, zero, s0" will set all the bits of s0 to 1 if it was 1, otherwise it'll remain at 0. |
| 2434 | break :result try func.binOp(tag, lhs, lhs_ty, rhs, rhs_ty); | 2539 | // |
| 2435 | }; | 2540 | // "xor a2, a0, a1" stores the bitwise XOR of a0 and a1 in a2. Effectively getting the difference between them. |
| 2436 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2541 | // |
| 2437 | } | 2542 | // "and a0, a2, s0" here we mask the result of the XOR with the negated s0. If a0 < a1, s0 is -1, which |
| 2438 | | 2543 | // doesn't change the bits of a2. If a0 >= a1, s0 is 0, nullifying a2. |
| 2439 | fn airAddWrap(func: *Func, inst: Air.Inst.Index) !void { | 2544 | // |
| 2440 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2545 | // "xor a2, a0, s0" the final XOR operation adjusts a2 to be the minimum value of a0 and a1. If a0 was less than |
| 2441 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement addwrap for {}", .{func.target.cpu.arch}); | 2546 | // a1, s0 was -1, flipping all the bits in a2 and effectively restoring a0. If a0 was greater than or equal to a1, |
| 2442 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2547 | // s0 was 0, leaving a2 unchanged as a0. |
| 2443 | } | 2548 | .min, .max => { |
| 2444 | | 2549 | const int_info = lhs_ty.intInfo(zcu); |
| 2445 | fn airAddSat(func: *Func, inst: Air.Inst.Index) !void { | 2550 | |
| 2446 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2551 | const mask_reg, const mask_lock = try func.allocReg(.int); |
| 2447 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement add_sat for {}", .{func.target.cpu.arch}); | 2552 | defer func.register_manager.unlockReg(mask_lock); |
| 2448 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2449 | } | | |
| 2450 | | | |
| 2451 | fn airSubWrap(func: *Func, inst: Air.Inst.Index) !void { | | |
| 2452 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | | |
| 2453 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | | |
| 2454 | // RISCV arthemtic instructions already wrap, so this is simply a sub binOp with | | |
| 2455 | // no overflow checks. | | |
| 2456 | const lhs = try func.resolveInst(bin_op.lhs); | | |
| 2457 | const rhs = try func.resolveInst(bin_op.rhs); | | |
| 2458 | const lhs_ty = func.typeOf(bin_op.lhs); | | |
| 2459 | const rhs_ty = func.typeOf(bin_op.rhs); | | |
| 2460 | | | |
| 2461 | break :result try func.binOp(.sub, lhs, lhs_ty, rhs, rhs_ty); | | |
| 2462 | }; | | |
| 2463 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2464 | } | | |
| 2465 | | | |
| 2466 | fn airSubSat(func: *Func, inst: Air.Inst.Index) !void { | | |
| 2467 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | | |
| 2468 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement sub_sat for {}", .{func.target.cpu.arch}); | | |
| 2469 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2470 | } | | |
| 2471 | | 2553 | |
| 2472 | fn airMul(func: *Func, inst: Air.Inst.Index) !void { | 2554 | _ = try func.addInst(.{ |
| 2473 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2555 | .tag = if (int_info.signedness == .unsigned) .sltu else .slt, |
| 2474 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2556 | .ops = .rrr, |
| 2475 | const lhs = try func.resolveInst(bin_op.lhs); | 2557 | .data = .{ .r_type = .{ |
| 2476 | const rhs = try func.resolveInst(bin_op.rhs); | 2558 | .rd = mask_reg, |
| 2477 | const lhs_ty = func.typeOf(bin_op.lhs); | 2559 | .rs1 = lhs_reg, |
| 2478 | const rhs_ty = func.typeOf(bin_op.rhs); | 2560 | .rs2 = rhs_reg, |
| 2479 | | 2561 | } }, |
| 2480 | break :result try func.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty); | 2562 | }); |
| 2481 | }; | | |
| 2482 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2483 | } | | |
| 2484 | | 2563 | |
| 2485 | fn airDiv(func: *Func, inst: Air.Inst.Index) !void { | 2564 | _ = try func.addInst(.{ |
| 2486 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2565 | .tag = .sub, |
| 2487 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2566 | .ops = .rrr, |
| 2488 | const lhs = try func.resolveInst(bin_op.lhs); | 2567 | .data = .{ .r_type = .{ |
| 2489 | const rhs = try func.resolveInst(bin_op.rhs); | 2568 | .rd = mask_reg, |
| 2490 | const lhs_ty = func.typeOf(bin_op.lhs); | 2569 | .rs1 = .zero, |
| 2491 | const rhs_ty = func.typeOf(bin_op.rhs); | 2570 | .rs2 = mask_reg, |
| | 2571 | } }, |
| | 2572 | }); |
| 2492 | | 2573 | |
| 2493 | break :result try func.binOp(.div_float, lhs, lhs_ty, rhs, rhs_ty); | 2574 | _ = try func.addInst(.{ |
| 2494 | }; | 2575 | .tag = .xor, |
| 2495 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2576 | .ops = .rrr, |
| 2496 | } | 2577 | .data = .{ .r_type = .{ |
| | 2578 | .rd = dst_reg, |
| | 2579 | .rs1 = lhs_reg, |
| | 2580 | .rs2 = rhs_reg, |
| | 2581 | } }, |
| | 2582 | }); |
| 2497 | | 2583 | |
| 2498 | fn airMulWrap(func: *Func, inst: Air.Inst.Index) !void { | 2584 | _ = try func.addInst(.{ |
| 2499 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2585 | .tag = .@"and", |
| 2500 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement mulwrap for {}", .{func.target.cpu.arch}); | 2586 | .ops = .rrr, |
| 2501 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2587 | .data = .{ .r_type = .{ |
| | 2588 | .rd = mask_reg, |
| | 2589 | .rs1 = dst_reg, |
| | 2590 | .rs2 = mask_reg, |
| | 2591 | } }, |
| | 2592 | }); |
| | 2593 | |
| | 2594 | _ = try func.addInst(.{ |
| | 2595 | .tag = .xor, |
| | 2596 | .ops = .rrr, |
| | 2597 | .data = .{ .r_type = .{ |
| | 2598 | .rd = dst_reg, |
| | 2599 | .rs1 = if (tag == .min) rhs_reg else lhs_reg, |
| | 2600 | .rs2 = mask_reg, |
| | 2601 | } }, |
| | 2602 | }); |
| | 2603 | }, |
| | 2604 | else => return func.fail("TODO: genBinOp {}", .{tag}), |
| | 2605 | } |
| 2502 | } | 2606 | } |
| 2503 | | 2607 | |
| 2504 | fn airMulSat(func: *Func, inst: Air.Inst.Index) !void { | 2608 | fn airPtrArithmetic(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2505 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2609 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2506 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement mul_sat for {}", .{func.target.cpu.arch}); | 2610 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2507 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2611 | const dst_mcv = try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| | 2612 | return func.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2508 | } | 2613 | } |
| 2509 | | 2614 | |
| 2510 | fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | 2615 | fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| ... | @@ -2513,19 +2618,16 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2513,19 +2618,16 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2513 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; | 2618 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2514 | | 2619 | |
| 2515 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2620 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 2516 | const lhs = try func.resolveInst(extra.lhs); | | |
| 2517 | const rhs = try func.resolveInst(extra.rhs); | | |
| 2518 | const lhs_ty = func.typeOf(extra.lhs); | 2621 | const lhs_ty = func.typeOf(extra.lhs); |
| 2519 | const rhs_ty = func.typeOf(extra.rhs); | | |
| 2520 | | 2622 | |
| 2521 | const int_info = lhs_ty.intInfo(zcu); | 2623 | const int_info = lhs_ty.intInfo(zcu); |
| 2522 | | 2624 | |
| 2523 | const tuple_ty = func.typeOfIndex(inst); | 2625 | const tuple_ty = func.typeOfIndex(inst); |
| 2524 | const result_mcv = try func.allocRegOrMem(inst, false); | 2626 | const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false); |
| 2525 | const offset = result_mcv.load_frame; | 2627 | const offset = result_mcv.load_frame; |
| 2526 | | 2628 | |
| 2527 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { | 2629 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 2528 | const add_result = try func.binOp(.add, lhs, lhs_ty, rhs, rhs_ty); | 2630 | const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs); |
| 2529 | const add_result_reg = try func.copyToTmpRegister(lhs_ty, add_result); | 2631 | const add_result_reg = try func.copyToTmpRegister(lhs_ty, add_result); |
| 2530 | const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg); | 2632 | const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg); |
| 2531 | defer func.register_manager.unlockReg(add_result_reg_lock); | 2633 | defer func.register_manager.unlockReg(add_result_reg_lock); |
| ... | @@ -2542,7 +2644,7 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2542,7 +2644,7 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2542 | .i_type = .{ | 2644 | .i_type = .{ |
| 2543 | .rd = shift_reg, | 2645 | .rd = shift_reg, |
| 2544 | .rs1 = add_result_reg, | 2646 | .rs1 = add_result_reg, |
| 2545 | .imm12 = Immediate.s(shift_amount), | 2647 | .imm12 = Immediate.u(shift_amount), |
| 2546 | }, | 2648 | }, |
| 2547 | }, | 2649 | }, |
| 2548 | }); | 2650 | }); |
| ... | @@ -2554,7 +2656,7 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2554,7 +2656,7 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2554 | .i_type = .{ | 2656 | .i_type = .{ |
| 2555 | .rd = shift_reg, | 2657 | .rd = shift_reg, |
| 2556 | .rs1 = shift_reg, | 2658 | .rs1 = shift_reg, |
| 2557 | .imm12 = Immediate.s(shift_amount), | 2659 | .imm12 = Immediate.u(shift_amount), |
| 2558 | }, | 2660 | }, |
| 2559 | }, | 2661 | }, |
| 2560 | }); | 2662 | }); |
| ... | @@ -2566,18 +2668,23 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2566,18 +2668,23 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2566 | add_result, | 2668 | add_result, |
| 2567 | ); | 2669 | ); |
| 2568 | | 2670 | |
| 2569 | const overflow_mcv = try func.binOp( | 2671 | const overflow_reg, const overflow_lock = try func.allocReg(.int); |
| | 2672 | defer func.register_manager.unlockReg(overflow_lock); |
| | 2673 | |
| | 2674 | try func.genBinOp( |
| 2570 | .cmp_neq, | 2675 | .cmp_neq, |
| 2571 | .{ .register = shift_reg }, | 2676 | .{ .register = shift_reg }, |
| 2572 | lhs_ty, | 2677 | lhs_ty, |
| 2573 | .{ .register = add_result_reg }, | 2678 | .{ .register = add_result_reg }, |
| 2574 | lhs_ty, | 2679 | lhs_ty, |
| | 2680 | overflow_reg, |
| 2575 | ); | 2681 | ); |
| | 2682 | |
| 2576 | try func.genSetMem( | 2683 | try func.genSetMem( |
| 2577 | .{ .frame = offset.index }, | 2684 | .{ .frame = offset.index }, |
| 2578 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), | 2685 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), |
| 2579 | Type.u1, | 2686 | Type.u1, |
| 2580 | overflow_mcv, | 2687 | .{ .register = overflow_reg }, |
| 2581 | ); | 2688 | ); |
| 2582 | | 2689 | |
| 2583 | break :result result_mcv; | 2690 | break :result result_mcv; |
| ... | @@ -2602,49 +2709,64 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2602,49 +2709,64 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2602 | | 2709 | |
| 2603 | const int_info = lhs_ty.intInfo(zcu); | 2710 | const int_info = lhs_ty.intInfo(zcu); |
| 2604 | | 2711 | |
| 2605 | if (!math.isPowerOfTwo(int_info.bits) or !(int_info.bits >= 8)) { | 2712 | if (!math.isPowerOfTwo(int_info.bits) or int_info.bits < 8) { |
| 2606 | return func.fail("TODO: airSubWithOverflow non-power of 2 and less than 8 bits", .{}); | 2713 | return func.fail("TODO: airSubWithOverflow non-power of 2 and less than 8 bits", .{}); |
| 2607 | } | 2714 | } |
| 2608 | | 2715 | |
| | 2716 | if (int_info.bits > 64) { |
| | 2717 | return func.fail("TODO: airSubWithOverflow > 64 bits", .{}); |
| | 2718 | } |
| | 2719 | |
| 2609 | const tuple_ty = func.typeOfIndex(inst); | 2720 | const tuple_ty = func.typeOfIndex(inst); |
| 2610 | const result_mcv = try func.allocRegOrMem(inst, false); | 2721 | const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false); |
| 2611 | const offset = result_mcv.load_frame; | 2722 | const offset = result_mcv.load_frame; |
| 2612 | | 2723 | |
| 2613 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{}); | 2724 | const dest_mcv = try func.binOp(null, .sub, extra.lhs, extra.rhs); |
| | 2725 | assert(dest_mcv == .register); |
| | 2726 | const dest_reg = dest_mcv.register; |
| | 2727 | |
| | 2728 | try func.genSetMem( |
| | 2729 | .{ .frame = offset.index }, |
| | 2730 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))), |
| | 2731 | lhs_ty, |
| | 2732 | .{ .register = dest_reg }, |
| | 2733 | ); |
| | 2734 | |
| | 2735 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs); |
| 2614 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); | 2736 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); |
| 2615 | | 2737 | |
| 2616 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{}); | 2738 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs); |
| 2617 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); | 2739 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); |
| 2618 | | 2740 | |
| 2619 | const dest_reg, const dest_lock = try func.allocReg(.int); | 2741 | const overflow_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = 0 }); |
| 2620 | defer func.register_manager.unlockReg(dest_lock); | 2742 | |
| | 2743 | const overflow_lock = func.register_manager.lockRegAssumeUnused(overflow_reg); |
| | 2744 | defer func.register_manager.unlockReg(overflow_lock); |
| 2621 | | 2745 | |
| 2622 | switch (int_info.signedness) { | 2746 | switch (int_info.signedness) { |
| 2623 | .unsigned => return func.fail("TODO: airSubWithOverflow unsigned", .{}), | 2747 | .unsigned => { |
| | 2748 | _ = try func.addInst(.{ |
| | 2749 | .tag = .sltu, |
| | 2750 | .ops = .rrr, |
| | 2751 | .data = .{ .r_type = .{ |
| | 2752 | .rd = overflow_reg, |
| | 2753 | .rs1 = lhs_reg, |
| | 2754 | .rs2 = rhs_reg, |
| | 2755 | } }, |
| | 2756 | }); |
| | 2757 | |
| | 2758 | try func.genSetMem( |
| | 2759 | .{ .frame = offset.index }, |
| | 2760 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), |
| | 2761 | Type.u1, |
| | 2762 | .{ .register = overflow_reg }, |
| | 2763 | ); |
| | 2764 | |
| | 2765 | break :result result_mcv; |
| | 2766 | }, |
| 2624 | .signed => { | 2767 | .signed => { |
| 2625 | switch (int_info.bits) { | 2768 | switch (int_info.bits) { |
| 2626 | 64 => { | 2769 | 64 => { |
| 2627 | // result | | |
| 2628 | _ = try func.addInst(.{ | | |
| 2629 | .tag = .sub, | | |
| 2630 | .ops = .rrr, | | |
| 2631 | .data = .{ .r_type = .{ | | |
| 2632 | .rd = dest_reg, | | |
| 2633 | .rs1 = lhs_reg, | | |
| 2634 | .rs2 = rhs_reg, | | |
| 2635 | } }, | | |
| 2636 | }); | | |
| 2637 | | | |
| 2638 | try func.genSetMem( | | |
| 2639 | .{ .frame = offset.index }, | | |
| 2640 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))), | | |
| 2641 | lhs_ty, | | |
| 2642 | .{ .register = dest_reg }, | | |
| 2643 | ); | | |
| 2644 | | | |
| 2645 | // overflow check | | |
| 2646 | const overflow_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = 0 }); | | |
| 2647 | | | |
| 2648 | _ = try func.addInst(.{ | 2770 | _ = try func.addInst(.{ |
| 2649 | .tag = .slt, | 2771 | .tag = .slt, |
| 2650 | .ops = .rrr, | 2772 | .ops = .rrr, |
| ... | @@ -2675,19 +2797,20 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2675,19 +2797,20 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2675 | } }, | 2797 | } }, |
| 2676 | }); | 2798 | }); |
| 2677 | | 2799 | |
| 2678 | const overflow_mcv = try func.binOp( | 2800 | try func.genBinOp( |
| 2679 | .cmp_neq, | 2801 | .cmp_neq, |
| 2680 | .{ .register = overflow_reg }, | 2802 | .{ .register = overflow_reg }, |
| 2681 | Type.usize, | 2803 | Type.usize, |
| 2682 | .{ .register = rhs_reg }, | 2804 | .{ .register = rhs_reg }, |
| 2683 | Type.usize, | 2805 | Type.usize, |
| | 2806 | overflow_reg, |
| 2684 | ); | 2807 | ); |
| 2685 | | 2808 | |
| 2686 | try func.genSetMem( | 2809 | try func.genSetMem( |
| 2687 | .{ .frame = offset.index }, | 2810 | .{ .frame = offset.index }, |
| 2688 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), | 2811 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), |
| 2689 | Type.u1, | 2812 | Type.u1, |
| 2690 | overflow_mcv, | 2813 | .{ .register = overflow_reg }, |
| 2691 | ); | 2814 | ); |
| 2692 | | 2815 | |
| 2693 | break :result result_mcv; | 2816 | break :result result_mcv; |
| ... | @@ -2702,16 +2825,42 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2702,16 +2825,42 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2702 | } | 2825 | } |
| 2703 | | 2826 | |
| 2704 | fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | 2827 | fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2705 | //const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)]; | 2828 | const zcu = func.bin_file.comp.module.?; |
| 2706 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 2829 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2707 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; | 2830 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2708 | const zcu = func.bin_file.comp.module.?; | 2831 | |
| 2709 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2832 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 2710 | const lhs = try func.resolveInst(extra.lhs); | 2833 | const lhs = try func.resolveInst(extra.lhs); |
| 2711 | const rhs = try func.resolveInst(extra.rhs); | 2834 | const rhs = try func.resolveInst(extra.rhs); |
| 2712 | const lhs_ty = func.typeOf(extra.lhs); | 2835 | const lhs_ty = func.typeOf(extra.lhs); |
| 2713 | const rhs_ty = func.typeOf(extra.rhs); | 2836 | const rhs_ty = func.typeOf(extra.rhs); |
| 2714 | | 2837 | |
| | 2838 | const tuple_ty = func.typeOfIndex(inst); |
| | 2839 | |
| | 2840 | // genSetReg needs to support register_offset src_mcv for this to be true. |
| | 2841 | const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false); |
| | 2842 | |
| | 2843 | const result_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu)); |
| | 2844 | const overflow_off: i32 = @intCast(tuple_ty.structFieldOffset(1, zcu)); |
| | 2845 | |
| | 2846 | const dest_reg, const dest_lock = try func.allocReg(.int); |
| | 2847 | defer func.register_manager.unlockReg(dest_lock); |
| | 2848 | |
| | 2849 | try func.genBinOp( |
| | 2850 | .mul, |
| | 2851 | lhs, |
| | 2852 | lhs_ty, |
| | 2853 | rhs, |
| | 2854 | rhs_ty, |
| | 2855 | dest_reg, |
| | 2856 | ); |
| | 2857 | |
| | 2858 | try func.genCopy( |
| | 2859 | lhs_ty, |
| | 2860 | result_mcv.offset(result_off), |
| | 2861 | .{ .register = dest_reg }, |
| | 2862 | ); |
| | 2863 | |
| 2715 | switch (lhs_ty.zigTypeTag(zcu)) { | 2864 | switch (lhs_ty.zigTypeTag(zcu)) { |
| 2716 | else => |x| return func.fail("TODO: airMulWithOverflow {s}", .{@tagName(x)}), | 2865 | else => |x| return func.fail("TODO: airMulWithOverflow {s}", .{@tagName(x)}), |
| 2717 | .Int => { | 2866 | .Int => { |
| ... | @@ -2719,74 +2868,53 @@ fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2719,74 +2868,53 @@ fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2719 | const int_info = lhs_ty.intInfo(zcu); | 2868 | const int_info = lhs_ty.intInfo(zcu); |
| 2720 | switch (int_info.bits) { | 2869 | switch (int_info.bits) { |
| 2721 | 1...32 => { | 2870 | 1...32 => { |
| 2722 | if (func.hasFeature(.m)) { | 2871 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 2723 | const dest = try func.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty); | 2872 | if (int_info.signedness == .unsigned) { |
| 2724 | | 2873 | switch (int_info.bits) { |
| 2725 | const add_result_lock = func.register_manager.lockRegAssumeUnused(dest.register); | 2874 | 1...8 => { |
| 2726 | defer func.register_manager.unlockReg(add_result_lock); | 2875 | const max_val = std.math.pow(u16, 2, int_info.bits) - 1; |
| 2727 | | 2876 | |
| 2728 | const tuple_ty = func.typeOfIndex(inst); | 2877 | const add_reg, const add_lock = try func.promoteReg(lhs_ty, lhs); |
| 2729 | | 2878 | defer if (add_lock) |lock| func.register_manager.unlockReg(lock); |
| 2730 | const result_mcv = try func.allocRegOrMem(inst, true); | 2879 | |
| 2731 | | 2880 | const overflow_reg, const overflow_lock = try func.allocReg(.int); |
| 2732 | const result_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu)); | 2881 | defer func.register_manager.unlockReg(overflow_lock); |
| 2733 | const overflow_off: i32 = @intCast(tuple_ty.structFieldOffset(1, zcu)); | 2882 | |
| 2734 | | 2883 | _ = try func.addInst(.{ |
| 2735 | try func.genCopy( | 2884 | .tag = .andi, |
| 2736 | lhs_ty, | 2885 | .ops = .rri, |
| 2737 | result_mcv.offset(result_off), | 2886 | .data = .{ .i_type = .{ |
| 2738 | dest, | 2887 | .rd = overflow_reg, |
| 2739 | ); | 2888 | .rs1 = add_reg, |
| 2740 | | 2889 | .imm12 = Immediate.s(max_val), |
| 2741 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { | 2890 | } }, |
| 2742 | if (int_info.signedness == .unsigned) { | 2891 | }); |
| 2743 | switch (int_info.bits) { | 2892 | |
| 2744 | 1...8 => { | 2893 | try func.genBinOp( |
| 2745 | const max_val = std.math.pow(u16, 2, int_info.bits) - 1; | 2894 | .cmp_neq, |
| 2746 | | 2895 | .{ .register = overflow_reg }, |
| 2747 | const add_reg, const add_lock = try func.promoteReg(lhs_ty, lhs, .{}); | 2896 | lhs_ty, |
| 2748 | defer if (add_lock) |lock| func.register_manager.unlockReg(lock); | 2897 | .{ .register = add_reg }, |
| 2749 | | 2898 | lhs_ty, |
| 2750 | const overflow_reg, const overflow_lock = try func.allocReg(.int); | 2899 | overflow_reg, |
| 2751 | defer func.register_manager.unlockReg(overflow_lock); | 2900 | ); |
| 2752 | | 2901 | |
| 2753 | _ = try func.addInst(.{ | 2902 | try func.genCopy( |
| 2754 | .tag = .andi, | 2903 | lhs_ty, |
| 2755 | .ops = .rri, | 2904 | result_mcv.offset(overflow_off), |
| 2756 | .data = .{ .i_type = .{ | 2905 | .{ .register = overflow_reg }, |
| 2757 | .rd = overflow_reg, | 2906 | ); |
| 2758 | .rs1 = add_reg, | 2907 | |
| 2759 | .imm12 = Immediate.s(max_val), | 2908 | break :result result_mcv; |
| 2760 | } }, | 2909 | }, |
| 2761 | }); | 2910 | |
| 2762 | | 2911 | else => return func.fail("TODO: airMulWithOverflow check for size {d}", .{int_info.bits}), |
| 2763 | const overflow_mcv = try func.binOp( | | |
| 2764 | .cmp_neq, | | |
| 2765 | .{ .register = overflow_reg }, | | |
| 2766 | lhs_ty, | | |
| 2767 | .{ .register = add_reg }, | | |
| 2768 | lhs_ty, | | |
| 2769 | ); | | |
| 2770 | | | |
| 2771 | try func.genCopy( | | |
| 2772 | lhs_ty, | | |
| 2773 | result_mcv.offset(overflow_off), | | |
| 2774 | overflow_mcv, | | |
| 2775 | ); | | |
| 2776 | | | |
| 2777 | break :result result_mcv; | | |
| 2778 | }, | | |
| 2779 | | | |
| 2780 | else => return func.fail("TODO: airMulWithOverflow check for size {d}", .{int_info.bits}), | | |
| 2781 | } | | |
| 2782 | } else { | | |
| 2783 | return func.fail("TODO: airMulWithOverflow calculate carry for signed addition", .{}); | | |
| 2784 | } | 2912 | } |
| 2785 | } else { | 2913 | } else { |
| 2786 | return func.fail("TODO: airMulWithOverflow with < 8 bits or non-pow of 2", .{}); | 2914 | return func.fail("TODO: airMulWithOverflow calculate carry for signed addition", .{}); |
| 2787 | } | 2915 | } |
| 2788 | } else { | 2916 | } else { |
| 2789 | return func.fail("TODO: emulate mul for targets without M feature", .{}); | 2917 | return func.fail("TODO: airMulWithOverflow with < 8 bits or non-pow of 2", .{}); |
| 2790 | } | 2918 | } |
| 2791 | }, | 2919 | }, |
| 2792 | else => return func.fail("TODO: airMulWithOverflow larger than 32-bit mul", .{}), | 2920 | else => return func.fail("TODO: airMulWithOverflow larger than 32-bit mul", .{}), |
| ... | @@ -2799,123 +2927,32 @@ fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2799,123 +2927,32 @@ fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2799 | } | 2927 | } |
| 2800 | | 2928 | |
| 2801 | fn airShlWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | 2929 | fn airShlWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2802 | _ = inst; | | |
| 2803 | return func.fail("TODO implement airShlWithOverflow for {}", .{func.target.cpu.arch}); | | |
| 2804 | } | | |
| 2805 | | | |
| 2806 | fn airRem(func: *Func, inst: Air.Inst.Index) !void { | | |
| 2807 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | | |
| 2808 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement rem for {}", .{func.target.cpu.arch}); | | |
| 2809 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2810 | } | | |
| 2811 | | | |
| 2812 | fn airMod(func: *Func, inst: Air.Inst.Index) !void { | | |
| 2813 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | | |
| 2814 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement zcu for {}", .{func.target.cpu.arch}); | | |
| 2815 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2816 | } | | |
| 2817 | | | |
| 2818 | fn airBitAnd(func: *Func, inst: Air.Inst.Index) !void { | | |
| 2819 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2930 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2820 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2931 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airShlWithOverflow", .{}); |
| 2821 | const lhs = try func.resolveInst(bin_op.lhs); | | |
| 2822 | const rhs = try func.resolveInst(bin_op.rhs); | | |
| 2823 | | | |
| 2824 | const lhs_ty = func.typeOf(bin_op.lhs); | | |
| 2825 | const rhs_ty = func.typeOf(bin_op.rhs); | | |
| 2826 | | | |
| 2827 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{}); | | |
| 2828 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2829 | | | |
| 2830 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{}); | | |
| 2831 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2832 | | | |
| 2833 | const dest_reg, const dest_lock = try func.allocReg(.int); | | |
| 2834 | defer func.register_manager.unlockReg(dest_lock); | | |
| 2835 | | | |
| 2836 | _ = try func.addInst(.{ | | |
| 2837 | .tag = .@"and", | | |
| 2838 | .ops = .rrr, | | |
| 2839 | .data = .{ .r_type = .{ | | |
| 2840 | .rd = dest_reg, | | |
| 2841 | .rs1 = lhs_reg, | | |
| 2842 | .rs2 = rhs_reg, | | |
| 2843 | } }, | | |
| 2844 | }); | | |
| 2845 | | | |
| 2846 | break :result .{ .register = dest_reg }; | | |
| 2847 | }; | | |
| 2848 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2932 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2849 | } | 2933 | } |
| 2850 | | 2934 | |
| 2851 | fn airBitOr(func: *Func, inst: Air.Inst.Index) !void { | 2935 | fn airAddSat(func: *Func, inst: Air.Inst.Index) !void { |
| 2852 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2936 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2853 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2937 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airAddSat", .{}); |
| 2854 | const lhs = try func.resolveInst(bin_op.lhs); | | |
| 2855 | const rhs = try func.resolveInst(bin_op.rhs); | | |
| 2856 | | | |
| 2857 | const lhs_ty = func.typeOf(bin_op.lhs); | | |
| 2858 | const rhs_ty = func.typeOf(bin_op.rhs); | | |
| 2859 | | | |
| 2860 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{}); | | |
| 2861 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2862 | | | |
| 2863 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{}); | | |
| 2864 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); | | |
| 2865 | | | |
| 2866 | const dest_reg, const dest_lock = try func.allocReg(.int); | | |
| 2867 | defer func.register_manager.unlockReg(dest_lock); | | |
| 2868 | | | |
| 2869 | _ = try func.addInst(.{ | | |
| 2870 | .tag = .@"or", | | |
| 2871 | .ops = .rrr, | | |
| 2872 | .data = .{ .r_type = .{ | | |
| 2873 | .rd = dest_reg, | | |
| 2874 | .rs1 = lhs_reg, | | |
| 2875 | .rs2 = rhs_reg, | | |
| 2876 | } }, | | |
| 2877 | }); | | |
| 2878 | | | |
| 2879 | break :result .{ .register = dest_reg }; | | |
| 2880 | }; | | |
| 2881 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2938 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2882 | } | 2939 | } |
| 2883 | | 2940 | |
| 2884 | fn airXor(func: *Func, inst: Air.Inst.Index) !void { | 2941 | fn airSubSat(func: *Func, inst: Air.Inst.Index) !void { |
| 2885 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2942 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2886 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement xor for {}", .{func.target.cpu.arch}); | 2943 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airSubSat", .{}); |
| 2887 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2944 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2888 | } | 2945 | } |
| 2889 | | 2946 | |
| 2890 | fn airShl(func: *Func, inst: Air.Inst.Index) !void { | 2947 | fn airMulSat(func: *Func, inst: Air.Inst.Index) !void { |
| 2891 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2948 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2892 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2949 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airMulSat", .{}); |
| 2893 | const lhs = try func.resolveInst(bin_op.lhs); | | |
| 2894 | const rhs = try func.resolveInst(bin_op.rhs); | | |
| 2895 | const lhs_ty = func.typeOf(bin_op.lhs); | | |
| 2896 | const rhs_ty = func.typeOf(bin_op.rhs); | | |
| 2897 | | | |
| 2898 | break :result try func.binOp(.shl, lhs, lhs_ty, rhs, rhs_ty); | | |
| 2899 | }; | | |
| 2900 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2950 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2901 | } | 2951 | } |
| 2902 | | 2952 | |
| 2903 | fn airShlSat(func: *Func, inst: Air.Inst.Index) !void { | 2953 | fn airShlSat(func: *Func, inst: Air.Inst.Index) !void { |
| 2904 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2954 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2905 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement shl_sat for {}", .{func.target.cpu.arch}); | 2955 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airShlSat", .{}); |
| 2906 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 2907 | } | | |
| 2908 | | | |
| 2909 | fn airShr(func: *Func, inst: Air.Inst.Index) !void { | | |
| 2910 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | | |
| 2911 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | | |
| 2912 | const lhs = try func.resolveInst(bin_op.lhs); | | |
| 2913 | const rhs = try func.resolveInst(bin_op.rhs); | | |
| 2914 | const lhs_ty = func.typeOf(bin_op.lhs); | | |
| 2915 | const rhs_ty = func.typeOf(bin_op.rhs); | | |
| 2916 | | | |
| 2917 | break :result try func.binOp(.shr, lhs, lhs_ty, rhs, rhs_ty); | | |
| 2918 | }; | | |
| 2919 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2956 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2920 | } | 2957 | } |
| 2921 | | 2958 | |
| ... | @@ -2935,7 +2972,7 @@ fn airOptionalPayload(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2935,7 +2972,7 @@ fn airOptionalPayload(func: *Func, inst: Air.Inst.Index) !void { |
| 2935 | break :result opt_mcv; | 2972 | break :result opt_mcv; |
| 2936 | } | 2973 | } |
| 2937 | | 2974 | |
| 2938 | const pl_mcv = try func.allocRegOrMem(inst, true); | 2975 | const pl_mcv = try func.allocRegOrMem(pl_ty, inst, true); |
| 2939 | try func.genCopy(pl_ty, pl_mcv, opt_mcv); | 2976 | try func.genCopy(pl_ty, pl_mcv, opt_mcv); |
| 2940 | break :result pl_mcv; | 2977 | break :result pl_mcv; |
| 2941 | }; | 2978 | }; |
| ... | @@ -2978,15 +3015,15 @@ fn airUnwrapErrErr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2978,15 +3015,15 @@ fn airUnwrapErrErr(func: *Func, inst: Air.Inst.Index) !void { |
| 2978 | const eu_lock = func.register_manager.lockReg(reg); | 3015 | const eu_lock = func.register_manager.lockReg(reg); |
| 2979 | defer if (eu_lock) |lock| func.register_manager.unlockReg(lock); | 3016 | defer if (eu_lock) |lock| func.register_manager.unlockReg(lock); |
| 2980 | | 3017 | |
| 2981 | var result = try func.copyToNewRegister(inst, operand); | 3018 | const result = try func.copyToNewRegister(inst, operand); |
| 2982 | | | |
| 2983 | if (err_off > 0) { | 3019 | if (err_off > 0) { |
| 2984 | result = try func.binOp( | 3020 | try func.genBinOp( |
| 2985 | .shr, | 3021 | .shr, |
| 2986 | result, | 3022 | result, |
| 2987 | err_union_ty, | 3023 | err_union_ty, |
| 2988 | .{ .immediate = @as(u6, @intCast(err_off * 8)) }, | 3024 | .{ .immediate = @as(u6, @intCast(err_off * 8)) }, |
| 2989 | Type.u8, | 3025 | Type.u8, |
| | 3026 | result.register, |
| 2990 | ); | 3027 | ); |
| 2991 | } | 3028 | } |
| 2992 | break :result result; | 3029 | break :result result; |
| ... | @@ -3031,19 +3068,18 @@ fn genUnwrapErrUnionPayloadMir( | ... | @@ -3031,19 +3068,18 @@ fn genUnwrapErrUnionPayloadMir( |
| 3031 | const eu_lock = func.register_manager.lockReg(reg); | 3068 | const eu_lock = func.register_manager.lockReg(reg); |
| 3032 | defer if (eu_lock) |lock| func.register_manager.unlockReg(lock); | 3069 | defer if (eu_lock) |lock| func.register_manager.unlockReg(lock); |
| 3033 | | 3070 | |
| 3034 | var result: MCValue = .{ .register = try func.copyToTmpRegister(err_union_ty, err_union) }; | 3071 | const result_reg = try func.copyToTmpRegister(err_union_ty, err_union); |
| 3035 | | | |
| 3036 | if (payload_off > 0) { | 3072 | if (payload_off > 0) { |
| 3037 | result = try func.binOp( | 3073 | try func.genBinOp( |
| 3038 | .shr, | 3074 | .shr, |
| 3039 | result, | 3075 | .{ .register = result_reg }, |
| 3040 | err_union_ty, | 3076 | err_union_ty, |
| 3041 | .{ .immediate = @as(u6, @intCast(payload_off * 8)) }, | 3077 | .{ .immediate = @as(u6, @intCast(payload_off * 8)) }, |
| 3042 | Type.u8, | 3078 | Type.u8, |
| | 3079 | result_reg, |
| 3043 | ); | 3080 | ); |
| 3044 | } | 3081 | } |
| 3045 | | 3082 | break :result .{ .register = result_reg }; |
| 3046 | break :result result; | | |
| 3047 | }, | 3083 | }, |
| 3048 | else => return func.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}), | 3084 | else => return func.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}), |
| 3049 | } | 3085 | } |
| ... | @@ -3108,7 +3144,7 @@ fn airWrapOptional(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3108,7 +3144,7 @@ fn airWrapOptional(func: *Func, inst: Air.Inst.Index) !void { |
| 3108 | }; | 3144 | }; |
| 3109 | defer if (pl_lock) |lock| func.register_manager.unlockReg(lock); | 3145 | defer if (pl_lock) |lock| func.register_manager.unlockReg(lock); |
| 3110 | | 3146 | |
| 3111 | const opt_mcv = try func.allocRegOrMem(inst, true); | 3147 | const opt_mcv = try func.allocRegOrMem(opt_ty, inst, true); |
| 3112 | try func.genCopy(pl_ty, opt_mcv, pl_mcv); | 3148 | try func.genCopy(pl_ty, opt_mcv, pl_mcv); |
| 3113 | | 3149 | |
| 3114 | if (!same_repr) { | 3150 | if (!same_repr) { |
| ... | @@ -3237,7 +3273,7 @@ fn airSlicePtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3237,7 +3273,7 @@ fn airSlicePtr(func: *Func, inst: Air.Inst.Index) !void { |
| 3237 | const src_mcv = try func.resolveInst(ty_op.operand); | 3273 | const src_mcv = try func.resolveInst(ty_op.operand); |
| 3238 | if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; | 3274 | if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 3239 | | 3275 | |
| 3240 | const dst_mcv = try func.allocRegOrMem(inst, true); | 3276 | const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true); |
| 3241 | const dst_ty = func.typeOfIndex(inst); | 3277 | const dst_ty = func.typeOfIndex(inst); |
| 3242 | try func.genCopy(dst_ty, dst_mcv, src_mcv); | 3278 | try func.genCopy(dst_ty, dst_mcv, src_mcv); |
| 3243 | break :result dst_mcv; | 3279 | break :result dst_mcv; |
| ... | @@ -3249,6 +3285,8 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3249,6 +3285,8 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void { |
| 3249 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3285 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3250 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 3286 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 3251 | const src_mcv = try func.resolveInst(ty_op.operand); | 3287 | const src_mcv = try func.resolveInst(ty_op.operand); |
| | 3288 | const ty = func.typeOfIndex(inst); |
| | 3289 | |
| 3252 | switch (src_mcv) { | 3290 | switch (src_mcv) { |
| 3253 | .load_frame => |frame_addr| { | 3291 | .load_frame => |frame_addr| { |
| 3254 | const len_mcv: MCValue = .{ .load_frame = .{ | 3292 | const len_mcv: MCValue = .{ .load_frame = .{ |
| ... | @@ -3257,7 +3295,7 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3257,7 +3295,7 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void { |
| 3257 | } }; | 3295 | } }; |
| 3258 | if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv; | 3296 | if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv; |
| 3259 | | 3297 | |
| 3260 | const dst_mcv = try func.allocRegOrMem(inst, true); | 3298 | const dst_mcv = try func.allocRegOrMem(ty, inst, true); |
| 3261 | try func.genCopy(Type.usize, dst_mcv, len_mcv); | 3299 | try func.genCopy(Type.usize, dst_mcv, len_mcv); |
| 3262 | break :result dst_mcv; | 3300 | break :result dst_mcv; |
| 3263 | }, | 3301 | }, |
| ... | @@ -3266,7 +3304,7 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3266,7 +3304,7 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void { |
| 3266 | | 3304 | |
| 3267 | if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv; | 3305 | if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv; |
| 3268 | | 3306 | |
| 3269 | const dst_mcv = try func.allocRegOrMem(inst, true); | 3307 | const dst_mcv = try func.allocRegOrMem(ty, inst, true); |
| 3270 | try func.genCopy(Type.usize, dst_mcv, len_mcv); | 3308 | try func.genCopy(Type.usize, dst_mcv, len_mcv); |
| 3271 | break :result dst_mcv; | 3309 | break :result dst_mcv; |
| 3272 | }, | 3310 | }, |
| ... | @@ -3289,41 +3327,19 @@ fn airPtrSlicePtrPtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3289,41 +3327,19 @@ fn airPtrSlicePtrPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 3289 | } | 3327 | } |
| 3290 | | 3328 | |
| 3291 | fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void { | 3329 | fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3292 | const zcu = func.bin_file.comp.module.?; | 3330 | const mod = func.bin_file.comp.module.?; |
| 3293 | const is_volatile = false; // TODO | | |
| 3294 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 3331 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3295 | | 3332 | |
| 3296 | if (!is_volatile and func.liveness.isUnused(inst)) return func.finishAir( | | |
| 3297 | inst, | | |
| 3298 | .unreach, | | |
| 3299 | .{ bin_op.lhs, bin_op.rhs, .none }, | | |
| 3300 | ); | | |
| 3301 | const result: MCValue = result: { | 3333 | const result: MCValue = result: { |
| 3302 | const slice_mcv = try func.resolveInst(bin_op.lhs); | 3334 | const elem_ty = func.typeOfIndex(inst); |
| 3303 | const index_mcv = try func.resolveInst(bin_op.rhs); | 3335 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none; |
| 3304 | | 3336 | |
| 3305 | const slice_ty = func.typeOf(bin_op.lhs); | 3337 | const slice_ty = func.typeOf(bin_op.lhs); |
| 3306 | | 3338 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod); |
| 3307 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(zcu); | 3339 | const elem_ptr = try func.genSliceElemPtr(bin_op.lhs, bin_op.rhs); |
| 3308 | | 3340 | const dst_mcv = try func.allocRegOrMem(elem_ty, inst, false); |
| 3309 | const index_lock: ?RegisterLock = if (index_mcv == .register) | 3341 | try func.load(dst_mcv, elem_ptr, slice_ptr_field_type); |
| 3310 | func.register_manager.lockRegAssumeUnused(index_mcv.register) | 3342 | break :result dst_mcv; |
| 3311 | else | | |
| 3312 | null; | | |
| 3313 | defer if (index_lock) |reg| func.register_manager.unlockReg(reg); | | |
| 3314 | | | |
| 3315 | const base_mcv: MCValue = switch (slice_mcv) { | | |
| 3316 | .load_frame, | | |
| 3317 | .load_symbol, | | |
| 3318 | => .{ .register = try func.copyToTmpRegister(slice_ptr_field_type, slice_mcv) }, | | |
| 3319 | else => return func.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), | | |
| 3320 | }; | | |
| 3321 | | | |
| 3322 | const dest = try func.allocRegOrMem(inst, true); | | |
| 3323 | const addr = try func.binOp(.ptr_add, base_mcv, slice_ptr_field_type, index_mcv, Type.usize); | | |
| 3324 | try func.load(dest, addr, slice_ptr_field_type); | | |
| 3325 | | | |
| 3326 | break :result dest; | | |
| 3327 | }; | 3343 | }; |
| 3328 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 3344 | return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3329 | } | 3345 | } |
| ... | @@ -3331,14 +3347,58 @@ fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3331,14 +3347,58 @@ fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3331 | fn airSliceElemPtr(func: *Func, inst: Air.Inst.Index) !void { | 3347 | fn airSliceElemPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 3332 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 3348 | const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3333 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; | 3349 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3334 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement slice_elem_ptr for {}", .{func.target.cpu.arch}); | 3350 | const dst_mcv = try func.genSliceElemPtr(extra.lhs, extra.rhs); |
| 3335 | return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | 3351 | return func.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| | 3352 | } |
| | 3353 | |
| | 3354 | fn genSliceElemPtr(func: *Func, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| | 3355 | const zcu = func.bin_file.comp.module.?; |
| | 3356 | const slice_ty = func.typeOf(lhs); |
| | 3357 | const slice_mcv = try func.resolveInst(lhs); |
| | 3358 | const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) { |
| | 3359 | .register => |reg| func.register_manager.lockRegAssumeUnused(reg), |
| | 3360 | else => null, |
| | 3361 | }; |
| | 3362 | defer if (slice_mcv_lock) |lock| func.register_manager.unlockReg(lock); |
| | 3363 | |
| | 3364 | const elem_ty = slice_ty.childType(zcu); |
| | 3365 | const elem_size = elem_ty.abiSize(zcu); |
| | 3366 | |
| | 3367 | const index_ty = func.typeOf(rhs); |
| | 3368 | const index_mcv = try func.resolveInst(rhs); |
| | 3369 | const index_mcv_lock: ?RegisterLock = switch (index_mcv) { |
| | 3370 | .register => |reg| func.register_manager.lockRegAssumeUnused(reg), |
| | 3371 | else => null, |
| | 3372 | }; |
| | 3373 | defer if (index_mcv_lock) |lock| func.register_manager.unlockReg(lock); |
| | 3374 | |
| | 3375 | const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_size); |
| | 3376 | const offset_reg_lock = func.register_manager.lockRegAssumeUnused(offset_reg); |
| | 3377 | defer func.register_manager.unlockReg(offset_reg_lock); |
| | 3378 | |
| | 3379 | const addr_reg, const addr_lock = try func.allocReg(.int); |
| | 3380 | defer func.register_manager.unlockReg(addr_lock); |
| | 3381 | try func.genSetReg(Type.usize, addr_reg, slice_mcv); |
| | 3382 | |
| | 3383 | _ = try func.addInst(.{ |
| | 3384 | .tag = .add, |
| | 3385 | .ops = .rrr, |
| | 3386 | .data = .{ .r_type = .{ |
| | 3387 | .rd = addr_reg, |
| | 3388 | .rs1 = addr_reg, |
| | 3389 | .rs2 = offset_reg, |
| | 3390 | } }, |
| | 3391 | }); |
| | 3392 | |
| | 3393 | return .{ .register = addr_reg }; |
| 3336 | } | 3394 | } |
| 3337 | | 3395 | |
| 3338 | fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { | 3396 | fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3339 | const zcu = func.bin_file.comp.module.?; | 3397 | const zcu = func.bin_file.comp.module.?; |
| 3340 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 3398 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3341 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 3399 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| | 3400 | const result_ty = func.typeOfIndex(inst); |
| | 3401 | |
| 3342 | const array_ty = func.typeOf(bin_op.lhs); | 3402 | const array_ty = func.typeOf(bin_op.lhs); |
| 3343 | const array_mcv = try func.resolveInst(bin_op.lhs); | 3403 | const array_mcv = try func.resolveInst(bin_op.lhs); |
| 3344 | | 3404 | |
| ... | @@ -3367,7 +3427,7 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3367,7 +3427,7 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3367 | const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg); | 3427 | const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg); |
| 3368 | defer func.register_manager.unlockReg(offset_lock); | 3428 | defer func.register_manager.unlockReg(offset_lock); |
| 3369 | | 3429 | |
| 3370 | const dst_mcv = try func.allocRegOrMem(inst, false); | 3430 | const dst_mcv = try func.allocRegOrMem(result_ty, inst, false); |
| 3371 | _ = try func.addInst(.{ | 3431 | _ = try func.addInst(.{ |
| 3372 | .tag = .add, | 3432 | .tag = .add, |
| 3373 | .ops = .rrr, | 3433 | .ops = .rrr, |
| ... | @@ -3427,7 +3487,19 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3427,7 +3487,19 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 3427 | const offset_reg_lock = func.register_manager.lockRegAssumeUnused(offset_reg); | 3487 | const offset_reg_lock = func.register_manager.lockRegAssumeUnused(offset_reg); |
| 3428 | defer func.register_manager.unlockReg(offset_reg_lock); | 3488 | defer func.register_manager.unlockReg(offset_reg_lock); |
| 3429 | | 3489 | |
| 3430 | break :result try func.binOp(.ptr_add, base_ptr_mcv, base_ptr_ty, .{ .register = offset_reg }, base_ptr_ty); | 3490 | const result_reg, const result_lock = try func.allocReg(.int); |
| | 3491 | defer func.register_manager.unlockReg(result_lock); |
| | 3492 | |
| | 3493 | try func.genBinOp( |
| | 3494 | .ptr_add, |
| | 3495 | base_ptr_mcv, |
| | 3496 | base_ptr_ty, |
| | 3497 | .{ .register = offset_reg }, |
| | 3498 | Type.usize, |
| | 3499 | result_reg, |
| | 3500 | ); |
| | 3501 | |
| | 3502 | break :result MCValue{ .register = result_reg }; |
| 3431 | }; | 3503 | }; |
| 3432 | return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | 3504 | return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 3433 | } | 3505 | } |
| ... | @@ -3487,7 +3559,7 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3487,7 +3559,7 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { |
| 3487 | .data = .{ .i_type = .{ | 3559 | .data = .{ .i_type = .{ |
| 3488 | .rd = temp_reg, | 3560 | .rd = temp_reg, |
| 3489 | .rs1 = operand_reg, | 3561 | .rs1 = operand_reg, |
| 3490 | .imm12 = Immediate.s(63), | 3562 | .imm12 = Immediate.u(63), |
| 3491 | } }, | 3563 | } }, |
| 3492 | }); | 3564 | }); |
| 3493 | | 3565 | |
| ... | @@ -3695,7 +3767,7 @@ fn airLoad(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3695,7 +3767,7 @@ fn airLoad(func: *Func, inst: Air.Inst.Index) !void { |
| 3695 | // The MCValue that holds the pointer can be re-used as the value. | 3767 | // The MCValue that holds the pointer can be re-used as the value. |
| 3696 | break :blk ptr; | 3768 | break :blk ptr; |
| 3697 | } else { | 3769 | } else { |
| 3698 | break :blk try func.allocRegOrMem(inst, true); | 3770 | break :blk try func.allocRegOrMem(elem_ty, inst, true); |
| 3699 | } | 3771 | } |
| 3700 | }; | 3772 | }; |
| 3701 | | 3773 | |
| ... | @@ -3876,7 +3948,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3876,7 +3948,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3876 | .tag = .srli, | 3948 | .tag = .srli, |
| 3877 | .ops = .rri, | 3949 | .ops = .rri, |
| 3878 | .data = .{ .i_type = .{ | 3950 | .data = .{ .i_type = .{ |
| 3879 | .imm12 = Immediate.s(@intCast(field_off)), | 3951 | .imm12 = Immediate.u(@intCast(field_off)), |
| 3880 | .rd = dst_reg, | 3952 | .rd = dst_reg, |
| 3881 | .rs1 = dst_reg, | 3953 | .rs1 = dst_reg, |
| 3882 | } }, | 3954 | } }, |
| ... | @@ -3911,7 +3983,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3911,7 +3983,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3911 | func.reuseOperand(inst, operand, 0, src_mcv)) | 3983 | func.reuseOperand(inst, operand, 0, src_mcv)) |
| 3912 | off_mcv | 3984 | off_mcv |
| 3913 | else dst: { | 3985 | else dst: { |
| 3914 | const dst_mcv = try func.allocRegOrMem(inst, true); | 3986 | const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true); |
| 3915 | try func.genCopy(field_ty, dst_mcv, off_mcv); | 3987 | try func.genCopy(field_ty, dst_mcv, off_mcv); |
| 3916 | break :dst dst_mcv; | 3988 | break :dst dst_mcv; |
| 3917 | }; | 3989 | }; |
| ... | @@ -3972,7 +4044,7 @@ fn airArg(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3972,7 +4044,7 @@ fn airArg(func: *Func, inst: Air.Inst.Index) !void { |
| 3972 | const src_mcv = func.args[arg_index]; | 4044 | const src_mcv = func.args[arg_index]; |
| 3973 | const arg_ty = func.typeOfIndex(inst); | 4045 | const arg_ty = func.typeOfIndex(inst); |
| 3974 | | 4046 | |
| 3975 | const dst_mcv = try func.allocRegOrMem(inst, false); | 4047 | const dst_mcv = try func.allocRegOrMem(arg_ty, inst, false); |
| 3976 | | 4048 | |
| 3977 | log.debug("airArg {} -> {}", .{ src_mcv, dst_mcv }); | 4049 | log.debug("airArg {} -> {}", .{ src_mcv, dst_mcv }); |
| 3978 | | 4050 | |
| ... | @@ -4004,13 +4076,13 @@ fn airBreakpoint(func: *Func) !void { | ... | @@ -4004,13 +4076,13 @@ fn airBreakpoint(func: *Func) !void { |
| 4004 | } | 4076 | } |
| 4005 | | 4077 | |
| 4006 | fn airRetAddr(func: *Func, inst: Air.Inst.Index) !void { | 4078 | fn airRetAddr(func: *Func, inst: Air.Inst.Index) !void { |
| 4007 | const dst_mcv = try func.allocRegOrMem(inst, true); | 4079 | const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true); |
| 4008 | try func.genCopy(Type.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } }); | 4080 | try func.genCopy(Type.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } }); |
| 4009 | return func.finishAir(inst, dst_mcv, .{ .none, .none, .none }); | 4081 | return func.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 4010 | } | 4082 | } |
| 4011 | | 4083 | |
| 4012 | fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void { | 4084 | fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void { |
| 4013 | const dst_mcv = try func.allocRegOrMem(inst, true); | 4085 | const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true); |
| 4014 | try func.genCopy(Type.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } }); | 4086 | try func.genCopy(Type.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } }); |
| 4015 | return func.finishAir(inst, dst_mcv, .{ .none, .none, .none }); | 4087 | return func.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 4016 | } | 4088 | } |
| ... | @@ -4196,10 +4268,7 @@ fn genCall( | ... | @@ -4196,10 +4268,7 @@ fn genCall( |
| 4196 | if (func.mod.pic) { | 4268 | if (func.mod.pic) { |
| 4197 | return func.fail("TODO: genCall pic", .{}); | 4269 | return func.fail("TODO: genCall pic", .{}); |
| 4198 | } else { | 4270 | } else { |
| 4199 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | 4271 | try func.genSetReg(Type.usize, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } }); |
| 4200 | const got_addr = sym.zigGotAddress(elf_file); | | |
| 4201 | try func.genSetReg(Type.usize, .ra, .{ .memory = @intCast(got_addr) }); | | |
| 4202 | | | |
| 4203 | _ = try func.addInst(.{ | 4272 | _ = try func.addInst(.{ |
| 4204 | .tag = .jalr, | 4273 | .tag = .jalr, |
| 4205 | .ops = .rri, | 4274 | .ops = .rri, |
| ... | @@ -4323,14 +4392,11 @@ fn airRetLoad(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4323,14 +4392,11 @@ fn airRetLoad(func: *Func, inst: Air.Inst.Index) !void { |
| 4323 | try func.exitlude_jump_relocs.append(func.gpa, index); | 4392 | try func.exitlude_jump_relocs.append(func.gpa, index); |
| 4324 | } | 4393 | } |
| 4325 | | 4394 | |
| 4326 | fn airCmp(func: *Func, inst: Air.Inst.Index) !void { | 4395 | fn airCmp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 4327 | const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)]; | | |
| 4328 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 4396 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 4329 | const zcu = func.bin_file.comp.module.?; | 4397 | const zcu = func.bin_file.comp.module.?; |
| 4330 | | 4398 | |
| 4331 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 4399 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 4332 | const lhs = try func.resolveInst(bin_op.lhs); | | |
| 4333 | const rhs = try func.resolveInst(bin_op.rhs); | | |
| 4334 | const lhs_ty = func.typeOf(bin_op.lhs); | 4400 | const lhs_ty = func.typeOf(bin_op.lhs); |
| 4335 | | 4401 | |
| 4336 | switch (lhs_ty.zigTypeTag(zcu)) { | 4402 | switch (lhs_ty.zigTypeTag(zcu)) { |
| ... | @@ -4346,7 +4412,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4346,7 +4412,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void { |
| 4346 | .Int => lhs_ty, | 4412 | .Int => lhs_ty, |
| 4347 | .Bool => Type.u1, | 4413 | .Bool => Type.u1, |
| 4348 | .Pointer => Type.usize, | 4414 | .Pointer => Type.usize, |
| 4349 | .ErrorSet => Type.u16, | 4415 | .ErrorSet => Type.anyerror, |
| 4350 | .Optional => blk: { | 4416 | .Optional => blk: { |
| 4351 | const payload_ty = lhs_ty.optionalChild(zcu); | 4417 | const payload_ty = lhs_ty.optionalChild(zcu); |
| 4352 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | 4418 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| ... | @@ -4362,7 +4428,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4362,7 +4428,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void { |
| 4362 | | 4428 | |
| 4363 | const int_info = int_ty.intInfo(zcu); | 4429 | const int_info = int_ty.intInfo(zcu); |
| 4364 | if (int_info.bits <= 64) { | 4430 | if (int_info.bits <= 64) { |
| 4365 | break :result try func.binOp(tag, lhs, int_ty, rhs, int_ty); | 4431 | break :result try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 4366 | } else { | 4432 | } else { |
| 4367 | return func.fail("TODO riscv cmp for ints > 64 bits", .{}); | 4433 | return func.fail("TODO riscv cmp for ints > 64 bits", .{}); |
| 4368 | } | 4434 | } |
| ... | @@ -4373,7 +4439,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4373,7 +4439,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void { |
| 4373 | if (float_bits > float_reg_size) { | 4439 | if (float_bits > float_reg_size) { |
| 4374 | return func.fail("TODO: airCmp float > 64/32 bits", .{}); | 4440 | return func.fail("TODO: airCmp float > 64/32 bits", .{}); |
| 4375 | } | 4441 | } |
| 4376 | break :result try func.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty); | 4442 | break :result try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 4377 | }, | 4443 | }, |
| 4378 | else => unreachable, | 4444 | else => unreachable, |
| 4379 | } | 4445 | } |
| ... | @@ -4537,7 +4603,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -4537,7 +4603,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 4537 | else | 4603 | else |
| 4538 | .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = Type.bool }; | 4604 | .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = Type.bool }; |
| 4539 | | 4605 | |
| 4540 | const return_mcv = try func.allocRegOrMem(inst, true); | 4606 | const return_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true); |
| 4541 | assert(return_mcv == .register); // should not be larger 8 bytes | 4607 | assert(return_mcv == .register); // should not be larger 8 bytes |
| 4542 | const return_reg = return_mcv.register; | 4608 | const return_reg = return_mcv.register; |
| 4543 | | 4609 | |
| ... | @@ -4569,7 +4635,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -4569,7 +4635,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 4569 | some_info.ty, | 4635 | some_info.ty, |
| 4570 | .{ .immediate = 0 }, | 4636 | .{ .immediate = 0 }, |
| 4571 | ), | 4637 | ), |
| 4572 | .size = .byte, | 4638 | .ty = Type.bool, |
| 4573 | }, | 4639 | }, |
| 4574 | }, | 4640 | }, |
| 4575 | }); | 4641 | }); |
| ... | @@ -4601,7 +4667,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -4601,7 +4667,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 4601 | some_info.ty, | 4667 | some_info.ty, |
| 4602 | .{ .immediate = 0 }, | 4668 | .{ .immediate = 0 }, |
| 4603 | ), | 4669 | ), |
| 4604 | .size = .byte, | 4670 | .ty = Type.bool, |
| 4605 | }, | 4671 | }, |
| 4606 | }, | 4672 | }, |
| 4607 | }); | 4673 | }); |
| ... | @@ -4623,9 +4689,9 @@ fn airIsNull(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4623,9 +4689,9 @@ fn airIsNull(func: *Func, inst: Air.Inst.Index) !void { |
| 4623 | fn airIsNullPtr(func: *Func, inst: Air.Inst.Index) !void { | 4689 | fn airIsNullPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 4624 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | 4690 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 4625 | const operand = try func.resolveInst(un_op); | 4691 | const operand = try func.resolveInst(un_op); |
| 4626 | _ = operand; // autofix | 4692 | _ = operand; |
| 4627 | const ty = func.typeOf(un_op); | 4693 | const ty = func.typeOf(un_op); |
| 4628 | _ = ty; // autofix | 4694 | _ = ty; |
| 4629 | | 4695 | |
| 4630 | if (true) return func.fail("TODO: airIsNullPtr", .{}); | 4696 | if (true) return func.fail("TODO: airIsNullPtr", .{}); |
| 4631 | | 4697 | |
| ... | @@ -4656,9 +4722,9 @@ fn airIsNonNull(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4656,9 +4722,9 @@ fn airIsNonNull(func: *Func, inst: Air.Inst.Index) !void { |
| 4656 | fn airIsNonNullPtr(func: *Func, inst: Air.Inst.Index) !void { | 4722 | fn airIsNonNullPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 4657 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | 4723 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 4658 | const operand = try func.resolveInst(un_op); | 4724 | const operand = try func.resolveInst(un_op); |
| 4659 | _ = operand; // autofix | 4725 | _ = operand; |
| 4660 | const ty = func.typeOf(un_op); | 4726 | const ty = func.typeOf(un_op); |
| 4661 | _ = ty; // autofix | 4727 | _ = ty; |
| 4662 | | 4728 | |
| 4663 | if (true) return func.fail("TODO: airIsNonNullPtr", .{}); | 4729 | if (true) return func.fail("TODO: airIsNonNullPtr", .{}); |
| 4664 | | 4730 | |
| ... | @@ -4685,7 +4751,7 @@ fn airIsErrPtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4685,7 +4751,7 @@ fn airIsErrPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 4685 | // The MCValue that holds the pointer can be re-used as the value. | 4751 | // The MCValue that holds the pointer can be re-used as the value. |
| 4686 | break :blk operand_ptr; | 4752 | break :blk operand_ptr; |
| 4687 | } else { | 4753 | } else { |
| 4688 | break :blk try func.allocRegOrMem(inst, true); | 4754 | break :blk try func.allocRegOrMem(func.typeOfIndex(inst), inst, true); |
| 4689 | } | 4755 | } |
| 4690 | }; | 4756 | }; |
| 4691 | try func.load(operand, operand_ptr, func.typeOf(un_op)); | 4757 | try func.load(operand, operand_ptr, func.typeOf(un_op)); |
| ... | @@ -4701,45 +4767,44 @@ fn airIsErrPtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4701,45 +4767,44 @@ fn airIsErrPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 4701 | /// | 4767 | /// |
| 4702 | /// Result is in the return register. | 4768 | /// Result is in the return register. |
| 4703 | fn isErr(func: *Func, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { | 4769 | fn isErr(func: *Func, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { |
| | 4770 | _ = maybe_inst; |
| 4704 | const zcu = func.bin_file.comp.module.?; | 4771 | const zcu = func.bin_file.comp.module.?; |
| 4705 | const err_ty = eu_ty.errorUnionSet(zcu); | 4772 | const err_ty = eu_ty.errorUnionSet(zcu); |
| 4706 | if (err_ty.errorSetIsEmpty(zcu)) return MCValue{ .immediate = 0 }; // always false | 4773 | if (err_ty.errorSetIsEmpty(zcu)) return MCValue{ .immediate = 0 }; // always false |
| 4707 | | | |
| 4708 | _ = maybe_inst; | | |
| 4709 | | | |
| 4710 | const err_off: u31 = @intCast(errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu)); | 4774 | const err_off: u31 = @intCast(errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu)); |
| 4711 | | 4775 | |
| | 4776 | const return_reg, const return_lock = try func.allocReg(.int); |
| | 4777 | defer func.register_manager.unlockReg(return_lock); |
| | 4778 | |
| 4712 | switch (eu_mcv) { | 4779 | switch (eu_mcv) { |
| 4713 | .register => |reg| { | 4780 | .register => |reg| { |
| 4714 | const eu_lock = func.register_manager.lockReg(reg); | 4781 | const eu_lock = func.register_manager.lockReg(reg); |
| 4715 | defer if (eu_lock) |lock| func.register_manager.unlockReg(lock); | 4782 | defer if (eu_lock) |lock| func.register_manager.unlockReg(lock); |
| 4716 | | 4783 | |
| 4717 | const return_reg = try func.copyToTmpRegister(eu_ty, eu_mcv); | 4784 | try func.genCopy(eu_ty, .{ .register = return_reg }, eu_mcv); |
| 4718 | const return_lock = func.register_manager.lockRegAssumeUnused(return_reg); | | |
| 4719 | defer func.register_manager.unlockReg(return_lock); | | |
| 4720 | | | |
| 4721 | var return_mcv: MCValue = .{ .register = return_reg }; | | |
| 4722 | | 4785 | |
| 4723 | if (err_off > 0) { | 4786 | if (err_off > 0) { |
| 4724 | return_mcv = try func.binOp( | 4787 | try func.genBinOp( |
| 4725 | .shr, | 4788 | .shr, |
| 4726 | return_mcv, | 4789 | .{ .register = return_reg }, |
| 4727 | eu_ty, | 4790 | eu_ty, |
| 4728 | .{ .immediate = @as(u6, @intCast(err_off * 8)) }, | 4791 | .{ .immediate = @as(u6, @intCast(err_off * 8)) }, |
| 4729 | Type.u8, | 4792 | Type.u8, |
| | 4793 | return_reg, |
| 4730 | ); | 4794 | ); |
| 4731 | } | 4795 | } |
| 4732 | | 4796 | |
| 4733 | return try func.binOp( | 4797 | try func.genBinOp( |
| 4734 | .cmp_neq, | 4798 | .cmp_neq, |
| 4735 | return_mcv, | 4799 | .{ .register = return_reg }, |
| 4736 | Type.u16, | 4800 | Type.anyerror, |
| 4737 | .{ .immediate = 0 }, | 4801 | .{ .immediate = 0 }, |
| 4738 | Type.u16, | 4802 | Type.u8, |
| | 4803 | return_reg, |
| 4739 | ); | 4804 | ); |
| 4740 | }, | 4805 | }, |
| 4741 | .load_frame => |frame_addr| { | 4806 | .load_frame => |frame_addr| { |
| 4742 | return func.binOp( | 4807 | try func.genBinOp( |
| 4743 | .cmp_neq, | 4808 | .cmp_neq, |
| 4744 | .{ .load_frame = .{ | 4809 | .{ .load_frame = .{ |
| 4745 | .index = frame_addr.index, | 4810 | .index = frame_addr.index, |
| ... | @@ -4748,10 +4813,13 @@ fn isErr(func: *Func, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) | ... | @@ -4748,10 +4813,13 @@ fn isErr(func: *Func, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) |
| 4748 | Type.anyerror, | 4813 | Type.anyerror, |
| 4749 | .{ .immediate = 0 }, | 4814 | .{ .immediate = 0 }, |
| 4750 | Type.anyerror, | 4815 | Type.anyerror, |
| | 4816 | return_reg, |
| 4751 | ); | 4817 | ); |
| 4752 | }, | 4818 | }, |
| 4753 | else => return func.fail("TODO implement isErr for {}", .{eu_mcv}), | 4819 | else => return func.fail("TODO implement isErr for {}", .{eu_mcv}), |
| 4754 | } | 4820 | } |
| | 4821 | |
| | 4822 | return .{ .register = return_reg }; |
| 4755 | } | 4823 | } |
| 4756 | | 4824 | |
| 4757 | fn airIsNonErr(func: *Func, inst: Air.Inst.Index) !void { | 4825 | fn airIsNonErr(func: *Func, inst: Air.Inst.Index) !void { |
| ... | @@ -4799,7 +4867,7 @@ fn airIsNonErrPtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4799,7 +4867,7 @@ fn airIsNonErrPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 4799 | // The MCValue that holds the pointer can be re-used as the value. | 4867 | // The MCValue that holds the pointer can be re-used as the value. |
| 4800 | break :blk operand_ptr; | 4868 | break :blk operand_ptr; |
| 4801 | } else { | 4869 | } else { |
| 4802 | break :blk try func.allocRegOrMem(inst, true); | 4870 | break :blk try func.allocRegOrMem(func.typeOfIndex(inst), inst, true); |
| 4803 | } | 4871 | } |
| 4804 | }; | 4872 | }; |
| 4805 | const operand_ptr_ty = func.typeOf(un_op); | 4873 | const operand_ptr_ty = func.typeOf(un_op); |
| ... | @@ -4916,16 +4984,18 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4916,16 +4984,18 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 4916 | // switch branches must be comptime-known, so this is stored in an immediate | 4984 | // switch branches must be comptime-known, so this is stored in an immediate |
| 4917 | const item_mcv = try func.resolveInst(item); | 4985 | const item_mcv = try func.resolveInst(item); |
| 4918 | | 4986 | |
| 4919 | const cmp_mcv: MCValue = try func.binOp( | 4987 | const cmp_reg, const cmp_lock = try func.allocReg(.int); |
| | 4988 | defer func.register_manager.unlockReg(cmp_lock); |
| | 4989 | |
| | 4990 | try func.genBinOp( |
| 4920 | .cmp_neq, | 4991 | .cmp_neq, |
| 4921 | condition, | 4992 | condition, |
| 4922 | condition_ty, | 4993 | condition_ty, |
| 4923 | item_mcv, | 4994 | item_mcv, |
| 4924 | condition_ty, | 4995 | condition_ty, |
| | 4996 | cmp_reg, |
| 4925 | ); | 4997 | ); |
| 4926 | | 4998 | |
| 4927 | const cmp_reg = try func.copyToTmpRegister(Type.bool, cmp_mcv); | | |
| 4928 | | | |
| 4929 | if (!(i < relocs.len - 1)) { | 4999 | if (!(i < relocs.len - 1)) { |
| 4930 | _ = try func.addInst(.{ | 5000 | _ = try func.addInst(.{ |
| 4931 | .tag = .pseudo, | 5001 | .tag = .pseudo, |
| ... | @@ -5019,7 +5089,7 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5019,7 +5089,7 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5019 | break :result block_tracking.short; | 5089 | break :result block_tracking.short; |
| 5020 | } | 5090 | } |
| 5021 | | 5091 | |
| 5022 | const dst_mcv = if (first_br) try func.allocRegOrMem(br.block_inst, true) else dst: { | 5092 | const dst_mcv = if (first_br) try func.allocRegOrMem(block_ty, br.block_inst, true) else dst: { |
| 5023 | try func.getValue(block_tracking.short, br.block_inst); | 5093 | try func.getValue(block_tracking.short, br.block_inst); |
| 5024 | break :dst block_tracking.short; | 5094 | break :dst block_tracking.short; |
| 5025 | }; | 5095 | }; |
| ... | @@ -5063,10 +5133,10 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5063,10 +5133,10 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void { |
| 5063 | const lhs_ty = Type.bool; | 5133 | const lhs_ty = Type.bool; |
| 5064 | const rhs_ty = Type.bool; | 5134 | const rhs_ty = Type.bool; |
| 5065 | | 5135 | |
| 5066 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{}); | 5136 | const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs); |
| 5067 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); | 5137 | defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock); |
| 5068 | | 5138 | |
| 5069 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{}); | 5139 | const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs); |
| 5070 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); | 5140 | defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock); |
| 5071 | | 5141 | |
| 5072 | const result_reg, const result_lock = try func.allocReg(.int); | 5142 | const result_reg, const result_lock = try func.allocReg(.int); |
| ... | @@ -5262,7 +5332,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | ... | @@ -5262,7 +5332,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 5262 | const src_info: ?struct { addr_reg: Register, addr_lock: ?RegisterLock } = switch (src_mcv) { | 5332 | const src_info: ?struct { addr_reg: Register, addr_lock: ?RegisterLock } = switch (src_mcv) { |
| 5263 | .register_pair, .memory, .indirect, .load_frame => null, | 5333 | .register_pair, .memory, .indirect, .load_frame => null, |
| 5264 | .load_symbol => src: { | 5334 | .load_symbol => src: { |
| 5265 | const src_addr_reg, const src_addr_lock = try func.promoteReg(Type.usize, src_mcv.address(), .{}); | 5335 | const src_addr_reg, const src_addr_lock = try func.promoteReg(Type.usize, src_mcv.address()); |
| 5266 | errdefer func.register_manager.unlockReg(src_addr_lock); | 5336 | errdefer func.register_manager.unlockReg(src_addr_lock); |
| 5267 | | 5337 | |
| 5268 | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; | 5338 | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; |
| ... | @@ -5557,7 +5627,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5557,7 +5627,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5557 | .data = .{ .i_type = .{ | 5627 | .data = .{ .i_type = .{ |
| 5558 | .rd = reg, | 5628 | .rd = reg, |
| 5559 | .rs1 = reg, | 5629 | .rs1 = reg, |
| 5560 | .imm12 = Immediate.s(32), | 5630 | .imm12 = Immediate.u(32), |
| 5561 | } }, | 5631 | } }, |
| 5562 | }); | 5632 | }); |
| 5563 | | 5633 | |
| ... | @@ -5604,10 +5674,9 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5604,10 +5674,9 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5604 | .m = .{ | 5674 | .m = .{ |
| 5605 | .base = .{ .frame = frame.index }, | 5675 | .base = .{ .frame = frame.index }, |
| 5606 | .mod = .{ | 5676 | .mod = .{ |
| 5607 | .rm = .{ | 5677 | .size = func.memSize(ty), |
| 5608 | .size = func.memSize(ty), | 5678 | .unsigned = ty.isUnsignedInt(zcu), |
| 5609 | .disp = frame.off, | 5679 | .disp = frame.off, |
| 5610 | }, | | |
| 5611 | }, | 5680 | }, |
| 5612 | }, | 5681 | }, |
| 5613 | } }, | 5682 | } }, |
| ... | @@ -5622,7 +5691,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5622,7 +5691,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5622 | .data = .{ .i_type = .{ | 5691 | .data = .{ .i_type = .{ |
| 5623 | .rd = reg, | 5692 | .rd = reg, |
| 5624 | .rs1 = reg, | 5693 | .rs1 = reg, |
| 5625 | .imm12 = Immediate.s(0), | 5694 | .imm12 = Immediate.u(0), |
| 5626 | } }, | 5695 | } }, |
| 5627 | }); | 5696 | }); |
| 5628 | }, | 5697 | }, |
| ... | @@ -5636,19 +5705,17 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5636,19 +5705,17 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5636 | .register_offset => |reg_off| .{ | 5705 | .register_offset => |reg_off| .{ |
| 5637 | .base = .{ .reg = reg_off.reg }, | 5706 | .base = .{ .reg = reg_off.reg }, |
| 5638 | .mod = .{ | 5707 | .mod = .{ |
| 5639 | .rm = .{ | 5708 | .size = func.memSize(ty), |
| 5640 | .size = func.memSize(ty), | 5709 | .disp = reg_off.off, |
| 5641 | .disp = reg_off.off, | 5710 | .unsigned = false, |
| 5642 | }, | | |
| 5643 | }, | 5711 | }, |
| 5644 | }, | 5712 | }, |
| 5645 | .lea_frame => |frame| .{ | 5713 | .lea_frame => |frame| .{ |
| 5646 | .base = .{ .frame = frame.index }, | 5714 | .base = .{ .frame = frame.index }, |
| 5647 | .mod = .{ | 5715 | .mod = .{ |
| 5648 | .rm = .{ | 5716 | .size = func.memSize(ty), |
| 5649 | .size = func.memSize(ty), | 5717 | .disp = frame.off, |
| 5650 | .disp = frame.off, | 5718 | .unsigned = false, |
| 5651 | }, | | |
| 5652 | }, | 5719 | }, |
| 5653 | }, | 5720 | }, |
| 5654 | else => unreachable, | 5721 | else => unreachable, |
| ... | @@ -5787,9 +5854,10 @@ fn genSetMem( | ... | @@ -5787,9 +5854,10 @@ fn genSetMem( |
| 5787 | .r = reg, | 5854 | .r = reg, |
| 5788 | .m = .{ | 5855 | .m = .{ |
| 5789 | .base = .{ .frame = frame_index }, | 5856 | .base = .{ .frame = frame_index }, |
| 5790 | .mod = .{ .rm = .{ | 5857 | .mod = .{ |
| 5791 | .size = Memory.Size.fromByteSize(src_size), | 5858 | .size = Memory.Size.fromByteSize(src_size), |
| 5792 | } }, | 5859 | .unsigned = false, |
| | 5860 | }, |
| 5793 | }, | 5861 | }, |
| 5794 | } }, | 5862 | } }, |
| 5795 | }); | 5863 | }); |
| ... | @@ -5802,10 +5870,11 @@ fn genSetMem( | ... | @@ -5802,10 +5870,11 @@ fn genSetMem( |
| 5802 | .r = reg, | 5870 | .r = reg, |
| 5803 | .m = .{ | 5871 | .m = .{ |
| 5804 | .base = base, | 5872 | .base = base, |
| 5805 | .mod = .{ .rm = .{ | 5873 | .mod = .{ |
| 5806 | .size = func.memSize(ty), | 5874 | .size = func.memSize(ty), |
| 5807 | .disp = disp, | 5875 | .disp = disp, |
| 5808 | } }, | 5876 | .unsigned = false, |
| | 5877 | }, |
| 5809 | }, | 5878 | }, |
| 5810 | } }, | 5879 | } }, |
| 5811 | }); | 5880 | }); |
| ... | @@ -5820,7 +5889,7 @@ fn genSetMem( | ... | @@ -5820,7 +5889,7 @@ fn genSetMem( |
| 5820 | .immediate => { | 5889 | .immediate => { |
| 5821 | // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with | 5890 | // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with |
| 5822 | // a register allocation. | 5891 | // a register allocation. |
| 5823 | const reg, const reg_lock = try func.promoteReg(ty, src_mcv, .{}); | 5892 | const reg, const reg_lock = try func.promoteReg(ty, src_mcv); |
| 5824 | defer if (reg_lock) |lock| func.register_manager.unlockReg(lock); | 5893 | defer if (reg_lock) |lock| func.register_manager.unlockReg(lock); |
| 5825 | | 5894 | |
| 5826 | return func.genSetMem(base, disp, ty, .{ .register = reg }); | 5895 | return func.genSetMem(base, disp, ty, .{ .register = reg }); |
| ... | @@ -5833,9 +5902,10 @@ fn airIntFromPtr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5833,9 +5902,10 @@ fn airIntFromPtr(func: *Func, inst: Air.Inst.Index) !void { |
| 5833 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | 5902 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 5834 | const result = result: { | 5903 | const result = result: { |
| 5835 | const src_mcv = try func.resolveInst(un_op); | 5904 | const src_mcv = try func.resolveInst(un_op); |
| | 5905 | const src_ty = func.typeOfIndex(inst); |
| 5836 | if (func.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; | 5906 | if (func.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; |
| 5837 | | 5907 | |
| 5838 | const dst_mcv = try func.allocRegOrMem(inst, true); | 5908 | const dst_mcv = try func.allocRegOrMem(src_ty, inst, true); |
| 5839 | const dst_ty = func.typeOfIndex(inst); | 5909 | const dst_ty = func.typeOfIndex(inst); |
| 5840 | try func.genCopy(dst_ty, dst_mcv, src_mcv); | 5910 | try func.genCopy(dst_ty, dst_mcv, src_mcv); |
| 5841 | break :result dst_mcv; | 5911 | break :result dst_mcv; |
| ... | @@ -5858,7 +5928,7 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5858,7 +5928,7 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void { |
| 5858 | | 5928 | |
| 5859 | const dst_mcv = if (dst_ty.abiSize(zcu) <= src_ty.abiSize(zcu) and | 5929 | const dst_mcv = if (dst_ty.abiSize(zcu) <= src_ty.abiSize(zcu) and |
| 5860 | func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { | 5930 | func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { |
| 5861 | const dst_mcv = try func.allocRegOrMem(inst, true); | 5931 | const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true); |
| 5862 | try func.genCopy(switch (math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) { | 5932 | try func.genCopy(switch (math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) { |
| 5863 | .lt => dst_ty, | 5933 | .lt => dst_ty, |
| 5864 | .eq => if (!dst_mcv.isMemory() or src_mcv.isMemory()) dst_ty else src_ty, | 5934 | .eq => if (!dst_mcv.isMemory() or src_mcv.isMemory()) dst_ty else src_ty, |
| ... | @@ -6080,7 +6150,7 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -6080,7 +6150,7 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void { |
| 6080 | .tag = .slli, | 6150 | .tag = .slli, |
| 6081 | .ops = .rri, | 6151 | .ops = .rri, |
| 6082 | .data = .{ .i_type = .{ | 6152 | .data = .{ .i_type = .{ |
| 6083 | .imm12 = Immediate.s(4), | 6153 | .imm12 = Immediate.u(4), |
| 6084 | .rd = err_reg, | 6154 | .rd = err_reg, |
| 6085 | .rs1 = err_reg, | 6155 | .rs1 = err_reg, |
| 6086 | } }, | 6156 | } }, |
| ... | @@ -6104,7 +6174,7 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -6104,7 +6174,7 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void { |
| 6104 | .r = start_reg, | 6174 | .r = start_reg, |
| 6105 | .m = .{ | 6175 | .m = .{ |
| 6106 | .base = .{ .reg = addr_reg }, | 6176 | .base = .{ .reg = addr_reg }, |
| 6107 | .mod = .{ .off = 0 }, | 6177 | .mod = .{ .size = .dword, .unsigned = true }, |
| 6108 | }, | 6178 | }, |
| 6109 | }, | 6179 | }, |
| 6110 | }, | 6180 | }, |
| ... | @@ -6118,13 +6188,13 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -6118,13 +6188,13 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void { |
| 6118 | .r = end_reg, | 6188 | .r = end_reg, |
| 6119 | .m = .{ | 6189 | .m = .{ |
| 6120 | .base = .{ .reg = addr_reg }, | 6190 | .base = .{ .reg = addr_reg }, |
| 6121 | .mod = .{ .off = 8 }, | 6191 | .mod = .{ .size = .dword, .unsigned = true }, |
| 6122 | }, | 6192 | }, |
| 6123 | }, | 6193 | }, |
| 6124 | }, | 6194 | }, |
| 6125 | }); | 6195 | }); |
| 6126 | | 6196 | |
| 6127 | const dst_mcv = try func.allocRegOrMem(inst, false); | 6197 | const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, false); |
| 6128 | const frame = dst_mcv.load_frame; | 6198 | const frame = dst_mcv.load_frame; |
| 6129 | try func.genSetMem( | 6199 | try func.genSetMem( |
| 6130 | .{ .frame = frame.index }, | 6200 | .{ .frame = frame.index }, |