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