| ... | @@ -1123,6 +1123,7 @@ const required_features = [_]Target.riscv.Feature{ | ... | @@ -1123,6 +1123,7 @@ const required_features = [_]Target.riscv.Feature{ |
| 1123 | .a, | 1123 | .a, |
| 1124 | .zicsr, | 1124 | .zicsr, |
| 1125 | .v, | 1125 | .v, |
| | 1126 | .zbb, |
| 1126 | }; | 1127 | }; |
| 1127 | | 1128 | |
| 1128 | fn gen(func: *Func) !void { | 1129 | fn gen(func: *Func) !void { |
| ... | @@ -2385,20 +2386,24 @@ fn genBinOp( | ... | @@ -2385,20 +2386,24 @@ fn genBinOp( |
| 2385 | .mul, | 2386 | .mul, |
| 2386 | .mul_wrap, | 2387 | .mul_wrap, |
| 2387 | .rem, | 2388 | .rem, |
| | 2389 | .div_trunc, |
| 2388 | => { | 2390 | => { |
| 2389 | if (!math.isPowerOfTwo(bit_size)) | | |
| 2390 | return func.fail( | | |
| 2391 | "TODO: genBinOp {s} non-pow 2, found {}", | | |
| 2392 | .{ @tagName(tag), bit_size }, | | |
| 2393 | ); | | |
| 2394 | | | |
| 2395 | switch (tag) { | 2391 | switch (tag) { |
| 2396 | .rem, | 2392 | .rem, |
| | 2393 | .div_trunc, |
| 2397 | => { | 2394 | => { |
| 2398 | try func.truncateRegister(lhs_ty, lhs_reg); | 2395 | if (!math.isPowerOfTwo(bit_size)) { |
| 2399 | try func.truncateRegister(rhs_ty, rhs_reg); | 2396 | try func.truncateRegister(lhs_ty, lhs_reg); |
| | 2397 | try func.truncateRegister(rhs_ty, rhs_reg); |
| | 2398 | } |
| | 2399 | }, |
| | 2400 | else => { |
| | 2401 | if (!math.isPowerOfTwo(bit_size)) |
| | 2402 | return func.fail( |
| | 2403 | "TODO: genBinOp verify {s} non-pow 2, found {}", |
| | 2404 | .{ @tagName(tag), bit_size }, |
| | 2405 | ); |
| 2400 | }, | 2406 | }, |
| 2401 | else => {}, | | |
| 2402 | } | 2407 | } |
| 2403 | | 2408 | |
| 2404 | switch (lhs_ty.zigTypeTag(zcu)) { | 2409 | switch (lhs_ty.zigTypeTag(zcu)) { |
| ... | @@ -2420,8 +2425,12 @@ fn genBinOp( | ... | @@ -2420,8 +2425,12 @@ fn genBinOp( |
| 2420 | else => unreachable, | 2425 | else => unreachable, |
| 2421 | }, | 2426 | }, |
| 2422 | .rem => switch (bit_size) { | 2427 | .rem => switch (bit_size) { |
| 2423 | 64 => if (is_unsigned) .remu else .rem, | 2428 | 8, 16, 32 => if (is_unsigned) .remuw else .remw, |
| 2424 | else => if (is_unsigned) .remuw else .remu, | 2429 | else => if (is_unsigned) .remu else .rem, |
| | 2430 | }, |
| | 2431 | .div_trunc => switch (bit_size) { |
| | 2432 | 8, 16, 32 => if (is_unsigned) .divuw else .divw, |
| | 2433 | else => if (is_unsigned) .divu else .div, |
| 2425 | }, | 2434 | }, |
| 2426 | else => unreachable, | 2435 | else => unreachable, |
| 2427 | }; | 2436 | }; |
| ... | @@ -2455,7 +2464,7 @@ fn genBinOp( | ... | @@ -2455,7 +2464,7 @@ fn genBinOp( |
| 2455 | 64 => .fmuld, | 2464 | 64 => .fmuld, |
| 2456 | else => unreachable, | 2465 | else => unreachable, |
| 2457 | }, | 2466 | }, |
| 2458 | else => unreachable, | 2467 | else => return func.fail("TODO: genBinOp {s} Float", .{@tagName(tag)}), |
| 2459 | }; | 2468 | }; |
| 2460 | | 2469 | |
| 2461 | _ = try func.addInst(.{ | 2470 | _ = try func.addInst(.{ |
| ... | @@ -2588,46 +2597,6 @@ fn genBinOp( | ... | @@ -2588,46 +2597,6 @@ fn genBinOp( |
| 2588 | } | 2597 | } |
| 2589 | }, | 2598 | }, |
| 2590 | | 2599 | |
| 2591 | .div_trunc, | | |
| 2592 | => { | | |
| 2593 | if (!math.isPowerOfTwo(bit_size)) | | |
| 2594 | return func.fail( | | |
| 2595 | "TODO: genBinOp {s} non-pow 2, found {}", | | |
| 2596 | .{ @tagName(tag), bit_size }, | | |
| 2597 | ); | | |
| 2598 | | | |
| 2599 | const mir_tag: Mir.Inst.Tag = switch (tag) { | | |
| 2600 | .div_trunc => switch (bit_size) { | | |
| 2601 | 8, 16, 32 => if (is_unsigned) .divuw else .divw, | | |
| 2602 | 64 => if (is_unsigned) .divu else .div, | | |
| 2603 | else => unreachable, | | |
| 2604 | }, | | |
| 2605 | else => unreachable, | | |
| 2606 | }; | | |
| 2607 | | | |
| 2608 | _ = try func.addInst(.{ | | |
| 2609 | .tag = mir_tag, | | |
| 2610 | .ops = .rrr, | | |
| 2611 | .data = .{ | | |
| 2612 | .r_type = .{ | | |
| 2613 | .rd = dst_reg, | | |
| 2614 | .rs1 = lhs_reg, | | |
| 2615 | .rs2 = rhs_reg, | | |
| 2616 | }, | | |
| 2617 | }, | | |
| 2618 | }); | | |
| 2619 | | | |
| 2620 | if (!is_unsigned) { | | |
| 2621 | // truncate when the instruction is larger than the bit size. | | |
| 2622 | switch (bit_size) { | | |
| 2623 | 8, 16 => try func.truncateRegister(lhs_ty, dst_reg), | | |
| 2624 | 32 => {}, // divw affects the first 32-bits | | |
| 2625 | 64 => {}, // div affects the entire register | | |
| 2626 | else => unreachable, | | |
| 2627 | } | | |
| 2628 | } | | |
| 2629 | }, | | |
| 2630 | | | |
| 2631 | .shr, | 2600 | .shr, |
| 2632 | .shr_exact, | 2601 | .shr_exact, |
| 2633 | .shl, | 2602 | .shl, |
| ... | @@ -3740,7 +3709,59 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3740,7 +3709,59 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 3740 | | 3709 | |
| 3741 | fn airClz(func: *Func, inst: Air.Inst.Index) !void { | 3710 | fn airClz(func: *Func, inst: Air.Inst.Index) !void { |
| 3742 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3711 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3743 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airClz for {}", .{func.target.cpu.arch}); | 3712 | const operand = try func.resolveInst(ty_op.operand); |
| | 3713 | const ty = func.typeOf(ty_op.operand); |
| | 3714 | |
| | 3715 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| | 3716 | const src_reg, const src_lock = try func.promoteReg(ty, operand); |
| | 3717 | defer if (src_lock) |lock| func.register_manager.unlockReg(lock); |
| | 3718 | |
| | 3719 | const dst_reg: Register = if (func.reuseOperand( |
| | 3720 | inst, |
| | 3721 | ty_op.operand, |
| | 3722 | 0, |
| | 3723 | operand, |
| | 3724 | ) and operand == .register) |
| | 3725 | operand.register |
| | 3726 | else |
| | 3727 | (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register; |
| | 3728 | |
| | 3729 | const bit_size = ty.bitSize(func.pt); |
| | 3730 | if (!math.isPowerOfTwo(bit_size)) try func.truncateRegister(ty, src_reg); |
| | 3731 | |
| | 3732 | if (bit_size > 64) { |
| | 3733 | return func.fail("TODO: airClz > 64 bits, found {d}", .{bit_size}); |
| | 3734 | } |
| | 3735 | |
| | 3736 | _ = try func.addInst(.{ |
| | 3737 | .tag = switch (bit_size) { |
| | 3738 | 32 => .clzw, |
| | 3739 | else => .clz, |
| | 3740 | }, |
| | 3741 | .ops = .rrr, |
| | 3742 | .data = .{ |
| | 3743 | .r_type = .{ |
| | 3744 | .rs2 = .zero, // rs2 is 0 filled in the spec |
| | 3745 | .rs1 = src_reg, |
| | 3746 | .rd = dst_reg, |
| | 3747 | }, |
| | 3748 | }, |
| | 3749 | }); |
| | 3750 | |
| | 3751 | if (!(bit_size == 32 or bit_size == 64)) { |
| | 3752 | _ = try func.addInst(.{ |
| | 3753 | .tag = .addi, |
| | 3754 | .ops = .rri, |
| | 3755 | .data = .{ .i_type = .{ |
| | 3756 | .rd = dst_reg, |
| | 3757 | .rs1 = dst_reg, |
| | 3758 | .imm12 = Immediate.s(-@as(i12, @intCast(64 - bit_size % 64))), |
| | 3759 | } }, |
| | 3760 | }); |
| | 3761 | } |
| | 3762 | |
| | 3763 | break :result .{ .register = dst_reg }; |
| | 3764 | }; |
| 3744 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3765 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3745 | } | 3766 | } |
| 3746 | | 3767 | |