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