diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td b/llvm/include/llvm/IR/IntrinsicsRISCV.td --- a/llvm/include/llvm/IR/IntrinsicsRISCV.td +++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td @@ -1877,3 +1877,4 @@ //===----------------------------------------------------------------------===// include "llvm/IR/IntrinsicsRISCVXTHead.td" include "llvm/IR/IntrinsicsRISCVXsf.td" +include "llvm/IR/IntrinsicsRISCVXCV.td" diff --git a/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td b/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/IR/IntrinsicsRISCVXCV.td @@ -0,0 +1,42 @@ +//===- IntrinsicsRISCVXCV.td - CORE-V intrinsics -----------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines all of the CORE-V vendor intrinsics for RISC-V. +// +//===----------------------------------------------------------------------===// + +class ScalarCoreVBitManipGprGprIntrinsic + : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrWillReturn, IntrSpeculatable]>; + +class ScalarCoreVBitManipGprIntrinsic + : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], + [IntrNoMem, IntrWillReturn, IntrSpeculatable]>; + +let TargetPrefix = "riscv" in { + def int_riscv_cv_bitmanip_extract : ScalarCoreVBitManipGprGprIntrinsic; + def int_riscv_cv_bitmanip_extractu : ScalarCoreVBitManipGprGprIntrinsic; + def int_riscv_cv_bitmanip_bclr : ScalarCoreVBitManipGprGprIntrinsic; + def int_riscv_cv_bitmanip_bset : ScalarCoreVBitManipGprGprIntrinsic; + + def int_riscv_cv_bitmanip_insert + : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrWillReturn, IntrSpeculatable]>; + + def int_riscv_cv_bitmanip_ff1 : ScalarCoreVBitManipGprIntrinsic; + def int_riscv_cv_bitmanip_fl1 : ScalarCoreVBitManipGprIntrinsic; + def int_riscv_cv_bitmanip_clb : ScalarCoreVBitManipGprIntrinsic; + def int_riscv_cv_bitmanip_cnt : ScalarCoreVBitManipGprIntrinsic; + + def int_riscv_cv_bitmanip_ror : ScalarCoreVBitManipGprGprIntrinsic; + + def int_riscv_cv_bitmanip_bitrev + : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrWillReturn, IntrSpeculatable, + ImmArg>, ImmArg>]>; +} // TargetPrefix = "riscv" diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp --- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp +++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp @@ -55,6 +55,8 @@ MachineBasicBlock::iterator MBBI); bool expandRV32ZdinxLoad(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI); + bool expandCoreVBitManip(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI); #ifndef NDEBUG unsigned getInstSizeInBytes(const MachineFunction &MF) const { unsigned Size = 0; @@ -142,6 +144,12 @@ case RISCV::PseudoVMSET_M_B64: // vmset.m vd => vmxnor.mm vd, vd, vd return expandVMSET_VMCLR(MBB, MBBI, RISCV::VMXNOR_MM); + case RISCV::CV_EXTRACT_PSEUDO: + case RISCV::CV_EXTRACTU_PSEUDO: + case RISCV::CV_BSET_PSEUDO: + case RISCV::CV_BCLR_PSEUDO: + case RISCV::CV_INSERT_PSEUDO: + return expandCoreVBitManip(MBB, MBBI); } return false; @@ -341,6 +349,43 @@ return true; } +bool RISCVExpandPseudo::expandCoreVBitManip(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) { + DebugLoc DL = MBBI->getDebugLoc(); + Register DstReg = MBBI->getOperand(0).getReg(); + Register SrcReg = MBBI->getOperand(1).getReg(); + uint16_t Imm = MBBI->getOperand(2).getImm(); + unsigned Opcode; + switch (MBBI->getOpcode()) { + case RISCV::CV_EXTRACT_PSEUDO: + Opcode = RISCV::CV_EXTRACT; + break; + case RISCV::CV_EXTRACTU_PSEUDO: + Opcode = RISCV::CV_EXTRACTU; + break; + case RISCV::CV_BCLR_PSEUDO: + Opcode = RISCV::CV_BCLR; + break; + case RISCV::CV_BSET_PSEUDO: + Opcode = RISCV::CV_BSET; + break; + case RISCV::CV_INSERT_PSEUDO: + Opcode = RISCV::CV_INSERT; + break; + + default: + llvm_unreachable("unknown instruction"); + } + const MCInstrDesc &Desc = TII->get(Opcode); + auto MBI = BuildMI(MBB, MBBI, DL, Desc, DstReg); + if (MBBI->getOpcode() == RISCV::CV_INSERT_PSEUDO) { + MBI.addReg(MBBI->getOperand(3).getReg()); + } + MBI.addReg(SrcReg).addImm((Imm >> 5) & 0x1f).addImm(Imm & 0x1f); + MBBI->eraseFromParent(); + return true; +} + class RISCVPreRAExpandPseudo : public MachineFunctionPass { public: const RISCVSubtarget *STI; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td @@ -33,7 +33,7 @@ class CVBitManipR funct7, string opcodestr> : RVInstR { + (ins GPR:$rs1), opcodestr, "$rd, $rs1"> { let rs2 = 0b00000; } } @@ -62,7 +62,7 @@ def CV_BCLRR : CVBitManipRR<0b0011100, "cv.bclrr">; def CV_BSETR : CVBitManipRR<0b0011101, "cv.bsetr">; - def CVROR : CVBitManipRR<0b0100000, "cv.ror">; + def CV_ROR : CVBitManipRR<0b0100000, "cv.ror">; def CV_FF1 : CVBitManipR<0b0100001, "cv.ff1">; def CV_FL1 : CVBitManipR<0b0100010, "cv.fl1">; def CV_CLB : CVBitManipR<0b0100011, "cv.clb">; @@ -505,3 +505,40 @@ (ins GPR:$rs1, simm5:$imm5, simm13_lsb0:$imm12), "cv.bneimm", "$rs1, $imm5, $imm12">, Sched<[]>; } + +def cv_tuimm2: Operand, TImmLeaf(Imm);}]>; +def cv_tuimm5: Operand, TImmLeaf(Imm);}]>; +def cv_uimm10: Operand, ImmLeaf(Imm);}]>; +def cv_tuimm10: Operand, TImmLeaf(Imm);}]>; + +multiclass PatCoreVBitManip { + def "CV_" # NAME # "_PSEUDO" : Pseudo<(outs GPR:$rd), + (ins GPR:$rs1, cv_uimm10:$imm), []>; + def : PatGprGpr("CV_" # NAME # "R")>; + def : PatGprImm("CV_" # NAME # "_PSEUDO"), cv_uimm10>; +} + +let Predicates = [HasVendorXCVbitmanip, IsRV32] in { + defm EXTRACT : PatCoreVBitManip; + defm EXTRACTU : PatCoreVBitManip; + defm BCLR : PatCoreVBitManip; + defm BSET : PatCoreVBitManip; + + def CV_INSERT_PSEUDO : Pseudo<(outs GPR:$rd_wb), + (ins GPR:$rs1, cv_tuimm10:$imm, GPR:$rd), []>; + def : Pat<(int_riscv_cv_bitmanip_insert GPR:$rs1, GPR:$rs2, GPR:$rd), + (CV_INSERTR GPR:$rd, GPR:$rs1, GPR:$rs2)>; + def : Pat<(int_riscv_cv_bitmanip_insert GPR:$rs1, cv_uimm10:$imm, GPR:$rd), + (CV_INSERT_PSEUDO GPR:$rs1, cv_uimm10:$imm, GPR:$rd)>; + + def : PatGpr; + def : PatGpr; + def : PatGpr; + def : PatGpr; + + def : PatGprGpr; + + def : Pat<(int_riscv_cv_bitmanip_bitrev GPR:$rs1, cv_tuimm5:$pts, + cv_tuimm2:$radix), + (CV_BITREV GPR:$rs1, cv_tuimm2:$radix, cv_tuimm5:$pts)>; +} diff --git a/llvm/test/CodeGen/RISCV/xcvbitmanip.ll b/llvm/test/CodeGen/RISCV/xcvbitmanip.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/xcvbitmanip.ll @@ -0,0 +1,180 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -O0 -mtriple=riscv32 -mattr=+m -mattr=+xcvbitmanip -verify-machineinstrs < %s \ +; RUN: | FileCheck %s +; RUN: llc -O3 -mtriple=riscv32 -mattr=+m -mattr=+xcvbitmanip -verify-machineinstrs < %s \ +; RUN: | FileCheck %s + +declare i32 @llvm.riscv.cv.bitmanip.extract(i32, i32) + +define i32 @test.cv.extractr(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.extractr: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.extractr a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.extract(i32 %a, i32 %b) + ret i32 %1 +} + +define i32 @test.cv.extract(i32 %a) { +; CHECK-LABEL: test.cv.extract: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.extract a0, a0, 2, 1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.extract(i32 %a, i32 65) + ret i32 %1 +} + +define i32 @test.cv.extract1023(i32 %a) { +; CHECK-LABEL: test.cv.extract1023: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.extract a0, a0, 31, 31 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.extract(i32 %a, i32 1023) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.extractu(i32, i32) + +define i32 @test.cv.extractur(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.extractur: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.extractur a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.extractu(i32 %a, i32 %b) + ret i32 %1 +} + +define i32 @test.cv.extractu(i32 %a) { +; CHECK-LABEL: test.cv.extractu: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.extractu a0, a0, 2, 1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.extractu(i32 %a, i32 65) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.insert(i32, i32, i32) + +define i32 @test.cv.insert(i32 %c, i32 %a) { +; CHECK-LABEL: test.cv.insert: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.insert a0, a1, 2, 1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.insert(i32 %a, i32 65, i32 %c) + ret i32 %1 +} + +define i32 @test.cv.insertr(i32 %c, i32 %b, i32 %a) { +; CHECK-LABEL: test.cv.insertr: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.insertr a0, a2, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.insert(i32 %a, i32 %b, i32 %c) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.bclr(i32, i32) + +define i32 @test.cv.bclrr(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.bclrr: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.bclrr a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.bclr(i32 %a, i32 %b) + ret i32 %1 +} + +define i32 @test.cv.bclr(i32 %a) { +; CHECK-LABEL: test.cv.bclr: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.bclr a0, a0, 2, 1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.bclr(i32 %a, i32 65) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.bset(i32, i32) + +define i32 @test.cv.bsetr(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.bsetr: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.bsetr a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.bset(i32 %a, i32 %b) + ret i32 %1 +} + +define i32 @test.cv.bset(i32 %a) { +; CHECK-LABEL: test.cv.bset: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.bset a0, a0, 2, 1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.bset(i32 %a, i32 65) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.ff1(i32) + +define i32 @test.cv.ff1(i32 %a) { +; CHECK-LABEL: test.cv.ff1: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.ff1 a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.ff1(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.fl1(i32) + +define i32 @test.cv.fl1(i32 %a) { +; CHECK-LABEL: test.cv.fl1: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.fl1 a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.fl1(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.clb(i32) + +define i32 @test.cv.clb(i32 %a) { +; CHECK-LABEL: test.cv.clb: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.clb a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.clb(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.cnt(i32) + +define i32 @test.cv.cnt(i32 %a) { +; CHECK-LABEL: test.cv.cnt: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.cnt a0, a0 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.cnt(i32 %a) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.ror(i32, i32) + +define i32 @test.cv.ror(i32 %a, i32 %b) { +; CHECK-LABEL: test.cv.ror: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.ror a0, a0, a1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.ror(i32 %a, i32 %b) + ret i32 %1 +} + +declare i32 @llvm.riscv.cv.bitmanip.bitrev(i32, i32, i32) + +define i32 @test.cv.bitrev(i32 %a) { +; CHECK-LABEL: test.cv.bitrev: +; CHECK: # %bb.0: +; CHECK-NEXT: cv.bitrev a0, a0, 2, 1 +; CHECK-NEXT: ret + %1 = call i32 @llvm.riscv.cv.bitmanip.bitrev(i32 %a, i32 1, i32 2) + ret i32 %1 +}