Deduplicate `isel` code

d5d7f927c071551dfb3f5abe5b18c148297c51e453ac07d537244cd7698cfa0d
Alexis Sellier committed ago 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) {