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