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