Skip to content

Commit

Permalink
[LLVM] [RVV 0.7.1] add vsetvl and vsetvlmax intrinsic (ruyisdk#12)
Browse files Browse the repository at this point in the history
* [LLVM][RVV 0.7.1] intrinsics for some binary operations

* [LLVM][RVV 0.7.1] `vsetvl` intrinsics

* [LLVM][RVV 0.7.1] test `vsetvl` intrinsics

* [LLVM][RVV 0.7.1] improve

* [LLVM][RVV 0.7.1] use separate SEW and LMUL for intrinsic vsetvl

* [LLVM][RVV 0.7.1] remove unnecessary comments

* [LLVM][RVV 0.7.1] test `vsetvlmax`

* [LLVM][RVV 0.7.1] simplify patch
  • Loading branch information
imkiva committed Apr 1, 2024
1 parent e06d305 commit 9864740
Show file tree
Hide file tree
Showing 7 changed files with 388 additions and 1 deletion.
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/IntrinsicsRISCV.td
Original file line number Diff line number Diff line change
Expand Up @@ -1841,3 +1841,4 @@ def int_riscv_sm3p1 : ScalarCryptoGprIntrinsic32;
//===----------------------------------------------------------------------===//
include "llvm/IR/IntrinsicsRISCVXTHead.td"
include "llvm/IR/IntrinsicsRISCVXsf.td"
include "llvm/IR/IntrinsicsRISCVXTHeadV.td"
24 changes: 24 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsRISCVXTHeadV.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===- IntrinsicsRISCVXTHeadV.td - RVV 0.7.1 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 RISC-V Vector Extension version 0.7.1 intrinsics.
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// Vectors version 0.7.1

let TargetPrefix = "riscv" in {
// 6. Configuration-Setting and Utility
def int_riscv_xvsetvl : Intrinsic<[llvm_i64_ty],
[/* AVL */ llvm_i64_ty, /* SEW */ llvm_i64_ty, /* LMUL */ llvm_i64_ty],
[IntrNoMem]>;
def int_riscv_xvsetvlmax : Intrinsic<[llvm_i64_ty],
[/* SEW */ llvm_i64_ty, /* LMUL */ llvm_i64_ty],
[IntrNoMem]>;
} // TargetPrefix = "riscv"
56 changes: 56 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,59 @@ void RISCVDAGToDAGISel::selectVSETVLI(SDNode *Node) {
CurDAG->getMachineNode(Opcode, DL, XLenVT, VLOperand, VTypeIOp));
}

void RISCVDAGToDAGISel::selectXVSETVLI(SDNode *Node) {
if (!Subtarget->hasVendorXTHeadV())
return;
assert(Node->getOpcode() == ISD::INTRINSIC_WO_CHAIN && "Unexpected opcode");

SDLoc DL(Node);
MVT XLenVT = Subtarget->getXLenVT();

unsigned IntNo = Node->getConstantOperandVal(0);

assert((IntNo == Intrinsic::riscv_xvsetvlmax ||
IntNo == Intrinsic::riscv_xvsetvl) &&
"Unexpected vsetvl intrinsic");

// declare i64 @llvm.riscv.xvsetvl (i64 %avl, i64 %sew, i64 %lmul);
// declare i64 @llvm.riscv.xvsetvlmax( i64 %sew, i64 %lmul);
bool IsMax = IntNo == Intrinsic::riscv_xvsetvlmax;
unsigned SEWPosition = IsMax ? 1 : 2;
unsigned ExpectedOperands = SEWPosition + 2;
assert(Node->getNumOperands() == ExpectedOperands &&
"Unexpected number of operands");

unsigned SEW = Node->getConstantOperandVal(SEWPosition) & 0x7;
unsigned LMUL = Node->getConstantOperandVal(SEWPosition + 1) & 0x7;

// encodeXTHeadVType needs the literal version of SEW and LMUL,
// instead of the binary encoding version.
// Like, it needs SEW=8/16/32/64/128 instead of SEW=0/1/2/3/4

// Currently,
// the intrinsics for RVV 0.7 should accept binary encoding,
// in order to keep consistent with the RVV 1.0 implemented in LLVM.

// So we need to convert the binary encoding to the literal version,
// and encodeXTHeadVType will convert them back to the binary,
// and then use them to generate the VTYPEI.
// It's true that we can make encodeXTHeadVTYPE accepts the binary version,
// but that will make encodeXTHeadVTYPE inconsistent with encodeVTYPE,
// which is the corresponding function for RVV 1.0.
SEW = RISCVVType::decodeVSEW(SEW);
LMUL = 1 << LMUL;
auto VTypeI = RISCVVType::encodeXTHeadVTYPE(SEW, LMUL, 1);
auto VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT);

// spec: if rs1 = x0, then use maximum vector length
auto AVLOp =
IsMax ? CurDAG->getRegister(RISCV::X0, XLenVT) : Node->getOperand(1);

auto Opcode = RISCV::XVSETVLI;
auto MN = CurDAG->getMachineNode(Opcode, DL, XLenVT, AVLOp, VTypeIOp);
ReplaceNode(Node, MN);
}

bool RISCVDAGToDAGISel::tryShrinkShlLogicImm(SDNode *Node) {
MVT VT = Node->getSimpleValueType(0);
unsigned Opcode = Node->getOpcode();
Expand Down Expand Up @@ -1548,6 +1601,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
case Intrinsic::riscv_vsetvli:
case Intrinsic::riscv_vsetvlimax:
return selectVSETVLI(Node);
case Intrinsic::riscv_xvsetvl:
case Intrinsic::riscv_xvsetvlmax:
return selectXVSETVLI(Node);
}
break;
}
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
void selectVSXSEG(SDNode *Node, bool IsMasked, bool IsOrdered);

void selectVSETVLI(SDNode *Node);
void selectXVSETVLI(SDNode *Node);

// Return the RISC-V condition code that matches the given DAG integer
// condition code. The CondCode must be one of those supported by the RISC-V
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Target/RISCV/RISCVInstrInfoXTHeadV.td
Original file line number Diff line number Diff line change
Expand Up @@ -888,4 +888,3 @@ def : InstAlias<"vmnot.m $vd, $vs",

} // Predicates = [HasVendorXTHeadV]
} // AsmVariantName = "RVV0p71"

145 changes: 145 additions & 0 deletions llvm/test/CodeGen/RISCV/rvv0p71/vsetvl.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
; RUN: llc -mtriple=riscv64 -mattr=+xtheadv < %s | FileCheck -check-prefix=CHECK %s

; https://github.com/riscv-non-isa/rvv-intrinsic-doc/blob/v0.7.1/rvv_intrinsic_funcs/01_configuration-setting_and_utility_functions.md

; The spec allowed e128, but intrinsic only support e8, e16, e32, e64
; vtype = ((ediv & 0b11) << 5) | ((sew & 0b111) << 2) | ((lmul & 0b11) << 0)
; -------------------------------------------
; | ASM name | e8 | e16 | e32 | e64 | e128 |
; | SEW | 0 | 1 | 2 | 3 | 4 |
; -------------------------------------------
; | ASM name | m1 | m2 | m4 | m8 |
; | LMUL | 0 | 1 | 2 | 3 |
; -----------------------------------
; In intrinsic, ediv is always 1

declare i64 @llvm.riscv.xvsetvl (i64 %avl, i64 %sew, i64 %lmul);
declare i64 @llvm.riscv.xvsetvlmax( i64 %sew, i64 %lmul);


define i64 @intrinsic_xvsetvl_e8m1(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e8m1
; CHECK: vsetvli a0, a0, e8, m1, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 0, i64 0)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e8m2(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e8m2
; CHECK: vsetvli a0, a0, e8, m2, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 0, i64 1)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e8m4(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e8m4
; CHECK: vsetvli a0, a0, e8, m4, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 0, i64 2)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e8m8(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e8m8
; CHECK: vsetvli a0, a0, e8, m8, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 0, i64 3)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e16m1(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e16m1
; CHECK: vsetvli a0, a0, e16, m1, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 1, i64 0)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e16m2(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e16m2
; CHECK: vsetvli a0, a0, e16, m2, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 1, i64 1)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e16m4(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e16m4
; CHECK: vsetvli a0, a0, e16, m4, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 1, i64 2)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e16m8(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e16m8
; CHECK: vsetvli a0, a0, e16, m8, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 1, i64 3)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e32m1(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e32m1
; CHECK: vsetvli a0, a0, e32, m1, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 2, i64 0)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e32m2(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e32m2
; CHECK: vsetvli a0, a0, e32, m2, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 2, i64 1)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e32m4(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e32m4
; CHECK: vsetvli a0, a0, e32, m4, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 2, i64 2)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e32m8(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e32m8
; CHECK: vsetvli a0, a0, e32, m8, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 2, i64 3)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e64m1(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e64m1
; CHECK: vsetvli a0, a0, e64, m1, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 3, i64 0)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e64m2(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e64m2
; CHECK: vsetvli a0, a0, e64, m2, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 3, i64 1)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e64m4(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e64m4
; CHECK: vsetvli a0, a0, e64, m4, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 3, i64 2)
ret i64 %v
}


define i64 @intrinsic_xvsetvl_e64m8(i64 %avl) {
; CHECK-LABEL: intrinsic_xvsetvl_e64m8
; CHECK: vsetvli a0, a0, e64, m8, d1
%v = call i64 @llvm.riscv.xvsetvl(i64 %avl, i64 3, i64 3)
ret i64 %v
}
Loading

0 comments on commit 9864740

Please sign in to comment.