xref: /src/contrib/llvm-project/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
17fa27ce4SDimitry Andric //===- CodeGenIntrinsics.cpp - Intrinsic Class Wrapper --------------------===//
27fa27ce4SDimitry Andric //
37fa27ce4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47fa27ce4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
57fa27ce4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67fa27ce4SDimitry Andric //
77fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
87fa27ce4SDimitry Andric //
97fa27ce4SDimitry Andric // This file defines a wrapper class for the 'Intrinsic' TableGen class.
107fa27ce4SDimitry Andric //
117fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
127fa27ce4SDimitry Andric 
137fa27ce4SDimitry Andric #include "CodeGenIntrinsics.h"
147fa27ce4SDimitry Andric #include "llvm/ADT/ArrayRef.h"
157fa27ce4SDimitry Andric #include "llvm/ADT/STLExtras.h"
167fa27ce4SDimitry Andric #include "llvm/ADT/Twine.h"
177fa27ce4SDimitry Andric #include "llvm/Support/ErrorHandling.h"
187fa27ce4SDimitry Andric #include "llvm/TableGen/Error.h"
197fa27ce4SDimitry Andric #include "llvm/TableGen/Record.h"
207fa27ce4SDimitry Andric #include <algorithm>
217fa27ce4SDimitry Andric #include <cassert>
227fa27ce4SDimitry Andric using namespace llvm;
237fa27ce4SDimitry Andric 
247fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
257fa27ce4SDimitry Andric // CodeGenIntrinsic Implementation
267fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
277fa27ce4SDimitry Andric 
CodeGenIntrinsicTable(const RecordKeeper & RC)287fa27ce4SDimitry Andric CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) {
297fa27ce4SDimitry Andric   std::vector<Record *> IntrProperties =
307fa27ce4SDimitry Andric       RC.getAllDerivedDefinitions("IntrinsicProperty");
317fa27ce4SDimitry Andric 
327fa27ce4SDimitry Andric   std::vector<Record *> DefaultProperties;
337fa27ce4SDimitry Andric   for (Record *Rec : IntrProperties)
347fa27ce4SDimitry Andric     if (Rec->getValueAsBit("IsDefault"))
357fa27ce4SDimitry Andric       DefaultProperties.push_back(Rec);
367fa27ce4SDimitry Andric 
377fa27ce4SDimitry Andric   std::vector<Record *> Defs = RC.getAllDerivedDefinitions("Intrinsic");
387fa27ce4SDimitry Andric   Intrinsics.reserve(Defs.size());
397fa27ce4SDimitry Andric 
407fa27ce4SDimitry Andric   for (unsigned I = 0, e = Defs.size(); I != e; ++I)
417fa27ce4SDimitry Andric     Intrinsics.push_back(CodeGenIntrinsic(Defs[I], DefaultProperties));
427fa27ce4SDimitry Andric 
437fa27ce4SDimitry Andric   llvm::sort(Intrinsics,
447fa27ce4SDimitry Andric              [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) {
457fa27ce4SDimitry Andric                return std::tie(LHS.TargetPrefix, LHS.Name) <
467fa27ce4SDimitry Andric                       std::tie(RHS.TargetPrefix, RHS.Name);
477fa27ce4SDimitry Andric              });
487fa27ce4SDimitry Andric   Targets.push_back({"", 0, 0});
497fa27ce4SDimitry Andric   for (size_t I = 0, E = Intrinsics.size(); I < E; ++I)
507fa27ce4SDimitry Andric     if (Intrinsics[I].TargetPrefix != Targets.back().Name) {
517fa27ce4SDimitry Andric       Targets.back().Count = I - Targets.back().Offset;
527fa27ce4SDimitry Andric       Targets.push_back({Intrinsics[I].TargetPrefix, I, 0});
537fa27ce4SDimitry Andric     }
547fa27ce4SDimitry Andric   Targets.back().Count = Intrinsics.size() - Targets.back().Offset;
557fa27ce4SDimitry Andric }
567fa27ce4SDimitry Andric 
CodeGenIntrinsic(Record * R,ArrayRef<Record * > DefaultProperties)577fa27ce4SDimitry Andric CodeGenIntrinsic::CodeGenIntrinsic(Record *R,
58ac9a064cSDimitry Andric                                    ArrayRef<Record *> DefaultProperties) {
597fa27ce4SDimitry Andric   TheDef = R;
607fa27ce4SDimitry Andric   std::string DefName = std::string(R->getName());
617fa27ce4SDimitry Andric   ArrayRef<SMLoc> DefLoc = R->getLoc();
627fa27ce4SDimitry Andric   Properties = 0;
637fa27ce4SDimitry Andric   isOverloaded = false;
647fa27ce4SDimitry Andric   isCommutative = false;
657fa27ce4SDimitry Andric   canThrow = false;
667fa27ce4SDimitry Andric   isNoReturn = false;
677fa27ce4SDimitry Andric   isNoCallback = false;
687fa27ce4SDimitry Andric   isNoSync = false;
697fa27ce4SDimitry Andric   isNoFree = false;
707fa27ce4SDimitry Andric   isWillReturn = false;
717fa27ce4SDimitry Andric   isCold = false;
727fa27ce4SDimitry Andric   isNoDuplicate = false;
737fa27ce4SDimitry Andric   isNoMerge = false;
747fa27ce4SDimitry Andric   isConvergent = false;
757fa27ce4SDimitry Andric   isSpeculatable = false;
767fa27ce4SDimitry Andric   hasSideEffects = false;
777fa27ce4SDimitry Andric   isStrictFP = false;
787fa27ce4SDimitry Andric 
797fa27ce4SDimitry Andric   if (DefName.size() <= 4 || DefName.substr(0, 4) != "int_")
807fa27ce4SDimitry Andric     PrintFatalError(DefLoc,
817fa27ce4SDimitry Andric                     "Intrinsic '" + DefName + "' does not start with 'int_'!");
827fa27ce4SDimitry Andric 
837fa27ce4SDimitry Andric   EnumName = DefName.substr(4);
847fa27ce4SDimitry Andric 
857fa27ce4SDimitry Andric   if (R->getValue(
867fa27ce4SDimitry Andric           "ClangBuiltinName")) // Ignore a missing ClangBuiltinName field.
877fa27ce4SDimitry Andric     ClangBuiltinName = std::string(R->getValueAsString("ClangBuiltinName"));
887fa27ce4SDimitry Andric   if (R->getValue("MSBuiltinName")) // Ignore a missing MSBuiltinName field.
897fa27ce4SDimitry Andric     MSBuiltinName = std::string(R->getValueAsString("MSBuiltinName"));
907fa27ce4SDimitry Andric 
917fa27ce4SDimitry Andric   TargetPrefix = std::string(R->getValueAsString("TargetPrefix"));
927fa27ce4SDimitry Andric   Name = std::string(R->getValueAsString("LLVMName"));
937fa27ce4SDimitry Andric 
947fa27ce4SDimitry Andric   if (Name == "") {
957fa27ce4SDimitry Andric     // If an explicit name isn't specified, derive one from the DefName.
967fa27ce4SDimitry Andric     Name = "llvm.";
977fa27ce4SDimitry Andric 
987fa27ce4SDimitry Andric     for (unsigned i = 0, e = EnumName.size(); i != e; ++i)
997fa27ce4SDimitry Andric       Name += (EnumName[i] == '_') ? '.' : EnumName[i];
1007fa27ce4SDimitry Andric   } else {
1017fa27ce4SDimitry Andric     // Verify it starts with "llvm.".
1027fa27ce4SDimitry Andric     if (Name.size() <= 5 || Name.substr(0, 5) != "llvm.")
1037fa27ce4SDimitry Andric       PrintFatalError(DefLoc, "Intrinsic '" + DefName +
1047fa27ce4SDimitry Andric                                   "'s name does not start with 'llvm.'!");
1057fa27ce4SDimitry Andric   }
1067fa27ce4SDimitry Andric 
1077fa27ce4SDimitry Andric   // If TargetPrefix is specified, make sure that Name starts with
1087fa27ce4SDimitry Andric   // "llvm.<targetprefix>.".
1097fa27ce4SDimitry Andric   if (!TargetPrefix.empty()) {
1107fa27ce4SDimitry Andric     if (Name.size() < 6 + TargetPrefix.size() ||
1117fa27ce4SDimitry Andric         Name.substr(5, 1 + TargetPrefix.size()) != (TargetPrefix + "."))
1127fa27ce4SDimitry Andric       PrintFatalError(DefLoc, "Intrinsic '" + DefName +
1137fa27ce4SDimitry Andric                                   "' does not start with 'llvm." +
1147fa27ce4SDimitry Andric                                   TargetPrefix + ".'!");
1157fa27ce4SDimitry Andric   }
1167fa27ce4SDimitry Andric 
1177fa27ce4SDimitry Andric   if (auto *Types = R->getValue("Types")) {
1187fa27ce4SDimitry Andric     auto *TypeList = cast<ListInit>(Types->getValue());
1197fa27ce4SDimitry Andric     isOverloaded = R->getValueAsBit("isOverloaded");
1207fa27ce4SDimitry Andric 
1217fa27ce4SDimitry Andric     unsigned I = 0;
1227fa27ce4SDimitry Andric     for (unsigned E = R->getValueAsListInit("RetTypes")->size(); I < E; ++I)
1237fa27ce4SDimitry Andric       IS.RetTys.push_back(TypeList->getElementAsRecord(I));
1247fa27ce4SDimitry Andric 
1257fa27ce4SDimitry Andric     for (unsigned E = TypeList->size(); I < E; ++I)
1267fa27ce4SDimitry Andric       IS.ParamTys.push_back(TypeList->getElementAsRecord(I));
1277fa27ce4SDimitry Andric   }
1287fa27ce4SDimitry Andric 
1297fa27ce4SDimitry Andric   // Parse the intrinsic properties.
1307fa27ce4SDimitry Andric   ListInit *PropList = R->getValueAsListInit("IntrProperties");
1317fa27ce4SDimitry Andric   for (unsigned i = 0, e = PropList->size(); i != e; ++i) {
1327fa27ce4SDimitry Andric     Record *Property = PropList->getElementAsRecord(i);
1337fa27ce4SDimitry Andric     assert(Property->isSubClassOf("IntrinsicProperty") &&
1347fa27ce4SDimitry Andric            "Expected a property!");
1357fa27ce4SDimitry Andric 
1367fa27ce4SDimitry Andric     setProperty(Property);
1377fa27ce4SDimitry Andric   }
1387fa27ce4SDimitry Andric 
1397fa27ce4SDimitry Andric   // Set default properties to true.
1407fa27ce4SDimitry Andric   setDefaultProperties(R, DefaultProperties);
1417fa27ce4SDimitry Andric 
1427fa27ce4SDimitry Andric   // Also record the SDPatternOperator Properties.
1437fa27ce4SDimitry Andric   Properties = parseSDPatternOperatorProperties(R);
1447fa27ce4SDimitry Andric 
1457fa27ce4SDimitry Andric   // Sort the argument attributes for later benefit.
1467fa27ce4SDimitry Andric   for (auto &Attrs : ArgumentAttributes)
1477fa27ce4SDimitry Andric     llvm::sort(Attrs);
1487fa27ce4SDimitry Andric }
1497fa27ce4SDimitry Andric 
setDefaultProperties(Record * R,ArrayRef<Record * > DefaultProperties)1507fa27ce4SDimitry Andric void CodeGenIntrinsic::setDefaultProperties(
151ac9a064cSDimitry Andric     Record *R, ArrayRef<Record *> DefaultProperties) {
1527fa27ce4SDimitry Andric   // opt-out of using default attributes.
1537fa27ce4SDimitry Andric   if (R->getValueAsBit("DisableDefaultAttributes"))
1547fa27ce4SDimitry Andric     return;
1557fa27ce4SDimitry Andric 
1567fa27ce4SDimitry Andric   for (Record *Rec : DefaultProperties)
1577fa27ce4SDimitry Andric     setProperty(Rec);
1587fa27ce4SDimitry Andric }
1597fa27ce4SDimitry Andric 
setProperty(Record * R)1607fa27ce4SDimitry Andric void CodeGenIntrinsic::setProperty(Record *R) {
1617fa27ce4SDimitry Andric   if (R->getName() == "IntrNoMem")
1627fa27ce4SDimitry Andric     ME = MemoryEffects::none();
1637fa27ce4SDimitry Andric   else if (R->getName() == "IntrReadMem") {
1647fa27ce4SDimitry Andric     if (ME.onlyWritesMemory())
1657fa27ce4SDimitry Andric       PrintFatalError(TheDef->getLoc(),
1667fa27ce4SDimitry Andric                       Twine("IntrReadMem cannot be used after IntrNoMem or "
1677fa27ce4SDimitry Andric                             "IntrWriteMem. Default is ReadWrite"));
1687fa27ce4SDimitry Andric     ME &= MemoryEffects::readOnly();
1697fa27ce4SDimitry Andric   } else if (R->getName() == "IntrWriteMem") {
1707fa27ce4SDimitry Andric     if (ME.onlyReadsMemory())
1717fa27ce4SDimitry Andric       PrintFatalError(TheDef->getLoc(),
1727fa27ce4SDimitry Andric                       Twine("IntrWriteMem cannot be used after IntrNoMem or "
1737fa27ce4SDimitry Andric                             "IntrReadMem. Default is ReadWrite"));
1747fa27ce4SDimitry Andric     ME &= MemoryEffects::writeOnly();
1757fa27ce4SDimitry Andric   } else if (R->getName() == "IntrArgMemOnly")
1767fa27ce4SDimitry Andric     ME &= MemoryEffects::argMemOnly();
1777fa27ce4SDimitry Andric   else if (R->getName() == "IntrInaccessibleMemOnly")
1787fa27ce4SDimitry Andric     ME &= MemoryEffects::inaccessibleMemOnly();
1797fa27ce4SDimitry Andric   else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
1807fa27ce4SDimitry Andric     ME &= MemoryEffects::inaccessibleOrArgMemOnly();
1817fa27ce4SDimitry Andric   else if (R->getName() == "Commutative")
1827fa27ce4SDimitry Andric     isCommutative = true;
1837fa27ce4SDimitry Andric   else if (R->getName() == "Throws")
1847fa27ce4SDimitry Andric     canThrow = true;
1857fa27ce4SDimitry Andric   else if (R->getName() == "IntrNoDuplicate")
1867fa27ce4SDimitry Andric     isNoDuplicate = true;
1877fa27ce4SDimitry Andric   else if (R->getName() == "IntrNoMerge")
1887fa27ce4SDimitry Andric     isNoMerge = true;
1897fa27ce4SDimitry Andric   else if (R->getName() == "IntrConvergent")
1907fa27ce4SDimitry Andric     isConvergent = true;
1917fa27ce4SDimitry Andric   else if (R->getName() == "IntrNoReturn")
1927fa27ce4SDimitry Andric     isNoReturn = true;
1937fa27ce4SDimitry Andric   else if (R->getName() == "IntrNoCallback")
1947fa27ce4SDimitry Andric     isNoCallback = true;
1957fa27ce4SDimitry Andric   else if (R->getName() == "IntrNoSync")
1967fa27ce4SDimitry Andric     isNoSync = true;
1977fa27ce4SDimitry Andric   else if (R->getName() == "IntrNoFree")
1987fa27ce4SDimitry Andric     isNoFree = true;
1997fa27ce4SDimitry Andric   else if (R->getName() == "IntrWillReturn")
2007fa27ce4SDimitry Andric     isWillReturn = !isNoReturn;
2017fa27ce4SDimitry Andric   else if (R->getName() == "IntrCold")
2027fa27ce4SDimitry Andric     isCold = true;
2037fa27ce4SDimitry Andric   else if (R->getName() == "IntrSpeculatable")
2047fa27ce4SDimitry Andric     isSpeculatable = true;
2057fa27ce4SDimitry Andric   else if (R->getName() == "IntrHasSideEffects")
2067fa27ce4SDimitry Andric     hasSideEffects = true;
2077fa27ce4SDimitry Andric   else if (R->getName() == "IntrStrictFP")
2087fa27ce4SDimitry Andric     isStrictFP = true;
2097fa27ce4SDimitry Andric   else if (R->isSubClassOf("NoCapture")) {
2107fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2117fa27ce4SDimitry Andric     addArgAttribute(ArgNo, NoCapture);
2127fa27ce4SDimitry Andric   } else if (R->isSubClassOf("NoAlias")) {
2137fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2147fa27ce4SDimitry Andric     addArgAttribute(ArgNo, NoAlias);
2157fa27ce4SDimitry Andric   } else if (R->isSubClassOf("NoUndef")) {
2167fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2177fa27ce4SDimitry Andric     addArgAttribute(ArgNo, NoUndef);
2187fa27ce4SDimitry Andric   } else if (R->isSubClassOf("NonNull")) {
2197fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2207fa27ce4SDimitry Andric     addArgAttribute(ArgNo, NonNull);
2217fa27ce4SDimitry Andric   } else if (R->isSubClassOf("Returned")) {
2227fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2237fa27ce4SDimitry Andric     addArgAttribute(ArgNo, Returned);
2247fa27ce4SDimitry Andric   } else if (R->isSubClassOf("ReadOnly")) {
2257fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2267fa27ce4SDimitry Andric     addArgAttribute(ArgNo, ReadOnly);
2277fa27ce4SDimitry Andric   } else if (R->isSubClassOf("WriteOnly")) {
2287fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2297fa27ce4SDimitry Andric     addArgAttribute(ArgNo, WriteOnly);
2307fa27ce4SDimitry Andric   } else if (R->isSubClassOf("ReadNone")) {
2317fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2327fa27ce4SDimitry Andric     addArgAttribute(ArgNo, ReadNone);
2337fa27ce4SDimitry Andric   } else if (R->isSubClassOf("ImmArg")) {
2347fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2357fa27ce4SDimitry Andric     addArgAttribute(ArgNo, ImmArg);
2367fa27ce4SDimitry Andric   } else if (R->isSubClassOf("Align")) {
2377fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2387fa27ce4SDimitry Andric     uint64_t Align = R->getValueAsInt("Align");
2397fa27ce4SDimitry Andric     addArgAttribute(ArgNo, Alignment, Align);
2407fa27ce4SDimitry Andric   } else if (R->isSubClassOf("Dereferenceable")) {
2417fa27ce4SDimitry Andric     unsigned ArgNo = R->getValueAsInt("ArgNo");
2427fa27ce4SDimitry Andric     uint64_t Bytes = R->getValueAsInt("Bytes");
2437fa27ce4SDimitry Andric     addArgAttribute(ArgNo, Dereferenceable, Bytes);
2447fa27ce4SDimitry Andric   } else
2457fa27ce4SDimitry Andric     llvm_unreachable("Unknown property!");
2467fa27ce4SDimitry Andric }
2477fa27ce4SDimitry Andric 
isParamAPointer(unsigned ParamIdx) const2487fa27ce4SDimitry Andric bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const {
2497fa27ce4SDimitry Andric   if (ParamIdx >= IS.ParamTys.size())
2507fa27ce4SDimitry Andric     return false;
2517fa27ce4SDimitry Andric   return (IS.ParamTys[ParamIdx]->isSubClassOf("LLVMQualPointerType") ||
2527fa27ce4SDimitry Andric           IS.ParamTys[ParamIdx]->isSubClassOf("LLVMAnyPointerType"));
2537fa27ce4SDimitry Andric }
2547fa27ce4SDimitry Andric 
isParamImmArg(unsigned ParamIdx) const2557fa27ce4SDimitry Andric bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const {
2567fa27ce4SDimitry Andric   // Convert argument index to attribute index starting from `FirstArgIndex`.
2577fa27ce4SDimitry Andric   ++ParamIdx;
2587fa27ce4SDimitry Andric   if (ParamIdx >= ArgumentAttributes.size())
2597fa27ce4SDimitry Andric     return false;
2607fa27ce4SDimitry Andric   ArgAttribute Val{ImmArg, 0};
2617fa27ce4SDimitry Andric   return std::binary_search(ArgumentAttributes[ParamIdx].begin(),
2627fa27ce4SDimitry Andric                             ArgumentAttributes[ParamIdx].end(), Val);
2637fa27ce4SDimitry Andric }
2647fa27ce4SDimitry Andric 
addArgAttribute(unsigned Idx,ArgAttrKind AK,uint64_t V)2657fa27ce4SDimitry Andric void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK,
2667fa27ce4SDimitry Andric                                        uint64_t V) {
2677fa27ce4SDimitry Andric   if (Idx >= ArgumentAttributes.size())
2687fa27ce4SDimitry Andric     ArgumentAttributes.resize(Idx + 1);
2697fa27ce4SDimitry Andric   ArgumentAttributes[Idx].emplace_back(AK, V);
2707fa27ce4SDimitry Andric }
271