xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/TargetBuiltins/Hexagon.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
1 //===------ Hexagon.cpp - Emit LLVM Code for builtins ---------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This contains code to emit Builtin calls as LLVM code.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CodeGenFunction.h"
14 #include "clang/Basic/TargetBuiltins.h"
15 #include "llvm/IR/IntrinsicsHexagon.h"
16 
17 using namespace clang;
18 using namespace CodeGen;
19 using namespace llvm;
20 
21 static std::pair<Intrinsic::ID, unsigned>
22 getIntrinsicForHexagonNonClangBuiltin(unsigned BuiltinID) {
23   struct Info {
24     unsigned BuiltinID;
25     Intrinsic::ID IntrinsicID;
26     unsigned VecLen;
27   };
28   static Info Infos[] = {
29 #define CUSTOM_BUILTIN_MAPPING(x,s) \
30   { Hexagon::BI__builtin_HEXAGON_##x, Intrinsic::hexagon_##x, s },
31     CUSTOM_BUILTIN_MAPPING(L2_loadrub_pci, 0)
32     CUSTOM_BUILTIN_MAPPING(L2_loadrb_pci, 0)
33     CUSTOM_BUILTIN_MAPPING(L2_loadruh_pci, 0)
34     CUSTOM_BUILTIN_MAPPING(L2_loadrh_pci, 0)
35     CUSTOM_BUILTIN_MAPPING(L2_loadri_pci, 0)
36     CUSTOM_BUILTIN_MAPPING(L2_loadrd_pci, 0)
37     CUSTOM_BUILTIN_MAPPING(L2_loadrub_pcr, 0)
38     CUSTOM_BUILTIN_MAPPING(L2_loadrb_pcr, 0)
39     CUSTOM_BUILTIN_MAPPING(L2_loadruh_pcr, 0)
40     CUSTOM_BUILTIN_MAPPING(L2_loadrh_pcr, 0)
41     CUSTOM_BUILTIN_MAPPING(L2_loadri_pcr, 0)
42     CUSTOM_BUILTIN_MAPPING(L2_loadrd_pcr, 0)
43     CUSTOM_BUILTIN_MAPPING(S2_storerb_pci, 0)
44     CUSTOM_BUILTIN_MAPPING(S2_storerh_pci, 0)
45     CUSTOM_BUILTIN_MAPPING(S2_storerf_pci, 0)
46     CUSTOM_BUILTIN_MAPPING(S2_storeri_pci, 0)
47     CUSTOM_BUILTIN_MAPPING(S2_storerd_pci, 0)
48     CUSTOM_BUILTIN_MAPPING(S2_storerb_pcr, 0)
49     CUSTOM_BUILTIN_MAPPING(S2_storerh_pcr, 0)
50     CUSTOM_BUILTIN_MAPPING(S2_storerf_pcr, 0)
51     CUSTOM_BUILTIN_MAPPING(S2_storeri_pcr, 0)
52     CUSTOM_BUILTIN_MAPPING(S2_storerd_pcr, 0)
53     // Legacy builtins that take a vector in place of a vector predicate.
54     CUSTOM_BUILTIN_MAPPING(V6_vmaskedstoreq, 64)
55     CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorenq, 64)
56     CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentq, 64)
57     CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentnq, 64)
58     CUSTOM_BUILTIN_MAPPING(V6_vmaskedstoreq_128B, 128)
59     CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorenq_128B, 128)
60     CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentq_128B, 128)
61     CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentnq_128B, 128)
62 #include "clang/Basic/BuiltinsHexagonMapCustomDep.def"
63 #undef CUSTOM_BUILTIN_MAPPING
64   };
65 
66   auto CmpInfo = [] (Info A, Info B) { return A.BuiltinID < B.BuiltinID; };
67   static const bool SortOnce = (llvm::sort(Infos, CmpInfo), true);
68   (void)SortOnce;
69 
70   const Info *F = llvm::lower_bound(Infos, Info{BuiltinID, 0, 0}, CmpInfo);
71   if (F == std::end(Infos) || F->BuiltinID != BuiltinID)
72     return {Intrinsic::not_intrinsic, 0};
73 
74   return {F->IntrinsicID, F->VecLen};
75 }
76 
77 Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
78                                                const CallExpr *E) {
79   Intrinsic::ID ID;
80   unsigned VecLen;
81   std::tie(ID, VecLen) = getIntrinsicForHexagonNonClangBuiltin(BuiltinID);
82 
83   auto MakeCircOp = [this, E](unsigned IntID, bool IsLoad) {
84     // The base pointer is passed by address, so it needs to be loaded.
85     Address A = EmitPointerWithAlignment(E->getArg(0));
86     Address BP = Address(A.emitRawPointer(*this), Int8PtrTy, A.getAlignment());
87     llvm::Value *Base = Builder.CreateLoad(BP);
88     // The treatment of both loads and stores is the same: the arguments for
89     // the builtin are the same as the arguments for the intrinsic.
90     // Load:
91     //   builtin(Base, Inc, Mod, Start) -> intr(Base, Inc, Mod, Start)
92     //   builtin(Base, Mod, Start)      -> intr(Base, Mod, Start)
93     // Store:
94     //   builtin(Base, Inc, Mod, Val, Start) -> intr(Base, Inc, Mod, Val, Start)
95     //   builtin(Base, Mod, Val, Start)      -> intr(Base, Mod, Val, Start)
96     SmallVector<llvm::Value*,5> Ops = { Base };
97     for (unsigned i = 1, e = E->getNumArgs(); i != e; ++i)
98       Ops.push_back(EmitScalarExpr(E->getArg(i)));
99 
100     llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(IntID), Ops);
101     // The load intrinsics generate two results (Value, NewBase), stores
102     // generate one (NewBase). The new base address needs to be stored.
103     llvm::Value *NewBase = IsLoad ? Builder.CreateExtractValue(Result, 1)
104                                   : Result;
105     llvm::Value *LV = EmitScalarExpr(E->getArg(0));
106     Address Dest = EmitPointerWithAlignment(E->getArg(0));
107     llvm::Value *RetVal =
108         Builder.CreateAlignedStore(NewBase, LV, Dest.getAlignment());
109     if (IsLoad)
110       RetVal = Builder.CreateExtractValue(Result, 0);
111     return RetVal;
112   };
113 
114   // Handle the conversion of bit-reverse load intrinsics to bit code.
115   // The intrinsic call after this function only reads from memory and the
116   // write to memory is dealt by the store instruction.
117   auto MakeBrevLd = [this, E](unsigned IntID, llvm::Type *DestTy) {
118     // The intrinsic generates one result, which is the new value for the base
119     // pointer. It needs to be returned. The result of the load instruction is
120     // passed to intrinsic by address, so the value needs to be stored.
121     llvm::Value *BaseAddress = EmitScalarExpr(E->getArg(0));
122 
123     // Expressions like &(*pt++) will be incremented per evaluation.
124     // EmitPointerWithAlignment and EmitScalarExpr evaluates the expression
125     // per call.
126     Address DestAddr = EmitPointerWithAlignment(E->getArg(1));
127     DestAddr = DestAddr.withElementType(Int8Ty);
128     llvm::Value *DestAddress = DestAddr.emitRawPointer(*this);
129 
130     // Operands are Base, Dest, Modifier.
131     // The intrinsic format in LLVM IR is defined as
132     // { ValueType, i8* } (i8*, i32).
133     llvm::Value *Result = Builder.CreateCall(
134         CGM.getIntrinsic(IntID), {BaseAddress, EmitScalarExpr(E->getArg(2))});
135 
136     // The value needs to be stored as the variable is passed by reference.
137     llvm::Value *DestVal = Builder.CreateExtractValue(Result, 0);
138 
139     // The store needs to be truncated to fit the destination type.
140     // While i32 and i64 are natively supported on Hexagon, i8 and i16 needs
141     // to be handled with stores of respective destination type.
142     DestVal = Builder.CreateTrunc(DestVal, DestTy);
143 
144     Builder.CreateAlignedStore(DestVal, DestAddress, DestAddr.getAlignment());
145     // The updated value of the base pointer is returned.
146     return Builder.CreateExtractValue(Result, 1);
147   };
148 
149   auto V2Q = [this, VecLen] (llvm::Value *Vec) {
150     Intrinsic::ID ID = VecLen == 128 ? Intrinsic::hexagon_V6_vandvrt_128B
151                                      : Intrinsic::hexagon_V6_vandvrt;
152     return Builder.CreateCall(CGM.getIntrinsic(ID),
153                               {Vec, Builder.getInt32(-1)});
154   };
155   auto Q2V = [this, VecLen] (llvm::Value *Pred) {
156     Intrinsic::ID ID = VecLen == 128 ? Intrinsic::hexagon_V6_vandqrt_128B
157                                      : Intrinsic::hexagon_V6_vandqrt;
158     return Builder.CreateCall(CGM.getIntrinsic(ID),
159                               {Pred, Builder.getInt32(-1)});
160   };
161 
162   switch (BuiltinID) {
163   // These intrinsics return a tuple {Vector, VectorPred} in LLVM IR,
164   // and the corresponding C/C++ builtins use loads/stores to update
165   // the predicate.
166   case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry:
167   case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B:
168   case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry:
169   case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B: {
170     // Get the type from the 0-th argument.
171     llvm::Type *VecType = ConvertType(E->getArg(0)->getType());
172     Address PredAddr =
173         EmitPointerWithAlignment(E->getArg(2)).withElementType(VecType);
174     llvm::Value *PredIn = V2Q(Builder.CreateLoad(PredAddr));
175     llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID),
176         {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), PredIn});
177 
178     llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1);
179     Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this),
180                                PredAddr.getAlignment());
181     return Builder.CreateExtractValue(Result, 0);
182   }
183   // These are identical to the builtins above, except they don't consume
184   // input carry, only generate carry-out. Since they still produce two
185   // outputs, generate the store of the predicate, but no load.
186   case Hexagon::BI__builtin_HEXAGON_V6_vaddcarryo:
187   case Hexagon::BI__builtin_HEXAGON_V6_vaddcarryo_128B:
188   case Hexagon::BI__builtin_HEXAGON_V6_vsubcarryo:
189   case Hexagon::BI__builtin_HEXAGON_V6_vsubcarryo_128B: {
190     // Get the type from the 0-th argument.
191     llvm::Type *VecType = ConvertType(E->getArg(0)->getType());
192     Address PredAddr =
193         EmitPointerWithAlignment(E->getArg(2)).withElementType(VecType);
194     llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID),
195         {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1))});
196 
197     llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1);
198     Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this),
199                                PredAddr.getAlignment());
200     return Builder.CreateExtractValue(Result, 0);
201   }
202 
203   case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstoreq:
204   case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorenq:
205   case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentq:
206   case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentnq:
207   case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstoreq_128B:
208   case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorenq_128B:
209   case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentq_128B:
210   case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentnq_128B: {
211     SmallVector<llvm::Value*,4> Ops;
212     const Expr *PredOp = E->getArg(0);
213     // There will be an implicit cast to a boolean vector. Strip it.
214     if (auto *Cast = dyn_cast<ImplicitCastExpr>(PredOp)) {
215       if (Cast->getCastKind() == CK_BitCast)
216         PredOp = Cast->getSubExpr();
217       Ops.push_back(V2Q(EmitScalarExpr(PredOp)));
218     }
219     for (int i = 1, e = E->getNumArgs(); i != e; ++i)
220       Ops.push_back(EmitScalarExpr(E->getArg(i)));
221     return Builder.CreateCall(CGM.getIntrinsic(ID), Ops);
222   }
223 
224   case Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci:
225   case Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci:
226   case Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci:
227   case Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci:
228   case Hexagon::BI__builtin_HEXAGON_L2_loadri_pci:
229   case Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci:
230   case Hexagon::BI__builtin_HEXAGON_L2_loadrub_pcr:
231   case Hexagon::BI__builtin_HEXAGON_L2_loadrb_pcr:
232   case Hexagon::BI__builtin_HEXAGON_L2_loadruh_pcr:
233   case Hexagon::BI__builtin_HEXAGON_L2_loadrh_pcr:
234   case Hexagon::BI__builtin_HEXAGON_L2_loadri_pcr:
235   case Hexagon::BI__builtin_HEXAGON_L2_loadrd_pcr:
236     return MakeCircOp(ID, /*IsLoad=*/true);
237   case Hexagon::BI__builtin_HEXAGON_S2_storerb_pci:
238   case Hexagon::BI__builtin_HEXAGON_S2_storerh_pci:
239   case Hexagon::BI__builtin_HEXAGON_S2_storerf_pci:
240   case Hexagon::BI__builtin_HEXAGON_S2_storeri_pci:
241   case Hexagon::BI__builtin_HEXAGON_S2_storerd_pci:
242   case Hexagon::BI__builtin_HEXAGON_S2_storerb_pcr:
243   case Hexagon::BI__builtin_HEXAGON_S2_storerh_pcr:
244   case Hexagon::BI__builtin_HEXAGON_S2_storerf_pcr:
245   case Hexagon::BI__builtin_HEXAGON_S2_storeri_pcr:
246   case Hexagon::BI__builtin_HEXAGON_S2_storerd_pcr:
247     return MakeCircOp(ID, /*IsLoad=*/false);
248   case Hexagon::BI__builtin_brev_ldub:
249     return MakeBrevLd(Intrinsic::hexagon_L2_loadrub_pbr, Int8Ty);
250   case Hexagon::BI__builtin_brev_ldb:
251     return MakeBrevLd(Intrinsic::hexagon_L2_loadrb_pbr, Int8Ty);
252   case Hexagon::BI__builtin_brev_lduh:
253     return MakeBrevLd(Intrinsic::hexagon_L2_loadruh_pbr, Int16Ty);
254   case Hexagon::BI__builtin_brev_ldh:
255     return MakeBrevLd(Intrinsic::hexagon_L2_loadrh_pbr, Int16Ty);
256   case Hexagon::BI__builtin_brev_ldw:
257     return MakeBrevLd(Intrinsic::hexagon_L2_loadri_pbr, Int32Ty);
258   case Hexagon::BI__builtin_brev_ldd:
259     return MakeBrevLd(Intrinsic::hexagon_L2_loadrd_pbr, Int64Ty);
260   } // switch
261 
262   return nullptr;
263 }
264