xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
1700637cbSDimitry Andric //===-------- RISCV.cpp - Emit LLVM Code for builtins ---------------------===//
2700637cbSDimitry Andric //
3700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6700637cbSDimitry Andric //
7700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8700637cbSDimitry Andric //
9700637cbSDimitry Andric // This contains code to emit Builtin calls as LLVM code.
10700637cbSDimitry Andric //
11700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12700637cbSDimitry Andric 
13700637cbSDimitry Andric #include "CodeGenFunction.h"
14700637cbSDimitry Andric #include "clang/Basic/TargetBuiltins.h"
15700637cbSDimitry Andric #include "llvm/IR/IntrinsicsRISCV.h"
16700637cbSDimitry Andric #include "llvm/TargetParser/RISCVISAInfo.h"
17700637cbSDimitry Andric #include "llvm/TargetParser/RISCVTargetParser.h"
18700637cbSDimitry Andric 
19700637cbSDimitry Andric using namespace clang;
20700637cbSDimitry Andric using namespace CodeGen;
21700637cbSDimitry Andric using namespace llvm;
22700637cbSDimitry Andric 
23*e64bea71SDimitry Andric // The 0th bit simulates the `vta` of RVV
24*e64bea71SDimitry Andric // The 1st bit simulates the `vma` of RVV
25*e64bea71SDimitry Andric static constexpr unsigned RVV_VTA = 0x1;
26*e64bea71SDimitry Andric static constexpr unsigned RVV_VMA = 0x2;
27*e64bea71SDimitry Andric 
28*e64bea71SDimitry Andric // RISC-V Vector builtin helper functions are marked NOINLINE to prevent
29*e64bea71SDimitry Andric // excessive inlining in CodeGenFunction::EmitRISCVBuiltinExpr's large switch
30*e64bea71SDimitry Andric // statement, which would significantly increase compilation time.
31*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVVLEFFBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)32*e64bea71SDimitry Andric emitRVVVLEFFBuiltin(CodeGenFunction *CGF, const CallExpr *E,
33*e64bea71SDimitry Andric                     ReturnValueSlot ReturnValue, llvm::Type *ResultType,
34*e64bea71SDimitry Andric                     Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
35*e64bea71SDimitry Andric                     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
36*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
37*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
38*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
39*e64bea71SDimitry Andric   if (IsMasked) {
40*e64bea71SDimitry Andric     // Move mask to right before vl.
41*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
42*e64bea71SDimitry Andric     if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
43*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
44*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
45*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[4]->getType(), Ops[2]->getType()};
46*e64bea71SDimitry Andric   } else {
47*e64bea71SDimitry Andric     if (PolicyAttrs & RVV_VTA)
48*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
49*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[3]->getType(), Ops[1]->getType()};
50*e64bea71SDimitry Andric   }
51*e64bea71SDimitry Andric   Value *NewVL = Ops[2];
52*e64bea71SDimitry Andric   Ops.erase(Ops.begin() + 2);
53*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
54*e64bea71SDimitry Andric   llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
55*e64bea71SDimitry Andric   llvm::Value *V = Builder.CreateExtractValue(LoadValue, {0});
56*e64bea71SDimitry Andric   // Store new_vl.
57*e64bea71SDimitry Andric   clang::CharUnits Align;
58*e64bea71SDimitry Andric   if (IsMasked)
59*e64bea71SDimitry Andric     Align = CGM.getNaturalPointeeTypeAlignment(
60*e64bea71SDimitry Andric         E->getArg(E->getNumArgs() - 2)->getType());
61*e64bea71SDimitry Andric   else
62*e64bea71SDimitry Andric     Align = CGM.getNaturalPointeeTypeAlignment(E->getArg(1)->getType());
63*e64bea71SDimitry Andric   llvm::Value *Val = Builder.CreateExtractValue(LoadValue, {1});
64*e64bea71SDimitry Andric   Builder.CreateStore(Val, Address(NewVL, Val->getType(), Align));
65*e64bea71SDimitry Andric   return V;
66*e64bea71SDimitry Andric }
67*e64bea71SDimitry Andric 
68*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVVSSEBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)69*e64bea71SDimitry Andric emitRVVVSSEBuiltin(CodeGenFunction *CGF, const CallExpr *E,
70*e64bea71SDimitry Andric                    ReturnValueSlot ReturnValue, llvm::Type *ResultType,
71*e64bea71SDimitry Andric                    Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
72*e64bea71SDimitry Andric                    int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
73*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
74*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
75*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
76*e64bea71SDimitry Andric   if (IsMasked) {
77*e64bea71SDimitry Andric     // Builtin: (mask, ptr, stride, value, vl). Intrinsic: (value, ptr, stride,
78*e64bea71SDimitry Andric     // mask, vl)
79*e64bea71SDimitry Andric     std::swap(Ops[0], Ops[3]);
80*e64bea71SDimitry Andric   } else {
81*e64bea71SDimitry Andric     // Builtin: (ptr, stride, value, vl). Intrinsic: (value, ptr, stride, vl)
82*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
83*e64bea71SDimitry Andric   }
84*e64bea71SDimitry Andric   if (IsMasked)
85*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[4]->getType()};
86*e64bea71SDimitry Andric   else
87*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()};
88*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
89*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
90*e64bea71SDimitry Andric }
91*e64bea71SDimitry Andric 
emitRVVIndexedStoreBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)92*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVIndexedStoreBuiltin(
93*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
94*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
95*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
96*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
97*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
98*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 4> IntrinsicTypes;
99*e64bea71SDimitry Andric   if (IsMasked) {
100*e64bea71SDimitry Andric     // Builtin: (mask, ptr, index, value, vl).
101*e64bea71SDimitry Andric     // Intrinsic: (value, ptr, index, mask, vl)
102*e64bea71SDimitry Andric     std::swap(Ops[0], Ops[3]);
103*e64bea71SDimitry Andric   } else {
104*e64bea71SDimitry Andric     // Builtin: (ptr, index, value, vl).
105*e64bea71SDimitry Andric     // Intrinsic: (value, ptr, index, vl)
106*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
107*e64bea71SDimitry Andric   }
108*e64bea71SDimitry Andric   if (IsMasked)
109*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(),
110*e64bea71SDimitry Andric                       Ops[4]->getType()};
111*e64bea71SDimitry Andric   else
112*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(),
113*e64bea71SDimitry Andric                       Ops[3]->getType()};
114*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
115*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
116*e64bea71SDimitry Andric }
117*e64bea71SDimitry Andric 
118*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVPseudoUnaryBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)119*e64bea71SDimitry Andric emitRVVPseudoUnaryBuiltin(CodeGenFunction *CGF, const CallExpr *E,
120*e64bea71SDimitry Andric                           ReturnValueSlot ReturnValue, llvm::Type *ResultType,
121*e64bea71SDimitry Andric                           Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
122*e64bea71SDimitry Andric                           int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
123*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
124*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
125*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
126*e64bea71SDimitry Andric   if (IsMasked) {
127*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
128*e64bea71SDimitry Andric     if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
129*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
130*e64bea71SDimitry Andric   } else {
131*e64bea71SDimitry Andric     if (PolicyAttrs & RVV_VTA)
132*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
133*e64bea71SDimitry Andric   }
134*e64bea71SDimitry Andric   auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType();
135*e64bea71SDimitry Andric   Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(ElemTy));
136*e64bea71SDimitry Andric   if (IsMasked) {
137*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
138*e64bea71SDimitry Andric     // maskedoff, op1, op2, mask, vl, policy
139*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, ElemTy, Ops[4]->getType()};
140*e64bea71SDimitry Andric   } else {
141*e64bea71SDimitry Andric     // passthru, op1, op2, vl
142*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, ElemTy, Ops[3]->getType()};
143*e64bea71SDimitry Andric   }
144*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
145*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
146*e64bea71SDimitry Andric }
147*e64bea71SDimitry Andric 
148*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVPseudoVNotBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)149*e64bea71SDimitry Andric emitRVVPseudoVNotBuiltin(CodeGenFunction *CGF, const CallExpr *E,
150*e64bea71SDimitry Andric                          ReturnValueSlot ReturnValue, llvm::Type *ResultType,
151*e64bea71SDimitry Andric                          Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
152*e64bea71SDimitry Andric                          int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
153*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
154*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
155*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
156*e64bea71SDimitry Andric   if (IsMasked) {
157*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
158*e64bea71SDimitry Andric     if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
159*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
160*e64bea71SDimitry Andric   } else {
161*e64bea71SDimitry Andric     if (PolicyAttrs & RVV_VTA)
162*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
163*e64bea71SDimitry Andric   }
164*e64bea71SDimitry Andric   auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType();
165*e64bea71SDimitry Andric   Ops.insert(Ops.begin() + 2, llvm::Constant::getAllOnesValue(ElemTy));
166*e64bea71SDimitry Andric   if (IsMasked) {
167*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
168*e64bea71SDimitry Andric     // maskedoff, op1, po2, mask, vl, policy
169*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, ElemTy, Ops[4]->getType()};
170*e64bea71SDimitry Andric   } else {
171*e64bea71SDimitry Andric     // passthru, op1, op2, vl
172*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, ElemTy, Ops[3]->getType()};
173*e64bea71SDimitry Andric   }
174*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
175*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
176*e64bea71SDimitry Andric }
177*e64bea71SDimitry Andric 
178*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVPseudoMaskBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)179*e64bea71SDimitry Andric emitRVVPseudoMaskBuiltin(CodeGenFunction *CGF, const CallExpr *E,
180*e64bea71SDimitry Andric                          ReturnValueSlot ReturnValue, llvm::Type *ResultType,
181*e64bea71SDimitry Andric                          Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
182*e64bea71SDimitry Andric                          int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
183*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
184*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
185*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
186*e64bea71SDimitry Andric   // op1, vl
187*e64bea71SDimitry Andric   IntrinsicTypes = {ResultType, Ops[1]->getType()};
188*e64bea71SDimitry Andric   Ops.insert(Ops.begin() + 1, Ops[0]);
189*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
190*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
191*e64bea71SDimitry Andric }
192*e64bea71SDimitry Andric 
emitRVVPseudoVFUnaryBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)193*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVPseudoVFUnaryBuiltin(
194*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
195*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
196*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
197*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
198*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
199*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
200*e64bea71SDimitry Andric   if (IsMasked) {
201*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
202*e64bea71SDimitry Andric     if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
203*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
204*e64bea71SDimitry Andric     Ops.insert(Ops.begin() + 2, Ops[1]);
205*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
206*e64bea71SDimitry Andric     // maskedoff, op1, op2, mask, vl
207*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops.back()->getType()};
208*e64bea71SDimitry Andric   } else {
209*e64bea71SDimitry Andric     if (PolicyAttrs & RVV_VTA)
210*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
211*e64bea71SDimitry Andric     // op1, po2, vl
212*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType()};
213*e64bea71SDimitry Andric     Ops.insert(Ops.begin() + 2, Ops[1]);
214*e64bea71SDimitry Andric   }
215*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
216*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
217*e64bea71SDimitry Andric }
218*e64bea71SDimitry Andric 
219*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVPseudoVWCVTBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)220*e64bea71SDimitry Andric emitRVVPseudoVWCVTBuiltin(CodeGenFunction *CGF, const CallExpr *E,
221*e64bea71SDimitry Andric                           ReturnValueSlot ReturnValue, llvm::Type *ResultType,
222*e64bea71SDimitry Andric                           Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
223*e64bea71SDimitry Andric                           int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
224*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
225*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
226*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 4> IntrinsicTypes;
227*e64bea71SDimitry Andric   if (IsMasked) {
228*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
229*e64bea71SDimitry Andric     if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
230*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
231*e64bea71SDimitry Andric   } else {
232*e64bea71SDimitry Andric     if (PolicyAttrs & RVV_VTA)
233*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
234*e64bea71SDimitry Andric   }
235*e64bea71SDimitry Andric   auto ElemTy = cast<llvm::VectorType>(Ops[1]->getType())->getElementType();
236*e64bea71SDimitry Andric   Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(ElemTy));
237*e64bea71SDimitry Andric   if (IsMasked) {
238*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
239*e64bea71SDimitry Andric     // maskedoff, op1, op2, mask, vl, policy
240*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[1]->getType(), ElemTy, Ops[4]->getType()};
241*e64bea71SDimitry Andric   } else {
242*e64bea71SDimitry Andric     // passtru, op1, op2, vl
243*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[1]->getType(), ElemTy, Ops[3]->getType()};
244*e64bea71SDimitry Andric   }
245*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
246*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
247*e64bea71SDimitry Andric }
248*e64bea71SDimitry Andric 
249*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVPseudoVNCVTBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)250*e64bea71SDimitry Andric emitRVVPseudoVNCVTBuiltin(CodeGenFunction *CGF, const CallExpr *E,
251*e64bea71SDimitry Andric                           ReturnValueSlot ReturnValue, llvm::Type *ResultType,
252*e64bea71SDimitry Andric                           Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
253*e64bea71SDimitry Andric                           int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
254*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
255*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
256*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 4> IntrinsicTypes;
257*e64bea71SDimitry Andric   if (IsMasked) {
258*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
259*e64bea71SDimitry Andric     if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
260*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
261*e64bea71SDimitry Andric   } else {
262*e64bea71SDimitry Andric     if (PolicyAttrs & RVV_VTA)
263*e64bea71SDimitry Andric       Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
264*e64bea71SDimitry Andric   }
265*e64bea71SDimitry Andric   Ops.insert(Ops.begin() + 2,
266*e64bea71SDimitry Andric              llvm::Constant::getNullValue(Ops.back()->getType()));
267*e64bea71SDimitry Andric   if (IsMasked) {
268*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
269*e64bea71SDimitry Andric     // maskedoff, op1, xlen, mask, vl
270*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[4]->getType(),
271*e64bea71SDimitry Andric                       Ops[4]->getType()};
272*e64bea71SDimitry Andric   } else {
273*e64bea71SDimitry Andric     // passthru, op1, xlen, vl
274*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType(),
275*e64bea71SDimitry Andric                       Ops[3]->getType()};
276*e64bea71SDimitry Andric   }
277*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
278*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
279*e64bea71SDimitry Andric }
280*e64bea71SDimitry Andric 
281*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVVlenbBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)282*e64bea71SDimitry Andric emitRVVVlenbBuiltin(CodeGenFunction *CGF, const CallExpr *E,
283*e64bea71SDimitry Andric                     ReturnValueSlot ReturnValue, llvm::Type *ResultType,
284*e64bea71SDimitry Andric                     Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
285*e64bea71SDimitry Andric                     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
286*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
287*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
288*e64bea71SDimitry Andric   LLVMContext &Context = CGM.getLLVMContext();
289*e64bea71SDimitry Andric   llvm::MDBuilder MDHelper(Context);
290*e64bea71SDimitry Andric   llvm::Metadata *OpsMD[] = {llvm::MDString::get(Context, "vlenb")};
291*e64bea71SDimitry Andric   llvm::MDNode *RegName = llvm::MDNode::get(Context, OpsMD);
292*e64bea71SDimitry Andric   llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
293*e64bea71SDimitry Andric   llvm::Function *F =
294*e64bea71SDimitry Andric       CGM.getIntrinsic(llvm::Intrinsic::read_register, {CGF->SizeTy});
295*e64bea71SDimitry Andric   return Builder.CreateCall(F, Metadata);
296*e64bea71SDimitry Andric }
297*e64bea71SDimitry Andric 
298*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVVsetvliBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)299*e64bea71SDimitry Andric emitRVVVsetvliBuiltin(CodeGenFunction *CGF, const CallExpr *E,
300*e64bea71SDimitry Andric                       ReturnValueSlot ReturnValue, llvm::Type *ResultType,
301*e64bea71SDimitry Andric                       Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
302*e64bea71SDimitry Andric                       int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
303*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
304*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
305*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, {ResultType});
306*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
307*e64bea71SDimitry Andric }
308*e64bea71SDimitry Andric 
309*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVVSEMaskBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)310*e64bea71SDimitry Andric emitRVVVSEMaskBuiltin(CodeGenFunction *CGF, const CallExpr *E,
311*e64bea71SDimitry Andric                       ReturnValueSlot ReturnValue, llvm::Type *ResultType,
312*e64bea71SDimitry Andric                       Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
313*e64bea71SDimitry Andric                       int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
314*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
315*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
316*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
317*e64bea71SDimitry Andric   if (IsMasked) {
318*e64bea71SDimitry Andric     // Builtin: (mask, ptr, value, vl).
319*e64bea71SDimitry Andric     // Intrinsic: (value, ptr, mask, vl)
320*e64bea71SDimitry Andric     std::swap(Ops[0], Ops[2]);
321*e64bea71SDimitry Andric   } else {
322*e64bea71SDimitry Andric     // Builtin: (ptr, value, vl).
323*e64bea71SDimitry Andric     // Intrinsic: (value, ptr, vl)
324*e64bea71SDimitry Andric     std::swap(Ops[0], Ops[1]);
325*e64bea71SDimitry Andric   }
326*e64bea71SDimitry Andric   if (IsMasked)
327*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()};
328*e64bea71SDimitry Andric   else
329*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()};
330*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
331*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
332*e64bea71SDimitry Andric }
333*e64bea71SDimitry Andric 
emitRVVUnitStridedSegLoadTupleBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)334*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVUnitStridedSegLoadTupleBuiltin(
335*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
336*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
337*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
338*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
339*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
340*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 4> IntrinsicTypes;
341*e64bea71SDimitry Andric   bool NoPassthru =
342*e64bea71SDimitry Andric       (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
343*e64bea71SDimitry Andric       (!IsMasked && (PolicyAttrs & RVV_VTA));
344*e64bea71SDimitry Andric   unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
345*e64bea71SDimitry Andric   if (IsMasked)
346*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[0]->getType(),
347*e64bea71SDimitry Andric                       Ops.back()->getType()};
348*e64bea71SDimitry Andric   else
349*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
350*e64bea71SDimitry Andric                       Ops.back()->getType()};
351*e64bea71SDimitry Andric   if (IsMasked)
352*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
353*e64bea71SDimitry Andric   if (NoPassthru)
354*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
355*e64bea71SDimitry Andric   if (IsMasked)
356*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
357*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
358*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
359*e64bea71SDimitry Andric   llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
360*e64bea71SDimitry Andric   if (ReturnValue.isNull())
361*e64bea71SDimitry Andric     return LoadValue;
362*e64bea71SDimitry Andric   return Builder.CreateStore(LoadValue, ReturnValue.getValue());
363*e64bea71SDimitry Andric }
364*e64bea71SDimitry Andric 
emitRVVUnitStridedSegStoreTupleBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)365*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVUnitStridedSegStoreTupleBuiltin(
366*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
367*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
368*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
369*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
370*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
371*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 4> IntrinsicTypes;
372*e64bea71SDimitry Andric   // Masked
373*e64bea71SDimitry Andric   // Builtin: (mask, ptr, v_tuple, vl)
374*e64bea71SDimitry Andric   // Intrinsic: (tuple, ptr, mask, vl, SegInstSEW)
375*e64bea71SDimitry Andric   // Unmasked
376*e64bea71SDimitry Andric   // Builtin: (ptr, v_tuple, vl)
377*e64bea71SDimitry Andric   // Intrinsic: (tuple, ptr, vl, SegInstSEW)
378*e64bea71SDimitry Andric   if (IsMasked)
379*e64bea71SDimitry Andric     std::swap(Ops[0], Ops[2]);
380*e64bea71SDimitry Andric   else
381*e64bea71SDimitry Andric     std::swap(Ops[0], Ops[1]);
382*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
383*e64bea71SDimitry Andric   if (IsMasked)
384*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(),
385*e64bea71SDimitry Andric                       Ops[3]->getType()};
386*e64bea71SDimitry Andric   else
387*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()};
388*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
389*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
390*e64bea71SDimitry Andric }
391*e64bea71SDimitry Andric 
emitRVVUnitStridedSegLoadFFTupleBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)392*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVUnitStridedSegLoadFFTupleBuiltin(
393*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
394*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
395*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
396*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
397*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
398*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 4> IntrinsicTypes;
399*e64bea71SDimitry Andric   bool NoPassthru =
400*e64bea71SDimitry Andric       (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
401*e64bea71SDimitry Andric       (!IsMasked && (PolicyAttrs & RVV_VTA));
402*e64bea71SDimitry Andric   unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
403*e64bea71SDimitry Andric   if (IsMasked)
404*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType(),
405*e64bea71SDimitry Andric                       Ops[0]->getType()};
406*e64bea71SDimitry Andric   else
407*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops.back()->getType(),
408*e64bea71SDimitry Andric                       Ops[Offset]->getType()};
409*e64bea71SDimitry Andric   if (IsMasked)
410*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
411*e64bea71SDimitry Andric   if (NoPassthru)
412*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
413*e64bea71SDimitry Andric   if (IsMasked)
414*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
415*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
416*e64bea71SDimitry Andric   Value *NewVL = Ops[2];
417*e64bea71SDimitry Andric   Ops.erase(Ops.begin() + 2);
418*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
419*e64bea71SDimitry Andric   llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
420*e64bea71SDimitry Andric   // Get alignment from the new vl operand
421*e64bea71SDimitry Andric   clang::CharUnits Align =
422*e64bea71SDimitry Andric       CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType());
423*e64bea71SDimitry Andric   llvm::Value *ReturnTuple = Builder.CreateExtractValue(LoadValue, 0);
424*e64bea71SDimitry Andric   // Store new_vl
425*e64bea71SDimitry Andric   llvm::Value *V = Builder.CreateExtractValue(LoadValue, 1);
426*e64bea71SDimitry Andric   Builder.CreateStore(V, Address(NewVL, V->getType(), Align));
427*e64bea71SDimitry Andric   if (ReturnValue.isNull())
428*e64bea71SDimitry Andric     return ReturnTuple;
429*e64bea71SDimitry Andric   return Builder.CreateStore(ReturnTuple, ReturnValue.getValue());
430*e64bea71SDimitry Andric }
431*e64bea71SDimitry Andric 
emitRVVStridedSegLoadTupleBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)432*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVStridedSegLoadTupleBuiltin(
433*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
434*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
435*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
436*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
437*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
438*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 4> IntrinsicTypes;
439*e64bea71SDimitry Andric   bool NoPassthru =
440*e64bea71SDimitry Andric       (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
441*e64bea71SDimitry Andric       (!IsMasked && (PolicyAttrs & RVV_VTA));
442*e64bea71SDimitry Andric   unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
443*e64bea71SDimitry Andric   if (IsMasked)
444*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType(),
445*e64bea71SDimitry Andric                       Ops[0]->getType()};
446*e64bea71SDimitry Andric   else
447*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
448*e64bea71SDimitry Andric                       Ops.back()->getType()};
449*e64bea71SDimitry Andric   if (IsMasked)
450*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
451*e64bea71SDimitry Andric   if (NoPassthru)
452*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
453*e64bea71SDimitry Andric   if (IsMasked)
454*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
455*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
456*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
457*e64bea71SDimitry Andric   llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
458*e64bea71SDimitry Andric   if (ReturnValue.isNull())
459*e64bea71SDimitry Andric     return LoadValue;
460*e64bea71SDimitry Andric   return Builder.CreateStore(LoadValue, ReturnValue.getValue());
461*e64bea71SDimitry Andric }
462*e64bea71SDimitry Andric 
emitRVVStridedSegStoreTupleBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)463*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVStridedSegStoreTupleBuiltin(
464*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
465*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
466*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
467*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
468*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
469*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 4> IntrinsicTypes;
470*e64bea71SDimitry Andric   // Masked
471*e64bea71SDimitry Andric   // Builtin: (mask, ptr, stride, v_tuple, vl)
472*e64bea71SDimitry Andric   // Intrinsic: (tuple, ptr, stride, mask, vl, SegInstSEW)
473*e64bea71SDimitry Andric   // Unmasked
474*e64bea71SDimitry Andric   // Builtin: (ptr, stride, v_tuple, vl)
475*e64bea71SDimitry Andric   // Intrinsic: (tuple, ptr, stride, vl, SegInstSEW)
476*e64bea71SDimitry Andric   if (IsMasked)
477*e64bea71SDimitry Andric     std::swap(Ops[0], Ops[3]);
478*e64bea71SDimitry Andric   else
479*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
480*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
481*e64bea71SDimitry Andric   if (IsMasked)
482*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[4]->getType(),
483*e64bea71SDimitry Andric                       Ops[3]->getType()};
484*e64bea71SDimitry Andric   else
485*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()};
486*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
487*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
488*e64bea71SDimitry Andric }
489*e64bea71SDimitry Andric 
490*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVAveragingBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)491*e64bea71SDimitry Andric emitRVVAveragingBuiltin(CodeGenFunction *CGF, const CallExpr *E,
492*e64bea71SDimitry Andric                         ReturnValueSlot ReturnValue, llvm::Type *ResultType,
493*e64bea71SDimitry Andric                         Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
494*e64bea71SDimitry Andric                         int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
495*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
496*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
497*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
498*e64bea71SDimitry Andric   // LLVM intrinsic
499*e64bea71SDimitry Andric   // Unmasked: (passthru, op0, op1, round_mode, vl)
500*e64bea71SDimitry Andric   // Masked:   (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl,
501*e64bea71SDimitry Andric   // policy)
502*e64bea71SDimitry Andric 
503*e64bea71SDimitry Andric   bool HasMaskedOff =
504*e64bea71SDimitry Andric       !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
505*e64bea71SDimitry Andric         (!IsMasked && PolicyAttrs & RVV_VTA));
506*e64bea71SDimitry Andric 
507*e64bea71SDimitry Andric   if (IsMasked)
508*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
509*e64bea71SDimitry Andric 
510*e64bea71SDimitry Andric   if (!HasMaskedOff)
511*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
512*e64bea71SDimitry Andric 
513*e64bea71SDimitry Andric   if (IsMasked)
514*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
515*e64bea71SDimitry Andric 
516*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(
517*e64bea71SDimitry Andric       ID, {ResultType, Ops[2]->getType(), Ops.back()->getType()});
518*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
519*e64bea71SDimitry Andric }
520*e64bea71SDimitry Andric 
emitRVVNarrowingClipBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)521*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVNarrowingClipBuiltin(
522*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
523*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
524*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
525*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
526*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
527*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
528*e64bea71SDimitry Andric   // LLVM intrinsic
529*e64bea71SDimitry Andric   // Unmasked: (passthru, op0, op1, round_mode, vl)
530*e64bea71SDimitry Andric   // Masked:   (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl,
531*e64bea71SDimitry Andric   // policy)
532*e64bea71SDimitry Andric 
533*e64bea71SDimitry Andric   bool HasMaskedOff =
534*e64bea71SDimitry Andric       !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
535*e64bea71SDimitry Andric         (!IsMasked && PolicyAttrs & RVV_VTA));
536*e64bea71SDimitry Andric 
537*e64bea71SDimitry Andric   if (IsMasked)
538*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
539*e64bea71SDimitry Andric 
540*e64bea71SDimitry Andric   if (!HasMaskedOff)
541*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
542*e64bea71SDimitry Andric 
543*e64bea71SDimitry Andric   if (IsMasked)
544*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
545*e64bea71SDimitry Andric 
546*e64bea71SDimitry Andric   llvm::Function *F =
547*e64bea71SDimitry Andric       CGM.getIntrinsic(ID, {ResultType, Ops[1]->getType(), Ops[2]->getType(),
548*e64bea71SDimitry Andric                             Ops.back()->getType()});
549*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
550*e64bea71SDimitry Andric }
551*e64bea71SDimitry Andric 
emitRVVFloatingPointBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)552*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVFloatingPointBuiltin(
553*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
554*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
555*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
556*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
557*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
558*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
559*e64bea71SDimitry Andric   // LLVM intrinsic
560*e64bea71SDimitry Andric   // Unmasked: (passthru, op0, op1, round_mode, vl)
561*e64bea71SDimitry Andric   // Masked:   (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
562*e64bea71SDimitry Andric 
563*e64bea71SDimitry Andric   bool HasMaskedOff =
564*e64bea71SDimitry Andric       !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
565*e64bea71SDimitry Andric         (!IsMasked && PolicyAttrs & RVV_VTA));
566*e64bea71SDimitry Andric   bool HasRoundModeOp =
567*e64bea71SDimitry Andric       IsMasked ? (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5)
568*e64bea71SDimitry Andric                : (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
569*e64bea71SDimitry Andric 
570*e64bea71SDimitry Andric   if (!HasRoundModeOp)
571*e64bea71SDimitry Andric     Ops.insert(Ops.end() - 1,
572*e64bea71SDimitry Andric                ConstantInt::get(Ops.back()->getType(), 7)); // frm
573*e64bea71SDimitry Andric 
574*e64bea71SDimitry Andric   if (IsMasked)
575*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
576*e64bea71SDimitry Andric 
577*e64bea71SDimitry Andric   if (!HasMaskedOff)
578*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
579*e64bea71SDimitry Andric 
580*e64bea71SDimitry Andric   if (IsMasked)
581*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
582*e64bea71SDimitry Andric 
583*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(
584*e64bea71SDimitry Andric       ID, {ResultType, Ops[2]->getType(), Ops.back()->getType()});
585*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
586*e64bea71SDimitry Andric }
587*e64bea71SDimitry Andric 
emitRVVWideningFloatingPointBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)588*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVWideningFloatingPointBuiltin(
589*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
590*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
591*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
592*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
593*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
594*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
595*e64bea71SDimitry Andric   // LLVM intrinsic
596*e64bea71SDimitry Andric   // Unmasked: (passthru, op0, op1, round_mode, vl)
597*e64bea71SDimitry Andric   // Masked:   (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
598*e64bea71SDimitry Andric 
599*e64bea71SDimitry Andric   bool HasMaskedOff =
600*e64bea71SDimitry Andric       !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
601*e64bea71SDimitry Andric         (!IsMasked && PolicyAttrs & RVV_VTA));
602*e64bea71SDimitry Andric   bool HasRoundModeOp =
603*e64bea71SDimitry Andric       IsMasked ? (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5)
604*e64bea71SDimitry Andric                : (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
605*e64bea71SDimitry Andric 
606*e64bea71SDimitry Andric   if (!HasRoundModeOp)
607*e64bea71SDimitry Andric     Ops.insert(Ops.end() - 1,
608*e64bea71SDimitry Andric                ConstantInt::get(Ops.back()->getType(), 7)); // frm
609*e64bea71SDimitry Andric 
610*e64bea71SDimitry Andric   if (IsMasked)
611*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
612*e64bea71SDimitry Andric 
613*e64bea71SDimitry Andric   if (!HasMaskedOff)
614*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
615*e64bea71SDimitry Andric 
616*e64bea71SDimitry Andric   if (IsMasked)
617*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
618*e64bea71SDimitry Andric 
619*e64bea71SDimitry Andric   llvm::Function *F =
620*e64bea71SDimitry Andric       CGM.getIntrinsic(ID, {ResultType, Ops[1]->getType(), Ops[2]->getType(),
621*e64bea71SDimitry Andric                             Ops.back()->getType()});
622*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
623*e64bea71SDimitry Andric }
624*e64bea71SDimitry Andric 
emitRVVIndexedSegLoadTupleBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)625*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVIndexedSegLoadTupleBuiltin(
626*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
627*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
628*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
629*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
630*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
631*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 5> IntrinsicTypes;
632*e64bea71SDimitry Andric 
633*e64bea71SDimitry Andric   bool NoPassthru =
634*e64bea71SDimitry Andric       (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
635*e64bea71SDimitry Andric       (!IsMasked && (PolicyAttrs & RVV_VTA));
636*e64bea71SDimitry Andric 
637*e64bea71SDimitry Andric   if (IsMasked)
638*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
639*e64bea71SDimitry Andric   if (NoPassthru)
640*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
641*e64bea71SDimitry Andric 
642*e64bea71SDimitry Andric   if (IsMasked)
643*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
644*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
645*e64bea71SDimitry Andric 
646*e64bea71SDimitry Andric   if (IsMasked)
647*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(),
648*e64bea71SDimitry Andric                       Ops[3]->getType(), Ops[4]->getType()};
649*e64bea71SDimitry Andric   else
650*e64bea71SDimitry Andric     IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType(),
651*e64bea71SDimitry Andric                       Ops[3]->getType()};
652*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
653*e64bea71SDimitry Andric   llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
654*e64bea71SDimitry Andric 
655*e64bea71SDimitry Andric   if (ReturnValue.isNull())
656*e64bea71SDimitry Andric     return LoadValue;
657*e64bea71SDimitry Andric   return Builder.CreateStore(LoadValue, ReturnValue.getValue());
658*e64bea71SDimitry Andric }
659*e64bea71SDimitry Andric 
emitRVVIndexedSegStoreTupleBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)660*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVIndexedSegStoreTupleBuiltin(
661*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
662*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
663*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
664*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
665*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
666*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 5> IntrinsicTypes;
667*e64bea71SDimitry Andric   // Masked
668*e64bea71SDimitry Andric   // Builtin: (mask, ptr, index, v_tuple, vl)
669*e64bea71SDimitry Andric   // Intrinsic: (tuple, ptr, index, mask, vl, SegInstSEW)
670*e64bea71SDimitry Andric   // Unmasked
671*e64bea71SDimitry Andric   // Builtin: (ptr, index, v_tuple, vl)
672*e64bea71SDimitry Andric   // Intrinsic: (tuple, ptr, index, vl, SegInstSEW)
673*e64bea71SDimitry Andric 
674*e64bea71SDimitry Andric   if (IsMasked)
675*e64bea71SDimitry Andric     std::swap(Ops[0], Ops[3]);
676*e64bea71SDimitry Andric   else
677*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
678*e64bea71SDimitry Andric 
679*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
680*e64bea71SDimitry Andric 
681*e64bea71SDimitry Andric   if (IsMasked)
682*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(),
683*e64bea71SDimitry Andric                       Ops[3]->getType(), Ops[4]->getType()};
684*e64bea71SDimitry Andric   else
685*e64bea71SDimitry Andric     IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(),
686*e64bea71SDimitry Andric                       Ops[3]->getType()};
687*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
688*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
689*e64bea71SDimitry Andric }
690*e64bea71SDimitry Andric 
691*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVFMABuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)692*e64bea71SDimitry Andric emitRVVFMABuiltin(CodeGenFunction *CGF, const CallExpr *E,
693*e64bea71SDimitry Andric                   ReturnValueSlot ReturnValue, llvm::Type *ResultType,
694*e64bea71SDimitry Andric                   Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
695*e64bea71SDimitry Andric                   int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
696*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
697*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
698*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
699*e64bea71SDimitry Andric   // LLVM intrinsic
700*e64bea71SDimitry Andric   // Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode,
701*e64bea71SDimitry Andric   //            vl, policy)
702*e64bea71SDimitry Andric   // Masked:   (vector_in, vector_in/scalar_in, vector_in, mask, frm,
703*e64bea71SDimitry Andric   //            vl, policy)
704*e64bea71SDimitry Andric 
705*e64bea71SDimitry Andric   bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
706*e64bea71SDimitry Andric 
707*e64bea71SDimitry Andric   if (!HasRoundModeOp)
708*e64bea71SDimitry Andric     Ops.insert(Ops.end() - 1,
709*e64bea71SDimitry Andric                ConstantInt::get(Ops.back()->getType(), 7)); // frm
710*e64bea71SDimitry Andric 
711*e64bea71SDimitry Andric   if (IsMasked)
712*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
713*e64bea71SDimitry Andric 
714*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
715*e64bea71SDimitry Andric 
716*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(
717*e64bea71SDimitry Andric       ID, {ResultType, Ops[1]->getType(), Ops.back()->getType()});
718*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
719*e64bea71SDimitry Andric }
720*e64bea71SDimitry Andric 
721*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVWideningFMABuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)722*e64bea71SDimitry Andric emitRVVWideningFMABuiltin(CodeGenFunction *CGF, const CallExpr *E,
723*e64bea71SDimitry Andric                           ReturnValueSlot ReturnValue, llvm::Type *ResultType,
724*e64bea71SDimitry Andric                           Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
725*e64bea71SDimitry Andric                           int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
726*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
727*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
728*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
729*e64bea71SDimitry Andric   // LLVM intrinsic
730*e64bea71SDimitry Andric   // Unmasked: (vector_in, vector_in/scalar_in, vector_in, round_mode, vl,
731*e64bea71SDimitry Andric   // policy) Masked:   (vector_in, vector_in/scalar_in, vector_in, mask, frm,
732*e64bea71SDimitry Andric   // vl, policy)
733*e64bea71SDimitry Andric 
734*e64bea71SDimitry Andric   bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
735*e64bea71SDimitry Andric 
736*e64bea71SDimitry Andric   if (!HasRoundModeOp)
737*e64bea71SDimitry Andric     Ops.insert(Ops.end() - 1,
738*e64bea71SDimitry Andric                ConstantInt::get(Ops.back()->getType(), 7)); // frm
739*e64bea71SDimitry Andric 
740*e64bea71SDimitry Andric   if (IsMasked)
741*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 4);
742*e64bea71SDimitry Andric 
743*e64bea71SDimitry Andric   Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
744*e64bea71SDimitry Andric 
745*e64bea71SDimitry Andric   llvm::Function *F =
746*e64bea71SDimitry Andric       CGM.getIntrinsic(ID, {ResultType, Ops[1]->getType(), Ops[2]->getType(),
747*e64bea71SDimitry Andric                             Ops.back()->getType()});
748*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
749*e64bea71SDimitry Andric }
750*e64bea71SDimitry Andric 
emitRVVFloatingUnaryBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)751*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVFloatingUnaryBuiltin(
752*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
753*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
754*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
755*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
756*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
757*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
758*e64bea71SDimitry Andric   // LLVM intrinsic
759*e64bea71SDimitry Andric   // Unmasked: (passthru, op0, round_mode, vl)
760*e64bea71SDimitry Andric   // Masked:   (passthru, op0, mask, frm, vl, policy)
761*e64bea71SDimitry Andric 
762*e64bea71SDimitry Andric   bool HasMaskedOff =
763*e64bea71SDimitry Andric       !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
764*e64bea71SDimitry Andric         (!IsMasked && PolicyAttrs & RVV_VTA));
765*e64bea71SDimitry Andric   bool HasRoundModeOp =
766*e64bea71SDimitry Andric       IsMasked ? (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4)
767*e64bea71SDimitry Andric                : (HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
768*e64bea71SDimitry Andric 
769*e64bea71SDimitry Andric   if (!HasRoundModeOp)
770*e64bea71SDimitry Andric     Ops.insert(Ops.end() - 1,
771*e64bea71SDimitry Andric                ConstantInt::get(Ops.back()->getType(), 7)); // frm
772*e64bea71SDimitry Andric 
773*e64bea71SDimitry Andric   if (IsMasked)
774*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
775*e64bea71SDimitry Andric 
776*e64bea71SDimitry Andric   if (!HasMaskedOff)
777*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
778*e64bea71SDimitry Andric 
779*e64bea71SDimitry Andric   if (IsMasked)
780*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
781*e64bea71SDimitry Andric 
782*e64bea71SDimitry Andric   IntrinsicTypes = {ResultType, Ops.back()->getType()};
783*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
784*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
785*e64bea71SDimitry Andric }
786*e64bea71SDimitry Andric 
emitRVVFloatingConvBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)787*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVFloatingConvBuiltin(
788*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
789*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
790*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
791*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
792*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
793*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
794*e64bea71SDimitry Andric   // LLVM intrinsic
795*e64bea71SDimitry Andric   // Unmasked: (passthru, op0, frm, vl)
796*e64bea71SDimitry Andric   // Masked:   (passthru, op0, mask, frm, vl, policy)
797*e64bea71SDimitry Andric   bool HasMaskedOff =
798*e64bea71SDimitry Andric       !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
799*e64bea71SDimitry Andric         (!IsMasked && PolicyAttrs & RVV_VTA));
800*e64bea71SDimitry Andric   bool HasRoundModeOp =
801*e64bea71SDimitry Andric       IsMasked ? (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4)
802*e64bea71SDimitry Andric                : (HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
803*e64bea71SDimitry Andric 
804*e64bea71SDimitry Andric   if (!HasRoundModeOp)
805*e64bea71SDimitry Andric     Ops.insert(Ops.end() - 1,
806*e64bea71SDimitry Andric                ConstantInt::get(Ops.back()->getType(), 7)); // frm
807*e64bea71SDimitry Andric 
808*e64bea71SDimitry Andric   if (IsMasked)
809*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
810*e64bea71SDimitry Andric 
811*e64bea71SDimitry Andric   if (!HasMaskedOff)
812*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
813*e64bea71SDimitry Andric 
814*e64bea71SDimitry Andric   if (IsMasked)
815*e64bea71SDimitry Andric     Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
816*e64bea71SDimitry Andric 
817*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(
818*e64bea71SDimitry Andric       ID, {ResultType, Ops[1]->getType(), Ops.back()->getType()});
819*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
820*e64bea71SDimitry Andric }
821*e64bea71SDimitry Andric 
emitRVVFloatingReductionBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)822*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *emitRVVFloatingReductionBuiltin(
823*e64bea71SDimitry Andric     CodeGenFunction *CGF, const CallExpr *E, ReturnValueSlot ReturnValue,
824*e64bea71SDimitry Andric     llvm::Type *ResultType, Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
825*e64bea71SDimitry Andric     int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
826*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
827*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
828*e64bea71SDimitry Andric   llvm::SmallVector<llvm::Type *, 3> IntrinsicTypes;
829*e64bea71SDimitry Andric   // LLVM intrinsic
830*e64bea71SDimitry Andric   // Unmasked: (passthru, op0, op1, round_mode, vl)
831*e64bea71SDimitry Andric   // Masked:   (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
832*e64bea71SDimitry Andric 
833*e64bea71SDimitry Andric   bool HasMaskedOff =
834*e64bea71SDimitry Andric       !((IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
835*e64bea71SDimitry Andric         (!IsMasked && PolicyAttrs & RVV_VTA));
836*e64bea71SDimitry Andric   bool HasRoundModeOp =
837*e64bea71SDimitry Andric       IsMasked ? (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5)
838*e64bea71SDimitry Andric                : (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
839*e64bea71SDimitry Andric 
840*e64bea71SDimitry Andric   if (!HasRoundModeOp)
841*e64bea71SDimitry Andric     Ops.insert(Ops.end() - 1,
842*e64bea71SDimitry Andric                ConstantInt::get(Ops.back()->getType(), 7)); // frm
843*e64bea71SDimitry Andric 
844*e64bea71SDimitry Andric   if (IsMasked)
845*e64bea71SDimitry Andric     std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 2);
846*e64bea71SDimitry Andric 
847*e64bea71SDimitry Andric   if (!HasMaskedOff)
848*e64bea71SDimitry Andric     Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
849*e64bea71SDimitry Andric 
850*e64bea71SDimitry Andric   llvm::Function *F = CGM.getIntrinsic(
851*e64bea71SDimitry Andric       ID, {ResultType, Ops[1]->getType(), Ops.back()->getType()});
852*e64bea71SDimitry Andric   return Builder.CreateCall(F, Ops, "");
853*e64bea71SDimitry Andric }
854*e64bea71SDimitry Andric 
855*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVReinterpretBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)856*e64bea71SDimitry Andric emitRVVReinterpretBuiltin(CodeGenFunction *CGF, const CallExpr *E,
857*e64bea71SDimitry Andric                           ReturnValueSlot ReturnValue, llvm::Type *ResultType,
858*e64bea71SDimitry Andric                           Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
859*e64bea71SDimitry Andric                           int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
860*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
861*e64bea71SDimitry Andric   auto &CGM = CGF->CGM;
862*e64bea71SDimitry Andric 
863*e64bea71SDimitry Andric   if (ResultType->isIntOrIntVectorTy(1) ||
864*e64bea71SDimitry Andric       Ops[0]->getType()->isIntOrIntVectorTy(1)) {
865*e64bea71SDimitry Andric     assert(isa<ScalableVectorType>(ResultType) &&
866*e64bea71SDimitry Andric            isa<ScalableVectorType>(Ops[0]->getType()));
867*e64bea71SDimitry Andric 
868*e64bea71SDimitry Andric     LLVMContext &Context = CGM.getLLVMContext();
869*e64bea71SDimitry Andric     ScalableVectorType *Boolean64Ty =
870*e64bea71SDimitry Andric         ScalableVectorType::get(llvm::Type::getInt1Ty(Context), 64);
871*e64bea71SDimitry Andric 
872*e64bea71SDimitry Andric     if (ResultType->isIntOrIntVectorTy(1)) {
873*e64bea71SDimitry Andric       // Casting from m1 vector integer -> vector boolean
874*e64bea71SDimitry Andric       // Ex: <vscale x 8 x i8>
875*e64bea71SDimitry Andric       //     --(bitcast)--------> <vscale x 64 x i1>
876*e64bea71SDimitry Andric       //     --(vector_extract)-> <vscale x  8 x i1>
877*e64bea71SDimitry Andric       llvm::Value *BitCast = Builder.CreateBitCast(Ops[0], Boolean64Ty);
878*e64bea71SDimitry Andric       return Builder.CreateExtractVector(ResultType, BitCast,
879*e64bea71SDimitry Andric                                          ConstantInt::get(CGF->Int64Ty, 0));
880*e64bea71SDimitry Andric     } else {
881*e64bea71SDimitry Andric       // Casting from vector boolean -> m1 vector integer
882*e64bea71SDimitry Andric       // Ex: <vscale x  1 x i1>
883*e64bea71SDimitry Andric       //       --(vector_insert)-> <vscale x 64 x i1>
884*e64bea71SDimitry Andric       //       --(bitcast)-------> <vscale x  8 x i8>
885*e64bea71SDimitry Andric       llvm::Value *Boolean64Val = Builder.CreateInsertVector(
886*e64bea71SDimitry Andric           Boolean64Ty, llvm::PoisonValue::get(Boolean64Ty), Ops[0],
887*e64bea71SDimitry Andric           ConstantInt::get(CGF->Int64Ty, 0));
888*e64bea71SDimitry Andric       return Builder.CreateBitCast(Boolean64Val, ResultType);
889*e64bea71SDimitry Andric     }
890*e64bea71SDimitry Andric   }
891*e64bea71SDimitry Andric   return Builder.CreateBitCast(Ops[0], ResultType);
892*e64bea71SDimitry Andric }
893*e64bea71SDimitry Andric 
894*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVGetBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)895*e64bea71SDimitry Andric emitRVVGetBuiltin(CodeGenFunction *CGF, const CallExpr *E,
896*e64bea71SDimitry Andric                   ReturnValueSlot ReturnValue, llvm::Type *ResultType,
897*e64bea71SDimitry Andric                   Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
898*e64bea71SDimitry Andric                   int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
899*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
900*e64bea71SDimitry Andric   auto *VecTy = cast<ScalableVectorType>(ResultType);
901*e64bea71SDimitry Andric   if (auto *OpVecTy = dyn_cast<ScalableVectorType>(Ops[0]->getType())) {
902*e64bea71SDimitry Andric     unsigned MaxIndex =
903*e64bea71SDimitry Andric         OpVecTy->getMinNumElements() / VecTy->getMinNumElements();
904*e64bea71SDimitry Andric     assert(isPowerOf2_32(MaxIndex));
905*e64bea71SDimitry Andric     // Mask to only valid indices.
906*e64bea71SDimitry Andric     Ops[1] = Builder.CreateZExt(Ops[1], Builder.getInt64Ty());
907*e64bea71SDimitry Andric     Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1);
908*e64bea71SDimitry Andric     Ops[1] =
909*e64bea71SDimitry Andric         Builder.CreateMul(Ops[1], ConstantInt::get(Ops[1]->getType(),
910*e64bea71SDimitry Andric                                                    VecTy->getMinNumElements()));
911*e64bea71SDimitry Andric     return Builder.CreateExtractVector(ResultType, Ops[0], Ops[1]);
912*e64bea71SDimitry Andric   }
913*e64bea71SDimitry Andric 
914*e64bea71SDimitry Andric   return Builder.CreateIntrinsic(
915*e64bea71SDimitry Andric       Intrinsic::riscv_tuple_extract, {ResultType, Ops[0]->getType()},
916*e64bea71SDimitry Andric       {Ops[0], Builder.CreateTrunc(Ops[1], Builder.getInt32Ty())});
917*e64bea71SDimitry Andric }
918*e64bea71SDimitry Andric 
919*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVSetBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)920*e64bea71SDimitry Andric emitRVVSetBuiltin(CodeGenFunction *CGF, const CallExpr *E,
921*e64bea71SDimitry Andric                   ReturnValueSlot ReturnValue, llvm::Type *ResultType,
922*e64bea71SDimitry Andric                   Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
923*e64bea71SDimitry Andric                   int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
924*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
925*e64bea71SDimitry Andric   if (auto *ResVecTy = dyn_cast<ScalableVectorType>(ResultType)) {
926*e64bea71SDimitry Andric     auto *VecTy = cast<ScalableVectorType>(Ops[2]->getType());
927*e64bea71SDimitry Andric     unsigned MaxIndex =
928*e64bea71SDimitry Andric         ResVecTy->getMinNumElements() / VecTy->getMinNumElements();
929*e64bea71SDimitry Andric     assert(isPowerOf2_32(MaxIndex));
930*e64bea71SDimitry Andric     // Mask to only valid indices.
931*e64bea71SDimitry Andric     Ops[1] = Builder.CreateZExt(Ops[1], Builder.getInt64Ty());
932*e64bea71SDimitry Andric     Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1);
933*e64bea71SDimitry Andric     Ops[1] =
934*e64bea71SDimitry Andric         Builder.CreateMul(Ops[1], ConstantInt::get(Ops[1]->getType(),
935*e64bea71SDimitry Andric                                                    VecTy->getMinNumElements()));
936*e64bea71SDimitry Andric     return Builder.CreateInsertVector(ResultType, Ops[0], Ops[2], Ops[1]);
937*e64bea71SDimitry Andric   }
938*e64bea71SDimitry Andric 
939*e64bea71SDimitry Andric   return Builder.CreateIntrinsic(
940*e64bea71SDimitry Andric       Intrinsic::riscv_tuple_insert, {ResultType, Ops[2]->getType()},
941*e64bea71SDimitry Andric       {Ops[0], Ops[2], Builder.CreateTrunc(Ops[1], Builder.getInt32Ty())});
942*e64bea71SDimitry Andric }
943*e64bea71SDimitry Andric 
944*e64bea71SDimitry Andric static LLVM_ATTRIBUTE_NOINLINE Value *
emitRVVCreateBuiltin(CodeGenFunction * CGF,const CallExpr * E,ReturnValueSlot ReturnValue,llvm::Type * ResultType,Intrinsic::ID ID,SmallVectorImpl<Value * > & Ops,int PolicyAttrs,bool IsMasked,unsigned SegInstSEW)945*e64bea71SDimitry Andric emitRVVCreateBuiltin(CodeGenFunction *CGF, const CallExpr *E,
946*e64bea71SDimitry Andric                      ReturnValueSlot ReturnValue, llvm::Type *ResultType,
947*e64bea71SDimitry Andric                      Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
948*e64bea71SDimitry Andric                      int PolicyAttrs, bool IsMasked, unsigned SegInstSEW) {
949*e64bea71SDimitry Andric   auto &Builder = CGF->Builder;
950*e64bea71SDimitry Andric   llvm::Value *ReturnVector = llvm::PoisonValue::get(ResultType);
951*e64bea71SDimitry Andric   auto *VecTy = cast<ScalableVectorType>(Ops[0]->getType());
952*e64bea71SDimitry Andric   for (unsigned I = 0, N = Ops.size(); I < N; ++I) {
953*e64bea71SDimitry Andric     if (isa<ScalableVectorType>(ResultType)) {
954*e64bea71SDimitry Andric       llvm::Value *Idx = ConstantInt::get(Builder.getInt64Ty(),
955*e64bea71SDimitry Andric                                           VecTy->getMinNumElements() * I);
956*e64bea71SDimitry Andric       ReturnVector =
957*e64bea71SDimitry Andric           Builder.CreateInsertVector(ResultType, ReturnVector, Ops[I], Idx);
958*e64bea71SDimitry Andric     } else {
959*e64bea71SDimitry Andric       llvm::Value *Idx = ConstantInt::get(Builder.getInt32Ty(), I);
960*e64bea71SDimitry Andric       ReturnVector = Builder.CreateIntrinsic(Intrinsic::riscv_tuple_insert,
961*e64bea71SDimitry Andric                                              {ResultType, Ops[I]->getType()},
962*e64bea71SDimitry Andric                                              {ReturnVector, Ops[I], Idx});
963*e64bea71SDimitry Andric     }
964*e64bea71SDimitry Andric   }
965*e64bea71SDimitry Andric   return ReturnVector;
966*e64bea71SDimitry Andric }
967*e64bea71SDimitry Andric 
EmitRISCVCpuInit()968700637cbSDimitry Andric Value *CodeGenFunction::EmitRISCVCpuInit() {
969700637cbSDimitry Andric   llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, {VoidPtrTy}, false);
970700637cbSDimitry Andric   llvm::FunctionCallee Func =
971700637cbSDimitry Andric       CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
972700637cbSDimitry Andric   auto *CalleeGV = cast<llvm::GlobalValue>(Func.getCallee());
973700637cbSDimitry Andric   CalleeGV->setDSOLocal(true);
974700637cbSDimitry Andric   CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
975700637cbSDimitry Andric   return Builder.CreateCall(Func, {llvm::ConstantPointerNull::get(VoidPtrTy)});
976700637cbSDimitry Andric }
977700637cbSDimitry Andric 
EmitRISCVCpuSupports(const CallExpr * E)978700637cbSDimitry Andric Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
979700637cbSDimitry Andric 
980700637cbSDimitry Andric   const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
981700637cbSDimitry Andric   StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
982700637cbSDimitry Andric   if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
983700637cbSDimitry Andric     return Builder.getFalse();
984700637cbSDimitry Andric 
985700637cbSDimitry Andric   return EmitRISCVCpuSupports(ArrayRef<StringRef>(FeatureStr));
986700637cbSDimitry Andric }
987700637cbSDimitry Andric 
loadRISCVFeatureBits(unsigned Index,CGBuilderTy & Builder,CodeGenModule & CGM)988700637cbSDimitry Andric static Value *loadRISCVFeatureBits(unsigned Index, CGBuilderTy &Builder,
989700637cbSDimitry Andric                                    CodeGenModule &CGM) {
990700637cbSDimitry Andric   llvm::Type *Int32Ty = Builder.getInt32Ty();
991700637cbSDimitry Andric   llvm::Type *Int64Ty = Builder.getInt64Ty();
992700637cbSDimitry Andric   llvm::ArrayType *ArrayOfInt64Ty =
993700637cbSDimitry Andric       llvm::ArrayType::get(Int64Ty, llvm::RISCVISAInfo::FeatureBitSize);
994700637cbSDimitry Andric   llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
995700637cbSDimitry Andric   llvm::Constant *RISCVFeaturesBits =
996700637cbSDimitry Andric       CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
997700637cbSDimitry Andric   cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
998700637cbSDimitry Andric   Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
999700637cbSDimitry Andric   llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
1000700637cbSDimitry Andric                                IndexVal};
1001700637cbSDimitry Andric   Value *Ptr =
1002700637cbSDimitry Andric       Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
1003700637cbSDimitry Andric   Value *FeaturesBit =
1004700637cbSDimitry Andric       Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
1005700637cbSDimitry Andric   return FeaturesBit;
1006700637cbSDimitry Andric }
1007700637cbSDimitry Andric 
EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs)1008700637cbSDimitry Andric Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs) {
1009700637cbSDimitry Andric   const unsigned RISCVFeatureLength = llvm::RISCVISAInfo::FeatureBitSize;
1010700637cbSDimitry Andric   uint64_t RequireBitMasks[RISCVFeatureLength] = {0};
1011700637cbSDimitry Andric 
1012700637cbSDimitry Andric   for (auto Feat : FeaturesStrs) {
1013700637cbSDimitry Andric     auto [GroupID, BitPos] = RISCVISAInfo::getRISCVFeaturesBitsInfo(Feat);
1014700637cbSDimitry Andric 
1015700637cbSDimitry Andric     // If there isn't BitPos for this feature, skip this version.
1016700637cbSDimitry Andric     // It also report the warning to user during compilation.
1017700637cbSDimitry Andric     if (BitPos == -1)
1018700637cbSDimitry Andric       return Builder.getFalse();
1019700637cbSDimitry Andric 
1020700637cbSDimitry Andric     RequireBitMasks[GroupID] |= (1ULL << BitPos);
1021700637cbSDimitry Andric   }
1022700637cbSDimitry Andric 
1023700637cbSDimitry Andric   Value *Result = nullptr;
1024700637cbSDimitry Andric   for (unsigned Idx = 0; Idx < RISCVFeatureLength; Idx++) {
1025700637cbSDimitry Andric     if (RequireBitMasks[Idx] == 0)
1026700637cbSDimitry Andric       continue;
1027700637cbSDimitry Andric 
1028700637cbSDimitry Andric     Value *Mask = Builder.getInt64(RequireBitMasks[Idx]);
1029700637cbSDimitry Andric     Value *Bitset =
1030700637cbSDimitry Andric         Builder.CreateAnd(loadRISCVFeatureBits(Idx, Builder, CGM), Mask);
1031700637cbSDimitry Andric     Value *CmpV = Builder.CreateICmpEQ(Bitset, Mask);
1032700637cbSDimitry Andric     Result = (!Result) ? CmpV : Builder.CreateAnd(Result, CmpV);
1033700637cbSDimitry Andric   }
1034700637cbSDimitry Andric 
1035700637cbSDimitry Andric   assert(Result && "Should have value here.");
1036700637cbSDimitry Andric 
1037700637cbSDimitry Andric   return Result;
1038700637cbSDimitry Andric }
1039700637cbSDimitry Andric 
EmitRISCVCpuIs(const CallExpr * E)1040700637cbSDimitry Andric Value *CodeGenFunction::EmitRISCVCpuIs(const CallExpr *E) {
1041700637cbSDimitry Andric   const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
1042700637cbSDimitry Andric   StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
1043700637cbSDimitry Andric   return EmitRISCVCpuIs(CPUStr);
1044700637cbSDimitry Andric }
1045700637cbSDimitry Andric 
EmitRISCVCpuIs(StringRef CPUStr)1046700637cbSDimitry Andric Value *CodeGenFunction::EmitRISCVCpuIs(StringRef CPUStr) {
1047700637cbSDimitry Andric   llvm::Type *Int32Ty = Builder.getInt32Ty();
1048700637cbSDimitry Andric   llvm::Type *Int64Ty = Builder.getInt64Ty();
1049700637cbSDimitry Andric   llvm::StructType *StructTy = llvm::StructType::get(Int32Ty, Int64Ty, Int64Ty);
1050700637cbSDimitry Andric   llvm::Constant *RISCVCPUModel =
1051700637cbSDimitry Andric       CGM.CreateRuntimeVariable(StructTy, "__riscv_cpu_model");
1052700637cbSDimitry Andric   cast<llvm::GlobalValue>(RISCVCPUModel)->setDSOLocal(true);
1053700637cbSDimitry Andric 
1054700637cbSDimitry Andric   auto loadRISCVCPUID = [&](unsigned Index) {
1055700637cbSDimitry Andric     Value *Ptr = Builder.CreateStructGEP(StructTy, RISCVCPUModel, Index);
1056700637cbSDimitry Andric     Value *CPUID = Builder.CreateAlignedLoad(StructTy->getTypeAtIndex(Index),
1057700637cbSDimitry Andric                                              Ptr, llvm::MaybeAlign());
1058700637cbSDimitry Andric     return CPUID;
1059700637cbSDimitry Andric   };
1060700637cbSDimitry Andric 
1061700637cbSDimitry Andric   const llvm::RISCV::CPUModel Model = llvm::RISCV::getCPUModel(CPUStr);
1062700637cbSDimitry Andric 
1063700637cbSDimitry Andric   // Compare mvendorid.
1064700637cbSDimitry Andric   Value *VendorID = loadRISCVCPUID(0);
1065700637cbSDimitry Andric   Value *Result =
1066700637cbSDimitry Andric       Builder.CreateICmpEQ(VendorID, Builder.getInt32(Model.MVendorID));
1067700637cbSDimitry Andric 
1068700637cbSDimitry Andric   // Compare marchid.
1069700637cbSDimitry Andric   Value *ArchID = loadRISCVCPUID(1);
1070700637cbSDimitry Andric   Result = Builder.CreateAnd(
1071700637cbSDimitry Andric       Result, Builder.CreateICmpEQ(ArchID, Builder.getInt64(Model.MArchID)));
1072700637cbSDimitry Andric 
1073700637cbSDimitry Andric   // Compare mimpid.
1074700637cbSDimitry Andric   Value *ImpID = loadRISCVCPUID(2);
1075700637cbSDimitry Andric   Result = Builder.CreateAnd(
1076700637cbSDimitry Andric       Result, Builder.CreateICmpEQ(ImpID, Builder.getInt64(Model.MImpID)));
1077700637cbSDimitry Andric 
1078700637cbSDimitry Andric   return Result;
1079700637cbSDimitry Andric }
1080700637cbSDimitry Andric 
EmitRISCVBuiltinExpr(unsigned BuiltinID,const CallExpr * E,ReturnValueSlot ReturnValue)1081700637cbSDimitry Andric Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
1082700637cbSDimitry Andric                                              const CallExpr *E,
1083700637cbSDimitry Andric                                              ReturnValueSlot ReturnValue) {
1084700637cbSDimitry Andric 
1085700637cbSDimitry Andric   if (BuiltinID == Builtin::BI__builtin_cpu_supports)
1086700637cbSDimitry Andric     return EmitRISCVCpuSupports(E);
1087700637cbSDimitry Andric   if (BuiltinID == Builtin::BI__builtin_cpu_init)
1088700637cbSDimitry Andric     return EmitRISCVCpuInit();
1089700637cbSDimitry Andric   if (BuiltinID == Builtin::BI__builtin_cpu_is)
1090700637cbSDimitry Andric     return EmitRISCVCpuIs(E);
1091700637cbSDimitry Andric 
1092700637cbSDimitry Andric   SmallVector<Value *, 4> Ops;
1093700637cbSDimitry Andric   llvm::Type *ResultType = ConvertType(E->getType());
1094700637cbSDimitry Andric 
1095700637cbSDimitry Andric   // Find out if any arguments are required to be integer constant expressions.
1096700637cbSDimitry Andric   unsigned ICEArguments = 0;
1097700637cbSDimitry Andric   ASTContext::GetBuiltinTypeError Error;
1098700637cbSDimitry Andric   getContext().GetBuiltinType(BuiltinID, Error, &ICEArguments);
1099700637cbSDimitry Andric   if (Error == ASTContext::GE_Missing_type) {
1100700637cbSDimitry Andric     // Vector intrinsics don't have a type string.
1101700637cbSDimitry Andric     assert(BuiltinID >= clang::RISCV::FirstRVVBuiltin &&
1102700637cbSDimitry Andric            BuiltinID <= clang::RISCV::LastRVVBuiltin);
1103700637cbSDimitry Andric     ICEArguments = 0;
1104700637cbSDimitry Andric     if (BuiltinID == RISCVVector::BI__builtin_rvv_vget_v ||
1105700637cbSDimitry Andric         BuiltinID == RISCVVector::BI__builtin_rvv_vset_v)
1106700637cbSDimitry Andric       ICEArguments = 1 << 1;
1107700637cbSDimitry Andric   } else {
1108700637cbSDimitry Andric     assert(Error == ASTContext::GE_None && "Unexpected error");
1109700637cbSDimitry Andric   }
1110700637cbSDimitry Andric 
1111700637cbSDimitry Andric   if (BuiltinID == RISCV::BI__builtin_riscv_ntl_load)
1112700637cbSDimitry Andric     ICEArguments |= (1 << 1);
1113700637cbSDimitry Andric   if (BuiltinID == RISCV::BI__builtin_riscv_ntl_store)
1114700637cbSDimitry Andric     ICEArguments |= (1 << 2);
1115700637cbSDimitry Andric 
1116700637cbSDimitry Andric   for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
1117700637cbSDimitry Andric     // Handle aggregate argument, namely RVV tuple types in segment load/store
1118700637cbSDimitry Andric     if (hasAggregateEvaluationKind(E->getArg(i)->getType())) {
1119700637cbSDimitry Andric       LValue L = EmitAggExprToLValue(E->getArg(i));
1120700637cbSDimitry Andric       llvm::Value *AggValue = Builder.CreateLoad(L.getAddress());
1121700637cbSDimitry Andric       Ops.push_back(AggValue);
1122700637cbSDimitry Andric       continue;
1123700637cbSDimitry Andric     }
1124700637cbSDimitry Andric     Ops.push_back(EmitScalarOrConstFoldImmArg(ICEArguments, i, E));
1125700637cbSDimitry Andric   }
1126700637cbSDimitry Andric 
1127700637cbSDimitry Andric   Intrinsic::ID ID = Intrinsic::not_intrinsic;
1128700637cbSDimitry Andric   int PolicyAttrs = 0;
1129700637cbSDimitry Andric   bool IsMasked = false;
1130700637cbSDimitry Andric   // This is used by segment load/store to determine it's llvm type.
1131700637cbSDimitry Andric   unsigned SegInstSEW = 8;
1132700637cbSDimitry Andric 
1133700637cbSDimitry Andric   // Required for overloaded intrinsics.
1134700637cbSDimitry Andric   llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes;
1135700637cbSDimitry Andric   switch (BuiltinID) {
1136700637cbSDimitry Andric   default: llvm_unreachable("unexpected builtin ID");
1137700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_orc_b_32:
1138700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_orc_b_64:
1139700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_clmul_32:
1140700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_clmul_64:
1141700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_clmulh_32:
1142700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_clmulh_64:
1143700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_clmulr_32:
1144700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_clmulr_64:
1145700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_xperm4_32:
1146700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_xperm4_64:
1147700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_xperm8_32:
1148700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_xperm8_64:
1149700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_brev8_32:
1150700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_brev8_64:
1151700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_zip_32:
1152700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_unzip_32: {
1153700637cbSDimitry Andric     switch (BuiltinID) {
1154700637cbSDimitry Andric     default: llvm_unreachable("unexpected builtin ID");
1155700637cbSDimitry Andric     // Zbb
1156700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_orc_b_32:
1157700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_orc_b_64:
1158700637cbSDimitry Andric       ID = Intrinsic::riscv_orc_b;
1159700637cbSDimitry Andric       break;
1160700637cbSDimitry Andric 
1161700637cbSDimitry Andric     // Zbc
1162700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_clmul_32:
1163700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_clmul_64:
1164700637cbSDimitry Andric       ID = Intrinsic::riscv_clmul;
1165700637cbSDimitry Andric       break;
1166700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_clmulh_32:
1167700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_clmulh_64:
1168700637cbSDimitry Andric       ID = Intrinsic::riscv_clmulh;
1169700637cbSDimitry Andric       break;
1170700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_clmulr_32:
1171700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_clmulr_64:
1172700637cbSDimitry Andric       ID = Intrinsic::riscv_clmulr;
1173700637cbSDimitry Andric       break;
1174700637cbSDimitry Andric 
1175700637cbSDimitry Andric     // Zbkx
1176700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_xperm8_32:
1177700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_xperm8_64:
1178700637cbSDimitry Andric       ID = Intrinsic::riscv_xperm8;
1179700637cbSDimitry Andric       break;
1180700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_xperm4_32:
1181700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_xperm4_64:
1182700637cbSDimitry Andric       ID = Intrinsic::riscv_xperm4;
1183700637cbSDimitry Andric       break;
1184700637cbSDimitry Andric 
1185700637cbSDimitry Andric     // Zbkb
1186700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_brev8_32:
1187700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_brev8_64:
1188700637cbSDimitry Andric       ID = Intrinsic::riscv_brev8;
1189700637cbSDimitry Andric       break;
1190700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_zip_32:
1191700637cbSDimitry Andric       ID = Intrinsic::riscv_zip;
1192700637cbSDimitry Andric       break;
1193700637cbSDimitry Andric     case RISCV::BI__builtin_riscv_unzip_32:
1194700637cbSDimitry Andric       ID = Intrinsic::riscv_unzip;
1195700637cbSDimitry Andric       break;
1196700637cbSDimitry Andric     }
1197700637cbSDimitry Andric 
1198700637cbSDimitry Andric     IntrinsicTypes = {ResultType};
1199700637cbSDimitry Andric     break;
1200700637cbSDimitry Andric   }
1201700637cbSDimitry Andric 
1202700637cbSDimitry Andric   // Zk builtins
1203700637cbSDimitry Andric 
1204700637cbSDimitry Andric   // Zknh
1205700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_sha256sig0:
1206700637cbSDimitry Andric     ID = Intrinsic::riscv_sha256sig0;
1207700637cbSDimitry Andric     break;
1208700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_sha256sig1:
1209700637cbSDimitry Andric     ID = Intrinsic::riscv_sha256sig1;
1210700637cbSDimitry Andric     break;
1211700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_sha256sum0:
1212700637cbSDimitry Andric     ID = Intrinsic::riscv_sha256sum0;
1213700637cbSDimitry Andric     break;
1214700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_sha256sum1:
1215700637cbSDimitry Andric     ID = Intrinsic::riscv_sha256sum1;
1216700637cbSDimitry Andric     break;
1217700637cbSDimitry Andric 
1218700637cbSDimitry Andric   // Zksed
1219700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_sm4ks:
1220700637cbSDimitry Andric     ID = Intrinsic::riscv_sm4ks;
1221700637cbSDimitry Andric     break;
1222700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_sm4ed:
1223700637cbSDimitry Andric     ID = Intrinsic::riscv_sm4ed;
1224700637cbSDimitry Andric     break;
1225700637cbSDimitry Andric 
1226700637cbSDimitry Andric   // Zksh
1227700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_sm3p0:
1228700637cbSDimitry Andric     ID = Intrinsic::riscv_sm3p0;
1229700637cbSDimitry Andric     break;
1230700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_sm3p1:
1231700637cbSDimitry Andric     ID = Intrinsic::riscv_sm3p1;
1232700637cbSDimitry Andric     break;
1233700637cbSDimitry Andric 
1234700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_clz_32:
1235700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_clz_64: {
1236700637cbSDimitry Andric     Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ops[0]->getType());
1237700637cbSDimitry Andric     Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
1238700637cbSDimitry Andric     if (Result->getType() != ResultType)
1239700637cbSDimitry Andric       Result =
1240700637cbSDimitry Andric           Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false, "cast");
1241700637cbSDimitry Andric     return Result;
1242700637cbSDimitry Andric   }
1243700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_ctz_32:
1244700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_ctz_64: {
1245700637cbSDimitry Andric     Function *F = CGM.getIntrinsic(Intrinsic::cttz, Ops[0]->getType());
1246700637cbSDimitry Andric     Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
1247700637cbSDimitry Andric     if (Result->getType() != ResultType)
1248700637cbSDimitry Andric       Result =
1249700637cbSDimitry Andric           Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false, "cast");
1250700637cbSDimitry Andric     return Result;
1251700637cbSDimitry Andric   }
1252700637cbSDimitry Andric 
1253700637cbSDimitry Andric   // Zihintntl
1254700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_ntl_load: {
1255700637cbSDimitry Andric     llvm::Type *ResTy = ConvertType(E->getType());
1256700637cbSDimitry Andric     unsigned DomainVal = 5; // Default __RISCV_NTLH_ALL
1257700637cbSDimitry Andric     if (Ops.size() == 2)
1258700637cbSDimitry Andric       DomainVal = cast<ConstantInt>(Ops[1])->getZExtValue();
1259700637cbSDimitry Andric 
1260700637cbSDimitry Andric     llvm::MDNode *RISCVDomainNode = llvm::MDNode::get(
1261700637cbSDimitry Andric         getLLVMContext(),
1262700637cbSDimitry Andric         llvm::ConstantAsMetadata::get(Builder.getInt32(DomainVal)));
1263700637cbSDimitry Andric     llvm::MDNode *NontemporalNode = llvm::MDNode::get(
1264700637cbSDimitry Andric         getLLVMContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
1265700637cbSDimitry Andric 
1266700637cbSDimitry Andric     int Width;
1267700637cbSDimitry Andric     if(ResTy->isScalableTy()) {
1268700637cbSDimitry Andric       const ScalableVectorType *SVTy = cast<ScalableVectorType>(ResTy);
1269700637cbSDimitry Andric       llvm::Type *ScalarTy = ResTy->getScalarType();
1270700637cbSDimitry Andric       Width = ScalarTy->getPrimitiveSizeInBits() *
1271700637cbSDimitry Andric               SVTy->getElementCount().getKnownMinValue();
1272700637cbSDimitry Andric     } else
1273700637cbSDimitry Andric       Width = ResTy->getPrimitiveSizeInBits();
1274700637cbSDimitry Andric     LoadInst *Load = Builder.CreateLoad(
1275700637cbSDimitry Andric         Address(Ops[0], ResTy, CharUnits::fromQuantity(Width / 8)));
1276700637cbSDimitry Andric 
1277700637cbSDimitry Andric     Load->setMetadata(llvm::LLVMContext::MD_nontemporal, NontemporalNode);
1278700637cbSDimitry Andric     Load->setMetadata(CGM.getModule().getMDKindID("riscv-nontemporal-domain"),
1279700637cbSDimitry Andric                       RISCVDomainNode);
1280700637cbSDimitry Andric 
1281700637cbSDimitry Andric     return Load;
1282700637cbSDimitry Andric   }
1283700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_ntl_store: {
1284700637cbSDimitry Andric     unsigned DomainVal = 5; // Default __RISCV_NTLH_ALL
1285700637cbSDimitry Andric     if (Ops.size() == 3)
1286700637cbSDimitry Andric       DomainVal = cast<ConstantInt>(Ops[2])->getZExtValue();
1287700637cbSDimitry Andric 
1288700637cbSDimitry Andric     llvm::MDNode *RISCVDomainNode = llvm::MDNode::get(
1289700637cbSDimitry Andric         getLLVMContext(),
1290700637cbSDimitry Andric         llvm::ConstantAsMetadata::get(Builder.getInt32(DomainVal)));
1291700637cbSDimitry Andric     llvm::MDNode *NontemporalNode = llvm::MDNode::get(
1292700637cbSDimitry Andric         getLLVMContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
1293700637cbSDimitry Andric 
1294700637cbSDimitry Andric     StoreInst *Store = Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
1295700637cbSDimitry Andric     Store->setMetadata(llvm::LLVMContext::MD_nontemporal, NontemporalNode);
1296700637cbSDimitry Andric     Store->setMetadata(CGM.getModule().getMDKindID("riscv-nontemporal-domain"),
1297700637cbSDimitry Andric                        RISCVDomainNode);
1298700637cbSDimitry Andric 
1299700637cbSDimitry Andric     return Store;
1300700637cbSDimitry Andric   }
1301700637cbSDimitry Andric   // Zihintpause
1302700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_pause: {
1303700637cbSDimitry Andric     llvm::Function *Fn = CGM.getIntrinsic(llvm::Intrinsic::riscv_pause);
1304700637cbSDimitry Andric     return Builder.CreateCall(Fn, {});
1305700637cbSDimitry Andric   }
1306700637cbSDimitry Andric 
1307700637cbSDimitry Andric   // XCValu
1308700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_addN:
1309700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_addN;
1310700637cbSDimitry Andric     break;
1311700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_addRN:
1312700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_addRN;
1313700637cbSDimitry Andric     break;
1314700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_adduN:
1315700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_adduN;
1316700637cbSDimitry Andric     break;
1317700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_adduRN:
1318700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_adduRN;
1319700637cbSDimitry Andric     break;
1320700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_clip:
1321700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_clip;
1322700637cbSDimitry Andric     break;
1323700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_clipu:
1324700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_clipu;
1325700637cbSDimitry Andric     break;
1326700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_extbs:
1327700637cbSDimitry Andric     return Builder.CreateSExt(Builder.CreateTrunc(Ops[0], Int8Ty), Int32Ty,
1328700637cbSDimitry Andric                               "extbs");
1329700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_extbz:
1330700637cbSDimitry Andric     return Builder.CreateZExt(Builder.CreateTrunc(Ops[0], Int8Ty), Int32Ty,
1331700637cbSDimitry Andric                               "extbz");
1332700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_exths:
1333700637cbSDimitry Andric     return Builder.CreateSExt(Builder.CreateTrunc(Ops[0], Int16Ty), Int32Ty,
1334700637cbSDimitry Andric                               "exths");
1335700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_exthz:
1336700637cbSDimitry Andric     return Builder.CreateZExt(Builder.CreateTrunc(Ops[0], Int16Ty), Int32Ty,
1337700637cbSDimitry Andric                               "exthz");
1338700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_sle:
1339700637cbSDimitry Andric     return Builder.CreateZExt(Builder.CreateICmpSLE(Ops[0], Ops[1]), Int32Ty,
1340700637cbSDimitry Andric                               "sle");
1341700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_sleu:
1342700637cbSDimitry Andric     return Builder.CreateZExt(Builder.CreateICmpULE(Ops[0], Ops[1]), Int32Ty,
1343700637cbSDimitry Andric                               "sleu");
1344700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_subN:
1345700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_subN;
1346700637cbSDimitry Andric     break;
1347700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_subRN:
1348700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_subRN;
1349700637cbSDimitry Andric     break;
1350700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_subuN:
1351700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_subuN;
1352700637cbSDimitry Andric     break;
1353700637cbSDimitry Andric   case RISCV::BI__builtin_riscv_cv_alu_subuRN:
1354700637cbSDimitry Andric     ID = Intrinsic::riscv_cv_alu_subuRN;
1355700637cbSDimitry Andric     break;
1356700637cbSDimitry Andric 
1357700637cbSDimitry Andric     // Vector builtins are handled from here.
1358700637cbSDimitry Andric #include "clang/Basic/riscv_vector_builtin_cg.inc"
1359700637cbSDimitry Andric 
1360700637cbSDimitry Andric     // SiFive Vector builtins are handled from here.
1361700637cbSDimitry Andric #include "clang/Basic/riscv_sifive_vector_builtin_cg.inc"
1362700637cbSDimitry Andric 
1363700637cbSDimitry Andric     // Andes Vector builtins are handled from here.
1364700637cbSDimitry Andric #include "clang/Basic/riscv_andes_vector_builtin_cg.inc"
1365700637cbSDimitry Andric   }
1366700637cbSDimitry Andric 
1367700637cbSDimitry Andric   assert(ID != Intrinsic::not_intrinsic);
1368700637cbSDimitry Andric 
1369700637cbSDimitry Andric   llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
1370700637cbSDimitry Andric   return Builder.CreateCall(F, Ops, "");
1371700637cbSDimitry Andric }
1372