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