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>
22using namespace llvm;
23
24//===----------------------------------------------------------------------===//
25// CodeGenIntrinsic Implementation
26//===----------------------------------------------------------------------===//
27
28CodeGenIntrinsicTable::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
57CodeGenIntrinsic::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
150void 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
160void 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
248bool 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
255bool 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
265void 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