xref: /llvm-project/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp (revision 0c6457b781ae8365ef2169376ae78675b5b4896b)
1fa3d789dSPierre van Houtryve //===- CodeGenIntrinsics.cpp - Intrinsic Class Wrapper --------------------===//
2fa3d789dSPierre van Houtryve //
3fa3d789dSPierre van Houtryve // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fa3d789dSPierre van Houtryve // See https://llvm.org/LICENSE.txt for license information.
5fa3d789dSPierre van Houtryve // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fa3d789dSPierre van Houtryve //
7fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===//
8fa3d789dSPierre van Houtryve //
9fa3d789dSPierre van Houtryve // This file defines a wrapper class for the 'Intrinsic' TableGen class.
10fa3d789dSPierre van Houtryve //
11fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===//
12fa3d789dSPierre van Houtryve 
13fa3d789dSPierre van Houtryve #include "CodeGenIntrinsics.h"
14fa3d789dSPierre van Houtryve #include "llvm/ADT/ArrayRef.h"
15fa3d789dSPierre van Houtryve #include "llvm/ADT/STLExtras.h"
16fa3d789dSPierre van Houtryve #include "llvm/ADT/Twine.h"
17fa3d789dSPierre van Houtryve #include "llvm/Support/ErrorHandling.h"
18fa3d789dSPierre van Houtryve #include "llvm/TableGen/Error.h"
19fa3d789dSPierre van Houtryve #include "llvm/TableGen/Record.h"
20fa3d789dSPierre van Houtryve #include <algorithm>
21fa3d789dSPierre van Houtryve #include <cassert>
22fa3d789dSPierre van Houtryve using namespace llvm;
23fa3d789dSPierre van Houtryve 
24fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===//
25fa3d789dSPierre van Houtryve // CodeGenIntrinsic Implementation
26fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===//
27fa3d789dSPierre van Houtryve 
28660cc986SRahul Joshi CodeGenIntrinsicContext::CodeGenIntrinsicContext(const RecordKeeper &RC) {
29660cc986SRahul Joshi   for (const Record *Rec : RC.getAllDerivedDefinitions("IntrinsicProperty"))
30fa3d789dSPierre van Houtryve     if (Rec->getValueAsBit("IsDefault"))
31fa3d789dSPierre van Houtryve       DefaultProperties.push_back(Rec);
3250be455aSRahul Joshi 
3350be455aSRahul Joshi   // The maximum number of values that an intrinsic can return is the size of
3450be455aSRahul Joshi   // of `IIT_RetNumbers` list - 1 (since we index into this list using the
3550be455aSRahul Joshi   // number of return values as the index).
3650be455aSRahul Joshi   const auto *IIT_RetNumbers =
3750be455aSRahul Joshi       dyn_cast_or_null<ListInit>(RC.getGlobal("IIT_RetNumbers"));
3850be455aSRahul Joshi   if (!IIT_RetNumbers)
3950be455aSRahul Joshi     PrintFatalError("unable to find 'IIT_RetNumbers' list");
4050be455aSRahul Joshi   MaxNumReturn = IIT_RetNumbers->size() - 1;
41660cc986SRahul Joshi }
42660cc986SRahul Joshi 
43660cc986SRahul Joshi CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) {
44660cc986SRahul Joshi   CodeGenIntrinsicContext Ctx(RC);
45fa3d789dSPierre van Houtryve 
4616df489fSRahul Joshi   ArrayRef<const Record *> Defs = RC.getAllDerivedDefinitions("Intrinsic");
47fa3d789dSPierre van Houtryve   Intrinsics.reserve(Defs.size());
48fa3d789dSPierre van Houtryve 
49ddda37a6SRahul Joshi   for (const Record *Def : Defs)
50e0458a24SRahul Joshi     Intrinsics.emplace_back(CodeGenIntrinsic(Def, Ctx));
51fa3d789dSPierre van Houtryve 
52fa3d789dSPierre van Houtryve   llvm::sort(Intrinsics,
53fa3d789dSPierre van Houtryve              [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) {
5491fd3e76SRahul Joshi                // Order target independent intrinsics before target dependent
5591fd3e76SRahul Joshi                // ones.
5691fd3e76SRahul Joshi                bool LHSHasTarget = !LHS.TargetPrefix.empty();
5791fd3e76SRahul Joshi                bool RHSHasTarget = !RHS.TargetPrefix.empty();
5891fd3e76SRahul Joshi 
5991fd3e76SRahul Joshi                // To ensure deterministic sorted order when duplicates are
6091fd3e76SRahul Joshi                // present, use record ID as a tie-breaker similar to
6191fd3e76SRahul Joshi                // sortAndReportDuplicates in Utils.cpp.
62e0458a24SRahul Joshi                unsigned LhsID = LHS.TheDef->getID();
63e0458a24SRahul Joshi                unsigned RhsID = RHS.TheDef->getID();
6491fd3e76SRahul Joshi 
6591fd3e76SRahul Joshi                return std::tie(LHSHasTarget, LHS.Name, LhsID) <
6691fd3e76SRahul Joshi                       std::tie(RHSHasTarget, RHS.Name, RhsID);
67fa3d789dSPierre van Houtryve              });
68e0458a24SRahul Joshi 
69fa3d789dSPierre van Houtryve   Targets.push_back({"", 0, 0});
70fa3d789dSPierre van Houtryve   for (size_t I = 0, E = Intrinsics.size(); I < E; ++I)
71fa3d789dSPierre van Houtryve     if (Intrinsics[I].TargetPrefix != Targets.back().Name) {
72fa3d789dSPierre van Houtryve       Targets.back().Count = I - Targets.back().Offset;
73fa3d789dSPierre van Houtryve       Targets.push_back({Intrinsics[I].TargetPrefix, I, 0});
74fa3d789dSPierre van Houtryve     }
75fa3d789dSPierre van Houtryve   Targets.back().Count = Intrinsics.size() - Targets.back().Offset;
76e0458a24SRahul Joshi 
77e0458a24SRahul Joshi   CheckDuplicateIntrinsics();
782f43e659SRahul Joshi   CheckTargetIndependentIntrinsics();
792a0073f6SRahul Joshi   CheckOverloadSuffixConflicts();
80e0458a24SRahul Joshi }
81e0458a24SRahul Joshi 
82e0458a24SRahul Joshi // Check for duplicate intrinsic names.
83e0458a24SRahul Joshi void CodeGenIntrinsicTable::CheckDuplicateIntrinsics() const {
84e0458a24SRahul Joshi   // Since the Intrinsics vector is already sorted by name, if there are 2 or
85e0458a24SRahul Joshi   // more intrinsics with duplicate names, they will appear adjacent in sorted
86e0458a24SRahul Joshi   // order. Note that if the intrinsic name was derived from the record name
87e0458a24SRahul Joshi   // there cannot be be duplicate as TableGen parser would have flagged that.
88e0458a24SRahul Joshi   // However, if the name was specified in the intrinsic definition, then its
89e0458a24SRahul Joshi   // possible to have duplicate names.
90e0458a24SRahul Joshi   auto I = std::adjacent_find(
91e0458a24SRahul Joshi       Intrinsics.begin(), Intrinsics.end(),
92e0458a24SRahul Joshi       [](const CodeGenIntrinsic &Int1, const CodeGenIntrinsic &Int2) {
93e0458a24SRahul Joshi         return Int1.Name == Int2.Name;
94e0458a24SRahul Joshi       });
95e0458a24SRahul Joshi   if (I == Intrinsics.end())
96e0458a24SRahul Joshi     return;
97e0458a24SRahul Joshi 
98e0458a24SRahul Joshi   // Found a duplicate intrinsics.
99e0458a24SRahul Joshi   const CodeGenIntrinsic &First = *I;
100e0458a24SRahul Joshi   const CodeGenIntrinsic &Second = *(I + 1);
101e0458a24SRahul Joshi   PrintError(Second.TheDef,
102e0458a24SRahul Joshi              Twine("Intrinsic `") + First.Name + "` is already defined");
103e0458a24SRahul Joshi   PrintFatalNote(First.TheDef, "Previous definition here");
104fa3d789dSPierre van Houtryve }
105fa3d789dSPierre van Houtryve 
1062f43e659SRahul Joshi // For target independent intrinsics, check that their second dotted component
1072f43e659SRahul Joshi // does not match any target name.
1082f43e659SRahul Joshi void CodeGenIntrinsicTable::CheckTargetIndependentIntrinsics() const {
1092f43e659SRahul Joshi   SmallDenseSet<StringRef> TargetNames;
1102f43e659SRahul Joshi   for (const auto &Target : ArrayRef(Targets).drop_front())
1112f43e659SRahul Joshi     TargetNames.insert(Target.Name);
1122f43e659SRahul Joshi 
1132f43e659SRahul Joshi   // Set of target independent intrinsics.
1142f43e659SRahul Joshi   const auto &Set = Targets[0];
1152f43e659SRahul Joshi   for (const auto &Int : ArrayRef(&Intrinsics[Set.Offset], Set.Count)) {
1162f43e659SRahul Joshi     StringRef Name = Int.Name;
1172f43e659SRahul Joshi     StringRef Prefix = Name.drop_front(5).split('.').first;
1182f43e659SRahul Joshi     if (!TargetNames.contains(Prefix))
1192f43e659SRahul Joshi       continue;
1202f43e659SRahul Joshi     PrintFatalError(Int.TheDef,
1212f43e659SRahul Joshi                     "target independent intrinsic `" + Name +
1222f43e659SRahul Joshi                         "' has prefix `llvm." + Prefix +
1232f43e659SRahul Joshi                         "` that conflicts with intrinsics for target `" +
1242f43e659SRahul Joshi                         Prefix + "`");
1252f43e659SRahul Joshi   }
1262f43e659SRahul Joshi }
1272f43e659SRahul Joshi 
1282a0073f6SRahul Joshi // Return true if the given Suffix looks like a mangled type. Note that this
1292a0073f6SRahul Joshi // check is conservative, but allows all existing LLVM intrinsic suffixes to be
1302a0073f6SRahul Joshi // considered as not looking like a mangling suffix.
1312a0073f6SRahul Joshi static bool doesSuffixLookLikeMangledType(StringRef Suffix) {
1322a0073f6SRahul Joshi   // Try to match against possible mangling suffixes for various types.
1332a0073f6SRahul Joshi   // See getMangledTypeStr() for the mangling suffixes possible. It includes
1342a0073f6SRahul Joshi   //  pointer       : p[0-9]+
1352a0073f6SRahul Joshi   //  array         : a[0-9]+.+
1362a0073f6SRahul Joshi   //  struct:       : s_/sl_.+
1372a0073f6SRahul Joshi   //  function      : f_.+
1382a0073f6SRahul Joshi   //  vector        : v/nxv[0-9]+.+
1392a0073f6SRahul Joshi   //  target type   : t.+
1402a0073f6SRahul Joshi   //  integer       : i[0-9]+
1412a0073f6SRahul Joshi   //  named types   : See `NamedTypes` below.
1422a0073f6SRahul Joshi 
1432a0073f6SRahul Joshi   // Match anything with an _, so match function and struct types.
1442a0073f6SRahul Joshi   if (Suffix.contains('_'))
1452a0073f6SRahul Joshi     return true;
1462a0073f6SRahul Joshi 
1472a0073f6SRahul Joshi   // [av][0-9]+.+, simplified to [av][0-9].+
1482a0073f6SRahul Joshi   if (Suffix.size() >= 2 && is_contained("av", Suffix[0]) && isDigit(Suffix[1]))
1492a0073f6SRahul Joshi     return true;
1502a0073f6SRahul Joshi 
1512a0073f6SRahul Joshi   // nxv[0-9]+.+, simplified to nxv[0-9].+
1522a0073f6SRahul Joshi   if (Suffix.size() >= 4 && Suffix.starts_with("nxv") && isDigit(Suffix[3]))
1532a0073f6SRahul Joshi     return true;
1542a0073f6SRahul Joshi 
1552a0073f6SRahul Joshi   // t.+
1562a0073f6SRahul Joshi   if (Suffix.size() > 1 && Suffix.starts_with('t'))
1572a0073f6SRahul Joshi     return false;
1582a0073f6SRahul Joshi 
1592a0073f6SRahul Joshi   // [pi][0-9]+
160*0c6457b7SMason Remy   if (Suffix.size() > 1 && is_contained("pi", Suffix[0]) &&
161*0c6457b7SMason Remy       all_of(Suffix.drop_front(), isDigit))
1622a0073f6SRahul Joshi     return true;
1632a0073f6SRahul Joshi 
1642a0073f6SRahul Joshi   // Match one of the named types.
1652a0073f6SRahul Joshi   static constexpr StringLiteral NamedTypes[] = {
1662a0073f6SRahul Joshi       "isVoid", "Metadata", "f16",  "f32",     "f64",
1672a0073f6SRahul Joshi       "f80",    "f128",     "bf16", "ppcf128", "x86amx"};
1682a0073f6SRahul Joshi   return is_contained(NamedTypes, Suffix);
1692a0073f6SRahul Joshi }
1702a0073f6SRahul Joshi 
1712a0073f6SRahul Joshi // Check for conflicts with overloaded intrinsics. If there exists an overloaded
1722a0073f6SRahul Joshi // intrinsic with base name `llvm.target.foo`, LLVM will add a mangling suffix
1732a0073f6SRahul Joshi // to it to encode the overload types. This mangling suffix is 1 or more .
1742a0073f6SRahul Joshi // prefixed mangled type string as defined in `getMangledTypeStr`. If there
1752a0073f6SRahul Joshi // exists another intrinsic `llvm.target.foo[.<suffixN>]+`, which has the same
1762a0073f6SRahul Joshi // prefix as the overloaded intrinsic, its possible that there may be a name
1772a0073f6SRahul Joshi // conflict with the overloaded intrinsic and either one may interfere with name
1782a0073f6SRahul Joshi // lookup for the other, leading to wrong intrinsic ID being assigned.
1792a0073f6SRahul Joshi //
1802a0073f6SRahul Joshi // The actual name lookup in the intrinsic name table is done by a search
1812a0073f6SRahul Joshi // on each successive '.' separted component of the intrinsic name (see
1822a0073f6SRahul Joshi // `lookupLLVMIntrinsicByName`). Consider first the case where there exists a
1832a0073f6SRahul Joshi // non-overloaded intrinsic `llvm.target.foo[.suffix]+`. For the non-overloaded
1842a0073f6SRahul Joshi // intrinsics, the name lookup is an exact match, so the presence of the
1852a0073f6SRahul Joshi // overloaded intrinsic with the same prefix will not interfere with the
1862a0073f6SRahul Joshi // search. However, a lookup intended to match the overloaded intrinsic might be
1872a0073f6SRahul Joshi // affected by the presence of another entry in the name table with the same
1882a0073f6SRahul Joshi // prefix.
1892a0073f6SRahul Joshi //
1902a0073f6SRahul Joshi // Since LLVM's name lookup first selects the target specific (or target
1912a0073f6SRahul Joshi // independent) slice of the name table to look into, intrinsics in 2 different
1922a0073f6SRahul Joshi // targets cannot conflict with each other. Within a specific target,
1932a0073f6SRahul Joshi // if we have an overloaded intrinsic with name `llvm.target.foo` and another
1942a0073f6SRahul Joshi // one with same prefix and one or more suffixes `llvm.target.foo[.<suffixN>]+`,
1952a0073f6SRahul Joshi // then the name search will try to first match against suffix0, then suffix1
1962a0073f6SRahul Joshi // etc. If suffix0 can match a mangled type, then the search for an
1972a0073f6SRahul Joshi // `llvm.target.foo` with a mangling suffix can match against suffix0,
1982a0073f6SRahul Joshi // preventing a match with `llvm.target.foo`. If suffix0 cannot match a mangled
1992a0073f6SRahul Joshi // type, then that cannot happen, so we do not need to check for later suffixes.
2002a0073f6SRahul Joshi //
2012a0073f6SRahul Joshi // Generalizing, the `llvm.target.foo[.suffixN]+` will cause a conflict if the
2022a0073f6SRahul Joshi // first suffix (.suffix0) can match a mangled type (and then we do not need to
2032a0073f6SRahul Joshi // check later suffixes) and will not cause a conflict if it cannot (and then
2042a0073f6SRahul Joshi // again, we do not need to check for later suffixes).
2052a0073f6SRahul Joshi void CodeGenIntrinsicTable::CheckOverloadSuffixConflicts() const {
2062a0073f6SRahul Joshi   for (const TargetSet &Set : Targets) {
2072a0073f6SRahul Joshi     const CodeGenIntrinsic *Overloaded = nullptr;
2082a0073f6SRahul Joshi     for (const CodeGenIntrinsic &Int : (*this)[Set]) {
2092a0073f6SRahul Joshi       // If we do not have an overloaded intrinsic to check against, nothing
2102a0073f6SRahul Joshi       // to do except potentially identifying this as a candidate for checking
2112a0073f6SRahul Joshi       // against in future iteration.
2122a0073f6SRahul Joshi       if (!Overloaded) {
2132a0073f6SRahul Joshi         if (Int.isOverloaded)
2142a0073f6SRahul Joshi           Overloaded = &Int;
2152a0073f6SRahul Joshi         continue;
2162a0073f6SRahul Joshi       }
2172a0073f6SRahul Joshi 
2182a0073f6SRahul Joshi       StringRef Name = Int.Name;
2192a0073f6SRahul Joshi       StringRef OverloadName = Overloaded->Name;
2202a0073f6SRahul Joshi       // If we have an overloaded intrinsic to check again, check if its name is
2212a0073f6SRahul Joshi       // a proper prefix of this intrinsic.
2222a0073f6SRahul Joshi       if (Name.starts_with(OverloadName) && Name[OverloadName.size()] == '.') {
2232a0073f6SRahul Joshi         // If yes, verify suffixes and flag an error.
2242a0073f6SRahul Joshi         StringRef Suffixes = Name.drop_front(OverloadName.size() + 1);
2252a0073f6SRahul Joshi 
2262a0073f6SRahul Joshi         // Only need to look at the first suffix.
2272a0073f6SRahul Joshi         StringRef Suffix0 = Suffixes.split('.').first;
2282a0073f6SRahul Joshi 
2292a0073f6SRahul Joshi         if (!doesSuffixLookLikeMangledType(Suffix0))
2302a0073f6SRahul Joshi           continue;
2312a0073f6SRahul Joshi 
2322a0073f6SRahul Joshi         unsigned SuffixSize = OverloadName.size() + 1 + Suffix0.size();
2332a0073f6SRahul Joshi         // If suffix looks like mangling suffix, flag it as an error.
2342a0073f6SRahul Joshi         PrintError(Int.TheDef->getLoc(),
2352a0073f6SRahul Joshi                    "intrinsic `" + Name + "` cannot share prefix `" +
2362a0073f6SRahul Joshi                        Name.take_front(SuffixSize) +
2372a0073f6SRahul Joshi                        "` with another overloaded intrinsic `" + OverloadName +
2382a0073f6SRahul Joshi                        "`");
2392a0073f6SRahul Joshi         PrintNote(Overloaded->TheDef->getLoc(),
2402a0073f6SRahul Joshi                   "Overloaded intrinsic `" + OverloadName + "` defined here");
2412a0073f6SRahul Joshi         continue;
2422a0073f6SRahul Joshi       }
2432a0073f6SRahul Joshi 
2442a0073f6SRahul Joshi       // If we find an intrinsic that is not a proper prefix, any later
2452a0073f6SRahul Joshi       // intrinsic is also not going to be a proper prefix, so invalidate the
2462a0073f6SRahul Joshi       // overloaded to check against.
2472a0073f6SRahul Joshi       Overloaded = nullptr;
2482a0073f6SRahul Joshi     }
2492a0073f6SRahul Joshi   }
2502a0073f6SRahul Joshi }
2512a0073f6SRahul Joshi 
25291fdfec2SRahul Joshi const CodeGenIntrinsic &CodeGenIntrinsicMap::operator[](const Record *Record) {
253660cc986SRahul Joshi   if (!Record->isSubClassOf("Intrinsic"))
254660cc986SRahul Joshi     PrintFatalError("Intrinsic defs should be subclass of 'Intrinsic' class");
255660cc986SRahul Joshi 
256660cc986SRahul Joshi   auto [Iter, Inserted] = Map.try_emplace(Record);
257660cc986SRahul Joshi   if (Inserted)
258660cc986SRahul Joshi     Iter->second = std::make_unique<CodeGenIntrinsic>(Record, Ctx);
259660cc986SRahul Joshi   return *Iter->second;
260660cc986SRahul Joshi }
261660cc986SRahul Joshi 
262ddda37a6SRahul Joshi CodeGenIntrinsic::CodeGenIntrinsic(const Record *R,
263660cc986SRahul Joshi                                    const CodeGenIntrinsicContext &Ctx)
264ddda37a6SRahul Joshi     : TheDef(R) {
265ddda37a6SRahul Joshi   StringRef DefName = TheDef->getName();
266fa3d789dSPierre van Houtryve   ArrayRef<SMLoc> DefLoc = R->getLoc();
267fa3d789dSPierre van Houtryve 
268ddda37a6SRahul Joshi   if (!DefName.starts_with("int_"))
269fa3d789dSPierre van Houtryve     PrintFatalError(DefLoc,
270fa3d789dSPierre van Houtryve                     "Intrinsic '" + DefName + "' does not start with 'int_'!");
271fa3d789dSPierre van Houtryve 
272fa3d789dSPierre van Houtryve   EnumName = DefName.substr(4);
273fa3d789dSPierre van Houtryve 
274ddda37a6SRahul Joshi   // Ignore a missing ClangBuiltinName field.
275ddda37a6SRahul Joshi   ClangBuiltinName =
276ddda37a6SRahul Joshi       R->getValueAsOptionalString("ClangBuiltinName").value_or("");
277ddda37a6SRahul Joshi   // Ignore a missing MSBuiltinName field.
278ddda37a6SRahul Joshi   MSBuiltinName = R->getValueAsOptionalString("MSBuiltinName").value_or("");
279fa3d789dSPierre van Houtryve 
280ddda37a6SRahul Joshi   TargetPrefix = R->getValueAsString("TargetPrefix");
281ddda37a6SRahul Joshi   Name = R->getValueAsString("LLVMName").str();
282fa3d789dSPierre van Houtryve 
283fa3d789dSPierre van Houtryve   if (Name == "") {
284fa3d789dSPierre van Houtryve     // If an explicit name isn't specified, derive one from the DefName.
285ddda37a6SRahul Joshi     Name = "llvm." + EnumName.str();
286ddda37a6SRahul Joshi     llvm::replace(Name, '_', '.');
287fa3d789dSPierre van Houtryve   } else {
288fa3d789dSPierre van Houtryve     // Verify it starts with "llvm.".
289ddda37a6SRahul Joshi     if (!StringRef(Name).starts_with("llvm."))
290fa3d789dSPierre van Houtryve       PrintFatalError(DefLoc, "Intrinsic '" + DefName +
291fa3d789dSPierre van Houtryve                                   "'s name does not start with 'llvm.'!");
292fa3d789dSPierre van Houtryve   }
293fa3d789dSPierre van Houtryve 
294fa3d789dSPierre van Houtryve   // If TargetPrefix is specified, make sure that Name starts with
295fa3d789dSPierre van Houtryve   // "llvm.<targetprefix>.".
296fa3d789dSPierre van Houtryve   if (!TargetPrefix.empty()) {
297ddda37a6SRahul Joshi     StringRef Prefix = StringRef(Name).drop_front(5); // Drop llvm.
298ddda37a6SRahul Joshi     if (!Prefix.consume_front(TargetPrefix) || !Prefix.starts_with('.'))
299fa3d789dSPierre van Houtryve       PrintFatalError(DefLoc, "Intrinsic '" + DefName +
300fa3d789dSPierre van Houtryve                                   "' does not start with 'llvm." +
301fa3d789dSPierre van Houtryve                                   TargetPrefix + ".'!");
302fa3d789dSPierre van Houtryve   }
303fa3d789dSPierre van Houtryve 
30450be455aSRahul Joshi   unsigned NumRet = R->getValueAsListInit("RetTypes")->size();
30550be455aSRahul Joshi   if (NumRet > Ctx.MaxNumReturn)
30650be455aSRahul Joshi     PrintFatalError(DefLoc, "intrinsics can only return upto " +
30750be455aSRahul Joshi                                 Twine(Ctx.MaxNumReturn) + " values, '" +
30850be455aSRahul Joshi                                 DefName + "' returns " + Twine(NumRet) +
30950be455aSRahul Joshi                                 " values");
31050be455aSRahul Joshi 
31198c6bbfeSRahul Joshi   const Record *TypeInfo = R->getValueAsDef("TypeInfo");
31298c6bbfeSRahul Joshi   if (!TypeInfo->isSubClassOf("TypeInfoGen"))
31398c6bbfeSRahul Joshi     PrintFatalError(DefLoc, "TypeInfo field in " + DefName +
31498c6bbfeSRahul Joshi                                 " should be of subclass of TypeInfoGen!");
315fa3d789dSPierre van Houtryve 
31698c6bbfeSRahul Joshi   isOverloaded = TypeInfo->getValueAsBit("isOverloaded");
31798c6bbfeSRahul Joshi   const ListInit *TypeList = TypeInfo->getValueAsListInit("Types");
318fa3d789dSPierre van Houtryve 
31998c6bbfeSRahul Joshi   // Types field is a concatenation of Return types followed by Param types.
32098c6bbfeSRahul Joshi   unsigned Idx = 0;
32198c6bbfeSRahul Joshi   for (; Idx < NumRet; ++Idx)
32298c6bbfeSRahul Joshi     IS.RetTys.push_back(TypeList->getElementAsRecord(Idx));
32398c6bbfeSRahul Joshi 
32498c6bbfeSRahul Joshi   for (unsigned E = TypeList->size(); Idx < E; ++Idx)
32598c6bbfeSRahul Joshi     IS.ParamTys.push_back(TypeList->getElementAsRecord(Idx));
326fa3d789dSPierre van Houtryve 
327fa3d789dSPierre van Houtryve   // Parse the intrinsic properties.
32862e2c7fbSRahul Joshi   const ListInit *PropList = R->getValueAsListInit("IntrProperties");
329fa3d789dSPierre van Houtryve   for (unsigned i = 0, e = PropList->size(); i != e; ++i) {
330ddda37a6SRahul Joshi     const Record *Property = PropList->getElementAsRecord(i);
331fa3d789dSPierre van Houtryve     assert(Property->isSubClassOf("IntrinsicProperty") &&
332fa3d789dSPierre van Houtryve            "Expected a property!");
333fa3d789dSPierre van Houtryve 
334fa3d789dSPierre van Houtryve     setProperty(Property);
335fa3d789dSPierre van Houtryve   }
336fa3d789dSPierre van Houtryve 
337fa3d789dSPierre van Houtryve   // Set default properties to true.
338660cc986SRahul Joshi   setDefaultProperties(Ctx.DefaultProperties);
339fa3d789dSPierre van Houtryve 
340fa3d789dSPierre van Houtryve   // Also record the SDPatternOperator Properties.
341fa3d789dSPierre van Houtryve   Properties = parseSDPatternOperatorProperties(R);
342fa3d789dSPierre van Houtryve 
343fa3d789dSPierre van Houtryve   // Sort the argument attributes for later benefit.
344fa3d789dSPierre van Houtryve   for (auto &Attrs : ArgumentAttributes)
345fa3d789dSPierre van Houtryve     llvm::sort(Attrs);
346fa3d789dSPierre van Houtryve }
347fa3d789dSPierre van Houtryve 
348fa3d789dSPierre van Houtryve void CodeGenIntrinsic::setDefaultProperties(
349ddda37a6SRahul Joshi     ArrayRef<const Record *> DefaultProperties) {
350fa3d789dSPierre van Houtryve   // opt-out of using default attributes.
351ddda37a6SRahul Joshi   if (TheDef->getValueAsBit("DisableDefaultAttributes"))
352fa3d789dSPierre van Houtryve     return;
353fa3d789dSPierre van Houtryve 
354ddda37a6SRahul Joshi   for (const Record *Rec : DefaultProperties)
355fa3d789dSPierre van Houtryve     setProperty(Rec);
356fa3d789dSPierre van Houtryve }
357fa3d789dSPierre van Houtryve 
358ddda37a6SRahul Joshi void CodeGenIntrinsic::setProperty(const Record *R) {
359fa3d789dSPierre van Houtryve   if (R->getName() == "IntrNoMem")
360fa3d789dSPierre van Houtryve     ME = MemoryEffects::none();
361fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrReadMem") {
362fa3d789dSPierre van Houtryve     if (ME.onlyWritesMemory())
363fa3d789dSPierre van Houtryve       PrintFatalError(TheDef->getLoc(),
364fa3d789dSPierre van Houtryve                       Twine("IntrReadMem cannot be used after IntrNoMem or "
365fa3d789dSPierre van Houtryve                             "IntrWriteMem. Default is ReadWrite"));
366fa3d789dSPierre van Houtryve     ME &= MemoryEffects::readOnly();
367fa3d789dSPierre van Houtryve   } else if (R->getName() == "IntrWriteMem") {
368fa3d789dSPierre van Houtryve     if (ME.onlyReadsMemory())
369fa3d789dSPierre van Houtryve       PrintFatalError(TheDef->getLoc(),
370fa3d789dSPierre van Houtryve                       Twine("IntrWriteMem cannot be used after IntrNoMem or "
371fa3d789dSPierre van Houtryve                             "IntrReadMem. Default is ReadWrite"));
372fa3d789dSPierre van Houtryve     ME &= MemoryEffects::writeOnly();
373fa3d789dSPierre van Houtryve   } else if (R->getName() == "IntrArgMemOnly")
374fa3d789dSPierre van Houtryve     ME &= MemoryEffects::argMemOnly();
375fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrInaccessibleMemOnly")
376fa3d789dSPierre van Houtryve     ME &= MemoryEffects::inaccessibleMemOnly();
377fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
378fa3d789dSPierre van Houtryve     ME &= MemoryEffects::inaccessibleOrArgMemOnly();
379fa3d789dSPierre van Houtryve   else if (R->getName() == "Commutative")
380fa3d789dSPierre van Houtryve     isCommutative = true;
381fa3d789dSPierre van Houtryve   else if (R->getName() == "Throws")
382fa3d789dSPierre van Houtryve     canThrow = true;
383fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrNoDuplicate")
384fa3d789dSPierre van Houtryve     isNoDuplicate = true;
385fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrNoMerge")
386fa3d789dSPierre van Houtryve     isNoMerge = true;
387fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrConvergent")
388fa3d789dSPierre van Houtryve     isConvergent = true;
389fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrNoReturn")
390fa3d789dSPierre van Houtryve     isNoReturn = true;
391fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrNoCallback")
392fa3d789dSPierre van Houtryve     isNoCallback = true;
393fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrNoSync")
394fa3d789dSPierre van Houtryve     isNoSync = true;
395fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrNoFree")
396fa3d789dSPierre van Houtryve     isNoFree = true;
397fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrWillReturn")
398fa3d789dSPierre van Houtryve     isWillReturn = !isNoReturn;
399fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrCold")
400fa3d789dSPierre van Houtryve     isCold = true;
401fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrSpeculatable")
402fa3d789dSPierre van Houtryve     isSpeculatable = true;
403fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrHasSideEffects")
404fa3d789dSPierre van Houtryve     hasSideEffects = true;
405fa3d789dSPierre van Houtryve   else if (R->getName() == "IntrStrictFP")
406fa3d789dSPierre van Houtryve     isStrictFP = true;
407fa3d789dSPierre van Houtryve   else if (R->isSubClassOf("NoCapture")) {
408fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
409fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, NoCapture);
410fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("NoAlias")) {
411fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
412fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, NoAlias);
413fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("NoUndef")) {
414fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
415fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, NoUndef);
416fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("NonNull")) {
417fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
418fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, NonNull);
419fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("Returned")) {
420fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
421fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, Returned);
422fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("ReadOnly")) {
423fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
424fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, ReadOnly);
425fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("WriteOnly")) {
426fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
427fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, WriteOnly);
428fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("ReadNone")) {
429fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
430fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, ReadNone);
431fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("ImmArg")) {
432fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
433fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, ImmArg);
434fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("Align")) {
435fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
436fa3d789dSPierre van Houtryve     uint64_t Align = R->getValueAsInt("Align");
437fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, Alignment, Align);
438fa3d789dSPierre van Houtryve   } else if (R->isSubClassOf("Dereferenceable")) {
439fa3d789dSPierre van Houtryve     unsigned ArgNo = R->getValueAsInt("ArgNo");
440fa3d789dSPierre van Houtryve     uint64_t Bytes = R->getValueAsInt("Bytes");
441fa3d789dSPierre van Houtryve     addArgAttribute(ArgNo, Dereferenceable, Bytes);
442fa3d789dSPierre van Houtryve   } else
443fa3d789dSPierre van Houtryve     llvm_unreachable("Unknown property!");
444fa3d789dSPierre van Houtryve }
445fa3d789dSPierre van Houtryve 
446fa3d789dSPierre van Houtryve bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
447fa3d789dSPierre van Houtryve   if (ParamIdx >= IS.ParamTys.size())
448fa3d789dSPierre van Houtryve     return false;
449fa3d789dSPierre van Houtryve   return (IS.ParamTys[ParamIdx]->isSubClassOf("LLVMQualPointerType") ||
450fa3d789dSPierre van Houtryve           IS.ParamTys[ParamIdx]->isSubClassOf("LLVMAnyPointerType"));
451fa3d789dSPierre van Houtryve }
452fa3d789dSPierre van Houtryve 
453fa3d789dSPierre van Houtryve bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const {
454fa3d789dSPierre van Houtryve   // Convert argument index to attribute index starting from `FirstArgIndex`.
455fa3d789dSPierre van Houtryve   ++ParamIdx;
456fa3d789dSPierre van Houtryve   if (ParamIdx >= ArgumentAttributes.size())
457fa3d789dSPierre van Houtryve     return false;
458fa3d789dSPierre van Houtryve   ArgAttribute Val{ImmArg, 0};
459fa3d789dSPierre van Houtryve   return std::binary_search(ArgumentAttributes[ParamIdx].begin(),
460fa3d789dSPierre van Houtryve                             ArgumentAttributes[ParamIdx].end(), Val);
461fa3d789dSPierre van Houtryve }
462fa3d789dSPierre van Houtryve 
463fa3d789dSPierre van Houtryve void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK,
464fa3d789dSPierre van Houtryve                                        uint64_t V) {
465fa3d789dSPierre van Houtryve   if (Idx >= ArgumentAttributes.size())
466fa3d789dSPierre van Houtryve     ArgumentAttributes.resize(Idx + 1);
467fa3d789dSPierre van Houtryve   ArgumentAttributes[Idx].emplace_back(AK, V);
468fa3d789dSPierre van Houtryve }
469