1//==--- riscv_sifive_vector.td - RISC-V SiFive VCIX function list ---------===//
2//
3//  Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4//  See https://llvm.org/LICENSE.txt for license information.
5//  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the builtins for RISC-V SiFive VCIX. See:
10//
11//     https://sifive.cdn.prismic.io/sifive/c3829e36-8552-41f0-a841-79945784241b_vcix-spec-software.pdf
12//
13//===----------------------------------------------------------------------===//
14
15include "riscv_vector_common.td"
16
17//===----------------------------------------------------------------------===//
18// Instruction definitions
19//===----------------------------------------------------------------------===//
20
21class VCIXSuffix<string range> {
22  list<string> suffix = !cond(!eq(range, "c"): ["8mf8", "8mf4", "8mf2", "8m1", "8m2", "8m4", "8m8"],
23                              !eq(range, "s"): ["16mf4", "16mf2", "16m1", "16m2", "16m4", "16m8"],
24                              !eq(range, "i"): ["32mf2", "32m1", "32m2", "32m4", "32m8"],
25                              !eq(range, "l"): ["64m1", "64m2", "64m4", "64m8"]);
26}
27
28class VCIXBuiltinSet<string name, string IR_name, string suffix,
29                     string prototype, string type_range,
30                     list<int> intrinsic_types>
31    : RVVBuiltin<suffix, prototype, type_range> {
32  let Name = name;
33  let OverloadedName = name;
34  let IRName = IR_name;
35  let HasMasked = false;
36  let IntrinsicTypes = intrinsic_types;
37}
38
39multiclass VCIXBuiltinSet<string name, string IR_name, string suffix,
40                          string prototype, string type_range,
41                          list<int> intrinsic_types> {
42  if !find(prototype, "0") then {
43    def : VCIXBuiltinSet<name, IR_name, suffix, prototype, type_range, intrinsic_types>;
44  }
45  def : VCIXBuiltinSet<name # "_se", IR_name # "_se", suffix, prototype, type_range, intrinsic_types>;
46}
47
48multiclass RVVVCIXBuiltinSet<list<string> range, string prototype,
49                             list<int> intrinsic_types, bit UseGPR> {
50  foreach r = range in
51    let RequiredFeatures = !if(!and(UseGPR, !eq(r, "l")),
52                               ["Xsfvcp", "RV64"], ["Xsfvcp"]) in
53      defm : VCIXBuiltinSet<NAME, NAME, "Uv", prototype, r, intrinsic_types>;
54}
55
56multiclass RVVVCIXBuiltinSetWVType<list<string> range, string prototype,
57                             list<int> intrinsic_types, bit UseGPR> {
58  foreach r = range in
59    let RequiredFeatures = !if(!and(UseGPR, !eq(r, "l")),
60                               ["Xsfvcp", "RV64"], ["Xsfvcp"]) in
61      // These intrinsics don't have any vector types in the output and inputs,
62      // but we still need to add vetvli for them. So we encode different
63      // VTYPE into the intrinsic names, and then will know which vsetvli is
64      // correct.
65      foreach s = VCIXSuffix<r>.suffix in
66        // Since we already encode the Vtype into the name, so just set
67        // Log2LMUL to zero.  Otherwise the RISCVVEmitter will expand
68        // lots of redundant intrinsic but have same names.
69        let Log2LMUL = [0] in
70          def : VCIXBuiltinSet<NAME # "_u" # s, NAME # "_e" # s,
71                               "", prototype, r, intrinsic_types>;
72}
73
74let SupportOverloading = false in {
75  defm sf_vc_x_se  : RVVVCIXBuiltinSetWVType<["c", "s", "i", "l"], "0KzKzKzUe", [0, 3], UseGPR=1>;
76  defm sf_vc_i_se  : RVVVCIXBuiltinSetWVType<["c", "s", "i", "l"], "0KzKzKzKz", [2, 3], UseGPR=0>;
77  defm sf_vc_xv    : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvUe",  [0, 2, 3],  UseGPR=1>;
78  defm sf_vc_iv    : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvKz",  [0, 2, 3],  UseGPR=0>;
79  defm sf_vc_vv    : RVVVCIXBuiltinSet<["csi", "l"], "0KzKzUvUv",  [0, 2, 3],  UseGPR=0>;
80  defm sf_vc_fv    : RVVVCIXBuiltinSet<["si",  "l"], "0KzKzUvFe",  [0, 2, 3],  UseGPR=0>;
81  defm sf_vc_xvv   : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvUe",  [0, 1, 2, 3],  UseGPR=1>;
82  defm sf_vc_ivv   : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvKz",  [0, 1, 2, 3],  UseGPR=0>;
83  defm sf_vc_vvv   : RVVVCIXBuiltinSet<["csi", "l"], "0KzUvUvUv",  [0, 1, 2, 3],  UseGPR=0>;
84  defm sf_vc_fvv   : RVVVCIXBuiltinSet<["si",  "l"], "0KzUvUvFe",  [0, 1, 2, 3],  UseGPR=0>;
85  defm sf_vc_v_x   : RVVVCIXBuiltinSet<["csi", "l"], "UvKzKzUe",   [-1, 1, 2], UseGPR=1>;
86  defm sf_vc_v_i   : RVVVCIXBuiltinSet<["csi", "l"], "UvKzKzKz",   [-1, 1, 2], UseGPR=0>;
87  defm sf_vc_v_xv  : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUe",   [-1, 0, 1, 2], UseGPR=1>;
88  defm sf_vc_v_iv  : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvKz",   [-1, 0, 1, 2], UseGPR=0>;
89  defm sf_vc_v_vv  : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUv",   [-1, 0, 1, 2], UseGPR=0>;
90  defm sf_vc_v_fv  : RVVVCIXBuiltinSet<["si",  "l"], "UvKzUvFe",   [-1, 0, 1, 2], UseGPR=0>;
91  defm sf_vc_v_xvv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvUe", [-1, 0, 1, 2, 3], UseGPR=1>;
92  defm sf_vc_v_ivv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvKz", [-1, 0, 1, 2, 3], UseGPR=0>;
93  defm sf_vc_v_vvv : RVVVCIXBuiltinSet<["csi", "l"], "UvKzUvUvUv", [-1, 0, 1, 2, 3], UseGPR=0>;
94  defm sf_vc_v_fvv : RVVVCIXBuiltinSet<["si",  "l"], "UvKzUvUvFe", [-1, 0, 1, 2, 3], UseGPR=0>;
95  let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
96    defm sf_vc_xvw   : RVVVCIXBuiltinSet<["csi"], "0KzUwUvUe",  [0, 1, 2, 3],  UseGPR=1>;
97    defm sf_vc_ivw   : RVVVCIXBuiltinSet<["csi"], "0KzUwUvKz",  [0, 1, 2, 3],  UseGPR=0>;
98    defm sf_vc_vvw   : RVVVCIXBuiltinSet<["csi"], "0KzUwUvUv",  [0, 1, 2, 3],  UseGPR=0>;
99    defm sf_vc_fvw   : RVVVCIXBuiltinSet<["si"],  "0KzUwUvFe",  [0, 1, 2, 3],  UseGPR=0>;
100    defm sf_vc_v_xvw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvUe", [-1, 0, 1, 2, 3], UseGPR=1>;
101    defm sf_vc_v_ivw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvKz", [-1, 0, 1, 2, 3], UseGPR=0>;
102    defm sf_vc_v_vvw : RVVVCIXBuiltinSet<["csi"], "UwKzUwUvUv", [-1, 0, 1, 2, 3], UseGPR=0>;
103    defm sf_vc_v_fvw : RVVVCIXBuiltinSet<["si"],  "UwKzUwUvFe", [-1, 0, 1, 2, 3], UseGPR=0>;
104  }
105}
106
107multiclass RVVVFWMACCBuiltinSet<list<list<string>> suffixes_prototypes> {
108  let OverloadedName = NAME,
109      Name = NAME,
110      HasMasked = false,
111      Log2LMUL = [-2, -1, 0, 1, 2] in
112    defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "y", suffixes_prototypes>;
113}
114
115multiclass RVVVQMACCDODBuiltinSet<list<list<string>> suffixes_prototypes> {
116  let OverloadedName = NAME,
117      Name = NAME,
118      HasMasked = false,
119      Log2LMUL = [0, 1, 2, 3] in
120    defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "i", suffixes_prototypes>;
121}
122
123multiclass RVVVQMACCQOQBuiltinSet<list<list<string>> suffixes_prototypes> {
124  let OverloadedName = NAME,
125      Name = NAME,
126      HasMasked = false,
127      Log2LMUL = [-1, 0, 1, 2] in
128    defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "s", suffixes_prototypes>;
129}
130
131multiclass RVVVFNRCLIPBuiltinSet<string suffix, string prototype, string type_range> {
132  let Log2LMUL = [-3, -2, -1, 0, 1, 2],
133      Name = NAME,
134      IRName = NAME,
135      MaskedIRName = NAME # "_mask" in
136  def : RVVConvBuiltin<suffix, prototype, type_range, NAME>;
137}
138
139let UnMaskedPolicyScheme = HasPolicyOperand in
140  let RequiredFeatures = ["Xsfvqmaccdod"] in {
141    defm sf_vqmaccu_2x8x2 : RVVVQMACCDODBuiltinSet<[["", "v", "vv(FixedSEW:8)SUv(FixedSEW:8)Uv"]]>;
142    defm sf_vqmacc_2x8x2 : RVVVQMACCDODBuiltinSet<[["", "v", "vv(FixedSEW:8)Sv(FixedSEW:8)v"]]>;
143    defm sf_vqmaccus_2x8x2 : RVVVQMACCDODBuiltinSet<[["", "v", "vv(FixedSEW:8)SUv(FixedSEW:8)v"]]>;
144    defm sf_vqmaccsu_2x8x2 : RVVVQMACCDODBuiltinSet<[["", "v", "vv(FixedSEW:8)Sv(FixedSEW:8)Uv"]]>;
145  }
146
147let UnMaskedPolicyScheme = HasPolicyOperand in
148  let RequiredFeatures = ["Xsfvqmaccqoq"] in {
149    defm sf_vqmaccu_4x8x4 : RVVVQMACCQOQBuiltinSet<[["", "w", "ww(FixedSEW:8)SUv(FixedSEW:8)Uv"]]>;
150    defm sf_vqmacc_4x8x4 : RVVVQMACCQOQBuiltinSet<[["", "w", "ww(FixedSEW:8)Sv(FixedSEW:8)v"]]>;
151    defm sf_vqmaccus_4x8x4 : RVVVQMACCQOQBuiltinSet<[["", "w", "ww(FixedSEW:8)SUv(FixedSEW:8)v"]]>;
152    defm sf_vqmaccsu_4x8x4 : RVVVQMACCQOQBuiltinSet<[["", "w", "ww(FixedSEW:8)Sv(FixedSEW:8)Uv"]]>;
153  }
154
155let UnMaskedPolicyScheme = HasPolicyOperand in
156  let RequiredFeatures = ["Xsfvfwmaccqqq"] in
157    defm sf_vfwmacc_4x4x4 : RVVVFWMACCBuiltinSet<[["", "Fw", "FwFwSvv"]]>;
158
159let UnMaskedPolicyScheme = HasPassthruOperand, RequiredFeatures = ["Xsfvfnrclipxfqf"] in {
160let ManualCodegen = [{
161  {
162    // LLVM intrinsic
163    // Unmasked: (passthru, vector_in, scalar_in, frm, vl)
164    // Masked:   (passthru, vector_in, scalar_in, mask, frm, vl, policy)
165
166    SmallVector<llvm::Value*, 7> Operands;
167    bool HasMaskedOff = !(
168        (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
169        (!IsMasked && PolicyAttrs & RVV_VTA));
170    bool HasRoundModeOp = IsMasked ?
171      (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
172      (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
173
174    unsigned Offset = IsMasked ?
175        (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
176
177    if (!HasMaskedOff)
178      Operands.push_back(llvm::PoisonValue::get(ResultType));
179    else
180      Operands.push_back(Ops[IsMasked ? 1 : 0]);
181
182    Operands.push_back(Ops[Offset]); // op0
183    Operands.push_back(Ops[Offset + 1]); // op1
184
185    if (IsMasked)
186      Operands.push_back(Ops[0]); // mask
187
188    if (HasRoundModeOp) {
189      Operands.push_back(Ops[Offset + 2]); // frm
190      Operands.push_back(Ops[Offset + 3]); // vl
191    } else {
192      Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
193      Operands.push_back(Ops[Offset + 2]); // vl
194    }
195
196    if (IsMasked)
197      Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
198
199    IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Operands.back()->getType()};
200    llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
201    return Builder.CreateCall(F, Operands, "");
202  }
203}] in {
204  let HasFRMRoundModeOp = true in {
205    defm sf_vfnrclip_x_f_qf : RVVVFNRCLIPBuiltinSet<"v", "vFqfu", "c">;
206    defm sf_vfnrclip_xu_f_qf : RVVVFNRCLIPBuiltinSet<"Uv", "UvFqfu", "c">;
207  }
208  defm sf_vfnrclip_x_f_qf : RVVVFNRCLIPBuiltinSet<"v", "vFqf", "c">;
209  defm sf_vfnrclip_xu_f_qf : RVVVFNRCLIPBuiltinSet<"Uv", "UvFqf", "c">;
210}
211}
212