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