Deduplicate `isel` code
d5d7f927c071551dfb3f5abe5b18c148297c51e453ac07d537244cd7698cfa0d
1 parent
043ee151
lib/std/arch/rv64/isel.rad
+30 -52
| 809 | 809 | /// instruction pattern based on the operation kind and type. |
|
| 810 | 810 | fn selectAluBinOp(s: *mut Selector, op: il::BinOp, typ: il::Type, rd: gen::Reg, rs1: gen::Reg, b: il::Val) { |
|
| 811 | 811 | match op { |
|
| 812 | 812 | case il::BinOp::Add => { |
|
| 813 | 813 | if typ == il::Type::W32 { |
|
| 814 | - | selectBinOpW(s, rd, rs1, b, super::SCRATCH2); |
|
| 814 | + | // Inline W32 ADD with immediate optimization. |
|
| 815 | + | if let case il::Val::Imm(imm) = b { |
|
| 816 | + | if encode::isSmallImm64(imm) { |
|
| 817 | + | emit::emit(s.e, encode::addiw(rd, rs1, imm as i32)); |
|
| 818 | + | return; |
|
| 819 | + | } |
|
| 820 | + | } |
|
| 821 | + | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 822 | + | emit::emit(s.e, encode::addw(rd, rs1, rs2)); |
|
| 815 | 823 | } else { |
|
| 816 | 824 | selectBinOp(s, rd, rs1, b, BinOp::Add, super::SCRATCH2); |
|
| 817 | 825 | } |
|
| 818 | 826 | } |
|
| 819 | 827 | case il::BinOp::Sub => { |
| 838 | 846 | case il::BinOp::Mul => { |
|
| 839 | 847 | // Strength-reduce multiplication by known constants. |
|
| 840 | 848 | if let case il::Val::Imm(imm) = b { |
|
| 841 | 849 | if imm == 0 { |
|
| 842 | 850 | emit::emit(s.e, encode::mv(rd, super::ZERO)); |
|
| 851 | + | return; |
|
| 843 | 852 | } else if imm == 1 { |
|
| 844 | 853 | emitMv(s, rd, rs1); |
|
| 854 | + | return; |
|
| 845 | 855 | } else if imm == 2 { |
|
| 846 | 856 | emit::emit(s.e, encode::slli(rd, rs1, 1)); |
|
| 857 | + | return; |
|
| 847 | 858 | } else if imm == 4 { |
|
| 848 | 859 | emit::emit(s.e, encode::slli(rd, rs1, 2)); |
|
| 860 | + | return; |
|
| 849 | 861 | } else if imm == 8 { |
|
| 850 | 862 | emit::emit(s.e, encode::slli(rd, rs1, 3)); |
|
| 851 | - | } else { |
|
| 852 | - | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 853 | - | emit::emit(s.e, |
|
| 854 | - | encode::mulw(rd, rs1, rs2) |
|
| 855 | - | if typ == il::Type::W32 else |
|
| 856 | - | encode::mul(rd, rs1, rs2)); |
|
| 863 | + | return; |
|
| 857 | 864 | } |
|
| 858 | - | } else { |
|
| 859 | - | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 860 | - | emit::emit(s.e, |
|
| 861 | - | encode::mulw(rd, rs1, rs2) |
|
| 862 | - | if typ == il::Type::W32 else |
|
| 863 | - | encode::mul(rd, rs1, rs2)); |
|
| 864 | 865 | } |
|
| 866 | + | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 867 | + | emit::emit(s.e, |
|
| 868 | + | encode::mulw(rd, rs1, rs2) |
|
| 869 | + | if typ == il::Type::W32 else |
|
| 870 | + | encode::mul(rd, rs1, rs2)); |
|
| 865 | 871 | } |
|
| 866 | 872 | case il::BinOp::Sdiv => { |
|
| 867 | 873 | let rs2 = resolveAndTrapIfZero(s, b); |
|
| 868 | 874 | emit::emit(s.e, |
|
| 869 | 875 | encode::divw(rd, rs1, rs2) |
| 901 | 907 | selectShift(s, rd, rs1, b, ShiftOp::Sll, typ, super::SCRATCH2), |
|
| 902 | 908 | case il::BinOp::Sshr => |
|
| 903 | 909 | selectShift(s, rd, rs1, b, ShiftOp::Sra, typ, super::SCRATCH2), |
|
| 904 | 910 | case il::BinOp::Ushr => |
|
| 905 | 911 | selectShift(s, rd, rs1, b, ShiftOp::Srl, typ, super::SCRATCH2), |
|
| 906 | - | case il::BinOp::Eq => { |
|
| 912 | + | case il::BinOp::Eq, il::BinOp::Ne => { |
|
| 907 | 913 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 908 | 914 | // Canonicalize both operands to the declared width. |
|
| 909 | - | // For W32 EQ, sign-extension suffices instead of |
|
| 910 | - | // zero-extension since both sides get same canonical form. |
|
| 911 | 915 | if typ == il::Type::W32 { |
|
| 912 | 916 | emitSext(s.e, rs1, rs1, typ); |
|
| 913 | 917 | if not isExtendedImm(b, typ, true) { |
|
| 914 | 918 | emitSext(s.e, rs2, rs2, typ); |
|
| 915 | 919 | } |
| 918 | 922 | if not isExtendedImm(b, typ, false) { |
|
| 919 | 923 | emitZext(s.e, rs2, rs2, typ); |
|
| 920 | 924 | } |
|
| 921 | 925 | } |
|
| 922 | 926 | emit::emit(s.e, encode::xor(rd, rs1, rs2)); |
|
| 923 | - | emit::emit(s.e, encode::sltiu(rd, rd, 1)); |
|
| 924 | - | } |
|
| 925 | - | case il::BinOp::Ne => { |
|
| 926 | - | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 927 | - | if typ == il::Type::W32 { |
|
| 928 | - | emitSext(s.e, rs1, rs1, typ); |
|
| 929 | - | if not isExtendedImm(b, typ, true) { |
|
| 930 | - | emitSext(s.e, rs2, rs2, typ); |
|
| 931 | - | } |
|
| 927 | + | if let case il::BinOp::Eq = op { |
|
| 928 | + | emit::emit(s.e, encode::sltiu(rd, rd, 1)); |
|
| 932 | 929 | } else { |
|
| 933 | - | emitZext(s.e, rs1, rs1, typ); |
|
| 934 | - | if not isExtendedImm(b, typ, false) { |
|
| 935 | - | emitZext(s.e, rs2, rs2, typ); |
|
| 936 | - | } |
|
| 930 | + | emit::emit(s.e, encode::sltu(rd, super::ZERO, rd)); |
|
| 937 | 931 | } |
|
| 938 | - | emit::emit(s.e, encode::xor(rd, rs1, rs2)); |
|
| 939 | - | emit::emit(s.e, encode::sltu(rd, super::ZERO, rd)); |
|
| 940 | 932 | } |
|
| 941 | 933 | case il::BinOp::Slt => |
|
| 942 | 934 | selectCmp(s, rd, rs1, b, CmpOp::Slt, super::SCRATCH2), |
|
| 943 | 935 | case il::BinOp::Ult => |
|
| 944 | 936 | selectCmp(s, rd, rs1, b, CmpOp::Ult, super::SCRATCH2), |
|
| 945 | - | case il::BinOp::Sge => { |
|
| 946 | - | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 947 | - | emit::emit(s.e, encode::slt(rd, rs1, rs2)); |
|
| 948 | - | emit::emit(s.e, encode::xori(rd, rd, 1)); // flip. |
|
| 949 | - | } |
|
| 950 | - | case il::BinOp::Uge => { |
|
| 937 | + | case il::BinOp::Sge, il::BinOp::Uge => { |
|
| 951 | 938 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 952 | - | emit::emit(s.e, encode::sltu(rd, rs1, rs2)); |
|
| 953 | - | emit::emit(s.e, encode::xori(rd, rd, 1)); // flip. |
|
| 939 | + | if let case il::BinOp::Sge = op { |
|
| 940 | + | emit::emit(s.e, encode::slt(rd, rs1, rs2)); |
|
| 941 | + | } else { |
|
| 942 | + | emit::emit(s.e, encode::sltu(rd, rs1, rs2)); |
|
| 943 | + | } |
|
| 944 | + | emit::emit(s.e, encode::xori(rd, rd, 1)); |
|
| 954 | 945 | } |
|
| 955 | 946 | } |
|
| 956 | 947 | } |
|
| 957 | 948 | ||
| 958 | 949 | /// Select a unary ALU operation. |
| 968 | 959 | case il::UnOp::Not => |
|
| 969 | 960 | emit::emit(s.e, encode::not_(rd, rs)), |
|
| 970 | 961 | } |
|
| 971 | 962 | } |
|
| 972 | 963 | ||
| 973 | - | /// Select 32-bit addition with immediate optimization. |
|
| 974 | - | /// Uses `addiw`/`addw` to operate on 32 bits and sign-extend the result. |
|
| 975 | - | fn selectBinOpW(s: *mut Selector, rd: gen::Reg, rs1: gen::Reg, b: il::Val, scratch: gen::Reg) { |
|
| 976 | - | if let case il::Val::Imm(imm) = b { |
|
| 977 | - | if encode::isSmallImm64(imm) { |
|
| 978 | - | emit::emit(s.e, encode::addiw(rd, rs1, imm as i32)); |
|
| 979 | - | return; |
|
| 980 | - | } |
|
| 981 | - | } |
|
| 982 | - | let rs2 = resolveVal(s, scratch, b); |
|
| 983 | - | emit::emit(s.e, encode::addw(rd, rs1, rs2)); |
|
| 984 | - | } |
|
| 985 | - | ||
| 986 | 964 | /// Select binary operation with immediate optimization. |
|
| 987 | 965 | fn selectBinOp(s: *mut Selector, rd: gen::Reg, rs1: gen::Reg, b: il::Val, op: BinOp, scratch: gen::Reg) { |
|
| 988 | 966 | // Try immediate optimization first. |
|
| 989 | 967 | if let case il::Val::Imm(imm) = b { |
|
| 990 | 968 | if encode::isSmallImm64(imm) { |