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 = ∬ 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