Skip to content

Commit eeb7668

Browse files
committed
[NFC][clang] Split clang/lib/CodeGen/CGBuiltin.cpp into target-specific files
clang/lib/CodeGen/CGBuiltin.cpp is over 1MB long (>23k LoC), and can take minutes to recompile (depending on compiler and host system) when modified, and 5 seconds for clangd to update for every edit. Splitting this file was discussed in this thread: https://discourse.llvm.org/t/splitting-clang-s-cgbuiltin-cpp-over-23k-lines-long-takes-1min-to-compile/ and the idea has received a number of +1 votes, hence this change.
1 parent 9b1f905 commit eeb7668

File tree

13 files changed

+18566
-17663
lines changed

13 files changed

+18566
-17663
lines changed

clang/lib/CodeGen/BuiltinTargets/AArch64.cpp

Lines changed: 8528 additions & 0 deletions
Large diffs are not rendered by default.

clang/lib/CodeGen/BuiltinTargets/AMDGPU.cpp

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

0 commit comments

Comments
 (0)