1 //===- LLVMAttrs.cpp - LLVM Attributes registration -----------------------===// 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 the attribute details for the LLVM IR dialect in MLIR. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" 14 #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 15 #include "mlir/IR/Builders.h" 16 #include "mlir/IR/DialectImplementation.h" 17 #include "mlir/Interfaces/FunctionInterfaces.h" 18 #include "llvm/ADT/StringExtras.h" 19 #include "llvm/ADT/TypeSwitch.h" 20 #include "llvm/BinaryFormat/Dwarf.h" 21 #include "llvm/IR/DebugInfoMetadata.h" 22 #include <optional> 23 24 using namespace mlir; 25 using namespace mlir::LLVM; 26 27 /// Parses DWARF expression arguments with respect to the DWARF operation 28 /// opcode. Some DWARF expression operations have a specific number of operands 29 /// and may appear in a textual form. 30 static ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode, 31 SmallVector<uint64_t> &args); 32 33 /// Prints DWARF expression arguments with respect to the specific DWARF 34 /// operation. Some operands are printed in their textual form. 35 static void printExpressionArg(AsmPrinter &printer, uint64_t opcode, 36 ArrayRef<uint64_t> args); 37 38 #include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.cpp.inc" 39 #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc" 40 #define GET_ATTRDEF_CLASSES 41 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc" 42 43 //===----------------------------------------------------------------------===// 44 // LLVMDialect registration 45 //===----------------------------------------------------------------------===// 46 47 void LLVMDialect::registerAttributes() { 48 addAttributes< 49 #define GET_ATTRDEF_LIST 50 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc" 51 52 >(); 53 } 54 55 //===----------------------------------------------------------------------===// 56 // AliasScopeAttr 57 //===----------------------------------------------------------------------===// 58 59 LogicalResult 60 AliasScopeAttr::verify(function_ref<InFlightDiagnostic()> emitError, 61 Attribute id, AliasScopeDomainAttr domain, 62 StringAttr description) { 63 (void)domain; 64 (void)description; 65 if (!llvm::isa<StringAttr, DistinctAttr>(id)) 66 return emitError() 67 << "id of an alias scope must be a StringAttr or a DistrinctAttr"; 68 69 return success(); 70 } 71 72 //===----------------------------------------------------------------------===// 73 // DINodeAttr 74 //===----------------------------------------------------------------------===// 75 76 bool DINodeAttr::classof(Attribute attr) { 77 return llvm::isa< 78 DIBasicTypeAttr, DICommonBlockAttr, DICompileUnitAttr, 79 DICompositeTypeAttr, DIDerivedTypeAttr, DIFileAttr, DIGenericSubrangeAttr, 80 DIGlobalVariableAttr, DIImportedEntityAttr, DILabelAttr, 81 DILexicalBlockAttr, DILexicalBlockFileAttr, DILocalVariableAttr, 82 DIModuleAttr, DINamespaceAttr, DINullTypeAttr, DIAnnotationAttr, 83 DIStringTypeAttr, DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>( 84 attr); 85 } 86 87 //===----------------------------------------------------------------------===// 88 // DIScopeAttr 89 //===----------------------------------------------------------------------===// 90 91 bool DIScopeAttr::classof(Attribute attr) { 92 return llvm::isa<DICommonBlockAttr, DICompileUnitAttr, DICompositeTypeAttr, 93 DIFileAttr, DILocalScopeAttr, DIModuleAttr, DINamespaceAttr>( 94 attr); 95 } 96 97 //===----------------------------------------------------------------------===// 98 // DILocalScopeAttr 99 //===----------------------------------------------------------------------===// 100 101 bool DILocalScopeAttr::classof(Attribute attr) { 102 return llvm::isa<DILexicalBlockAttr, DILexicalBlockFileAttr, 103 DISubprogramAttr>(attr); 104 } 105 106 //===----------------------------------------------------------------------===// 107 // DIVariableAttr 108 //===----------------------------------------------------------------------===// 109 110 bool DIVariableAttr::classof(Attribute attr) { 111 return llvm::isa<DILocalVariableAttr, DIGlobalVariableAttr>(attr); 112 } 113 114 //===----------------------------------------------------------------------===// 115 // DITypeAttr 116 //===----------------------------------------------------------------------===// 117 118 bool DITypeAttr::classof(Attribute attr) { 119 return llvm::isa<DINullTypeAttr, DIBasicTypeAttr, DICompositeTypeAttr, 120 DIDerivedTypeAttr, DIStringTypeAttr, DISubroutineTypeAttr>( 121 attr); 122 } 123 124 //===----------------------------------------------------------------------===// 125 // TBAANodeAttr 126 //===----------------------------------------------------------------------===// 127 128 bool TBAANodeAttr::classof(Attribute attr) { 129 return llvm::isa<TBAATypeDescriptorAttr, TBAARootAttr>(attr); 130 } 131 132 //===----------------------------------------------------------------------===// 133 // MemoryEffectsAttr 134 //===----------------------------------------------------------------------===// 135 136 MemoryEffectsAttr MemoryEffectsAttr::get(MLIRContext *context, 137 ArrayRef<ModRefInfo> memInfoArgs) { 138 if (memInfoArgs.empty()) 139 return MemoryEffectsAttr::get(context, ModRefInfo::ModRef, 140 ModRefInfo::ModRef, ModRefInfo::ModRef); 141 if (memInfoArgs.size() == 3) 142 return MemoryEffectsAttr::get(context, memInfoArgs[0], memInfoArgs[1], 143 memInfoArgs[2]); 144 return {}; 145 } 146 147 bool MemoryEffectsAttr::isReadWrite() { 148 if (this->getArgMem() != ModRefInfo::ModRef) 149 return false; 150 if (this->getInaccessibleMem() != ModRefInfo::ModRef) 151 return false; 152 if (this->getOther() != ModRefInfo::ModRef) 153 return false; 154 return true; 155 } 156 157 //===----------------------------------------------------------------------===// 158 // DIExpression 159 //===----------------------------------------------------------------------===// 160 161 DIExpressionAttr DIExpressionAttr::get(MLIRContext *context) { 162 return get(context, ArrayRef<DIExpressionElemAttr>({})); 163 } 164 165 ParseResult parseExpressionArg(AsmParser &parser, uint64_t opcode, 166 SmallVector<uint64_t> &args) { 167 auto operandParser = [&]() -> LogicalResult { 168 uint64_t operand = 0; 169 if (!args.empty() && opcode == llvm::dwarf::DW_OP_LLVM_convert) { 170 // Attempt to parse a keyword. 171 StringRef keyword; 172 if (succeeded(parser.parseOptionalKeyword(&keyword))) { 173 operand = llvm::dwarf::getAttributeEncoding(keyword); 174 if (operand == 0) { 175 // The keyword is invalid. 176 return parser.emitError(parser.getCurrentLocation()) 177 << "encountered unknown attribute encoding \"" << keyword 178 << "\""; 179 } 180 } 181 } 182 183 // operand should be non-zero if a keyword was parsed. Otherwise, the 184 // operand MUST be an integer. 185 if (operand == 0) { 186 // Parse the next operand as an integer. 187 if (parser.parseInteger(operand)) { 188 return parser.emitError(parser.getCurrentLocation()) 189 << "expected integer operand"; 190 } 191 } 192 193 args.push_back(operand); 194 return success(); 195 }; 196 197 // Parse operands as a comma-separated list. 198 return parser.parseCommaSeparatedList(operandParser); 199 } 200 201 void printExpressionArg(AsmPrinter &printer, uint64_t opcode, 202 ArrayRef<uint64_t> args) { 203 size_t i = 0; 204 llvm::interleaveComma(args, printer, [&](uint64_t operand) { 205 if (i > 0 && opcode == llvm::dwarf::DW_OP_LLVM_convert) { 206 if (const StringRef keyword = 207 llvm::dwarf::AttributeEncodingString(operand); 208 !keyword.empty()) { 209 printer << keyword; 210 return; 211 } 212 } 213 // All operands are expected to be printed as integers. 214 printer << operand; 215 i++; 216 }); 217 } 218 219 //===----------------------------------------------------------------------===// 220 // DICompositeTypeAttr 221 //===----------------------------------------------------------------------===// 222 223 DIRecursiveTypeAttrInterface 224 DICompositeTypeAttr::withRecId(DistinctAttr recId) { 225 return DICompositeTypeAttr::get( 226 getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(), 227 getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(), 228 getAlignInBits(), getElements(), getDataLocation(), getRank(), 229 getAllocated(), getAssociated()); 230 } 231 232 DIRecursiveTypeAttrInterface 233 DICompositeTypeAttr::getRecSelf(DistinctAttr recId) { 234 return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true, 235 0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {}, 236 {}, {}, {}); 237 } 238 239 //===----------------------------------------------------------------------===// 240 // DISubprogramAttr 241 //===----------------------------------------------------------------------===// 242 243 DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) { 244 return DISubprogramAttr::get(getContext(), recId, getIsRecSelf(), getId(), 245 getCompileUnit(), getScope(), getName(), 246 getLinkageName(), getFile(), getLine(), 247 getScopeLine(), getSubprogramFlags(), getType(), 248 getRetainedNodes(), getAnnotations()); 249 } 250 251 DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) { 252 return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true, 253 {}, {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {}); 254 } 255 256 //===----------------------------------------------------------------------===// 257 // ConstantRangeAttr 258 //===----------------------------------------------------------------------===// 259 260 Attribute ConstantRangeAttr::parse(AsmParser &parser, Type odsType) { 261 llvm::SMLoc loc = parser.getCurrentLocation(); 262 IntegerType widthType; 263 if (parser.parseLess() || parser.parseType(widthType) || 264 parser.parseComma()) { 265 return Attribute{}; 266 } 267 unsigned bitWidth = widthType.getWidth(); 268 APInt lower(bitWidth, 0); 269 APInt upper(bitWidth, 0); 270 if (parser.parseInteger(lower) || parser.parseComma() || 271 parser.parseInteger(upper) || parser.parseGreater()) 272 return Attribute{}; 273 // Non-positive numbers may use more bits than `bitWidth` 274 lower = lower.sextOrTrunc(bitWidth); 275 upper = upper.sextOrTrunc(bitWidth); 276 return parser.getChecked<ConstantRangeAttr>(loc, parser.getContext(), lower, 277 upper); 278 } 279 280 void ConstantRangeAttr::print(AsmPrinter &printer) const { 281 printer << "<i" << getLower().getBitWidth() << ", " << getLower() << ", " 282 << getUpper() << ">"; 283 } 284 285 LogicalResult 286 ConstantRangeAttr::verify(llvm::function_ref<InFlightDiagnostic()> emitError, 287 APInt lower, APInt upper) { 288 if (lower.getBitWidth() != upper.getBitWidth()) 289 return emitError() 290 << "expected lower and upper to have matching bitwidths but got " 291 << lower.getBitWidth() << " vs. " << upper.getBitWidth(); 292 return success(); 293 } 294 295 //===----------------------------------------------------------------------===// 296 // TargetFeaturesAttr 297 //===----------------------------------------------------------------------===// 298 299 TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context, 300 llvm::ArrayRef<StringRef> features) { 301 return Base::get(context, 302 llvm::map_to_vector(features, [&](StringRef feature) { 303 return StringAttr::get(context, feature); 304 })); 305 } 306 307 TargetFeaturesAttr 308 TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError, 309 MLIRContext *context, 310 llvm::ArrayRef<StringRef> features) { 311 return Base::getChecked(emitError, context, 312 llvm::map_to_vector(features, [&](StringRef feature) { 313 return StringAttr::get(context, feature); 314 })); 315 } 316 317 TargetFeaturesAttr TargetFeaturesAttr::get(MLIRContext *context, 318 StringRef targetFeatures) { 319 SmallVector<StringRef> features; 320 targetFeatures.split(features, ',', /*MaxSplit=*/-1, 321 /*KeepEmpty=*/false); 322 return get(context, features); 323 } 324 325 TargetFeaturesAttr 326 TargetFeaturesAttr::getChecked(function_ref<InFlightDiagnostic()> emitError, 327 MLIRContext *context, StringRef targetFeatures) { 328 SmallVector<StringRef> features; 329 targetFeatures.split(features, ',', /*MaxSplit=*/-1, 330 /*KeepEmpty=*/false); 331 ArrayRef featuresRef(features); 332 return getChecked(emitError, context, featuresRef); 333 } 334 335 LogicalResult 336 TargetFeaturesAttr::verify(function_ref<InFlightDiagnostic()> emitError, 337 llvm::ArrayRef<StringAttr> features) { 338 for (StringAttr featureAttr : features) { 339 if (!featureAttr || featureAttr.empty()) 340 return emitError() << "target features can not be null or empty"; 341 auto feature = featureAttr.strref(); 342 if (feature[0] != '+' && feature[0] != '-') 343 return emitError() << "target features must start with '+' or '-'"; 344 if (feature.contains(',')) 345 return emitError() << "target features can not contain ','"; 346 } 347 return success(); 348 } 349 350 bool TargetFeaturesAttr::contains(StringAttr feature) const { 351 if (nullOrEmpty()) 352 return false; 353 // Note: Using StringAttr does pointer comparisons. 354 return llvm::is_contained(getFeatures(), feature); 355 } 356 357 bool TargetFeaturesAttr::contains(StringRef feature) const { 358 if (nullOrEmpty()) 359 return false; 360 return llvm::is_contained(getFeatures(), feature); 361 } 362 363 std::string TargetFeaturesAttr::getFeaturesString() const { 364 std::string featuresString; 365 llvm::raw_string_ostream ss(featuresString); 366 llvm::interleave( 367 getFeatures(), ss, [&](auto &feature) { ss << feature.strref(); }, ","); 368 return featuresString; 369 } 370 371 TargetFeaturesAttr TargetFeaturesAttr::featuresAt(Operation *op) { 372 auto parentFunction = op->getParentOfType<FunctionOpInterface>(); 373 if (!parentFunction) 374 return {}; 375 return parentFunction.getOperation()->getAttrOfType<TargetFeaturesAttr>( 376 getAttributeName()); 377 } 378