| ... | ... | @@ -499,20 +499,29 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 499 | 499 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), |
| 500 | 500 | |
| 501 | 501 | .add => try self.airBinOp(inst, .add), |
| 502 | | .addwrap => @panic("TODO try self.airAddWrap(inst)"), |
| 502 | .addwrap => try self.airBinOp(inst, .addwrap), |
| 503 | .sub => try self.airBinOp(inst, .sub), |
| 504 | .subwrap => try self.airBinOp(inst, .subwrap), |
| 505 | .mul => try self.airBinOp(inst, .mul), |
| 506 | .mulwrap => try self.airBinOp(inst, .mulwrap), |
| 507 | .shl => try self.airBinOp(inst, .shl), |
| 508 | .shl_exact => try self.airBinOp(inst, .shl_exact), |
| 509 | .shr => try self.airBinOp(inst, .shr), |
| 510 | .shr_exact => try self.airBinOp(inst, .shr_exact), |
| 511 | .bool_and => try self.airBinOp(inst, .bool_and), |
| 512 | .bool_or => try self.airBinOp(inst, .bool_or), |
| 513 | .bit_and => try self.airBinOp(inst, .bit_and), |
| 514 | .bit_or => try self.airBinOp(inst, .bit_or), |
| 515 | .xor => try self.airBinOp(inst, .xor), |
| 516 | |
| 503 | 517 | .add_sat => @panic("TODO try self.airAddSat(inst)"), |
| 504 | | .sub => @panic("TODO try self.airBinOp(inst)"), |
| 505 | | .subwrap => @panic("TODO try self.airSubWrap(inst)"), |
| 506 | 518 | .sub_sat => @panic("TODO try self.airSubSat(inst)"), |
| 507 | | .mul => @panic("TODO try self.airMul(inst)"), |
| 508 | | .mulwrap => @panic("TODO try self.airMulWrap(inst)"), |
| 509 | 519 | .mul_sat => @panic("TODO try self.airMulSat(inst)"), |
| 510 | | .rem => try self.airRem(inst), |
| 511 | | .mod => try self.airMod(inst), |
| 512 | | .shl, .shl_exact => @panic("TODO try self.airShl(inst)"), |
| 513 | 520 | .shl_sat => @panic("TODO try self.airShlSat(inst)"), |
| 514 | 521 | .min => @panic("TODO try self.airMin(inst)"), |
| 515 | 522 | .max => @panic("TODO try self.airMax(inst)"), |
| 523 | .rem => try self.airRem(inst), |
| 524 | .mod => try self.airMod(inst), |
| 516 | 525 | .slice => try self.airSlice(inst), |
| 517 | 526 | |
| 518 | 527 | .sqrt, |
| ... | ... | @@ -548,13 +557,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 548 | 557 | .cmp_vector => @panic("TODO try self.airCmpVector(inst)"), |
| 549 | 558 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 550 | 559 | |
| 551 | | .bool_and => try self.airBinOp(inst, .bool_and), |
| 552 | | .bool_or => try self.airBinOp(inst, .bool_or), |
| 553 | | .bit_and => try self.airBinOp(inst, .bit_and), |
| 554 | | .bit_or => try self.airBinOp(inst, .bit_or), |
| 555 | | .xor => try self.airBinOp(inst, .xor), |
| 556 | | .shr, .shr_exact => @panic("TODO try self.airShr(inst)"), |
| 557 | | |
| 558 | 560 | .alloc => try self.airAlloc(inst), |
| 559 | 561 | .ret_ptr => try self.airRetPtr(inst), |
| 560 | 562 | .arg => try self.airArg(inst), |
| ... | ... | @@ -2397,6 +2399,10 @@ fn binOp( |
| 2397 | 2399 | switch (tag) { |
| 2398 | 2400 | .add, |
| 2399 | 2401 | .sub, |
| 2402 | .mul, |
| 2403 | .bit_and, |
| 2404 | .bit_or, |
| 2405 | .xor, |
| 2400 | 2406 | .cmp_eq, |
| 2401 | 2407 | => { |
| 2402 | 2408 | switch (lhs_ty.zigTypeTag()) { |
| ... | ... | @@ -2411,12 +2417,20 @@ fn binOp( |
| 2411 | 2417 | // operands |
| 2412 | 2418 | const lhs_immediate_ok = switch (tag) { |
| 2413 | 2419 | .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 2420 | .mul => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 2421 | .bit_and => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 2422 | .bit_or => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 2423 | .xor => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 2414 | 2424 | .sub, .cmp_eq => false, |
| 2415 | 2425 | else => unreachable, |
| 2416 | 2426 | }; |
| 2417 | 2427 | const rhs_immediate_ok = switch (tag) { |
| 2418 | 2428 | .add, |
| 2419 | 2429 | .sub, |
| 2430 | .mul, |
| 2431 | .bit_and, |
| 2432 | .bit_or, |
| 2433 | .xor, |
| 2420 | 2434 | .cmp_eq, |
| 2421 | 2435 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 2422 | 2436 | else => unreachable, |
| ... | ... | @@ -2425,6 +2439,10 @@ fn binOp( |
| 2425 | 2439 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2426 | 2440 | .add => .add, |
| 2427 | 2441 | .sub => .sub, |
| 2442 | .mul => .mulx, |
| 2443 | .bit_and => .@"and", |
| 2444 | .bit_or => .@"or", |
| 2445 | .xor => .xor, |
| 2428 | 2446 | .cmp_eq => .cmp, |
| 2429 | 2447 | else => unreachable, |
| 2430 | 2448 | }; |
| ... | ... | @@ -2446,72 +2464,60 @@ fn binOp( |
| 2446 | 2464 | } |
| 2447 | 2465 | }, |
| 2448 | 2466 | |
| 2449 | | .div_trunc => { |
| 2467 | .addwrap, |
| 2468 | .subwrap, |
| 2469 | .mulwrap, |
| 2470 | => { |
| 2471 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 2472 | .addwrap => .add, |
| 2473 | .subwrap => .sub, |
| 2474 | .mulwrap => .mul, |
| 2475 | else => unreachable, |
| 2476 | }; |
| 2477 | |
| 2478 | // Generate the base operation |
| 2479 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2480 | |
| 2481 | // Truncate if necessary |
| 2450 | 2482 | switch (lhs_ty.zigTypeTag()) { |
| 2451 | 2483 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2452 | 2484 | .Int => { |
| 2453 | | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2454 | 2485 | const int_info = lhs_ty.intInfo(self.target.*); |
| 2455 | 2486 | if (int_info.bits <= 64) { |
| 2456 | | const rhs_immediate_ok = switch (tag) { |
| 2457 | | .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 2458 | | else => unreachable, |
| 2459 | | }; |
| 2460 | | |
| 2461 | | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2462 | | .div_trunc => switch (int_info.signedness) { |
| 2463 | | .signed => Mir.Inst.Tag.sdivx, |
| 2464 | | .unsigned => Mir.Inst.Tag.udivx, |
| 2465 | | }, |
| 2466 | | else => unreachable, |
| 2467 | | }; |
| 2468 | | |
| 2469 | | if (rhs_immediate_ok) { |
| 2470 | | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, true, metadata); |
| 2471 | | } else { |
| 2472 | | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2473 | | } |
| 2487 | const result_reg = result.register; |
| 2488 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| 2489 | return result; |
| 2474 | 2490 | } else { |
| 2475 | | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 2491 | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| 2476 | 2492 | } |
| 2477 | 2493 | }, |
| 2478 | 2494 | else => unreachable, |
| 2479 | 2495 | } |
| 2480 | 2496 | }, |
| 2481 | 2497 | |
| 2482 | | .mul => { |
| 2498 | .div_trunc => { |
| 2483 | 2499 | switch (lhs_ty.zigTypeTag()) { |
| 2484 | 2500 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2485 | 2501 | .Int => { |
| 2486 | 2502 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2487 | 2503 | const int_info = lhs_ty.intInfo(self.target.*); |
| 2488 | 2504 | if (int_info.bits <= 64) { |
| 2489 | | // Only say yes if the operation is |
| 2490 | | // commutative, i.e. we can swap both of the |
| 2491 | | // operands |
| 2492 | | const lhs_immediate_ok = switch (tag) { |
| 2493 | | .mul => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 2494 | | else => unreachable, |
| 2495 | | }; |
| 2496 | 2505 | const rhs_immediate_ok = switch (tag) { |
| 2497 | | .mul => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 2506 | .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 2498 | 2507 | else => unreachable, |
| 2499 | 2508 | }; |
| 2500 | 2509 | |
| 2501 | 2510 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2502 | | .mul => .mulx, |
| 2511 | .div_trunc => switch (int_info.signedness) { |
| 2512 | .signed => Mir.Inst.Tag.sdivx, |
| 2513 | .unsigned => Mir.Inst.Tag.udivx, |
| 2514 | }, |
| 2503 | 2515 | else => unreachable, |
| 2504 | 2516 | }; |
| 2505 | 2517 | |
| 2506 | 2518 | if (rhs_immediate_ok) { |
| 2507 | | // At this point, rhs is an immediate |
| 2508 | | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata); |
| 2509 | | } else if (lhs_immediate_ok) { |
| 2510 | | // swap lhs and rhs |
| 2511 | | // At this point, lhs is an immediate |
| 2512 | | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); |
| 2519 | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, true, metadata); |
| 2513 | 2520 | } else { |
| 2514 | | // TODO convert large immediates to register before adding |
| 2515 | 2521 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2516 | 2522 | } |
| 2517 | 2523 | } else { |
| ... | ... | @@ -2552,58 +2558,6 @@ fn binOp( |
| 2552 | 2558 | } |
| 2553 | 2559 | }, |
| 2554 | 2560 | |
| 2555 | | .bit_and, |
| 2556 | | .bit_or, |
| 2557 | | .xor, |
| 2558 | | => { |
| 2559 | | switch (lhs_ty.zigTypeTag()) { |
| 2560 | | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2561 | | .Int => { |
| 2562 | | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2563 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 2564 | | if (int_info.bits <= 64) { |
| 2565 | | // Only say yes if the operation is |
| 2566 | | // commutative, i.e. we can swap both of the |
| 2567 | | // operands |
| 2568 | | const lhs_immediate_ok = switch (tag) { |
| 2569 | | .bit_and, |
| 2570 | | .bit_or, |
| 2571 | | .xor, |
| 2572 | | => lhs == .immediate and lhs.immediate <= std.math.maxInt(u13), |
| 2573 | | else => unreachable, |
| 2574 | | }; |
| 2575 | | const rhs_immediate_ok = switch (tag) { |
| 2576 | | .bit_and, |
| 2577 | | .bit_or, |
| 2578 | | .xor, |
| 2579 | | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u13), |
| 2580 | | else => unreachable, |
| 2581 | | }; |
| 2582 | | |
| 2583 | | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2584 | | .bit_and => .@"and", |
| 2585 | | .bit_or => .@"or", |
| 2586 | | .xor => .xor, |
| 2587 | | else => unreachable, |
| 2588 | | }; |
| 2589 | | |
| 2590 | | if (rhs_immediate_ok) { |
| 2591 | | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata); |
| 2592 | | } else if (lhs_immediate_ok) { |
| 2593 | | // swap lhs and rhs |
| 2594 | | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); |
| 2595 | | } else { |
| 2596 | | // TODO convert large immediates to register before adding |
| 2597 | | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2598 | | } |
| 2599 | | } else { |
| 2600 | | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 2601 | | } |
| 2602 | | }, |
| 2603 | | else => unreachable, |
| 2604 | | } |
| 2605 | | }, |
| 2606 | | |
| 2607 | 2561 | .bool_and, |
| 2608 | 2562 | .bool_or, |
| 2609 | 2563 | => { |
| ... | ... | @@ -2624,36 +2578,41 @@ fn binOp( |
| 2624 | 2578 | } |
| 2625 | 2579 | }, |
| 2626 | 2580 | |
| 2627 | | .shl => { |
| 2581 | .shl, |
| 2582 | .shr, |
| 2583 | => { |
| 2628 | 2584 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 2629 | 2585 | .shl => .shl_exact, |
| 2586 | .shr => .shr_exact, |
| 2630 | 2587 | else => unreachable, |
| 2631 | 2588 | }; |
| 2632 | 2589 | |
| 2633 | | // Generate a shl_exact/shr_exact |
| 2590 | // Generate the base operation |
| 2634 | 2591 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2635 | 2592 | |
| 2636 | 2593 | // Truncate if necessary |
| 2637 | | switch (tag) { |
| 2638 | | .shl => switch (lhs_ty.zigTypeTag()) { |
| 2639 | | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2640 | | .Int => { |
| 2641 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 2642 | | if (int_info.bits <= 64) { |
| 2643 | | const result_reg = result.register; |
| 2644 | | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| 2645 | | return result; |
| 2646 | | } else { |
| 2647 | | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| 2648 | | } |
| 2649 | | }, |
| 2650 | | else => unreachable, |
| 2594 | switch (lhs_ty.zigTypeTag()) { |
| 2595 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2596 | .Int => { |
| 2597 | const int_info = lhs_ty.intInfo(self.target.*); |
| 2598 | if (int_info.bits <= 64) { |
| 2599 | // 32 and 64 bit operands doesn't need truncating |
| 2600 | if (int_info.bits == 32 or int_info.bits == 64) return result; |
| 2601 | |
| 2602 | const result_reg = result.register; |
| 2603 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| 2604 | return result; |
| 2605 | } else { |
| 2606 | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| 2607 | } |
| 2651 | 2608 | }, |
| 2652 | 2609 | else => unreachable, |
| 2653 | 2610 | } |
| 2654 | 2611 | }, |
| 2655 | 2612 | |
| 2656 | | .shl_exact => { |
| 2613 | .shl_exact, |
| 2614 | .shr_exact, |
| 2615 | => { |
| 2657 | 2616 | switch (lhs_ty.zigTypeTag()) { |
| 2658 | 2617 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2659 | 2618 | .Int => { |
| ... | ... | @@ -2662,7 +2621,11 @@ fn binOp( |
| 2662 | 2621 | const rhs_immediate_ok = rhs == .immediate; |
| 2663 | 2622 | |
| 2664 | 2623 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2665 | | .shl_exact => .sllx, |
| 2624 | .shl_exact => if (int_info.bits <= 32) Mir.Inst.Tag.sll else Mir.Inst.Tag.sllx, |
| 2625 | .shr_exact => switch (int_info.signedness) { |
| 2626 | .signed => if (int_info.bits <= 32) Mir.Inst.Tag.sra else Mir.Inst.Tag.srax, |
| 2627 | .unsigned => if (int_info.bits <= 32) Mir.Inst.Tag.srl else Mir.Inst.Tag.srlx, |
| 2628 | }, |
| 2666 | 2629 | else => unreachable, |
| 2667 | 2630 | }; |
| 2668 | 2631 | |
| ... | ... | @@ -2769,7 +2732,21 @@ fn binOpImmediate( |
| 2769 | 2732 | .rs2_or_imm = .{ .imm = @intCast(u12, rhs.immediate) }, |
| 2770 | 2733 | }, |
| 2771 | 2734 | }, |
| 2772 | | .sllx => .{ |
| 2735 | .sll, |
| 2736 | .srl, |
| 2737 | .sra, |
| 2738 | => .{ |
| 2739 | .shift = .{ |
| 2740 | .is_imm = true, |
| 2741 | .rd = dest_reg, |
| 2742 | .rs1 = lhs_reg, |
| 2743 | .rs2_or_imm = .{ .imm = @intCast(u5, rhs.immediate) }, |
| 2744 | }, |
| 2745 | }, |
| 2746 | .sllx, |
| 2747 | .srlx, |
| 2748 | .srax, |
| 2749 | => .{ |
| 2773 | 2750 | .shift = .{ |
| 2774 | 2751 | .is_imm = true, |
| 2775 | 2752 | .rd = dest_reg, |
| ... | ... | @@ -2893,7 +2870,13 @@ fn binOpRegister( |
| 2893 | 2870 | .rs2_or_imm = .{ .rs2 = rhs_reg }, |
| 2894 | 2871 | }, |
| 2895 | 2872 | }, |
| 2896 | | .sllx => .{ |
| 2873 | .sll, |
| 2874 | .srl, |
| 2875 | .sra, |
| 2876 | .sllx, |
| 2877 | .srlx, |
| 2878 | .srax, |
| 2879 | => .{ |
| 2897 | 2880 | .shift = .{ |
| 2898 | 2881 | .is_imm = false, |
| 2899 | 2882 | .rd = dest_reg, |