diff --git a/clang/include/clang/Basic/BuiltinsRISCV.def b/clang/include/clang/Basic/BuiltinsRISCV.def --- a/clang/include/clang/Basic/BuiltinsRISCV.def +++ b/clang/include/clang/Basic/BuiltinsRISCV.def @@ -18,7 +18,7 @@ // Zbb extension TARGET_BUILTIN(__builtin_riscv_orc_b_32, "ZiZi", "nc", "zbb") TARGET_BUILTIN(__builtin_riscv_orc_b_64, "WiWi", "nc", "zbb,64bit") -TARGET_BUILTIN(__builtin_riscv_clz_32, "ZiZi", "nc", "zbb") +TARGET_BUILTIN(__builtin_riscv_clz_32, "ZiZi", "nc", "zbb|experimental-zbpbo") TARGET_BUILTIN(__builtin_riscv_clz_64, "WiWi", "nc", "zbb,64bit") TARGET_BUILTIN(__builtin_riscv_ctz_32, "ZiZi", "nc", "zbb") TARGET_BUILTIN(__builtin_riscv_ctz_64, "WiWi", "nc", "zbb,64bit") @@ -46,8 +46,10 @@ TARGET_BUILTIN(__builtin_riscv_bfp_64, "WiWiWi", "nc", "experimental-zbf,64bit") // Zbp extension -TARGET_BUILTIN(__builtin_riscv_grev_32, "ZiZiZi", "nc", "experimental-zbp") -TARGET_BUILTIN(__builtin_riscv_grev_64, "WiWiWi", "nc", "experimental-zbp,64bit") +TARGET_BUILTIN(__builtin_riscv_grev_32, "ZiZiZi", "nc", + "experimental-zbp|experimental-zbpbo") +TARGET_BUILTIN(__builtin_riscv_grev_64, "WiWiWi", "nc", + "experimental-zbp|experimental-zbpbo,64bit") TARGET_BUILTIN(__builtin_riscv_gorc_32, "ZiZiZi", "nc", "experimental-zbp") TARGET_BUILTIN(__builtin_riscv_gorc_64, "WiWiWi", "nc", "experimental-zbp,64bit") TARGET_BUILTIN(__builtin_riscv_shfl_32, "ZiZiZi", "nc", "experimental-zbp") @@ -71,9 +73,11 @@ // Zbt extension TARGET_BUILTIN(__builtin_riscv_fsl_32, "LiLiLiLi", "nc", "experimental-zbt") -TARGET_BUILTIN(__builtin_riscv_fsr_32, "LiLiLiLi", "nc", "experimental-zbt") +TARGET_BUILTIN(__builtin_riscv_fsr_32, "LiLiLiLi", "nc", + "experimental-zbt|experimental-zbpbo") TARGET_BUILTIN(__builtin_riscv_fsl_64, "WiWiWiWi", "nc", "experimental-zbt,64bit") -TARGET_BUILTIN(__builtin_riscv_fsr_64, "WiWiWiWi", "nc", "experimental-zbt,64bit") +TARGET_BUILTIN(__builtin_riscv_fsr_64, "WiWiWiWi", "nc", + "experimental-zbt|experimental-zbpbo,64bit") // Zbkb extension TARGET_BUILTIN(__builtin_riscv_brev8, "LiLi", "nc", "zbkb") diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -4316,7 +4316,7 @@ << Arg->getSourceRange(); } -static bool isRISCV32Builtin(unsigned BuiltinID) { +static bool isRISCV32Builtin(unsigned BuiltinID, const TargetInfo &TI) { // These builtins only work on riscv32 targets. switch (BuiltinID) { case RISCV::BI__builtin_riscv_zip_32: @@ -4332,6 +4332,9 @@ case RISCV::BI__builtin_riscv_sha512sum0r_32: case RISCV::BI__builtin_riscv_sha512sum1r_32: return true; + case RISCV::BI__builtin_riscv_clz_32: + if (!TI.hasFeature("zbb")) + return true; } return false; @@ -4349,7 +4352,7 @@ // Check for 32-bit only builtins on a 64-bit target. const llvm::Triple &TT = TI.getTriple(); - if (TT.getArch() != llvm::Triple::riscv32 && isRISCV32Builtin(BuiltinID)) + if (TT.getArch() != llvm::Triple::riscv32 && isRISCV32Builtin(BuiltinID, TI)) return Diag(TheCall->getCallee()->getBeginLoc(), diag::err_32_bit_builtin_64_bit_tgt); diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics/riscv32-zbpbo.c b/clang/test/CodeGen/RISCV/rvp-intrinsics/riscv32-zbpbo.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvp-intrinsics/riscv32-zbpbo.c @@ -0,0 +1,60 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -target-feature +experimental-zbpbo -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=RV32ZBPBO + +// RV32ZBPBO-LABEL: @clz_32( +// RV32ZBPBO-NEXT: entry: +// RV32ZBPBO-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBPBO-NEXT: store i32 [[A:%.*]], i32* [[A_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP1:%.*]] = call i32 @llvm.ctlz.i32(i32 [[TMP0]], i1 false) +// RV32ZBPBO-NEXT: ret i32 [[TMP1]] +// +int clz_32(int a) { + return __builtin_riscv_clz_32(a); +} + +// RV32ZBPBO-LABEL: @fsr( +// RV32ZBPBO-NEXT: entry: +// RV32ZBPBO-NEXT: [[RS1_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBPBO-NEXT: [[RS2_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBPBO-NEXT: [[RS3_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBPBO-NEXT: store i32 [[RS1:%.*]], i32* [[RS1_ADDR]], align 4 +// RV32ZBPBO-NEXT: store i32 [[RS2:%.*]], i32* [[RS2_ADDR]], align 4 +// RV32ZBPBO-NEXT: store i32 [[RS3:%.*]], i32* [[RS3_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP0:%.*]] = load i32, i32* [[RS1_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP1:%.*]] = load i32, i32* [[RS2_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP2:%.*]] = load i32, i32* [[RS3_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP3:%.*]] = call i32 @llvm.riscv.fsr.i32(i32 [[TMP0]], i32 [[TMP1]], i32 [[TMP2]]) +// RV32ZBPBO-NEXT: ret i32 [[TMP3]] +// +int fsr(int rs1, int rs2, int rs3) { + return __builtin_riscv_fsr_32(rs1, rs2, rs3); +} + +// RV32ZBPBO-LABEL: @fsri( +// RV32ZBPBO-NEXT: entry: +// RV32ZBPBO-NEXT: [[RS1_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBPBO-NEXT: [[RS2_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBPBO-NEXT: store i32 [[RS1:%.*]], i32* [[RS1_ADDR]], align 4 +// RV32ZBPBO-NEXT: store i32 [[RS2:%.*]], i32* [[RS2_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP0:%.*]] = load i32, i32* [[RS1_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP1:%.*]] = load i32, i32* [[RS2_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.fsr.i32(i32 [[TMP0]], i32 [[TMP1]], i32 15) +// RV32ZBPBO-NEXT: ret i32 [[TMP2]] +// +int fsri(int rs1, int rs2) { + return __builtin_riscv_fsr_32(rs1, rs2, 15); +} + +// RV32ZBPBO-LABEL: @grevi( +// RV32ZBPBO-NEXT: entry: +// RV32ZBPBO-NEXT: [[RS1_ADDR:%.*]] = alloca i32, align 4 +// RV32ZBPBO-NEXT: store i32 [[RS1:%.*]], i32* [[RS1_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP0:%.*]] = load i32, i32* [[RS1_ADDR]], align 4 +// RV32ZBPBO-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.grev.i32(i32 [[TMP0]], i32 13) +// RV32ZBPBO-NEXT: ret i32 [[TMP1]] +// +long grevi(long rs1) { + return __builtin_riscv_grev_32(rs1, 13); +} diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics/riscv64-zbpbo.c b/clang/test/CodeGen/RISCV/rvp-intrinsics/riscv64-zbpbo.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvp-intrinsics/riscv64-zbpbo.c @@ -0,0 +1,33 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -no-opaque-pointers -triple riscv64 -target-feature +experimental-zbpbo -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=RV64ZBPBO + +// RV64ZBPBO-LABEL: @fsrw( +// RV64ZBPBO-NEXT: entry: +// RV64ZBPBO-NEXT: [[RS1_ADDR:%.*]] = alloca i64, align 8 +// RV64ZBPBO-NEXT: [[RS2_ADDR:%.*]] = alloca i64, align 8 +// RV64ZBPBO-NEXT: [[RS3_ADDR:%.*]] = alloca i64, align 8 +// RV64ZBPBO-NEXT: store i64 [[RS1:%.*]], i64* [[RS1_ADDR]], align 8 +// RV64ZBPBO-NEXT: store i64 [[RS2:%.*]], i64* [[RS2_ADDR]], align 8 +// RV64ZBPBO-NEXT: store i64 [[RS3:%.*]], i64* [[RS3_ADDR]], align 8 +// RV64ZBPBO-NEXT: [[TMP0:%.*]] = load i64, i64* [[RS1_ADDR]], align 8 +// RV64ZBPBO-NEXT: [[TMP1:%.*]] = load i64, i64* [[RS2_ADDR]], align 8 +// RV64ZBPBO-NEXT: [[TMP2:%.*]] = load i64, i64* [[RS3_ADDR]], align 8 +// RV64ZBPBO-NEXT: [[TMP3:%.*]] = call i64 @llvm.riscv.fsr.i64(i64 [[TMP0]], i64 [[TMP1]], i64 [[TMP2]]) +// RV64ZBPBO-NEXT: ret i64 [[TMP3]] +// +long fsrw(long rs1, long rs2, long rs3) { + return __builtin_riscv_fsr_64(rs1, rs2, rs3); +} + +// RV64ZBPBO-LABEL: @grevi( +// RV64ZBPBO-NEXT: entry: +// RV64ZBPBO-NEXT: [[RS1_ADDR:%.*]] = alloca i64, align 8 +// RV64ZBPBO-NEXT: store i64 [[RS1:%.*]], i64* [[RS1_ADDR]], align 8 +// RV64ZBPBO-NEXT: [[TMP0:%.*]] = load i64, i64* [[RS1_ADDR]], align 8 +// RV64ZBPBO-NEXT: [[TMP1:%.*]] = call i64 @llvm.riscv.grev.i64(i64 [[TMP0]], i64 13) +// RV64ZBPBO-NEXT: ret i64 [[TMP1]] +// +long grevi(long rs1) { + return __builtin_riscv_grev_64(rs1, 13); +} diff --git a/clang/test/Driver/riscv-arch.c b/clang/test/Driver/riscv-arch.c --- a/clang/test/Driver/riscv-arch.c +++ b/clang/test/Driver/riscv-arch.c @@ -452,6 +452,25 @@ // RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-ZBA %s // RV32-ZBA: "-target-feature" "+zba" +// RUN: %clang -target riscv32-unknown-elf -march=rv32izbpbo -### %s -c 2>&1 | \ +// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZBPBO-NOFLAG %s +// RV32-EXPERIMENTAL-ZBPBO-NOFLAG: error: invalid arch name 'rv32izbpbo' +// RV32-EXPERIMENTAL-ZBPBO-NOFLAG: requires '-menable-experimental-extensions' + +// RUN: %clang -target riscv32-unknown-elf -march=rv32izbpbo -menable-experimental-extensions -### %s -c 2>&1 | \ +// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZBPBO-NOVERS %s +// RV32-EXPERIMENTAL-ZBPBO-NOVERS: error: invalid arch name 'rv32izbpbo' +// RV32-EXPERIMENTAL-ZBPBO-NOVERS: experimental extension requires explicit version number + +// RUN: %clang -target riscv32-unknown-elf -march=rv32izbpbo0p1 -menable-experimental-extensions -### %s -c 2>&1 | \ +// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZBPBO-BADVERS %s +// RV32-EXPERIMENTAL-ZBPBO-BADVERS: error: invalid arch name 'rv32izbpbo0p1' +// RV32-EXPERIMENTAL-ZBPBO-BADVERS: unsupported version number 0.1 for experimental extension + +// RUN: %clang -target riscv32-unknown-elf -march=rv32izbpbo0p911 -menable-experimental-extensions -### %s -c 2>&1 | \ +// RUN: FileCheck -check-prefix=RV32-EXPERIMENTAL-ZBPBO-GOODVERS %s +// RV32-EXPERIMENTAL-ZBPBO-GOODVERS: "-target-feature" "+experimental-zbpbo" + // RUN: %clang --target=riscv32-unknown-elf -march=rv32iv0p1 -### %s -c 2>&1 | \ // RUN: FileCheck -check-prefix=RV32-V-BADVERS %s // RV32-V-BADVERS: error: invalid arch name 'rv32iv0p1' diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c --- a/clang/test/Preprocessor/riscv-target-features.c +++ b/clang/test/Preprocessor/riscv-target-features.c @@ -224,6 +224,15 @@ // CHECK-ZBT-NOT: __riscv_b // CHECK-ZBT-EXT: __riscv_zbt 93000{{$}} +// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \ +// RUN: -march=rv32izbpbo0p911 -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-ZBPBO-EXT %s +// RUN: %clang -target riscv64-unknown-linux-gnu -menable-experimental-extensions \ +// RUN: -march=rv64izbpbo0p911 -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-ZBPBO-EXT %s +// CHECK-ZBPBO-NOT: __riscv_p +// CHECK-ZBPBO-EXT: __riscv_zbpbo 911000{{$}} + // RUN: %clang -target riscv32-unknown-linux-gnu \ // RUN: -march=rv32iv1p0 -x c -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-V-EXT %s diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -108,6 +108,7 @@ {"zbp", RISCVExtensionVersion{0, 93}}, {"zbr", RISCVExtensionVersion{0, 93}}, {"zbt", RISCVExtensionVersion{0, 93}}, + {"zbpbo", RISCVExtensionVersion{0, 911}}, {"zvfh", RISCVExtensionVersion{0, 1}}, }; diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td --- a/llvm/lib/Target/RISCV/RISCV.td +++ b/llvm/lib/Target/RISCV/RISCV.td @@ -247,6 +247,41 @@ "'Zbc' (Carry-Less Multiplication) or " "'Zbkc' (Carry-less multiply instructions for Cryptography)">; +def FeatureStdExtZbpbo + : SubtargetFeature<"experimental-zbpbo", "HasStdExtZbpbo", "true", + "'Zbpbo' ('B' & 'P' Overlay Instructions)">; +def HasStdExtZbpbo + : Predicate<"Subtarget->hasStdExtZbpbo()">, + AssemblerPredicate<(all_of FeatureStdExtZbpbo), + "'Zbpbo' ('B' & 'P' Overlay Instructions)">; + +def HasStdExtZbbOrZbpbo + : Predicate<"Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbpbo()">, + AssemblerPredicate<(any_of FeatureStdExtZbb, FeatureStdExtZbpbo), + "'Zbb' (Basic Bit-Manipulation) or " + "'Zbpbo' ('B' & 'P' Overlay Instructions)">; + +def HasStdExtZbpOrZbpbo + : Predicate<"Subtarget->hasStdExtZbp() || Subtarget->hasStdExtZbpbo()">, + AssemblerPredicate<(any_of FeatureStdExtZbp, FeatureStdExtZbpbo), + "'Zbp' (Permutation 'Zb' Instructions) or " + "'Zbpbo' ('B' & 'P' Overlay Instructions)">; + +def HasStdExtZbpOrZbkbOrZbpbo + : Predicate<"Subtarget->hasStdExtZbp() || Subtarget->hasStdExtZbkb()" + "|| Subtarget->hasStdExtZbpbo()">, + AssemblerPredicate<(any_of FeatureStdExtZbp, FeatureStdExtZbkb, + FeatureStdExtZbpbo), + "'Zbp' (Permutation 'Zb' Instructions) or " + "'Zbkb' (Bitmanip instructions for Cryptography) or " + "'Zbpbo' ('B' & 'P' Overlay Instructions)">; + +def HasStdExtZbtOrZbpbo + : Predicate<"Subtarget->hasStdExtZbt() || Subtarget->hasStdExtZbpbo()">, + AssemblerPredicate<(any_of FeatureStdExtZbt, FeatureStdExtZbpbo), + "'Zbt' (Ternary 'Zb' Instructions) or " + "'Zbpbo' ('B' & 'P' Overlay Instructions)">; + def FeatureStdExtZknd : SubtargetFeature<"zknd", "HasStdExtZknd", "true", "'Zknd' (NIST Suite: AES Decryption)">; diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -283,6 +283,11 @@ if (Subtarget.is64Bit()) setOperationAction(ISD::ABS, MVT::i32, Custom); } + if (Subtarget.hasStdExtZbpbo()) { + setOperationAction({ISD::SMIN, ISD::SMAX}, XLenVT, Legal); + setOperationAction(ISD::CTLZ, MVT::i32, Legal); + setOperationAction({ISD::BITREVERSE, ISD::BSWAP}, MVT::i16, Custom); + } if (Subtarget.hasStdExtZbt()) { setOperationAction({ISD::FSHL, ISD::FSHR}, XLenVT, Custom); @@ -7092,7 +7097,8 @@ MVT XLenVT = Subtarget.getXLenVT(); assert((VT == MVT::i8 || VT == MVT::i16 || (VT == MVT::i32 && Subtarget.is64Bit())) && - Subtarget.hasStdExtZbp() && "Unexpected custom legalisation"); + (Subtarget.hasStdExtZbp() || Subtarget.hasStdExtZbpbo()) && + "Unexpected custom legalisation"); SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, XLenVT, N->getOperand(0)); unsigned Imm = VT.getSizeInBits() - 1; // If this is BSWAP rather than BITREVERSE, clear the lower 3 bits. @@ -7797,7 +7803,8 @@ EVT VT = N->getValueType(0); SDLoc DL(N); - if (!Subtarget.hasStdExtZbp() || Src.getOpcode() != RISCVISD::GREV) + if (!(Subtarget.hasStdExtZbp() || Subtarget.hasStdExtZbpbo()) || + Src.getOpcode() != RISCVISD::GREV) return SDValue(); if (!isa(N->getOperand(1)) || diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td @@ -402,9 +402,13 @@ Sched<[WriteORC, ReadORC, ReadORC]>; def GREV : ALU_rr<0b0110100, 0b101, "grev">, Sched<[WriteREV, ReadREV, ReadREV]>; +} // Predicates = [HasStdExtZbp] +let Predicates = [HasStdExtZbpOrZbpbo] in def GREVI : RVBShift_ri<0b01101, 0b101, OPC_OP_IMM, "grevi">, Sched<[WriteREVImm, ReadREVImm]>; + +let Predicates = [HasStdExtZbp] in { def GORCI : RVBShift_ri<0b00101, 0b101, OPC_OP_IMM, "gorci">, Sched<[WriteORCImm, ReadORCImm]>; @@ -451,34 +455,41 @@ } // Predicates = [HasStdExtZbpOrZbkx] let Predicates = [HasStdExtZbt] in { -def CMIX : RVBTernaryR<0b11, 0b001, OPC_OP, "cmix", "$rd, $rs2, $rs1, $rs3">, - Sched<[WriteCMix, ReadCMix, ReadCMix, ReadCMix]>; def CMOV : RVBTernaryR<0b11, 0b101, OPC_OP, "cmov", "$rd, $rs2, $rs1, $rs3">, Sched<[WriteCMov, ReadCMov, ReadCMov, ReadCMov]>; def FSL : RVBTernaryR<0b10, 0b001, OPC_OP, "fsl", "$rd, $rs1, $rs3, $rs2">, Sched<[WriteFSReg, ReadFSReg, ReadFSReg, ReadFSReg]>; +} // Predicates = [HasStdExtZbt] + +let Predicates = [HasStdExtZbtOrZbpbo] in { +def CMIX : RVBTernaryR<0b11, 0b001, OPC_OP, "cmix", "$rd, $rs2, $rs1, $rs3">, + Sched<[WriteCMix, ReadCMix, ReadCMix, ReadCMix]>; def FSR : RVBTernaryR<0b10, 0b101, OPC_OP, "fsr", "$rd, $rs1, $rs3, $rs2">, Sched<[WriteFSReg, ReadFSReg, ReadFSReg, ReadFSReg]>; def FSRI : RVBTernaryImm6<0b101, OPC_OP_IMM, "fsri", "$rd, $rs1, $rs3, $shamt">, Sched<[WriteFSRImm, ReadFSRImm, ReadFSRImm]>; -} // Predicates = [HasStdExtZbt] +} // Predicates = [HasStdExtZbtOrZbpbo] let Predicates = [HasStdExtZbt, IsRV64] in { def FSLW : RVBTernaryR<0b10, 0b001, OPC_OP_32, "fslw", "$rd, $rs1, $rs3, $rs2">, Sched<[WriteFSReg32, ReadFSReg32, ReadFSReg32, ReadFSReg32]>; -def FSRW : RVBTernaryR<0b10, 0b101, OPC_OP_32, "fsrw", - "$rd, $rs1, $rs3, $rs2">, - Sched<[WriteFSReg32, ReadFSReg32, ReadFSReg32, ReadFSReg32]>; def FSRIW : RVBTernaryImm5<0b10, 0b101, OPC_OP_IMM_32, "fsriw", "$rd, $rs1, $rs3, $shamt">, Sched<[WriteFSRImm32, ReadFSRImm32, ReadFSRImm32]>; } // Predicates = [HasStdExtZbt, IsRV64] -let Predicates = [HasStdExtZbb] in { +let Predicates = [HasStdExtZbtOrZbpbo, IsRV64] in +def FSRW : RVBTernaryR<0b10, 0b101, OPC_OP_32, "fsrw", + "$rd, $rs1, $rs3, $rs2">, + Sched<[WriteFSReg32, ReadFSReg32, ReadFSReg32, ReadFSReg32]>; + +let Predicates = [HasStdExtZbbOrZbpbo] in def CLZ : RVBUnary<0b0110000, 0b00000, 0b001, OPC_OP_IMM, "clz">, Sched<[WriteCLZ, ReadCLZ]>; + +let Predicates = [HasStdExtZbb] in { def CTZ : RVBUnary<0b0110000, 0b00001, 0b001, OPC_OP_IMM, "ctz">, Sched<[WriteCTZ, ReadCTZ]>; def CPOP : RVBUnary<0b0110000, 0b00010, 0b001, OPC_OP_IMM, "cpop">, @@ -537,13 +548,16 @@ Sched<[WriteCLMUL, ReadCLMUL, ReadCLMUL]>; } // Predicates = [HasStdExtZbcOrZbkc] -let Predicates = [HasStdExtZbb] in { +let Predicates = [HasStdExtZbbOrZbpbo] in { def MIN : ALU_rr<0b0000101, 0b100, "min", /*Commutable*/1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; -def MINU : ALU_rr<0b0000101, 0b101, "minu", /*Commutable*/1>, - Sched<[WriteIALU, ReadIALU, ReadIALU]>; def MAX : ALU_rr<0b0000101, 0b110, "max", /*Commutable*/1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; +} // Predicates = [HasStdExtZbbOrZbpbo] + +let Predicates = [HasStdExtZbb] in { +def MINU : ALU_rr<0b0000101, 0b101, "minu", /*Commutable*/1>, + Sched<[WriteIALU, ReadIALU, ReadIALU]>; def MAXU : ALU_rr<0b0000101, 0b111, "maxu", /*Commutable*/1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; } // Predicates = [HasStdExtZbb] @@ -566,18 +580,19 @@ Sched<[WriteCompress32, ReadCompress32, ReadCompress32]>; } // Predicates = [HasStdExtZbe, IsRV64] -let Predicates = [HasStdExtZbpOrZbkb] in { +let Predicates = [HasStdExtZbpOrZbkbOrZbpbo] in def PACK : ALU_rr<0b0000100, 0b100, "pack">, Sched<[WritePACK, ReadPACK, ReadPACK]>; + +let Predicates = [HasStdExtZbpOrZbkb] in def PACKH : ALU_rr<0b0000100, 0b111, "packh">, Sched<[WritePACK, ReadPACK, ReadPACK]>; -} // Predicates = [HasStdExtZbpOrZbkb] let Predicates = [HasStdExtZbpOrZbkb, IsRV64] in def PACKW : ALUW_rr<0b0000100, 0b100, "packw">, Sched<[WritePACK32, ReadPACK32, ReadPACK32]>; -let Predicates = [HasStdExtZbp] in +let Predicates = [HasStdExtZbpOrZbpbo] in def PACKU : ALU_rr<0b0100100, 0b100, "packu">, Sched<[WritePACKU, ReadPACKU, ReadPACKU]>; @@ -661,7 +676,6 @@ def : InstAlias<"rev.n $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b00011)>; def : InstAlias<"rev4.b $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b00100)>; def : InstAlias<"rev2.b $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b00110)>; -def : InstAlias<"rev8.h $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b01000)>; def : InstAlias<"rev4.h $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b01100)>; def : InstAlias<"rev2.h $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b01110)>; def : InstAlias<"rev.h $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b01111)>; @@ -692,12 +706,14 @@ def : InstAlias<"orc.h $rd, $rs", (GORCI GPR:$rd, GPR:$rs, 0b01111)>; } // Predicates = [HasStdExtZbp] +let Predicates = [HasStdExtZbpOrZbpbo] in +def : InstAlias<"rev8.h $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b01000)>; + let Predicates = [HasStdExtZbp, IsRV32] in { def : InstAlias<"rev16 $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b10000)>; // rev8 is considered an instruction rather than an alias. def : InstAlias<"rev4 $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b11100)>; def : InstAlias<"rev2 $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b11110)>; -def : InstAlias<"rev $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b11111)>; def : InstAlias<"zip8 $rd, $rs", (SHFLI GPR:$rd, GPR:$rs, 0b1000)>; def : InstAlias<"unzip8 $rd, $rs", (UNSHFLI GPR:$rd, GPR:$rs, 0b1000)>; @@ -714,6 +730,11 @@ def : InstAlias<"orc $rd, $rs", (GORCI GPR:$rd, GPR:$rs, 0b11111)>; } // Predicates = [HasStdExtZbp, IsRV32] +let Predicates = [HasStdExtZbpOrZbpbo, IsRV32] in +def : InstAlias<"rev $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b11111)>; +let Predicates = [HasStdExtZbpOrZbpbo, IsRV64] in +def : InstAlias<"rev $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b111111)>; + let Predicates = [HasStdExtZbp, IsRV64] in { def : InstAlias<"rev16.w $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b010000)>; def : InstAlias<"rev8.w $rd, $rs", (GREVI GPR:$rd, GPR:$rs, 0b011000)>; @@ -807,6 +828,20 @@ (BEXTI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt), 0>; } // Predicates = [HasStdExtZbs] +let Predicates = [HasStdExtZbpbo, IsRV32] in { +def : InstAlias<"pkbb16 $rd, $rs1, $rs2", + (PACK GPR:$rd, GPR:$rs1, GPR:$rs2)>; +def : InstAlias<"pktt16 $rd, $rs1, $rs2", + (PACKU GPR:$rd, GPR:$rs1, GPR:$rs2)>; +} // Predicates = [HasStdExtZbpbo] + +let Predicates = [HasStdExtZbpbo, IsRV64] in { +def : InstAlias<"pkbb32 $rd, $rs1, $rs2", + (PACK GPR:$rd, GPR:$rs1, GPR:$rs2)>; +def : InstAlias<"pktt32 $rd, $rs1, $rs2", + (PACKU GPR:$rd, GPR:$rs1, GPR:$rs2)>; +} // Predicates = [HasStdExtZbpbo] + //===----------------------------------------------------------------------===// // Codegen patterns //===----------------------------------------------------------------------===// @@ -901,13 +936,16 @@ def : Pat<(i32 (riscv_unshfl GPR:$rs1, 15)), (UNZIP_RV32 GPR:$rs1)>; } // Predicates = [HasStdExtZbpOrZbkb, IsRV32] -let Predicates = [HasStdExtZbp] in { +let Predicates = [HasStdExtZbpOrZbpbo] in { def : PatGprGpr; -def : PatGprGpr; def : PatGprImm; +def : PatGprGpr; +} // Predicates = [HasStdExtZbpOrZbpbo] + +let Predicates = [HasStdExtZbp] in { +def : PatGprGpr; def : PatGprImm; -def : PatGprGpr; def : PatGprGpr; def : PatGprImm; def : PatGprImm; @@ -948,12 +986,14 @@ def : Pat<(i64 (riscv_grev GPR:$rs1, 56)), (REV8_RV64 GPR:$rs1)>; } // Predicates = [HasStdExtZbp, IsRV64] -let Predicates = [HasStdExtZbt] in { +let Predicates = [HasStdExtZbtOrZbpbo] in { def : Pat<(or (and (not GPR:$rs2), GPR:$rs3), (and GPR:$rs2, GPR:$rs1)), (CMIX GPR:$rs1, GPR:$rs2, GPR:$rs3)>; def : Pat<(xor (and (xor GPR:$rs1, GPR:$rs3), GPR:$rs2), GPR:$rs3), (CMIX GPR:$rs1, GPR:$rs2, GPR:$rs3)>; +} // Predicates = [HasStdExtZbtOrZbpbo] +let Predicates = [HasStdExtZbt] in { def : Pat<(select (XLenVT (setne GPR:$rs2, 0)), GPR:$rs1, GPR:$rs3), (CMOV GPR:$rs1, GPR:$rs2, GPR:$rs3)>; def : Pat<(select (XLenVT (seteq GPR:$rs2, 0)), GPR:$rs3, GPR:$rs1), @@ -985,9 +1025,11 @@ (CMOV GPR:$rs1, GPR:$rs2, GPR:$rs3)>; } // Predicates = [HasStdExtZbt] -let Predicates = [HasStdExtZbt] in { +let Predicates = [HasStdExtZbt] in def : Pat<(riscv_fsl GPR:$rs1, GPR:$rs3, GPR:$rs2), (FSL GPR:$rs1, GPR:$rs2, GPR:$rs3)>; + +let Predicates = [HasStdExtZbtOrZbpbo] in { def : Pat<(riscv_fsr GPR:$rs1, GPR:$rs3, GPR:$rs2), (FSR GPR:$rs1, GPR:$rs2, GPR:$rs3)>; def : Pat<(riscv_fsr GPR:$rs1, GPR:$rs3, uimmlog2xlen:$shamt), @@ -996,13 +1038,15 @@ // XLen and swap the operands. def : Pat<(riscv_fsl GPR:$rs3, GPR:$rs1, uimmlog2xlen:$shamt), (FSRI GPR:$rs1, GPR:$rs3, (ImmSubFromXLen uimmlog2xlen:$shamt))>; -} // Predicates = [HasStdExtZbt] +} // Predicates = [HasStdExtZbtOrZbpbo] + +let Predicates = [HasStdExtZbtOrZbpbo, IsRV64] in +def : Pat<(riscv_fsrw GPR:$rs1, GPR:$rs3, GPR:$rs2), + (FSRW GPR:$rs1, GPR:$rs2, GPR:$rs3)>; let Predicates = [HasStdExtZbt, IsRV64] in { def : Pat<(riscv_fslw GPR:$rs1, GPR:$rs3, GPR:$rs2), (FSLW GPR:$rs1, GPR:$rs2, GPR:$rs3)>; -def : Pat<(riscv_fsrw GPR:$rs1, GPR:$rs3, GPR:$rs2), - (FSRW GPR:$rs1, GPR:$rs2, GPR:$rs3)>; def : Pat<(riscv_fsrw GPR:$rs1, GPR:$rs3, uimm5:$shamt), (FSRIW GPR:$rs1, GPR:$rs3, uimm5:$shamt)>; // We can use FSRIW for FSLW by immediate if we subtract the immediate from @@ -1011,8 +1055,10 @@ (FSRIW GPR:$rs1, GPR:$rs3, (ImmSubFrom32 uimm5:$shamt))>; } // Predicates = [HasStdExtZbt, IsRV64] -let Predicates = [HasStdExtZbb] in { +let Predicates = [HasStdExtZbbOrZbpbo] in def : PatGpr; + +let Predicates = [HasStdExtZbb] in { def : PatGpr; def : PatGpr; } // Predicates = [HasStdExtZbb] @@ -1028,9 +1074,12 @@ def : Pat<(sext_inreg GPR:$rs1, i16), (SEXT_H GPR:$rs1)>; } // Predicates = [HasStdExtZbb] -let Predicates = [HasStdExtZbb] in { +let Predicates = [HasStdExtZbbOrZbpbo] in { def : PatGprGpr; def : PatGprGpr; +} // Predicates = [HasStdExtZbbOrZbpbo] + +let Predicates = [HasStdExtZbb] in { def : PatGprGpr; def : PatGprGpr; } // Predicates = [HasStdExtZbb] @@ -1052,14 +1101,15 @@ (PACKH GPR:$rs1, GPR:$rs2)>; } // Predicates = [HasStdExtZbpOrZbkb] -let Predicates = [HasStdExtZbpOrZbkb, IsRV32] in +let Predicates = [HasStdExtZbpOrZbkbOrZbpbo, IsRV32] in def : Pat<(i32 (or (and GPR:$rs1, 0x0000FFFF), (shl GPR:$rs2, (i32 16)))), (PACK GPR:$rs1, GPR:$rs2)>; -let Predicates = [HasStdExtZbpOrZbkb, IsRV64] in { +let Predicates = [HasStdExtZbpOrZbkbOrZbpbo, IsRV64] in def : Pat<(i64 (or (and GPR:$rs1, 0x00000000FFFFFFFF), (shl GPR:$rs2, (i64 32)))), (PACK GPR:$rs1, GPR:$rs2)>; +let Predicates = [HasStdExtZbpOrZbkb, IsRV64] in { def : Pat<(i64 (sext_inreg (or (shl GPR:$rs2, (i64 16)), (and GPR:$rs1, 0x000000000000FFFF)), i32)), @@ -1069,18 +1119,18 @@ (PACKW GPR:$rs1, GPR:$rs2)>; } // Predicates = [HasStdExtZbpOrZbkb, IsRV64] -let Predicates = [HasStdExtZbp, IsRV32] in +let Predicates = [HasStdExtZbpOrZbpbo, IsRV32] in def : Pat<(i32 (or (and GPR:$rs2, 0xFFFF0000), (srl GPR:$rs1, (i32 16)))), (PACKU GPR:$rs1, GPR:$rs2)>; -let Predicates = [HasStdExtZbp, IsRV64] in { +let Predicates = [HasStdExtZbpOrZbpbo, IsRV64] in def : Pat<(i64 (or (and GPR:$rs2, 0xFFFFFFFF00000000), (srl GPR:$rs1, (i64 32)))), (PACKU GPR:$rs1, GPR:$rs2)>; +let Predicates = [HasStdExtZbp, IsRV64] in def : Pat<(i64 (or (and (assertsexti32 GPR:$rs2), 0xFFFFFFFFFFFF0000), (srl (and GPR:$rs1, 0xFFFFFFFF), (i64 16)))), (PACKUW GPR:$rs1, GPR:$rs2)>; -} // Predicates = [HasStdExtZbp, IsRV64] let Predicates = [HasStdExtZbbOrZbp, IsRV32] in def : Pat<(i32 (and GPR:$rs, 0xFFFF)), (ZEXT_H_RV32 GPR:$rs)>; diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h --- a/llvm/lib/Target/RISCV/RISCVSubtarget.h +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -60,6 +60,7 @@ bool HasStdExtZbr = false; bool HasStdExtZbs = false; bool HasStdExtZbt = false; + bool HasStdExtZbpbo = false; bool HasStdExtV = false; bool HasStdExtZve32x = false; bool HasStdExtZve32f = false; @@ -161,6 +162,7 @@ bool hasStdExtZbf() const { return HasStdExtZbf; } bool hasStdExtZbm() const { return HasStdExtZbm; } bool hasStdExtZbp() const { return HasStdExtZbp; } + bool hasStdExtZbpbo() const { return HasStdExtZbpbo; } bool hasStdExtZbr() const { return HasStdExtZbr; } bool hasStdExtZbs() const { return HasStdExtZbs; } bool hasStdExtZbt() const { return HasStdExtZbt; } diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll --- a/llvm/test/CodeGen/RISCV/attributes.ll +++ b/llvm/test/CodeGen/RISCV/attributes.ll @@ -18,6 +18,7 @@ ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbr %s -o - | FileCheck --check-prefix=RV32ZBR %s ; RUN: llc -mtriple=riscv32 -mattr=+zbs %s -o - | FileCheck --check-prefix=RV32ZBS %s ; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbt %s -o - | FileCheck --check-prefix=RV32ZBT %s +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbpbo %s -o - | FileCheck --check-prefix=RV32ZBPBO %s ; RUN: llc -mtriple=riscv32 -mattr=+v %s -o - | FileCheck --check-prefix=RV32V %s ; RUN: llc -mtriple=riscv32 -mattr=+zbb,+zfh,+v,+f %s -o - | FileCheck --check-prefix=RV32COMBINED %s ; RUN: llc -mtriple=riscv32 -mattr=+zbkb %s -o - | FileCheck --check-prefix=RV32ZBKB %s @@ -57,6 +58,7 @@ ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbr %s -o - | FileCheck --check-prefix=RV64ZBR %s ; RUN: llc -mtriple=riscv64 -mattr=+zbs %s -o - | FileCheck --check-prefix=RV64ZBS %s ; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbt %s -o - | FileCheck --check-prefix=RV64ZBT %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbpbo %s -o - | FileCheck --check-prefix=RV64ZBPBO %s ; RUN: llc -mtriple=riscv64 -mattr=+v %s -o - | FileCheck --check-prefix=RV64V %s ; RUN: llc -mtriple=riscv64 -mattr=+zbb,+zfh,+v,+f %s -o - | FileCheck --check-prefix=RV64COMBINED %s ; RUN: llc -mtriple=riscv64 -mattr=+zbkb %s -o - | FileCheck --check-prefix=RV64ZBKB %s @@ -97,6 +99,7 @@ ; RV32ZBR: .attribute 5, "rv32i2p0_zbr0p93" ; RV32ZBS: .attribute 5, "rv32i2p0_zbs1p0" ; RV32ZBT: .attribute 5, "rv32i2p0_zbt0p93" +; RV32ZBPBO: .attribute 5, "rv32i2p0_zbpbo0p911" ; RV32V: .attribute 5, "rv32i2p0_f2p0_d2p0_v1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0" ; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_d2p0_v1p0_zfh1p0_zbb1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0" ; RV32ZBKB: .attribute 5, "rv32i2p0_zbkb1p0" @@ -137,6 +140,7 @@ ; RV64ZBR: .attribute 5, "rv64i2p0_zbr0p93" ; RV64ZBS: .attribute 5, "rv64i2p0_zbs1p0" ; RV64ZBT: .attribute 5, "rv64i2p0_zbt0p93" +; RV64ZBPBO: .attribute 5, "rv64i2p0_zbpbo0p911" ; RV64V: .attribute 5, "rv64i2p0_f2p0_d2p0_v1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0" ; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_d2p0_v1p0_zfh1p0_zbb1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0" ; RV64ZBKB: .attribute 5, "rv64i2p0_zbkb1p0" diff --git a/llvm/test/CodeGen/RISCV/rv32zbpbo-intrinsics.ll b/llvm/test/CodeGen/RISCV/rv32zbpbo-intrinsics.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv32zbpbo-intrinsics.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbpbo -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32ZBPBO + +declare i32 @llvm.riscv.fsr.i32(i32, i32, i32) + +define i32 @fsr_i32(i32 %a, i32 %b, i32 %c) nounwind { +; RV32ZBPBO-LABEL: fsr_i32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: fsr a0, a0, a1, a2 +; RV32ZBPBO-NEXT: ret + %1 = call i32 @llvm.riscv.fsr.i32(i32 %a, i32 %b, i32 %c) + ret i32 %1 +} + +define i32 @fsri_i32(i32 %a, i32 %b) nounwind { +; RV32ZBPBO-LABEL: fsri_i32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: fsri a0, a0, a1, 15 +; RV32ZBPBO-NEXT: ret + %1 = call i32 @llvm.riscv.fsr.i32(i32 %a, i32 %b, i32 15) + ret i32 %1 +} + +declare i32 @llvm.riscv.grev.i32(i32 %a, i32 %b) + +define i32 @revi32(i32 %a) nounwind { +; RV32ZBPBO-LABEL: revi32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: rev a0, a0 +; RV32ZBPBO-NEXT: ret + %tmp = call i32 @llvm.riscv.grev.i32(i32 %a, i32 31) + ret i32 %tmp +} diff --git a/llvm/test/CodeGen/RISCV/rv32zbpbo.ll b/llvm/test/CodeGen/RISCV/rv32zbpbo.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv32zbpbo.ll @@ -0,0 +1,224 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zbpbo -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32ZBPBO + +declare i32 @llvm.ctlz.i32(i32, i1) + +define i32 @ctlz_i32(i32 %a) nounwind { +; CHECK-LABEL: ctlz_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: beqz a0, .LBB0_2 +; CHECK-NEXT: # %bb.1: # %cond.false +; CHECK-NEXT: srli a1, a0, 1 +; CHECK-NEXT: or a0, a0, a1 +; CHECK-NEXT: srli a1, a0, 2 +; CHECK-NEXT: or a0, a0, a1 +; CHECK-NEXT: srli a1, a0, 4 +; CHECK-NEXT: or a0, a0, a1 +; CHECK-NEXT: srli a1, a0, 8 +; CHECK-NEXT: or a0, a0, a1 +; CHECK-NEXT: srli a1, a0, 16 +; CHECK-NEXT: or a0, a0, a1 +; CHECK-NEXT: not a0, a0 +; CHECK-NEXT: srli a1, a0, 1 +; CHECK-NEXT: lui a2, 349525 +; CHECK-NEXT: addi a2, a2, 1365 +; CHECK-NEXT: and a1, a1, a2 +; CHECK-NEXT: sub a0, a0, a1 +; CHECK-NEXT: lui a1, 209715 +; CHECK-NEXT: addi a1, a1, 819 +; CHECK-NEXT: and a2, a0, a1 +; CHECK-NEXT: srli a0, a0, 2 +; CHECK-NEXT: and a0, a0, a1 +; CHECK-NEXT: add a0, a2, a0 +; CHECK-NEXT: srli a1, a0, 4 +; CHECK-NEXT: add a0, a0, a1 +; CHECK-NEXT: lui a1, 61681 +; CHECK-NEXT: addi a1, a1, -241 +; CHECK-NEXT: and a0, a0, a1 +; CHECK-NEXT: lui a1, 4112 +; CHECK-NEXT: addi a1, a1, 257 +; CHECK-NEXT: call __mulsi3@plt +; CHECK-NEXT: srli a0, a0, 24 +; CHECK-NEXT: j .LBB0_3 +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: li a0, 32 +; CHECK-NEXT: .LBB0_3: # %cond.end +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret +; RV32I-LABEL: ctlz_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32I-NEXT: beqz a0, .LBB0_2 +; RV32I-NEXT: # %bb.1: # %cond.false +; RV32I-NEXT: srli a1, a0, 1 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: srli a1, a0, 2 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: srli a1, a0, 8 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: srli a1, a0, 16 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: not a0, a0 +; RV32I-NEXT: srli a1, a0, 1 +; RV32I-NEXT: lui a2, 349525 +; RV32I-NEXT: addi a2, a2, 1365 +; RV32I-NEXT: and a1, a1, a2 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: lui a1, 209715 +; RV32I-NEXT: addi a1, a1, 819 +; RV32I-NEXT: and a2, a0, a1 +; RV32I-NEXT: srli a0, a0, 2 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: add a0, a2, a0 +; RV32I-NEXT: srli a1, a0, 4 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: lui a1, 61681 +; RV32I-NEXT: addi a1, a1, -241 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: lui a1, 4112 +; RV32I-NEXT: addi a1, a1, 257 +; RV32I-NEXT: call __mulsi3@plt +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: j .LBB0_3 +; RV32I-NEXT: .LBB0_2: +; RV32I-NEXT: li a0, 32 +; RV32I-NEXT: .LBB0_3: # %cond.end +; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV32ZBPBO-LABEL: ctlz_i32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: beqz a0, .LBB0_2 +; RV32ZBPBO-NEXT: # %bb.1: # %cond.false +; RV32ZBPBO-NEXT: clz a0, a0 +; RV32ZBPBO-NEXT: ret +; RV32ZBPBO-NEXT: .LBB0_2: +; RV32ZBPBO-NEXT: li a0, 32 +; RV32ZBPBO-NEXT: ret + %1 = call i32 @llvm.ctlz.i32(i32 %a, i1 false) + ret i32 %1 +} + +define i32 @pack_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: pack_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: slli a0, a0, 16 +; RV32I-NEXT: srli a0, a0, 16 +; RV32I-NEXT: slli a1, a1, 16 +; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: ret +; +; RV32ZBPBO-LABEL: pack_i32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: pkbb16 a0, a0, a1 +; RV32ZBPBO-NEXT: ret + %shl = and i32 %a, 65535 + %shl1 = shl i32 %b, 16 + %or = or i32 %shl1, %shl + ret i32 %or +} + +define i32 @packu_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: packu_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: srli a0, a0, 16 +; RV32I-NEXT: lui a2, 1048560 +; RV32I-NEXT: and a1, a1, a2 +; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: ret +; +; RV32ZBPBO-LABEL: packu_i32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: pktt16 a0, a0, a1 +; RV32ZBPBO-NEXT: ret + %shr = lshr i32 %a, 16 + %shr1 = and i32 %b, -65536 + %or = or i32 %shr1, %shr + ret i32 %or +} + +define i32 @max_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: max_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: blt a1, a0, .LBB3_2 +; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: .LBB3_2: +; RV32I-NEXT: ret +; +; RV32ZBPBO-LABEL: max_i32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: max a0, a0, a1 +; RV32ZBPBO-NEXT: ret + %cmp = icmp sgt i32 %a, %b + %cond = select i1 %cmp, i32 %a, i32 %b + ret i32 %cond +} + +define i32 @min_i32(i32 %a, i32 %b) nounwind { +; RV32I-LABEL: min_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: blt a0, a1, .LBB4_2 +; RV32I-NEXT: # %bb.1: +; RV32I-NEXT: mv a0, a1 +; RV32I-NEXT: .LBB4_2: +; RV32I-NEXT: ret +; +; RV32ZBPBO-LABEL: min_i32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: min a0, a0, a1 +; RV32ZBPBO-NEXT: ret + %cmp = icmp slt i32 %a, %b + %cond = select i1 %cmp, i32 %a, i32 %b + ret i32 %cond +} + +declare i16 @llvm.bswap.i16(i16) + +define zeroext i16 @bswap_i16(i16 zeroext %a) nounwind { +; RV32I-LABEL: bswap_i16: +; RV32I: # %bb.0: +; RV32I-NEXT: srli a1, a0, 8 +; RV32I-NEXT: slli a0, a0, 8 +; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: slli a0, a0, 16 +; RV32I-NEXT: srli a0, a0, 16 +; RV32I-NEXT: ret +; +; RV32ZBPBO-LABEL: bswap_i16: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: rev8.h a0, a0 +; RV32ZBPBO-NEXT: ret + %1 = tail call i16 @llvm.bswap.i16(i16 %a) + ret i16 %1 +} + +define i32 @cmix_i32(i32 %a, i32 %b, i32 %c) nounwind { +; RV32I-LABEL: cmix_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: and a0, a1, a0 +; RV32I-NEXT: not a1, a1 +; RV32I-NEXT: and a1, a1, a2 +; RV32I-NEXT: or a0, a1, a0 +; RV32I-NEXT: ret +; +; RV32ZBPBO-LABEL: cmix_i32: +; RV32ZBPBO: # %bb.0: +; RV32ZBPBO-NEXT: cmix a0, a1, a0, a2 +; RV32ZBPBO-NEXT: ret + %and = and i32 %b, %a + %neg = xor i32 %b, -1 + %and1 = and i32 %neg, %c + %or = or i32 %and1, %and + ret i32 %or +} diff --git a/llvm/test/CodeGen/RISCV/rv64zbpbo-intrinsics.ll b/llvm/test/CodeGen/RISCV/rv64zbpbo-intrinsics.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv64zbpbo-intrinsics.ll @@ -0,0 +1,25 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbpbo -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64ZBPBO + +declare i32 @llvm.riscv.fsr.i32(i32, i32, i32) + +define i32 @fsr_i32(i32 %a, i32 %b, i32 %c) nounwind { +; RV64ZBPBO-LABEL: fsr_i32: +; RV64ZBPBO: # %bb.0: +; RV64ZBPBO-NEXT: fsrw a0, a0, a1, a2 +; RV64ZBPBO-NEXT: ret + %1 = call i32 @llvm.riscv.fsr.i32(i32 %a, i32 %b, i32 %c) + ret i32 %1 +} + +declare i64 @llvm.riscv.grev.i64(i64 %a, i64 %b) + +define i64 @revi64(i64 %a) nounwind { +; RV64ZBPBO-LABEL: revi64: +; RV64ZBPBO: # %bb.0: +; RV64ZBPBO-NEXT: rev a0, a0 +; RV64ZBPBO-NEXT: ret + %tmp = call i64 @llvm.riscv.grev.i64(i64 %a, i64 63) + ret i64 %tmp +} diff --git a/llvm/test/CodeGen/RISCV/rv64zbpbo.ll b/llvm/test/CodeGen/RISCV/rv64zbpbo.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rv64zbpbo.ll @@ -0,0 +1,119 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64I +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zbpbo -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64ZBPBO + +define i64 @pack_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: pack_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: slli a1, a1, 32 +; RV64I-NEXT: or a0, a1, a0 +; RV64I-NEXT: ret +; +; RV64ZBPBO-LABEL: pack_i64: +; RV64ZBPBO: # %bb.0: +; RV64ZBPBO-NEXT: pkbb32 a0, a0, a1 +; RV64ZBPBO-NEXT: ret + %shl = and i64 %a, 4294967295 + %shl1 = shl i64 %b, 32 + %or = or i64 %shl1, %shl + ret i64 %or +} + +define i64 @packu_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: packu_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: srli a1, a1, 32 +; RV64I-NEXT: slli a1, a1, 32 +; RV64I-NEXT: or a0, a1, a0 +; RV64I-NEXT: ret +; +; RV64ZBPBO-LABEL: packu_i64: +; RV64ZBPBO: # %bb.0: +; RV64ZBPBO-NEXT: pktt32 a0, a0, a1 +; RV64ZBPBO-NEXT: ret + %shr = lshr i64 %a, 32 + %shr1 = and i64 %b, -4294967296 + %or = or i64 %shr1, %shr + ret i64 %or +} + +define i64 @max_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: max_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: blt a1, a0, .LBB2_2 +; RV64I-NEXT: # %bb.1: +; RV64I-NEXT: mv a0, a1 +; RV64I-NEXT: .LBB2_2: +; RV64I-NEXT: ret +; +; RV64ZBPBO-LABEL: max_i64: +; RV64ZBPBO: # %bb.0: +; RV64ZBPBO-NEXT: max a0, a0, a1 +; RV64ZBPBO-NEXT: ret + %cmp = icmp sgt i64 %a, %b + %cond = select i1 %cmp, i64 %a, i64 %b + ret i64 %cond +} + +define i64 @min_i64(i64 %a, i64 %b) nounwind { +; RV64I-LABEL: min_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: blt a0, a1, .LBB3_2 +; RV64I-NEXT: # %bb.1: +; RV64I-NEXT: mv a0, a1 +; RV64I-NEXT: .LBB3_2: +; RV64I-NEXT: ret +; +; RV64ZBPBO-LABEL: min_i64: +; RV64ZBPBO: # %bb.0: +; RV64ZBPBO-NEXT: min a0, a0, a1 +; RV64ZBPBO-NEXT: ret + %cmp = icmp slt i64 %a, %b + %cond = select i1 %cmp, i64 %a, i64 %b + ret i64 %cond +} + +declare i16 @llvm.bswap.i16(i16) + +define zeroext i16 @bswap_i16(i16 zeroext %a) nounwind { +; RV64I-LABEL: bswap_i16: +; RV64I: # %bb.0: +; RV64I-NEXT: srli a1, a0, 8 +; RV64I-NEXT: slli a0, a0, 8 +; RV64I-NEXT: or a0, a0, a1 +; RV64I-NEXT: slli a0, a0, 48 +; RV64I-NEXT: srli a0, a0, 48 +; RV64I-NEXT: ret +; +; RV64ZBPBO-LABEL: bswap_i16: +; RV64ZBPBO: # %bb.0: +; RV64ZBPBO-NEXT: rev8.h a0, a0 +; RV64ZBPBO-NEXT: ret + %1 = tail call i16 @llvm.bswap.i16(i16 %a) + ret i16 %1 +} + +define i64 @cmix_i64(i64 %a, i64 %b, i64 %c) nounwind { +; RV64I-LABEL: cmix_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: and a0, a1, a0 +; RV64I-NEXT: not a1, a1 +; RV64I-NEXT: and a1, a1, a2 +; RV64I-NEXT: or a0, a1, a0 +; RV64I-NEXT: ret +; +; RV64ZBPBO-LABEL: cmix_i64: +; RV64ZBPBO: # %bb.0: +; RV64ZBPBO-NEXT: cmix a0, a1, a0, a2 +; RV64ZBPBO-NEXT: ret + %and = and i64 %b, %a + %neg = xor i64 %b, -1 + %and1 = and i64 %neg, %c + %or = or i64 %and1, %and + ret i64 %or +} diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s --- a/llvm/test/MC/RISCV/attribute-arch.s +++ b/llvm/test/MC/RISCV/attribute-arch.s @@ -187,3 +187,6 @@ .attribute arch, "rv32if_zkt1p0_zve32f1p0_zve32x1p0_zvl32b1p0" # CHECK: attribute 5, "rv32i2p0_f2p0_zkt1p0_zve32f1p0_zve32x1p0_zvl32b1p0" + +.attribute arch, "rv32izbpbo0p911" +# CHECK: attribute 5, "rv32i2p0_zbpbo0p911" diff --git a/llvm/test/MC/RISCV/rv32zbpbo-aliases-valid.s b/llvm/test/MC/RISCV/rv32zbpbo-aliases-valid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv32zbpbo-aliases-valid.s @@ -0,0 +1,26 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zbpbo -riscv-no-aliases \ +# RUN: | FileCheck -check-prefixes=CHECK-S-OBJ-NOALIAS %s +# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zbpbo \ +# RUN: | FileCheck -check-prefixes=CHECK-S-OBJ %s +# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-zbpbo < %s \ +# RUN: | llvm-objdump -d -r -M no-aliases --mattr=+experimental-zbpbo - \ +# RUN: | FileCheck -check-prefixes=CHECK-S-OBJ-NOALIAS %s +# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+experimental-zbpbo < %s \ +# RUN: | llvm-objdump -d -r --mattr=+experimental-zbpbo - \ +# RUN: | FileCheck -check-prefixes=CHECK-S-OBJ %s + +# CHECK-S-OBJ-NOALIAS: grevi t0, t1, 8 +# CHECK-S-OBJ: rev8.h t0, t1 +rev8.h x5, x6 + +# CHECK-S-OBJ-NOALIAS: grevi t0, t1, 31 +# CHECK-S-OBJ: rev t0, t1 +rev x5, x6 + +# CHECK-S-OBJ-NOALIAS: pack t0, t1, t2 +# CHECK-S-OBJ: pkbb16 t0, t1, t2 +pkbb16 x5, x6, x7 + +# CHECK-S-OBJ-NOALIAS: packu t0, t1, t2 +# CHECK-S-OBJ: pktt16 t0, t1, t2 +pktt16 x5, x6, x7 diff --git a/llvm/test/MC/RISCV/rv32zbpbo-valid.s b/llvm/test/MC/RISCV/rv32zbpbo-valid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv32zbpbo-valid.s @@ -0,0 +1,37 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zbpbo -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zbpbo < %s \ +# RUN: | llvm-objdump --mattr=+experimental-zbpbo -M no-aliases -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: clz t0, t1 +# CHECK-ASM: encoding: [0x93,0x12,0x03,0x60] +clz t0, t1 + +# CHECK-ASM-AND-OBJ: pack t0, t1, t2 +# CHECK-ASM: encoding: [0xb3,0x42,0x73,0x08] +pack t0, t1, t2 + +# CHECK-ASM-AND-OBJ: packu t0, t1, t2 +# CHECK-ASM: encoding: [0xb3,0x42,0x73,0x48] +packu t0, t1, t2 + +# CHECK-ASM-AND-OBJ: fsr t0, t1, t2, t3 +# CHECK-ASM: encoding: [0xb3,0x52,0xc3,0x3d] +fsr t0, t1, t2, t3 + +# CHECK-ASM-AND-OBJ: fsri t0, t1, t2, 0 +# CHECK-ASM: encoding: [0x93,0x52,0x03,0x3c] +fsri t0, t1, t2, 0 + +# CHECK-ASM-AND-OBJ: max t0, t1, t2 +# CHECK-ASM: encoding: [0xb3,0x62,0x73,0x0a] +max t0, t1, t2 + +# CHECK-ASM-AND-OBJ: min t0, t1, t2 +# CHECK-ASM: encoding: [0xb3,0x42,0x73,0x0a] +min t0, t1, t2 + +# CHECK-ASM-AND-OBJ: cmix t0, t1, t2, t3 +# CHECK-ASM: encoding: [0xb3,0x92,0x63,0xe6] +cmix t0, t1, t2, t3 diff --git a/llvm/test/MC/RISCV/rv64zbpbo-aliases-valid.s b/llvm/test/MC/RISCV/rv64zbpbo-aliases-valid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv64zbpbo-aliases-valid.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-zbpbo -riscv-no-aliases \ +# RUN: | FileCheck -check-prefixes=CHECK-S-OBJ-NOALIAS %s +# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-zbpbo \ +# RUN: | FileCheck -check-prefixes=CHECK-S-OBJ %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+experimental-zbpbo < %s \ +# RUN: | llvm-objdump -d -r -M no-aliases --mattr=+experimental-zbpbo - \ +# RUN: | FileCheck -check-prefixes=CHECK-S-OBJ-NOALIAS %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+experimental-zbpbo < %s \ +# RUN: | llvm-objdump -d -r --mattr=+experimental-zbpbo - \ +# RUN: | FileCheck -check-prefixes=CHECK-S-OBJ %s + +# CHECK-S-OBJ-NOALIAS: grevi t0, t1, 8 +# CHECK-S-OBJ: rev8.h t0, t1 +rev8.h x5, x6 + +# CHECK-S-OBJ-NOALIAS: grevi t0, t1, 63 +# CHECK-S-OBJ: rev t0, t1 +rev x5, x6 diff --git a/llvm/test/MC/RISCV/rv64zbpbo-valid.s b/llvm/test/MC/RISCV/rv64zbpbo-valid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/rv64zbpbo-valid.s @@ -0,0 +1,29 @@ +# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-zbpbo -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+experimental-zbpbo < %s \ +# RUN: | llvm-objdump --mattr=+experimental-zbpbo -M no-aliases -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: pack t0, t1, t2 +# CHECK-ASM: encoding: [0xb3,0x42,0x73,0x08] +pack t0, t1, t2 + +# CHECK-ASM-AND-OBJ: packu t0, t1, t2 +# CHECK-ASM: encoding: [0xb3,0x42,0x73,0x48] +packu t0, t1, t2 + +# CHECK-ASM-AND-OBJ: fsrw t0, t1, t2, t3 +# CHECK-ASM: encoding: [0xbb,0x52,0xc3,0x3d] +fsrw t0, t1, t2, t3 + +# CHECK-ASM-AND-OBJ: max t0, t1, t2 +# CHECK-ASM: encoding: [0xb3,0x62,0x73,0x0a] +max t0, t1, t2 + +# CHECK-ASM-AND-OBJ: min t0, t1, t2 +# CHECK-ASM: encoding: [0xb3,0x42,0x73,0x0a] +min t0, t1, t2 + +# CHECK-ASM-AND-OBJ: cmix t0, t1, t2, t3 +# CHECK-ASM: encoding: [0xb3,0x92,0x63,0xe6] +cmix t0, t1, t2, t3