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