xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- CodeGenIntrinsics.cpp - Intrinsic Class Wrapper --------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This file defines a wrapper class for the 'Intrinsic' TableGen class.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "CodeGenIntrinsics.h"
14*0fca6ea1SDimitry Andric #include "llvm/ADT/ArrayRef.h"
15*0fca6ea1SDimitry Andric #include "llvm/ADT/STLExtras.h"
16*0fca6ea1SDimitry Andric #include "llvm/ADT/Twine.h"
17*0fca6ea1SDimitry Andric #include "llvm/Support/ErrorHandling.h"
18*0fca6ea1SDimitry Andric #include "llvm/TableGen/Error.h"
19*0fca6ea1SDimitry Andric #include "llvm/TableGen/Record.h"
20*0fca6ea1SDimitry Andric #include <algorithm>
21*0fca6ea1SDimitry Andric #include <cassert>
22*0fca6ea1SDimitry Andric using namespace llvm;
23*0fca6ea1SDimitry Andric 
24*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
25*0fca6ea1SDimitry Andric // CodeGenIntrinsic Implementation
26*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) {
29*0fca6ea1SDimitry Andric   std::vector<Record *> IntrProperties =
30*0fca6ea1SDimitry Andric       RC.getAllDerivedDefinitions("IntrinsicProperty");
31*0fca6ea1SDimitry Andric 
32*0fca6ea1SDimitry Andric   std::vector<Record *> DefaultProperties;
33*0fca6ea1SDimitry Andric   for (Record *Rec : IntrProperties)
34*0fca6ea1SDimitry Andric     if (Rec->getValueAsBit("IsDefault"))
35*0fca6ea1SDimitry Andric       DefaultProperties.push_back(Rec);
36*0fca6ea1SDimitry Andric 
37*0fca6ea1SDimitry Andric   std::vector<Record *> Defs = RC.getAllDerivedDefinitions("Intrinsic");
38*0fca6ea1SDimitry Andric   Intrinsics.reserve(Defs.size());
39*0fca6ea1SDimitry Andric 
40*0fca6ea1SDimitry Andric   for (unsigned I = 0, e = Defs.size(); I != e; ++I)
41*0fca6ea1SDimitry Andric     Intrinsics.push_back(CodeGenIntrinsic(Defs[I], DefaultProperties));
42*0fca6ea1SDimitry Andric 
43*0fca6ea1SDimitry Andric   llvm::sort(Intrinsics,
44*0fca6ea1SDimitry Andric              [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) {
45*0fca6ea1SDimitry Andric                return std::tie(LHS.TargetPrefix, LHS.Name) <
46*0fca6ea1SDimitry Andric                       std::tie(RHS.TargetPrefix, RHS.Name);
47*0fca6ea1SDimitry Andric              });
48*0fca6ea1SDimitry Andric   Targets.push_back({"", 0, 0});
49*0fca6ea1SDimitry Andric   for (size_t I = 0, E = Intrinsics.size(); I < E; ++I)
50*0fca6ea1SDimitry Andric     if (Intrinsics[I].TargetPrefix != Targets.back().Name) {
51*0fca6ea1SDimitry Andric       Targets.back().Count = I - Targets.back().Offset;
52*0fca6ea1SDimitry Andric       Targets.push_back({Intrinsics[I].TargetPrefix, I, 0});
53*0fca6ea1SDimitry Andric     }
54*0fca6ea1SDimitry Andric   Targets.back().Count = Intrinsics.size() - Targets.back().Offset;
55*0fca6ea1SDimitry Andric }
56*0fca6ea1SDimitry Andric 
57*0fca6ea1SDimitry Andric CodeGenIntrinsic::CodeGenIntrinsic(Record *R,
58*0fca6ea1SDimitry Andric                                    ArrayRef<Record *> DefaultProperties) {
59*0fca6ea1SDimitry Andric   TheDef = R;
60*0fca6ea1SDimitry Andric   std::string DefName = std::string(R->getName());
61*0fca6ea1SDimitry Andric   ArrayRef<SMLoc> DefLoc = R->getLoc();
62*0fca6ea1SDimitry Andric   Properties = 0;
63*0fca6ea1SDimitry Andric   isOverloaded = false;
64*0fca6ea1SDimitry Andric   isCommutative = false;
65*0fca6ea1SDimitry Andric   canThrow = false;
66*0fca6ea1SDimitry Andric   isNoReturn = false;
67*0fca6ea1SDimitry Andric   isNoCallback = false;
68*0fca6ea1SDimitry Andric   isNoSync = false;
69*0fca6ea1SDimitry Andric   isNoFree = false;
70*0fca6ea1SDimitry Andric   isWillReturn = false;
71*0fca6ea1SDimitry Andric   isCold = false;
72*0fca6ea1SDimitry Andric   isNoDuplicate = false;
73*0fca6ea1SDimitry Andric   isNoMerge = false;
74*0fca6ea1SDimitry Andric   isConvergent = false;
75*0fca6ea1SDimitry Andric   isSpeculatable = false;
76*0fca6ea1SDimitry Andric   hasSideEffects = false;
77*0fca6ea1SDimitry Andric   isStrictFP = false;
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric   if (DefName.size() <= 4 || DefName.substr(0, 4) != "int_")
80*0fca6ea1SDimitry Andric     PrintFatalError(DefLoc,
81*0fca6ea1SDimitry Andric                     "Intrinsic '" + DefName + "' does not start with 'int_'!");
82*0fca6ea1SDimitry Andric 
83*0fca6ea1SDimitry Andric   EnumName = DefName.substr(4);
84*0fca6ea1SDimitry Andric 
85*0fca6ea1SDimitry Andric   if (R->getValue(
86*0fca6ea1SDimitry Andric           "ClangBuiltinName")) // Ignore a missing ClangBuiltinName field.
87*0fca6ea1SDimitry Andric     ClangBuiltinName = std::string(R->getValueAsString("ClangBuiltinName"));
88*0fca6ea1SDimitry Andric   if (R->getValue("MSBuiltinName")) // Ignore a missing MSBuiltinName field.
89*0fca6ea1SDimitry Andric     MSBuiltinName = std::string(R->getValueAsString("MSBuiltinName"));
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric   TargetPrefix = std::string(R->getValueAsString("TargetPrefix"));
92*0fca6ea1SDimitry Andric   Name = std::string(R->getValueAsString("LLVMName"));
93*0fca6ea1SDimitry Andric 
94*0fca6ea1SDimitry Andric   if (Name == "") {
95*0fca6ea1SDimitry Andric     // If an explicit name isn't specified, derive one from the DefName.
96*0fca6ea1SDimitry Andric     Name = "llvm.";
97*0fca6ea1SDimitry Andric 
98*0fca6ea1SDimitry Andric     for (unsigned i = 0, e = EnumName.size(); i != e; ++i)
99*0fca6ea1SDimitry Andric       Name += (EnumName[i] == '_') ? '.' : EnumName[i];
100*0fca6ea1SDimitry Andric   } else {
101*0fca6ea1SDimitry Andric     // Verify it starts with "llvm.".
102*0fca6ea1SDimitry Andric     if (Name.size() <= 5 || Name.substr(0, 5) != "llvm.")
103*0fca6ea1SDimitry Andric       PrintFatalError(DefLoc, "Intrinsic '" + DefName +
104*0fca6ea1SDimitry Andric                                   "'s name does not start with 'llvm.'!");
105*0fca6ea1SDimitry Andric   }
106*0fca6ea1SDimitry Andric 
107*0fca6ea1SDimitry Andric   // If TargetPrefix is specified, make sure that Name starts with
108*0fca6ea1SDimitry Andric   // "llvm.<targetprefix>.".
109*0fca6ea1SDimitry Andric   if (!TargetPrefix.empty()) {
110*0fca6ea1SDimitry Andric     if (Name.size() < 6 + TargetPrefix.size() ||
111*0fca6ea1SDimitry Andric         Name.substr(5, 1 + TargetPrefix.size()) != (TargetPrefix + "."))
112*0fca6ea1SDimitry Andric       PrintFatalError(DefLoc, "Intrinsic '" + DefName +
113*0fca6ea1SDimitry Andric                                   "' does not start with 'llvm." +
114*0fca6ea1SDimitry Andric                                   TargetPrefix + ".'!");
115*0fca6ea1SDimitry Andric   }
116*0fca6ea1SDimitry Andric 
117*0fca6ea1SDimitry Andric   if (auto *Types = R->getValue("Types")) {
118*0fca6ea1SDimitry Andric     auto *TypeList = cast<ListInit>(Types->getValue());
119*0fca6ea1SDimitry Andric     isOverloaded = R->getValueAsBit("isOverloaded");
120*0fca6ea1SDimitry Andric 
121*0fca6ea1SDimitry Andric     unsigned I = 0;
122*0fca6ea1SDimitry Andric     for (unsigned E = R->getValueAsListInit("RetTypes")->size(); I < E; ++I)
123*0fca6ea1SDimitry Andric       IS.RetTys.push_back(TypeList->getElementAsRecord(I));
124*0fca6ea1SDimitry Andric 
125*0fca6ea1SDimitry Andric     for (unsigned E = TypeList->size(); I < E; ++I)
126*0fca6ea1SDimitry Andric       IS.ParamTys.push_back(TypeList->getElementAsRecord(I));
127*0fca6ea1SDimitry Andric   }
128*0fca6ea1SDimitry Andric 
129*0fca6ea1SDimitry Andric   // Parse the intrinsic properties.
130*0fca6ea1SDimitry Andric   ListInit *PropList = R->getValueAsListInit("IntrProperties");
131*0fca6ea1SDimitry Andric   for (unsigned i = 0, e = PropList->size(); i != e; ++i) {
132*0fca6ea1SDimitry Andric     Record *Property = PropList->getElementAsRecord(i);
133*0fca6ea1SDimitry Andric     assert(Property->isSubClassOf("IntrinsicProperty") &&
134*0fca6ea1SDimitry Andric            "Expected a property!");
135*0fca6ea1SDimitry Andric 
136*0fca6ea1SDimitry Andric     setProperty(Property);
137*0fca6ea1SDimitry Andric   }
138*0fca6ea1SDimitry Andric 
139*0fca6ea1SDimitry Andric   // Set default properties to true.
140*0fca6ea1SDimitry Andric   setDefaultProperties(R, DefaultProperties);
141*0fca6ea1SDimitry Andric 
142*0fca6ea1SDimitry Andric   // Also record the SDPatternOperator Properties.
143*0fca6ea1SDimitry Andric   Properties = parseSDPatternOperatorProperties(R);
144*0fca6ea1SDimitry Andric 
145*0fca6ea1SDimitry Andric   // Sort the argument attributes for later benefit.
146*0fca6ea1SDimitry Andric   for (auto &Attrs : ArgumentAttributes)
147*0fca6ea1SDimitry Andric     llvm::sort(Attrs);
148*0fca6ea1SDimitry Andric }
149*0fca6ea1SDimitry Andric 
150*0fca6ea1SDimitry Andric void CodeGenIntrinsic::setDefaultProperties(
151*0fca6ea1SDimitry Andric     Record *R, ArrayRef<Record *> DefaultProperties) {
152*0fca6ea1SDimitry Andric   // opt-out of using default attributes.
153*0fca6ea1SDimitry Andric   if (R->getValueAsBit("DisableDefaultAttributes"))
154*0fca6ea1SDimitry Andric     return;
155*0fca6ea1SDimitry Andric 
156*0fca6ea1SDimitry Andric   for (Record *Rec : DefaultProperties)
157*0fca6ea1SDimitry Andric     setProperty(Rec);
158*0fca6ea1SDimitry Andric }
159*0fca6ea1SDimitry Andric 
160*0fca6ea1SDimitry Andric void CodeGenIntrinsic::setProperty(Record *R) {
161*0fca6ea1SDimitry Andric   if (R->getName() == "IntrNoMem")
162*0fca6ea1SDimitry Andric     ME = MemoryEffects::none();
163*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrReadMem") {
164*0fca6ea1SDimitry Andric     if (ME.onlyWritesMemory())
165*0fca6ea1SDimitry Andric       PrintFatalError(TheDef->getLoc(),
166*0fca6ea1SDimitry Andric                       Twine("IntrReadMem cannot be used after IntrNoMem or "
167*0fca6ea1SDimitry Andric                             "IntrWriteMem. Default is ReadWrite"));
168*0fca6ea1SDimitry Andric     ME &= MemoryEffects::readOnly();
169*0fca6ea1SDimitry Andric   } else if (R->getName() == "IntrWriteMem") {
170*0fca6ea1SDimitry Andric     if (ME.onlyReadsMemory())
171*0fca6ea1SDimitry Andric       PrintFatalError(TheDef->getLoc(),
172*0fca6ea1SDimitry Andric                       Twine("IntrWriteMem cannot be used after IntrNoMem or "
173*0fca6ea1SDimitry Andric                             "IntrReadMem. Default is ReadWrite"));
174*0fca6ea1SDimitry Andric     ME &= MemoryEffects::writeOnly();
175*0fca6ea1SDimitry Andric   } else if (R->getName() == "IntrArgMemOnly")
176*0fca6ea1SDimitry Andric     ME &= MemoryEffects::argMemOnly();
177*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrInaccessibleMemOnly")
178*0fca6ea1SDimitry Andric     ME &= MemoryEffects::inaccessibleMemOnly();
179*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
180*0fca6ea1SDimitry Andric     ME &= MemoryEffects::inaccessibleOrArgMemOnly();
181*0fca6ea1SDimitry Andric   else if (R->getName() == "Commutative")
182*0fca6ea1SDimitry Andric     isCommutative = true;
183*0fca6ea1SDimitry Andric   else if (R->getName() == "Throws")
184*0fca6ea1SDimitry Andric     canThrow = true;
185*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrNoDuplicate")
186*0fca6ea1SDimitry Andric     isNoDuplicate = true;
187*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrNoMerge")
188*0fca6ea1SDimitry Andric     isNoMerge = true;
189*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrConvergent")
190*0fca6ea1SDimitry Andric     isConvergent = true;
191*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrNoReturn")
192*0fca6ea1SDimitry Andric     isNoReturn = true;
193*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrNoCallback")
194*0fca6ea1SDimitry Andric     isNoCallback = true;
195*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrNoSync")
196*0fca6ea1SDimitry Andric     isNoSync = true;
197*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrNoFree")
198*0fca6ea1SDimitry Andric     isNoFree = true;
199*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrWillReturn")
200*0fca6ea1SDimitry Andric     isWillReturn = !isNoReturn;
201*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrCold")
202*0fca6ea1SDimitry Andric     isCold = true;
203*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrSpeculatable")
204*0fca6ea1SDimitry Andric     isSpeculatable = true;
205*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrHasSideEffects")
206*0fca6ea1SDimitry Andric     hasSideEffects = true;
207*0fca6ea1SDimitry Andric   else if (R->getName() == "IntrStrictFP")
208*0fca6ea1SDimitry Andric     isStrictFP = true;
209*0fca6ea1SDimitry Andric   else if (R->isSubClassOf("NoCapture")) {
210*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
211*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, NoCapture);
212*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("NoAlias")) {
213*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
214*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, NoAlias);
215*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("NoUndef")) {
216*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
217*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, NoUndef);
218*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("NonNull")) {
219*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
220*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, NonNull);
221*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("Returned")) {
222*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
223*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, Returned);
224*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("ReadOnly")) {
225*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
226*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, ReadOnly);
227*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("WriteOnly")) {
228*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
229*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, WriteOnly);
230*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("ReadNone")) {
231*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
232*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, ReadNone);
233*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("ImmArg")) {
234*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
235*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, ImmArg);
236*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("Align")) {
237*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
238*0fca6ea1SDimitry Andric     uint64_t Align = R->getValueAsInt("Align");
239*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, Alignment, Align);
240*0fca6ea1SDimitry Andric   } else if (R->isSubClassOf("Dereferenceable")) {
241*0fca6ea1SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
242*0fca6ea1SDimitry Andric     uint64_t Bytes = R->getValueAsInt("Bytes");
243*0fca6ea1SDimitry Andric     addArgAttribute(ArgNo, Dereferenceable, Bytes);
244*0fca6ea1SDimitry Andric   } else
245*0fca6ea1SDimitry Andric     llvm_unreachable("Unknown property!");
246*0fca6ea1SDimitry Andric }
247*0fca6ea1SDimitry Andric 
248*0fca6ea1SDimitry Andric bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
249*0fca6ea1SDimitry Andric   if (ParamIdx >= IS.ParamTys.size())
250*0fca6ea1SDimitry Andric     return false;
251*0fca6ea1SDimitry Andric   return (IS.ParamTys[ParamIdx]->isSubClassOf("LLVMQualPointerType") ||
252*0fca6ea1SDimitry Andric           IS.ParamTys[ParamIdx]->isSubClassOf("LLVMAnyPointerType"));
253*0fca6ea1SDimitry Andric }
254*0fca6ea1SDimitry Andric 
255*0fca6ea1SDimitry Andric bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const {
256*0fca6ea1SDimitry Andric   // Convert argument index to attribute index starting from `FirstArgIndex`.
257*0fca6ea1SDimitry Andric   ++ParamIdx;
258*0fca6ea1SDimitry Andric   if (ParamIdx >= ArgumentAttributes.size())
259*0fca6ea1SDimitry Andric     return false;
260*0fca6ea1SDimitry Andric   ArgAttribute Val{ImmArg, 0};
261*0fca6ea1SDimitry Andric   return std::binary_search(ArgumentAttributes[ParamIdx].begin(),
262*0fca6ea1SDimitry Andric                             ArgumentAttributes[ParamIdx].end(), Val);
263*0fca6ea1SDimitry Andric }
264*0fca6ea1SDimitry Andric 
265*0fca6ea1SDimitry Andric void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK,
266*0fca6ea1SDimitry Andric                                        uint64_t V) {
267*0fca6ea1SDimitry Andric   if (Idx >= ArgumentAttributes.size())
268*0fca6ea1SDimitry Andric     ArgumentAttributes.resize(Idx + 1);
269*0fca6ea1SDimitry Andric   ArgumentAttributes[Idx].emplace_back(AK, V);
270*0fca6ea1SDimitry Andric }
271