1 //===- LLVMDialect.cpp - LLVM IR Ops and Dialect 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 types and operation details for the LLVM IR dialect in 10 // MLIR, and the LLVM IR dialect. It also registers the dialect. 11 // 12 //===----------------------------------------------------------------------===// 13 #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 14 #include "TypeDetail.h" 15 #include "mlir/Dialect/LLVMIR/LLVMTypes.h" 16 #include "mlir/IR/Builders.h" 17 #include "mlir/IR/BuiltinOps.h" 18 #include "mlir/IR/BuiltinTypes.h" 19 #include "mlir/IR/DialectImplementation.h" 20 #include "mlir/IR/FunctionImplementation.h" 21 #include "mlir/IR/MLIRContext.h" 22 #include "mlir/IR/Matchers.h" 23 24 #include "llvm/ADT/StringSwitch.h" 25 #include "llvm/ADT/TypeSwitch.h" 26 #include "llvm/AsmParser/Parser.h" 27 #include "llvm/Bitcode/BitcodeReader.h" 28 #include "llvm/Bitcode/BitcodeWriter.h" 29 #include "llvm/IR/Attributes.h" 30 #include "llvm/IR/Function.h" 31 #include "llvm/IR/Type.h" 32 #include "llvm/Support/Mutex.h" 33 #include "llvm/Support/SourceMgr.h" 34 35 #include <numeric> 36 37 using namespace mlir; 38 using namespace mlir::LLVM; 39 using mlir::LLVM::linkage::getMaxEnumValForLinkage; 40 41 #include "mlir/Dialect/LLVMIR/LLVMOpsDialect.cpp.inc" 42 43 static constexpr const char kVolatileAttrName[] = "volatile_"; 44 static constexpr const char kNonTemporalAttrName[] = "nontemporal"; 45 static constexpr const char kElemTypeAttrName[] = "elem_type"; 46 47 #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc" 48 #include "mlir/Dialect/LLVMIR/LLVMOpsInterfaces.cpp.inc" 49 #define GET_ATTRDEF_CLASSES 50 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc" 51 52 static auto processFMFAttr(ArrayRef<NamedAttribute> attrs) { 53 SmallVector<NamedAttribute, 8> filteredAttrs( 54 llvm::make_filter_range(attrs, [&](NamedAttribute attr) { 55 if (attr.getName() == "fastmathFlags") { 56 auto defAttr = FMFAttr::get(attr.getValue().getContext(), {}); 57 return defAttr != attr.getValue(); 58 } 59 return true; 60 })); 61 return filteredAttrs; 62 } 63 64 static ParseResult parseLLVMOpAttrs(OpAsmParser &parser, 65 NamedAttrList &result) { 66 return parser.parseOptionalAttrDict(result); 67 } 68 69 static void printLLVMOpAttrs(OpAsmPrinter &printer, Operation *op, 70 DictionaryAttr attrs) { 71 printer.printOptionalAttrDict(processFMFAttr(attrs.getValue())); 72 } 73 74 /// Verifies `symbol`'s use in `op` to ensure the symbol is a valid and 75 /// fully defined llvm.func. 76 static LogicalResult verifySymbolAttrUse(FlatSymbolRefAttr symbol, 77 Operation *op, 78 SymbolTableCollection &symbolTable) { 79 StringRef name = symbol.getValue(); 80 auto func = 81 symbolTable.lookupNearestSymbolFrom<LLVMFuncOp>(op, symbol.getAttr()); 82 if (!func) 83 return op->emitOpError("'") 84 << name << "' does not reference a valid LLVM function"; 85 if (func.isExternal()) 86 return op->emitOpError("'") << name << "' does not have a definition"; 87 return success(); 88 } 89 90 //===----------------------------------------------------------------------===// 91 // Printing/parsing for LLVM::CmpOp. 92 //===----------------------------------------------------------------------===// 93 94 void ICmpOp::print(OpAsmPrinter &p) { 95 p << " \"" << stringifyICmpPredicate(getPredicate()) << "\" " << getOperand(0) 96 << ", " << getOperand(1); 97 p.printOptionalAttrDict((*this)->getAttrs(), {"predicate"}); 98 p << " : " << getLhs().getType(); 99 } 100 101 void FCmpOp::print(OpAsmPrinter &p) { 102 p << " \"" << stringifyFCmpPredicate(getPredicate()) << "\" " << getOperand(0) 103 << ", " << getOperand(1); 104 p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()), {"predicate"}); 105 p << " : " << getLhs().getType(); 106 } 107 108 // <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use 109 // attribute-dict? `:` type 110 // <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use 111 // attribute-dict? `:` type 112 template <typename CmpPredicateType> 113 static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result) { 114 Builder &builder = parser.getBuilder(); 115 116 StringAttr predicateAttr; 117 OpAsmParser::UnresolvedOperand lhs, rhs; 118 Type type; 119 SMLoc predicateLoc, trailingTypeLoc; 120 if (parser.getCurrentLocation(&predicateLoc) || 121 parser.parseAttribute(predicateAttr, "predicate", result.attributes) || 122 parser.parseOperand(lhs) || parser.parseComma() || 123 parser.parseOperand(rhs) || 124 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 125 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) || 126 parser.resolveOperand(lhs, type, result.operands) || 127 parser.resolveOperand(rhs, type, result.operands)) 128 return failure(); 129 130 // Replace the string attribute `predicate` with an integer attribute. 131 int64_t predicateValue = 0; 132 if (std::is_same<CmpPredicateType, ICmpPredicate>()) { 133 Optional<ICmpPredicate> predicate = 134 symbolizeICmpPredicate(predicateAttr.getValue()); 135 if (!predicate) 136 return parser.emitError(predicateLoc) 137 << "'" << predicateAttr.getValue() 138 << "' is an incorrect value of the 'predicate' attribute"; 139 predicateValue = static_cast<int64_t>(predicate.getValue()); 140 } else { 141 Optional<FCmpPredicate> predicate = 142 symbolizeFCmpPredicate(predicateAttr.getValue()); 143 if (!predicate) 144 return parser.emitError(predicateLoc) 145 << "'" << predicateAttr.getValue() 146 << "' is an incorrect value of the 'predicate' attribute"; 147 predicateValue = static_cast<int64_t>(predicate.getValue()); 148 } 149 150 result.attributes.set("predicate", 151 parser.getBuilder().getI64IntegerAttr(predicateValue)); 152 153 // The result type is either i1 or a vector type <? x i1> if the inputs are 154 // vectors. 155 Type resultType = IntegerType::get(builder.getContext(), 1); 156 if (!isCompatibleType(type)) 157 return parser.emitError(trailingTypeLoc, 158 "expected LLVM dialect-compatible type"); 159 if (LLVM::isCompatibleVectorType(type)) { 160 if (LLVM::isScalableVectorType(type)) { 161 resultType = LLVM::getVectorType( 162 resultType, LLVM::getVectorNumElements(type).getKnownMinValue(), 163 /*isScalable=*/true); 164 } else { 165 resultType = LLVM::getVectorType( 166 resultType, LLVM::getVectorNumElements(type).getFixedValue(), 167 /*isScalable=*/false); 168 } 169 } 170 171 result.addTypes({resultType}); 172 return success(); 173 } 174 175 ParseResult ICmpOp::parse(OpAsmParser &parser, OperationState &result) { 176 return parseCmpOp<ICmpPredicate>(parser, result); 177 } 178 179 ParseResult FCmpOp::parse(OpAsmParser &parser, OperationState &result) { 180 return parseCmpOp<FCmpPredicate>(parser, result); 181 } 182 183 //===----------------------------------------------------------------------===// 184 // Printing, parsing and verification for LLVM::AllocaOp. 185 //===----------------------------------------------------------------------===// 186 187 void AllocaOp::print(OpAsmPrinter &p) { 188 Type elemTy = getType().cast<LLVM::LLVMPointerType>().getElementType(); 189 if (!elemTy) 190 elemTy = *getElemType(); 191 192 auto funcTy = 193 FunctionType::get(getContext(), {getArraySize().getType()}, {getType()}); 194 195 p << ' ' << getArraySize() << " x " << elemTy; 196 if (getAlignment().hasValue() && *getAlignment() != 0) 197 p.printOptionalAttrDict((*this)->getAttrs(), {kElemTypeAttrName}); 198 else 199 p.printOptionalAttrDict((*this)->getAttrs(), 200 {"alignment", kElemTypeAttrName}); 201 p << " : " << funcTy; 202 } 203 204 // <operation> ::= `llvm.alloca` ssa-use `x` type attribute-dict? 205 // `:` type `,` type 206 ParseResult AllocaOp::parse(OpAsmParser &parser, OperationState &result) { 207 OpAsmParser::UnresolvedOperand arraySize; 208 Type type, elemType; 209 SMLoc trailingTypeLoc; 210 if (parser.parseOperand(arraySize) || parser.parseKeyword("x") || 211 parser.parseType(elemType) || 212 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 213 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 214 return failure(); 215 216 Optional<NamedAttribute> alignmentAttr = 217 result.attributes.getNamed("alignment"); 218 if (alignmentAttr.hasValue()) { 219 auto alignmentInt = 220 alignmentAttr.getValue().getValue().dyn_cast<IntegerAttr>(); 221 if (!alignmentInt) 222 return parser.emitError(parser.getNameLoc(), 223 "expected integer alignment"); 224 if (alignmentInt.getValue().isNullValue()) 225 result.attributes.erase("alignment"); 226 } 227 228 // Extract the result type from the trailing function type. 229 auto funcType = type.dyn_cast<FunctionType>(); 230 if (!funcType || funcType.getNumInputs() != 1 || 231 funcType.getNumResults() != 1) 232 return parser.emitError( 233 trailingTypeLoc, 234 "expected trailing function type with one argument and one result"); 235 236 if (parser.resolveOperand(arraySize, funcType.getInput(0), result.operands)) 237 return failure(); 238 239 Type resultType = funcType.getResult(0); 240 if (auto ptrResultType = resultType.dyn_cast<LLVMPointerType>()) { 241 if (ptrResultType.isOpaque()) 242 result.addAttribute(kElemTypeAttrName, TypeAttr::get(elemType)); 243 } 244 245 result.addTypes({funcType.getResult(0)}); 246 return success(); 247 } 248 249 /// Checks that the elemental type is present in either the pointer type or 250 /// the attribute, but not both. 251 static LogicalResult verifyOpaquePtr(Operation *op, LLVMPointerType ptrType, 252 Optional<Type> ptrElementType) { 253 if (ptrType.isOpaque() && !ptrElementType.hasValue()) { 254 return op->emitOpError() << "expected '" << kElemTypeAttrName 255 << "' attribute if opaque pointer type is used"; 256 } 257 if (!ptrType.isOpaque() && ptrElementType.hasValue()) { 258 return op->emitOpError() 259 << "unexpected '" << kElemTypeAttrName 260 << "' attribute when non-opaque pointer type is used"; 261 } 262 return success(); 263 } 264 265 LogicalResult AllocaOp::verify() { 266 return verifyOpaquePtr(getOperation(), getType().cast<LLVMPointerType>(), 267 getElemType()); 268 } 269 270 //===----------------------------------------------------------------------===// 271 // LLVM::BrOp 272 //===----------------------------------------------------------------------===// 273 274 SuccessorOperands BrOp::getSuccessorOperands(unsigned index) { 275 assert(index == 0 && "invalid successor index"); 276 return SuccessorOperands(getDestOperandsMutable()); 277 } 278 279 //===----------------------------------------------------------------------===// 280 // LLVM::CondBrOp 281 //===----------------------------------------------------------------------===// 282 283 SuccessorOperands CondBrOp::getSuccessorOperands(unsigned index) { 284 assert(index < getNumSuccessors() && "invalid successor index"); 285 return SuccessorOperands(index == 0 ? getTrueDestOperandsMutable() 286 : getFalseDestOperandsMutable()); 287 } 288 289 //===----------------------------------------------------------------------===// 290 // LLVM::SwitchOp 291 //===----------------------------------------------------------------------===// 292 293 void SwitchOp::build(OpBuilder &builder, OperationState &result, Value value, 294 Block *defaultDestination, ValueRange defaultOperands, 295 ArrayRef<int32_t> caseValues, BlockRange caseDestinations, 296 ArrayRef<ValueRange> caseOperands, 297 ArrayRef<int32_t> branchWeights) { 298 ElementsAttr caseValuesAttr; 299 if (!caseValues.empty()) 300 caseValuesAttr = builder.getI32VectorAttr(caseValues); 301 302 ElementsAttr weightsAttr; 303 if (!branchWeights.empty()) 304 weightsAttr = builder.getI32VectorAttr(llvm::to_vector<4>(branchWeights)); 305 306 build(builder, result, value, defaultOperands, caseOperands, caseValuesAttr, 307 weightsAttr, defaultDestination, caseDestinations); 308 } 309 310 /// <cases> ::= integer `:` bb-id (`(` ssa-use-and-type-list `)`)? 311 /// ( `,` integer `:` bb-id (`(` ssa-use-and-type-list `)`)? )? 312 static ParseResult parseSwitchOpCases( 313 OpAsmParser &parser, Type flagType, ElementsAttr &caseValues, 314 SmallVectorImpl<Block *> &caseDestinations, 315 SmallVectorImpl<SmallVector<OpAsmParser::UnresolvedOperand>> &caseOperands, 316 SmallVectorImpl<SmallVector<Type>> &caseOperandTypes) { 317 SmallVector<APInt> values; 318 unsigned bitWidth = flagType.getIntOrFloatBitWidth(); 319 do { 320 int64_t value = 0; 321 OptionalParseResult integerParseResult = parser.parseOptionalInteger(value); 322 if (values.empty() && !integerParseResult.hasValue()) 323 return success(); 324 325 if (!integerParseResult.hasValue() || integerParseResult.getValue()) 326 return failure(); 327 values.push_back(APInt(bitWidth, value)); 328 329 Block *destination; 330 SmallVector<OpAsmParser::UnresolvedOperand> operands; 331 SmallVector<Type> operandTypes; 332 if (parser.parseColon() || parser.parseSuccessor(destination)) 333 return failure(); 334 if (!parser.parseOptionalLParen()) { 335 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::None, 336 /*allowResultNumber=*/false) || 337 parser.parseColonTypeList(operandTypes) || parser.parseRParen()) 338 return failure(); 339 } 340 caseDestinations.push_back(destination); 341 caseOperands.emplace_back(operands); 342 caseOperandTypes.emplace_back(operandTypes); 343 } while (!parser.parseOptionalComma()); 344 345 ShapedType caseValueType = 346 VectorType::get(static_cast<int64_t>(values.size()), flagType); 347 caseValues = DenseIntElementsAttr::get(caseValueType, values); 348 return success(); 349 } 350 351 static void printSwitchOpCases(OpAsmPrinter &p, SwitchOp op, Type flagType, 352 ElementsAttr caseValues, 353 SuccessorRange caseDestinations, 354 OperandRangeRange caseOperands, 355 const TypeRangeRange &caseOperandTypes) { 356 if (!caseValues) 357 return; 358 359 size_t index = 0; 360 llvm::interleave( 361 llvm::zip(caseValues.cast<DenseIntElementsAttr>(), caseDestinations), 362 [&](auto i) { 363 p << " "; 364 p << std::get<0>(i).getLimitedValue(); 365 p << ": "; 366 p.printSuccessorAndUseList(std::get<1>(i), caseOperands[index++]); 367 }, 368 [&] { 369 p << ','; 370 p.printNewline(); 371 }); 372 p.printNewline(); 373 } 374 375 LogicalResult SwitchOp::verify() { 376 if ((!getCaseValues() && !getCaseDestinations().empty()) || 377 (getCaseValues() && 378 getCaseValues()->size() != 379 static_cast<int64_t>(getCaseDestinations().size()))) 380 return emitOpError("expects number of case values to match number of " 381 "case destinations"); 382 if (getBranchWeights() && getBranchWeights()->size() != getNumSuccessors()) 383 return emitError("expects number of branch weights to match number of " 384 "successors: ") 385 << getBranchWeights()->size() << " vs " << getNumSuccessors(); 386 return success(); 387 } 388 389 SuccessorOperands SwitchOp::getSuccessorOperands(unsigned index) { 390 assert(index < getNumSuccessors() && "invalid successor index"); 391 return SuccessorOperands(index == 0 ? getDefaultOperandsMutable() 392 : getCaseOperandsMutable(index - 1)); 393 } 394 395 //===----------------------------------------------------------------------===// 396 // Code for LLVM::GEPOp. 397 //===----------------------------------------------------------------------===// 398 399 constexpr int GEPOp::kDynamicIndex; 400 401 /// Populates `indices` with positions of GEP indices that would correspond to 402 /// LLVMStructTypes potentially nested in the given type. The type currently 403 /// visited gets `currentIndex` and LLVM container types are visited 404 /// recursively. The recursion is bounded and takes care of recursive types by 405 /// means of the `visited` set. 406 static void recordStructIndices(Type type, unsigned currentIndex, 407 SmallVectorImpl<unsigned> &indices, 408 SmallVectorImpl<unsigned> *structSizes, 409 SmallPtrSet<Type, 4> &visited) { 410 if (visited.contains(type)) 411 return; 412 413 visited.insert(type); 414 415 llvm::TypeSwitch<Type>(type) 416 .Case<LLVMStructType>([&](LLVMStructType structType) { 417 indices.push_back(currentIndex); 418 if (structSizes) 419 structSizes->push_back(structType.getBody().size()); 420 for (Type elementType : structType.getBody()) 421 recordStructIndices(elementType, currentIndex + 1, indices, 422 structSizes, visited); 423 }) 424 .Case<VectorType, LLVMScalableVectorType, LLVMFixedVectorType, 425 LLVMArrayType>([&](auto containerType) { 426 recordStructIndices(containerType.getElementType(), currentIndex + 1, 427 indices, structSizes, visited); 428 }); 429 } 430 431 /// Populates `indices` with positions of GEP indices that correspond to 432 /// LLVMStructTypes potentially nested in the given `baseGEPType`, which must 433 /// be either an LLVMPointer type or a vector thereof. If `structSizes` is 434 /// provided, it is populated with sizes of the indexed structs for bounds 435 /// verification purposes. 436 void GEPOp::findKnownStructIndices(Type sourceElementType, 437 SmallVectorImpl<unsigned> &indices, 438 SmallVectorImpl<unsigned> *structSizes) { 439 SmallPtrSet<Type, 4> visited; 440 recordStructIndices(sourceElementType, /*currentIndex=*/1, indices, 441 structSizes, visited); 442 } 443 444 void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType, 445 Value basePtr, ValueRange operands, 446 ArrayRef<NamedAttribute> attributes) { 447 build(builder, result, resultType, basePtr, operands, 448 SmallVector<int32_t>(operands.size(), LLVM::GEPOp::kDynamicIndex), 449 attributes); 450 } 451 452 /// Returns the elemental type of any LLVM-compatible vector type or self. 453 static Type extractVectorElementType(Type type) { 454 if (auto vectorType = type.dyn_cast<VectorType>()) 455 return vectorType.getElementType(); 456 if (auto scalableVectorType = type.dyn_cast<LLVMScalableVectorType>()) 457 return scalableVectorType.getElementType(); 458 if (auto fixedVectorType = type.dyn_cast<LLVMFixedVectorType>()) 459 return fixedVectorType.getElementType(); 460 return type; 461 } 462 463 void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType, 464 Value basePtr, ValueRange indices, 465 ArrayRef<int32_t> structIndices, 466 ArrayRef<NamedAttribute> attributes) { 467 auto ptrType = 468 extractVectorElementType(basePtr.getType()).cast<LLVMPointerType>(); 469 assert(!ptrType.isOpaque() && 470 "expected non-opaque pointer, provide elementType explicitly when " 471 "opaque pointers are used"); 472 build(builder, result, resultType, ptrType.getElementType(), basePtr, indices, 473 structIndices, attributes); 474 } 475 476 void GEPOp::build(OpBuilder &builder, OperationState &result, Type resultType, 477 Type elementType, Value basePtr, ValueRange indices, 478 ArrayRef<int32_t> structIndices, 479 ArrayRef<NamedAttribute> attributes) { 480 SmallVector<Value> remainingIndices; 481 SmallVector<int32_t> updatedStructIndices(structIndices.begin(), 482 structIndices.end()); 483 SmallVector<unsigned> structRelatedPositions; 484 findKnownStructIndices(elementType, structRelatedPositions); 485 486 SmallVector<unsigned> operandsToErase; 487 for (unsigned pos : structRelatedPositions) { 488 // GEP may not be indexing as deep as some structs are located. 489 if (pos >= structIndices.size()) 490 continue; 491 492 // If the index is already static, it's fine. 493 if (structIndices[pos] != kDynamicIndex) 494 continue; 495 496 // Find the corresponding operand. 497 unsigned operandPos = 498 std::count(structIndices.begin(), std::next(structIndices.begin(), pos), 499 kDynamicIndex); 500 501 // Extract the constant value from the operand and put it into the attribute 502 // instead. 503 APInt staticIndexValue; 504 bool matched = 505 matchPattern(indices[operandPos], m_ConstantInt(&staticIndexValue)); 506 (void)matched; 507 assert(matched && "index into a struct must be a constant"); 508 assert(staticIndexValue.sge(APInt::getSignedMinValue(/*numBits=*/32)) && 509 "struct index underflows 32-bit integer"); 510 assert(staticIndexValue.sle(APInt::getSignedMaxValue(/*numBits=*/32)) && 511 "struct index overflows 32-bit integer"); 512 auto staticIndex = static_cast<int32_t>(staticIndexValue.getSExtValue()); 513 updatedStructIndices[pos] = staticIndex; 514 operandsToErase.push_back(operandPos); 515 } 516 517 for (unsigned i = 0, e = indices.size(); i < e; ++i) { 518 if (!llvm::is_contained(operandsToErase, i)) 519 remainingIndices.push_back(indices[i]); 520 } 521 522 assert(remainingIndices.size() == static_cast<size_t>(llvm::count( 523 updatedStructIndices, kDynamicIndex)) && 524 "expected as many index operands as dynamic index attr elements"); 525 526 result.addTypes(resultType); 527 result.addAttributes(attributes); 528 result.addAttribute("structIndices", 529 builder.getI32TensorAttr(updatedStructIndices)); 530 if (extractVectorElementType(basePtr.getType()) 531 .cast<LLVMPointerType>() 532 .isOpaque()) 533 result.addAttribute(kElemTypeAttrName, TypeAttr::get(elementType)); 534 result.addOperands(basePtr); 535 result.addOperands(remainingIndices); 536 } 537 538 static ParseResult 539 parseGEPIndices(OpAsmParser &parser, 540 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &indices, 541 DenseIntElementsAttr &structIndices) { 542 SmallVector<int32_t> constantIndices; 543 544 auto idxParser = [&]() -> ParseResult { 545 int32_t constantIndex; 546 OptionalParseResult parsedInteger = 547 parser.parseOptionalInteger(constantIndex); 548 if (parsedInteger.hasValue()) { 549 if (failed(parsedInteger.getValue())) 550 return failure(); 551 constantIndices.push_back(constantIndex); 552 return success(); 553 } 554 555 constantIndices.push_back(LLVM::GEPOp::kDynamicIndex); 556 return parser.parseOperand(indices.emplace_back()); 557 }; 558 if (parser.parseCommaSeparatedList(idxParser)) 559 return failure(); 560 561 structIndices = parser.getBuilder().getI32TensorAttr(constantIndices); 562 return success(); 563 } 564 565 static void printGEPIndices(OpAsmPrinter &printer, LLVM::GEPOp gepOp, 566 OperandRange indices, 567 DenseIntElementsAttr structIndices) { 568 unsigned operandIdx = 0; 569 llvm::interleaveComma(structIndices.getValues<int32_t>(), printer, 570 [&](int32_t cst) { 571 if (cst == LLVM::GEPOp::kDynamicIndex) 572 printer.printOperand(indices[operandIdx++]); 573 else 574 printer << cst; 575 }); 576 } 577 578 LogicalResult LLVM::GEPOp::verify() { 579 if (failed(verifyOpaquePtr( 580 getOperation(), 581 extractVectorElementType(getType()).cast<LLVMPointerType>(), 582 getElemType()))) 583 return failure(); 584 585 SmallVector<unsigned> indices; 586 SmallVector<unsigned> structSizes; 587 findKnownStructIndices(getSourceElementType(), indices, &structSizes); 588 DenseIntElementsAttr structIndices = getStructIndices(); 589 for (unsigned i : llvm::seq<unsigned>(0, indices.size())) { 590 unsigned index = indices[i]; 591 // GEP may not be indexing as deep as some structs nested in the type. 592 if (index >= structIndices.getNumElements()) 593 continue; 594 595 int32_t staticIndex = structIndices.getValues<int32_t>()[index]; 596 if (staticIndex == LLVM::GEPOp::kDynamicIndex) 597 return emitOpError() << "expected index " << index 598 << " indexing a struct to be constant"; 599 if (staticIndex < 0 || static_cast<unsigned>(staticIndex) >= structSizes[i]) 600 return emitOpError() << "index " << index 601 << " indexing a struct is out of bounds"; 602 } 603 return success(); 604 } 605 606 Type LLVM::GEPOp::getSourceElementType() { 607 if (Optional<Type> elemType = getElemType()) 608 return *elemType; 609 610 return extractVectorElementType(getBase().getType()) 611 .cast<LLVMPointerType>() 612 .getElementType(); 613 } 614 615 //===----------------------------------------------------------------------===// 616 // Builder, printer and parser for for LLVM::LoadOp. 617 //===----------------------------------------------------------------------===// 618 619 LogicalResult verifySymbolAttribute( 620 Operation *op, StringRef attributeName, 621 llvm::function_ref<LogicalResult(Operation *, SymbolRefAttr)> 622 verifySymbolType) { 623 if (Attribute attribute = op->getAttr(attributeName)) { 624 // The attribute is already verified to be a symbol ref array attribute via 625 // a constraint in the operation definition. 626 for (SymbolRefAttr symbolRef : 627 attribute.cast<ArrayAttr>().getAsRange<SymbolRefAttr>()) { 628 StringAttr metadataName = symbolRef.getRootReference(); 629 StringAttr symbolName = symbolRef.getLeafReference(); 630 // We want @metadata::@symbol, not just @symbol 631 if (metadataName == symbolName) { 632 return op->emitOpError() << "expected '" << symbolRef 633 << "' to specify a fully qualified reference"; 634 } 635 auto metadataOp = SymbolTable::lookupNearestSymbolFrom<LLVM::MetadataOp>( 636 op->getParentOp(), metadataName); 637 if (!metadataOp) 638 return op->emitOpError() 639 << "expected '" << symbolRef << "' to reference a metadata op"; 640 Operation *symbolOp = 641 SymbolTable::lookupNearestSymbolFrom(metadataOp, symbolName); 642 if (!symbolOp) 643 return op->emitOpError() 644 << "expected '" << symbolRef << "' to be a valid reference"; 645 if (failed(verifySymbolType(symbolOp, symbolRef))) { 646 return failure(); 647 } 648 } 649 } 650 return success(); 651 } 652 653 // Verifies that metadata ops are wired up properly. 654 template <typename OpTy> 655 static LogicalResult verifyOpMetadata(Operation *op, StringRef attributeName) { 656 auto verifySymbolType = [op](Operation *symbolOp, 657 SymbolRefAttr symbolRef) -> LogicalResult { 658 if (!isa<OpTy>(symbolOp)) { 659 return op->emitOpError() 660 << "expected '" << symbolRef << "' to resolve to a " 661 << OpTy::getOperationName(); 662 } 663 return success(); 664 }; 665 666 return verifySymbolAttribute(op, attributeName, verifySymbolType); 667 } 668 669 static LogicalResult verifyMemoryOpMetadata(Operation *op) { 670 // access_groups 671 if (failed(verifyOpMetadata<LLVM::AccessGroupMetadataOp>( 672 op, LLVMDialect::getAccessGroupsAttrName()))) 673 return failure(); 674 675 // alias_scopes 676 if (failed(verifyOpMetadata<LLVM::AliasScopeMetadataOp>( 677 op, LLVMDialect::getAliasScopesAttrName()))) 678 return failure(); 679 680 // noalias_scopes 681 if (failed(verifyOpMetadata<LLVM::AliasScopeMetadataOp>( 682 op, LLVMDialect::getNoAliasScopesAttrName()))) 683 return failure(); 684 685 return success(); 686 } 687 688 LogicalResult LoadOp::verify() { return verifyMemoryOpMetadata(*this); } 689 690 void LoadOp::build(OpBuilder &builder, OperationState &result, Type t, 691 Value addr, unsigned alignment, bool isVolatile, 692 bool isNonTemporal) { 693 result.addOperands(addr); 694 result.addTypes(t); 695 if (isVolatile) 696 result.addAttribute(kVolatileAttrName, builder.getUnitAttr()); 697 if (isNonTemporal) 698 result.addAttribute(kNonTemporalAttrName, builder.getUnitAttr()); 699 if (alignment != 0) 700 result.addAttribute("alignment", builder.getI64IntegerAttr(alignment)); 701 } 702 703 void LoadOp::print(OpAsmPrinter &p) { 704 p << ' '; 705 if (getVolatile_()) 706 p << "volatile "; 707 p << getAddr(); 708 p.printOptionalAttrDict((*this)->getAttrs(), 709 {kVolatileAttrName, kElemTypeAttrName}); 710 p << " : " << getAddr().getType(); 711 if (getAddr().getType().cast<LLVMPointerType>().isOpaque()) 712 p << " -> " << getType(); 713 } 714 715 // Extract the pointee type from the LLVM pointer type wrapped in MLIR. Return 716 // the resulting type if any, null type if opaque pointers are used, and None 717 // if the given type is not the pointer type. 718 static Optional<Type> getLoadStoreElementType(OpAsmParser &parser, Type type, 719 SMLoc trailingTypeLoc) { 720 auto llvmTy = type.dyn_cast<LLVM::LLVMPointerType>(); 721 if (!llvmTy) { 722 parser.emitError(trailingTypeLoc, "expected LLVM pointer type"); 723 return llvm::None; 724 } 725 return llvmTy.getElementType(); 726 } 727 728 // <operation> ::= `llvm.load` `volatile` ssa-use attribute-dict? `:` type 729 // (`->` type)? 730 ParseResult LoadOp::parse(OpAsmParser &parser, OperationState &result) { 731 OpAsmParser::UnresolvedOperand addr; 732 Type type; 733 SMLoc trailingTypeLoc; 734 735 if (succeeded(parser.parseOptionalKeyword("volatile"))) 736 result.addAttribute(kVolatileAttrName, parser.getBuilder().getUnitAttr()); 737 738 if (parser.parseOperand(addr) || 739 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 740 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) || 741 parser.resolveOperand(addr, type, result.operands)) 742 return failure(); 743 744 Optional<Type> elemTy = 745 getLoadStoreElementType(parser, type, trailingTypeLoc); 746 if (!elemTy) 747 return failure(); 748 if (*elemTy) { 749 result.addTypes(*elemTy); 750 return success(); 751 } 752 753 Type trailingType; 754 if (parser.parseArrow() || parser.parseType(trailingType)) 755 return failure(); 756 result.addTypes(trailingType); 757 return success(); 758 } 759 760 //===----------------------------------------------------------------------===// 761 // Builder, printer and parser for LLVM::StoreOp. 762 //===----------------------------------------------------------------------===// 763 764 LogicalResult StoreOp::verify() { return verifyMemoryOpMetadata(*this); } 765 766 void StoreOp::build(OpBuilder &builder, OperationState &result, Value value, 767 Value addr, unsigned alignment, bool isVolatile, 768 bool isNonTemporal) { 769 result.addOperands({value, addr}); 770 result.addTypes({}); 771 if (isVolatile) 772 result.addAttribute(kVolatileAttrName, builder.getUnitAttr()); 773 if (isNonTemporal) 774 result.addAttribute(kNonTemporalAttrName, builder.getUnitAttr()); 775 if (alignment != 0) 776 result.addAttribute("alignment", builder.getI64IntegerAttr(alignment)); 777 } 778 779 void StoreOp::print(OpAsmPrinter &p) { 780 p << ' '; 781 if (getVolatile_()) 782 p << "volatile "; 783 p << getValue() << ", " << getAddr(); 784 p.printOptionalAttrDict((*this)->getAttrs(), {kVolatileAttrName}); 785 p << " : "; 786 if (getAddr().getType().cast<LLVMPointerType>().isOpaque()) 787 p << getValue().getType() << ", "; 788 p << getAddr().getType(); 789 } 790 791 // <operation> ::= `llvm.store` `volatile` ssa-use `,` ssa-use 792 // attribute-dict? `:` type (`,` type)? 793 ParseResult StoreOp::parse(OpAsmParser &parser, OperationState &result) { 794 OpAsmParser::UnresolvedOperand addr, value; 795 Type type; 796 SMLoc trailingTypeLoc; 797 798 if (succeeded(parser.parseOptionalKeyword("volatile"))) 799 result.addAttribute(kVolatileAttrName, parser.getBuilder().getUnitAttr()); 800 801 if (parser.parseOperand(value) || parser.parseComma() || 802 parser.parseOperand(addr) || 803 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 804 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 805 return failure(); 806 807 Type operandType; 808 if (succeeded(parser.parseOptionalComma())) { 809 operandType = type; 810 if (parser.parseType(type)) 811 return failure(); 812 } else { 813 Optional<Type> maybeOperandType = 814 getLoadStoreElementType(parser, type, trailingTypeLoc); 815 if (!maybeOperandType) 816 return failure(); 817 operandType = *maybeOperandType; 818 } 819 820 if (parser.resolveOperand(value, operandType, result.operands) || 821 parser.resolveOperand(addr, type, result.operands)) 822 return failure(); 823 824 return success(); 825 } 826 827 ///===---------------------------------------------------------------------===// 828 /// LLVM::InvokeOp 829 ///===---------------------------------------------------------------------===// 830 831 SuccessorOperands InvokeOp::getSuccessorOperands(unsigned index) { 832 assert(index < getNumSuccessors() && "invalid successor index"); 833 return SuccessorOperands(index == 0 ? getNormalDestOperandsMutable() 834 : getUnwindDestOperandsMutable()); 835 } 836 837 LogicalResult InvokeOp::verify() { 838 if (getNumResults() > 1) 839 return emitOpError("must have 0 or 1 result"); 840 841 Block *unwindDest = getUnwindDest(); 842 if (unwindDest->empty()) 843 return emitError("must have at least one operation in unwind destination"); 844 845 // In unwind destination, first operation must be LandingpadOp 846 if (!isa<LandingpadOp>(unwindDest->front())) 847 return emitError("first operation in unwind destination should be a " 848 "llvm.landingpad operation"); 849 850 return success(); 851 } 852 853 void InvokeOp::print(OpAsmPrinter &p) { 854 auto callee = getCallee(); 855 bool isDirect = callee.hasValue(); 856 857 p << ' '; 858 859 // Either function name or pointer 860 if (isDirect) 861 p.printSymbolName(callee.getValue()); 862 else 863 p << getOperand(0); 864 865 p << '(' << getOperands().drop_front(isDirect ? 0 : 1) << ')'; 866 p << " to "; 867 p.printSuccessorAndUseList(getNormalDest(), getNormalDestOperands()); 868 p << " unwind "; 869 p.printSuccessorAndUseList(getUnwindDest(), getUnwindDestOperands()); 870 871 p.printOptionalAttrDict((*this)->getAttrs(), 872 {InvokeOp::getOperandSegmentSizeAttr(), "callee"}); 873 p << " : "; 874 p.printFunctionalType(llvm::drop_begin(getOperandTypes(), isDirect ? 0 : 1), 875 getResultTypes()); 876 } 877 878 /// <operation> ::= `llvm.invoke` (function-id | ssa-use) `(` ssa-use-list `)` 879 /// `to` bb-id (`[` ssa-use-and-type-list `]`)? 880 /// `unwind` bb-id (`[` ssa-use-and-type-list `]`)? 881 /// attribute-dict? `:` function-type 882 ParseResult InvokeOp::parse(OpAsmParser &parser, OperationState &result) { 883 SmallVector<OpAsmParser::UnresolvedOperand, 8> operands; 884 FunctionType funcType; 885 SymbolRefAttr funcAttr; 886 SMLoc trailingTypeLoc; 887 Block *normalDest, *unwindDest; 888 SmallVector<Value, 4> normalOperands, unwindOperands; 889 Builder &builder = parser.getBuilder(); 890 891 // Parse an operand list that will, in practice, contain 0 or 1 operand. In 892 // case of an indirect call, there will be 1 operand before `(`. In case of a 893 // direct call, there will be no operands and the parser will stop at the 894 // function identifier without complaining. 895 if (parser.parseOperandList(operands)) 896 return failure(); 897 bool isDirect = operands.empty(); 898 899 // Optionally parse a function identifier. 900 if (isDirect && parser.parseAttribute(funcAttr, "callee", result.attributes)) 901 return failure(); 902 903 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || 904 parser.parseKeyword("to") || 905 parser.parseSuccessorAndUseList(normalDest, normalOperands) || 906 parser.parseKeyword("unwind") || 907 parser.parseSuccessorAndUseList(unwindDest, unwindOperands) || 908 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 909 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(funcType)) 910 return failure(); 911 912 if (isDirect) { 913 // Make sure types match. 914 if (parser.resolveOperands(operands, funcType.getInputs(), 915 parser.getNameLoc(), result.operands)) 916 return failure(); 917 result.addTypes(funcType.getResults()); 918 } else { 919 // Construct the LLVM IR Dialect function type that the first operand 920 // should match. 921 if (funcType.getNumResults() > 1) 922 return parser.emitError(trailingTypeLoc, 923 "expected function with 0 or 1 result"); 924 925 Type llvmResultType; 926 if (funcType.getNumResults() == 0) { 927 llvmResultType = LLVM::LLVMVoidType::get(builder.getContext()); 928 } else { 929 llvmResultType = funcType.getResult(0); 930 if (!isCompatibleType(llvmResultType)) 931 return parser.emitError(trailingTypeLoc, 932 "expected result to have LLVM type"); 933 } 934 935 SmallVector<Type, 8> argTypes; 936 argTypes.reserve(funcType.getNumInputs()); 937 for (Type ty : funcType.getInputs()) { 938 if (isCompatibleType(ty)) 939 argTypes.push_back(ty); 940 else 941 return parser.emitError(trailingTypeLoc, 942 "expected LLVM types as inputs"); 943 } 944 945 auto llvmFuncType = LLVM::LLVMFunctionType::get(llvmResultType, argTypes); 946 auto wrappedFuncType = LLVM::LLVMPointerType::get(llvmFuncType); 947 948 auto funcArguments = llvm::makeArrayRef(operands).drop_front(); 949 950 // Make sure that the first operand (indirect callee) matches the wrapped 951 // LLVM IR function type, and that the types of the other call operands 952 // match the types of the function arguments. 953 if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || 954 parser.resolveOperands(funcArguments, funcType.getInputs(), 955 parser.getNameLoc(), result.operands)) 956 return failure(); 957 958 result.addTypes(llvmResultType); 959 } 960 result.addSuccessors({normalDest, unwindDest}); 961 result.addOperands(normalOperands); 962 result.addOperands(unwindOperands); 963 964 result.addAttribute( 965 InvokeOp::getOperandSegmentSizeAttr(), 966 builder.getI32VectorAttr({static_cast<int32_t>(operands.size()), 967 static_cast<int32_t>(normalOperands.size()), 968 static_cast<int32_t>(unwindOperands.size())})); 969 return success(); 970 } 971 972 ///===----------------------------------------------------------------------===// 973 /// Verifying/Printing/Parsing for LLVM::LandingpadOp. 974 ///===----------------------------------------------------------------------===// 975 976 LogicalResult LandingpadOp::verify() { 977 Value value; 978 if (LLVMFuncOp func = (*this)->getParentOfType<LLVMFuncOp>()) { 979 if (!func.getPersonality().hasValue()) 980 return emitError( 981 "llvm.landingpad needs to be in a function with a personality"); 982 } 983 984 if (!getCleanup() && getOperands().empty()) 985 return emitError("landingpad instruction expects at least one clause or " 986 "cleanup attribute"); 987 988 for (unsigned idx = 0, ie = getNumOperands(); idx < ie; idx++) { 989 value = getOperand(idx); 990 bool isFilter = value.getType().isa<LLVMArrayType>(); 991 if (isFilter) { 992 // FIXME: Verify filter clauses when arrays are appropriately handled 993 } else { 994 // catch - global addresses only. 995 // Bitcast ops should have global addresses as their args. 996 if (auto bcOp = value.getDefiningOp<BitcastOp>()) { 997 if (auto addrOp = bcOp.getArg().getDefiningOp<AddressOfOp>()) 998 continue; 999 return emitError("constant clauses expected").attachNote(bcOp.getLoc()) 1000 << "global addresses expected as operand to " 1001 "bitcast used in clauses for landingpad"; 1002 } 1003 // NullOp and AddressOfOp allowed 1004 if (value.getDefiningOp<NullOp>()) 1005 continue; 1006 if (value.getDefiningOp<AddressOfOp>()) 1007 continue; 1008 return emitError("clause #") 1009 << idx << " is not a known constant - null, addressof, bitcast"; 1010 } 1011 } 1012 return success(); 1013 } 1014 1015 void LandingpadOp::print(OpAsmPrinter &p) { 1016 p << (getCleanup() ? " cleanup " : " "); 1017 1018 // Clauses 1019 for (auto value : getOperands()) { 1020 // Similar to llvm - if clause is an array type then it is filter 1021 // clause else catch clause 1022 bool isArrayTy = value.getType().isa<LLVMArrayType>(); 1023 p << '(' << (isArrayTy ? "filter " : "catch ") << value << " : " 1024 << value.getType() << ") "; 1025 } 1026 1027 p.printOptionalAttrDict((*this)->getAttrs(), {"cleanup"}); 1028 1029 p << ": " << getType(); 1030 } 1031 1032 /// <operation> ::= `llvm.landingpad` `cleanup`? 1033 /// ((`catch` | `filter`) operand-type ssa-use)* attribute-dict? 1034 ParseResult LandingpadOp::parse(OpAsmParser &parser, OperationState &result) { 1035 // Check for cleanup 1036 if (succeeded(parser.parseOptionalKeyword("cleanup"))) 1037 result.addAttribute("cleanup", parser.getBuilder().getUnitAttr()); 1038 1039 // Parse clauses with types 1040 while (succeeded(parser.parseOptionalLParen()) && 1041 (succeeded(parser.parseOptionalKeyword("filter")) || 1042 succeeded(parser.parseOptionalKeyword("catch")))) { 1043 OpAsmParser::UnresolvedOperand operand; 1044 Type ty; 1045 if (parser.parseOperand(operand) || parser.parseColon() || 1046 parser.parseType(ty) || 1047 parser.resolveOperand(operand, ty, result.operands) || 1048 parser.parseRParen()) 1049 return failure(); 1050 } 1051 1052 Type type; 1053 if (parser.parseColon() || parser.parseType(type)) 1054 return failure(); 1055 1056 result.addTypes(type); 1057 return success(); 1058 } 1059 1060 //===----------------------------------------------------------------------===// 1061 // Verifying/Printing/parsing for LLVM::CallOp. 1062 //===----------------------------------------------------------------------===// 1063 1064 LogicalResult CallOp::verify() { 1065 if (getNumResults() > 1) 1066 return emitOpError("must have 0 or 1 result"); 1067 1068 // Type for the callee, we'll get it differently depending if it is a direct 1069 // or indirect call. 1070 Type fnType; 1071 1072 bool isIndirect = false; 1073 1074 // If this is an indirect call, the callee attribute is missing. 1075 FlatSymbolRefAttr calleeName = getCalleeAttr(); 1076 if (!calleeName) { 1077 isIndirect = true; 1078 if (!getNumOperands()) 1079 return emitOpError( 1080 "must have either a `callee` attribute or at least an operand"); 1081 auto ptrType = getOperand(0).getType().dyn_cast<LLVMPointerType>(); 1082 if (!ptrType) 1083 return emitOpError("indirect call expects a pointer as callee: ") 1084 << ptrType; 1085 fnType = ptrType.getElementType(); 1086 } else { 1087 Operation *callee = 1088 SymbolTable::lookupNearestSymbolFrom(*this, calleeName.getAttr()); 1089 if (!callee) 1090 return emitOpError() 1091 << "'" << calleeName.getValue() 1092 << "' does not reference a symbol in the current scope"; 1093 auto fn = dyn_cast<LLVMFuncOp>(callee); 1094 if (!fn) 1095 return emitOpError() << "'" << calleeName.getValue() 1096 << "' does not reference a valid LLVM function"; 1097 1098 fnType = fn.getFunctionType(); 1099 } 1100 1101 LLVMFunctionType funcType = fnType.dyn_cast<LLVMFunctionType>(); 1102 if (!funcType) 1103 return emitOpError("callee does not have a functional type: ") << fnType; 1104 1105 // Verify that the operand and result types match the callee. 1106 1107 if (!funcType.isVarArg() && 1108 funcType.getNumParams() != (getNumOperands() - isIndirect)) 1109 return emitOpError() << "incorrect number of operands (" 1110 << (getNumOperands() - isIndirect) 1111 << ") for callee (expecting: " 1112 << funcType.getNumParams() << ")"; 1113 1114 if (funcType.getNumParams() > (getNumOperands() - isIndirect)) 1115 return emitOpError() << "incorrect number of operands (" 1116 << (getNumOperands() - isIndirect) 1117 << ") for varargs callee (expecting at least: " 1118 << funcType.getNumParams() << ")"; 1119 1120 for (unsigned i = 0, e = funcType.getNumParams(); i != e; ++i) 1121 if (getOperand(i + isIndirect).getType() != funcType.getParamType(i)) 1122 return emitOpError() << "operand type mismatch for operand " << i << ": " 1123 << getOperand(i + isIndirect).getType() 1124 << " != " << funcType.getParamType(i); 1125 1126 if (getNumResults() == 0 && 1127 !funcType.getReturnType().isa<LLVM::LLVMVoidType>()) 1128 return emitOpError() << "expected function call to produce a value"; 1129 1130 if (getNumResults() != 0 && 1131 funcType.getReturnType().isa<LLVM::LLVMVoidType>()) 1132 return emitOpError() 1133 << "calling function with void result must not produce values"; 1134 1135 if (getNumResults() > 1) 1136 return emitOpError() 1137 << "expected LLVM function call to produce 0 or 1 result"; 1138 1139 if (getNumResults() && getResult(0).getType() != funcType.getReturnType()) 1140 return emitOpError() << "result type mismatch: " << getResult(0).getType() 1141 << " != " << funcType.getReturnType(); 1142 1143 return success(); 1144 } 1145 1146 void CallOp::print(OpAsmPrinter &p) { 1147 auto callee = getCallee(); 1148 bool isDirect = callee.hasValue(); 1149 1150 // Print the direct callee if present as a function attribute, or an indirect 1151 // callee (first operand) otherwise. 1152 p << ' '; 1153 if (isDirect) 1154 p.printSymbolName(callee.getValue()); 1155 else 1156 p << getOperand(0); 1157 1158 auto args = getOperands().drop_front(isDirect ? 0 : 1); 1159 p << '(' << args << ')'; 1160 p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()), {"callee"}); 1161 1162 // Reconstruct the function MLIR function type from operand and result types. 1163 p << " : "; 1164 p.printFunctionalType(args.getTypes(), getResultTypes()); 1165 } 1166 1167 // <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)` 1168 // attribute-dict? `:` function-type 1169 ParseResult CallOp::parse(OpAsmParser &parser, OperationState &result) { 1170 SmallVector<OpAsmParser::UnresolvedOperand, 8> operands; 1171 Type type; 1172 SymbolRefAttr funcAttr; 1173 SMLoc trailingTypeLoc; 1174 1175 // Parse an operand list that will, in practice, contain 0 or 1 operand. In 1176 // case of an indirect call, there will be 1 operand before `(`. In case of a 1177 // direct call, there will be no operands and the parser will stop at the 1178 // function identifier without complaining. 1179 if (parser.parseOperandList(operands)) 1180 return failure(); 1181 bool isDirect = operands.empty(); 1182 1183 // Optionally parse a function identifier. 1184 if (isDirect) 1185 if (parser.parseAttribute(funcAttr, "callee", result.attributes)) 1186 return failure(); 1187 1188 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || 1189 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 1190 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 1191 return failure(); 1192 1193 auto funcType = type.dyn_cast<FunctionType>(); 1194 if (!funcType) 1195 return parser.emitError(trailingTypeLoc, "expected function type"); 1196 if (funcType.getNumResults() > 1) 1197 return parser.emitError(trailingTypeLoc, 1198 "expected function with 0 or 1 result"); 1199 if (isDirect) { 1200 // Make sure types match. 1201 if (parser.resolveOperands(operands, funcType.getInputs(), 1202 parser.getNameLoc(), result.operands)) 1203 return failure(); 1204 if (funcType.getNumResults() != 0 && 1205 !funcType.getResult(0).isa<LLVM::LLVMVoidType>()) 1206 result.addTypes(funcType.getResults()); 1207 } else { 1208 Builder &builder = parser.getBuilder(); 1209 Type llvmResultType; 1210 if (funcType.getNumResults() == 0) { 1211 llvmResultType = LLVM::LLVMVoidType::get(builder.getContext()); 1212 } else { 1213 llvmResultType = funcType.getResult(0); 1214 if (!isCompatibleType(llvmResultType)) 1215 return parser.emitError(trailingTypeLoc, 1216 "expected result to have LLVM type"); 1217 } 1218 1219 SmallVector<Type, 8> argTypes; 1220 argTypes.reserve(funcType.getNumInputs()); 1221 for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) { 1222 auto argType = funcType.getInput(i); 1223 if (!isCompatibleType(argType)) 1224 return parser.emitError(trailingTypeLoc, 1225 "expected LLVM types as inputs"); 1226 argTypes.push_back(argType); 1227 } 1228 auto llvmFuncType = LLVM::LLVMFunctionType::get(llvmResultType, argTypes); 1229 auto wrappedFuncType = LLVM::LLVMPointerType::get(llvmFuncType); 1230 1231 auto funcArguments = 1232 ArrayRef<OpAsmParser::UnresolvedOperand>(operands).drop_front(); 1233 1234 // Make sure that the first operand (indirect callee) matches the wrapped 1235 // LLVM IR function type, and that the types of the other call operands 1236 // match the types of the function arguments. 1237 if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || 1238 parser.resolveOperands(funcArguments, funcType.getInputs(), 1239 parser.getNameLoc(), result.operands)) 1240 return failure(); 1241 1242 if (!llvmResultType.isa<LLVM::LLVMVoidType>()) 1243 result.addTypes(llvmResultType); 1244 } 1245 1246 return success(); 1247 } 1248 1249 //===----------------------------------------------------------------------===// 1250 // Printing/parsing for LLVM::ExtractElementOp. 1251 //===----------------------------------------------------------------------===// 1252 // Expects vector to be of wrapped LLVM vector type and position to be of 1253 // wrapped LLVM i32 type. 1254 void LLVM::ExtractElementOp::build(OpBuilder &b, OperationState &result, 1255 Value vector, Value position, 1256 ArrayRef<NamedAttribute> attrs) { 1257 auto vectorType = vector.getType(); 1258 auto llvmType = LLVM::getVectorElementType(vectorType); 1259 build(b, result, llvmType, vector, position); 1260 result.addAttributes(attrs); 1261 } 1262 1263 void ExtractElementOp::print(OpAsmPrinter &p) { 1264 p << ' ' << getVector() << "[" << getPosition() << " : " 1265 << getPosition().getType() << "]"; 1266 p.printOptionalAttrDict((*this)->getAttrs()); 1267 p << " : " << getVector().getType(); 1268 } 1269 1270 // <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use 1271 // attribute-dict? `:` type 1272 ParseResult ExtractElementOp::parse(OpAsmParser &parser, 1273 OperationState &result) { 1274 SMLoc loc; 1275 OpAsmParser::UnresolvedOperand vector, position; 1276 Type type, positionType; 1277 if (parser.getCurrentLocation(&loc) || parser.parseOperand(vector) || 1278 parser.parseLSquare() || parser.parseOperand(position) || 1279 parser.parseColonType(positionType) || parser.parseRSquare() || 1280 parser.parseOptionalAttrDict(result.attributes) || 1281 parser.parseColonType(type) || 1282 parser.resolveOperand(vector, type, result.operands) || 1283 parser.resolveOperand(position, positionType, result.operands)) 1284 return failure(); 1285 if (!LLVM::isCompatibleVectorType(type)) 1286 return parser.emitError( 1287 loc, "expected LLVM dialect-compatible vector type for operand #1"); 1288 result.addTypes(LLVM::getVectorElementType(type)); 1289 return success(); 1290 } 1291 1292 LogicalResult ExtractElementOp::verify() { 1293 Type vectorType = getVector().getType(); 1294 if (!LLVM::isCompatibleVectorType(vectorType)) 1295 return emitOpError("expected LLVM dialect-compatible vector type for " 1296 "operand #1, got") 1297 << vectorType; 1298 Type valueType = LLVM::getVectorElementType(vectorType); 1299 if (valueType != getRes().getType()) 1300 return emitOpError() << "Type mismatch: extracting from " << vectorType 1301 << " should produce " << valueType 1302 << " but this op returns " << getRes().getType(); 1303 return success(); 1304 } 1305 1306 //===----------------------------------------------------------------------===// 1307 // Printing/parsing for LLVM::ExtractValueOp. 1308 //===----------------------------------------------------------------------===// 1309 1310 void ExtractValueOp::print(OpAsmPrinter &p) { 1311 p << ' ' << getContainer() << getPosition(); 1312 p.printOptionalAttrDict((*this)->getAttrs(), {"position"}); 1313 p << " : " << getContainer().getType(); 1314 } 1315 1316 // Extract the type at `position` in the wrapped LLVM IR aggregate type 1317 // `containerType`. Position is an integer array attribute where each value 1318 // is a zero-based position of the element in the aggregate type. Return the 1319 // resulting type wrapped in MLIR, or nullptr on error. 1320 static Type getInsertExtractValueElementType(OpAsmParser &parser, 1321 Type containerType, 1322 ArrayAttr positionAttr, 1323 SMLoc attributeLoc, 1324 SMLoc typeLoc) { 1325 Type llvmType = containerType; 1326 if (!isCompatibleType(containerType)) 1327 return parser.emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr; 1328 1329 // Infer the element type from the structure type: iteratively step inside the 1330 // type by taking the element type, indexed by the position attribute for 1331 // structures. Check the position index before accessing, it is supposed to 1332 // be in bounds. 1333 for (Attribute subAttr : positionAttr) { 1334 auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>(); 1335 if (!positionElementAttr) 1336 return parser.emitError(attributeLoc, 1337 "expected an array of integer literals"), 1338 nullptr; 1339 int position = positionElementAttr.getInt(); 1340 if (auto arrayType = llvmType.dyn_cast<LLVMArrayType>()) { 1341 if (position < 0 || 1342 static_cast<unsigned>(position) >= arrayType.getNumElements()) 1343 return parser.emitError(attributeLoc, "position out of bounds"), 1344 nullptr; 1345 llvmType = arrayType.getElementType(); 1346 } else if (auto structType = llvmType.dyn_cast<LLVMStructType>()) { 1347 if (position < 0 || 1348 static_cast<unsigned>(position) >= structType.getBody().size()) 1349 return parser.emitError(attributeLoc, "position out of bounds"), 1350 nullptr; 1351 llvmType = structType.getBody()[position]; 1352 } else { 1353 return parser.emitError(typeLoc, "expected LLVM IR structure/array type"), 1354 nullptr; 1355 } 1356 } 1357 return llvmType; 1358 } 1359 1360 // Extract the type at `position` in the wrapped LLVM IR aggregate type 1361 // `containerType`. Returns null on failure. 1362 static Type getInsertExtractValueElementType(Type containerType, 1363 ArrayAttr positionAttr, 1364 Operation *op) { 1365 Type llvmType = containerType; 1366 if (!isCompatibleType(containerType)) { 1367 op->emitError("expected LLVM IR Dialect type, got ") << containerType; 1368 return {}; 1369 } 1370 1371 // Infer the element type from the structure type: iteratively step inside the 1372 // type by taking the element type, indexed by the position attribute for 1373 // structures. Check the position index before accessing, it is supposed to 1374 // be in bounds. 1375 for (Attribute subAttr : positionAttr) { 1376 auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>(); 1377 if (!positionElementAttr) { 1378 op->emitOpError("expected an array of integer literals, got: ") 1379 << subAttr; 1380 return {}; 1381 } 1382 int position = positionElementAttr.getInt(); 1383 if (auto arrayType = llvmType.dyn_cast<LLVMArrayType>()) { 1384 if (position < 0 || 1385 static_cast<unsigned>(position) >= arrayType.getNumElements()) { 1386 op->emitOpError("position out of bounds: ") << position; 1387 return {}; 1388 } 1389 llvmType = arrayType.getElementType(); 1390 } else if (auto structType = llvmType.dyn_cast<LLVMStructType>()) { 1391 if (position < 0 || 1392 static_cast<unsigned>(position) >= structType.getBody().size()) { 1393 op->emitOpError("position out of bounds") << position; 1394 return {}; 1395 } 1396 llvmType = structType.getBody()[position]; 1397 } else { 1398 op->emitOpError("expected LLVM IR structure/array type, got: ") 1399 << llvmType; 1400 return {}; 1401 } 1402 } 1403 return llvmType; 1404 } 1405 1406 // <operation> ::= `llvm.extractvalue` ssa-use 1407 // `[` integer-literal (`,` integer-literal)* `]` 1408 // attribute-dict? `:` type 1409 ParseResult ExtractValueOp::parse(OpAsmParser &parser, OperationState &result) { 1410 OpAsmParser::UnresolvedOperand container; 1411 Type containerType; 1412 ArrayAttr positionAttr; 1413 SMLoc attributeLoc, trailingTypeLoc; 1414 1415 if (parser.parseOperand(container) || 1416 parser.getCurrentLocation(&attributeLoc) || 1417 parser.parseAttribute(positionAttr, "position", result.attributes) || 1418 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 1419 parser.getCurrentLocation(&trailingTypeLoc) || 1420 parser.parseType(containerType) || 1421 parser.resolveOperand(container, containerType, result.operands)) 1422 return failure(); 1423 1424 auto elementType = getInsertExtractValueElementType( 1425 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 1426 if (!elementType) 1427 return failure(); 1428 1429 result.addTypes(elementType); 1430 return success(); 1431 } 1432 1433 OpFoldResult LLVM::ExtractValueOp::fold(ArrayRef<Attribute> operands) { 1434 auto insertValueOp = getContainer().getDefiningOp<InsertValueOp>(); 1435 OpFoldResult result = {}; 1436 while (insertValueOp) { 1437 if (getPosition() == insertValueOp.getPosition()) 1438 return insertValueOp.getValue(); 1439 unsigned min = 1440 std::min(getPosition().size(), insertValueOp.getPosition().size()); 1441 // If one is fully prefix of the other, stop propagating back as it will 1442 // miss dependencies. For instance, %3 should not fold to %f0 in the 1443 // following example: 1444 // ``` 1445 // %1 = llvm.insertvalue %f0, %0[0, 0] : 1446 // !llvm.array<4 x !llvm.array<4xf32>> 1447 // %2 = llvm.insertvalue %arr, %1[0] : 1448 // !llvm.array<4 x !llvm.array<4xf32>> 1449 // %3 = llvm.extractvalue %2[0, 0] : !llvm.array<4 x !llvm.array<4xf32>> 1450 // ``` 1451 if (getPosition().getValue().take_front(min) == 1452 insertValueOp.getPosition().getValue().take_front(min)) 1453 return result; 1454 1455 // If neither a prefix, nor the exact position, we can extract out of the 1456 // value being inserted into. Moreover, we can try again if that operand 1457 // is itself an insertvalue expression. 1458 getContainerMutable().assign(insertValueOp.getContainer()); 1459 result = getResult(); 1460 insertValueOp = insertValueOp.getContainer().getDefiningOp<InsertValueOp>(); 1461 } 1462 return result; 1463 } 1464 1465 LogicalResult ExtractValueOp::verify() { 1466 Type valueType = getInsertExtractValueElementType(getContainer().getType(), 1467 getPositionAttr(), *this); 1468 if (!valueType) 1469 return failure(); 1470 1471 if (getRes().getType() != valueType) 1472 return emitOpError() << "Type mismatch: extracting from " 1473 << getContainer().getType() << " should produce " 1474 << valueType << " but this op returns " 1475 << getRes().getType(); 1476 return success(); 1477 } 1478 1479 //===----------------------------------------------------------------------===// 1480 // Printing/parsing for LLVM::InsertElementOp. 1481 //===----------------------------------------------------------------------===// 1482 1483 void InsertElementOp::print(OpAsmPrinter &p) { 1484 p << ' ' << getValue() << ", " << getVector() << "[" << getPosition() << " : " 1485 << getPosition().getType() << "]"; 1486 p.printOptionalAttrDict((*this)->getAttrs()); 1487 p << " : " << getVector().getType(); 1488 } 1489 1490 // <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use 1491 // attribute-dict? `:` type 1492 ParseResult InsertElementOp::parse(OpAsmParser &parser, 1493 OperationState &result) { 1494 SMLoc loc; 1495 OpAsmParser::UnresolvedOperand vector, value, position; 1496 Type vectorType, positionType; 1497 if (parser.getCurrentLocation(&loc) || parser.parseOperand(value) || 1498 parser.parseComma() || parser.parseOperand(vector) || 1499 parser.parseLSquare() || parser.parseOperand(position) || 1500 parser.parseColonType(positionType) || parser.parseRSquare() || 1501 parser.parseOptionalAttrDict(result.attributes) || 1502 parser.parseColonType(vectorType)) 1503 return failure(); 1504 1505 if (!LLVM::isCompatibleVectorType(vectorType)) 1506 return parser.emitError( 1507 loc, "expected LLVM dialect-compatible vector type for operand #1"); 1508 Type valueType = LLVM::getVectorElementType(vectorType); 1509 if (!valueType) 1510 return failure(); 1511 1512 if (parser.resolveOperand(vector, vectorType, result.operands) || 1513 parser.resolveOperand(value, valueType, result.operands) || 1514 parser.resolveOperand(position, positionType, result.operands)) 1515 return failure(); 1516 1517 result.addTypes(vectorType); 1518 return success(); 1519 } 1520 1521 LogicalResult InsertElementOp::verify() { 1522 Type valueType = LLVM::getVectorElementType(getVector().getType()); 1523 if (valueType != getValue().getType()) 1524 return emitOpError() << "Type mismatch: cannot insert " 1525 << getValue().getType() << " into " 1526 << getVector().getType(); 1527 return success(); 1528 } 1529 1530 //===----------------------------------------------------------------------===// 1531 // Printing/parsing for LLVM::InsertValueOp. 1532 //===----------------------------------------------------------------------===// 1533 1534 void InsertValueOp::print(OpAsmPrinter &p) { 1535 p << ' ' << getValue() << ", " << getContainer() << getPosition(); 1536 p.printOptionalAttrDict((*this)->getAttrs(), {"position"}); 1537 p << " : " << getContainer().getType(); 1538 } 1539 1540 // <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use 1541 // `[` integer-literal (`,` integer-literal)* `]` 1542 // attribute-dict? `:` type 1543 ParseResult InsertValueOp::parse(OpAsmParser &parser, OperationState &result) { 1544 OpAsmParser::UnresolvedOperand container, value; 1545 Type containerType; 1546 ArrayAttr positionAttr; 1547 SMLoc attributeLoc, trailingTypeLoc; 1548 1549 if (parser.parseOperand(value) || parser.parseComma() || 1550 parser.parseOperand(container) || 1551 parser.getCurrentLocation(&attributeLoc) || 1552 parser.parseAttribute(positionAttr, "position", result.attributes) || 1553 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 1554 parser.getCurrentLocation(&trailingTypeLoc) || 1555 parser.parseType(containerType)) 1556 return failure(); 1557 1558 auto valueType = getInsertExtractValueElementType( 1559 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 1560 if (!valueType) 1561 return failure(); 1562 1563 if (parser.resolveOperand(container, containerType, result.operands) || 1564 parser.resolveOperand(value, valueType, result.operands)) 1565 return failure(); 1566 1567 result.addTypes(containerType); 1568 return success(); 1569 } 1570 1571 LogicalResult InsertValueOp::verify() { 1572 Type valueType = getInsertExtractValueElementType(getContainer().getType(), 1573 getPositionAttr(), *this); 1574 if (!valueType) 1575 return failure(); 1576 1577 if (getValue().getType() != valueType) 1578 return emitOpError() << "Type mismatch: cannot insert " 1579 << getValue().getType() << " into " 1580 << getContainer().getType(); 1581 1582 return success(); 1583 } 1584 1585 //===----------------------------------------------------------------------===// 1586 // Printing, parsing and verification for LLVM::ReturnOp. 1587 //===----------------------------------------------------------------------===// 1588 1589 LogicalResult ReturnOp::verify() { 1590 if (getNumOperands() > 1) 1591 return emitOpError("expected at most 1 operand"); 1592 1593 if (auto parent = (*this)->getParentOfType<LLVMFuncOp>()) { 1594 Type expectedType = parent.getFunctionType().getReturnType(); 1595 if (expectedType.isa<LLVMVoidType>()) { 1596 if (getNumOperands() == 0) 1597 return success(); 1598 InFlightDiagnostic diag = emitOpError("expected no operands"); 1599 diag.attachNote(parent->getLoc()) << "when returning from function"; 1600 return diag; 1601 } 1602 if (getNumOperands() == 0) { 1603 if (expectedType.isa<LLVMVoidType>()) 1604 return success(); 1605 InFlightDiagnostic diag = emitOpError("expected 1 operand"); 1606 diag.attachNote(parent->getLoc()) << "when returning from function"; 1607 return diag; 1608 } 1609 if (expectedType != getOperand(0).getType()) { 1610 InFlightDiagnostic diag = emitOpError("mismatching result types"); 1611 diag.attachNote(parent->getLoc()) << "when returning from function"; 1612 return diag; 1613 } 1614 } 1615 return success(); 1616 } 1617 1618 //===----------------------------------------------------------------------===// 1619 // ResumeOp 1620 //===----------------------------------------------------------------------===// 1621 1622 LogicalResult ResumeOp::verify() { 1623 if (!getValue().getDefiningOp<LandingpadOp>()) 1624 return emitOpError("expects landingpad value as operand"); 1625 // No check for personality of function - landingpad op verifies it. 1626 return success(); 1627 } 1628 1629 //===----------------------------------------------------------------------===// 1630 // Verifier for LLVM::AddressOfOp. 1631 //===----------------------------------------------------------------------===// 1632 1633 template <typename OpTy> 1634 static OpTy lookupSymbolInModule(Operation *parent, StringRef name) { 1635 Operation *module = parent; 1636 while (module && !satisfiesLLVMModule(module)) 1637 module = module->getParentOp(); 1638 assert(module && "unexpected operation outside of a module"); 1639 return dyn_cast_or_null<OpTy>( 1640 mlir::SymbolTable::lookupSymbolIn(module, name)); 1641 } 1642 1643 GlobalOp AddressOfOp::getGlobal() { 1644 return lookupSymbolInModule<LLVM::GlobalOp>((*this)->getParentOp(), 1645 getGlobalName()); 1646 } 1647 1648 LLVMFuncOp AddressOfOp::getFunction() { 1649 return lookupSymbolInModule<LLVM::LLVMFuncOp>((*this)->getParentOp(), 1650 getGlobalName()); 1651 } 1652 1653 LogicalResult AddressOfOp::verify() { 1654 auto global = getGlobal(); 1655 auto function = getFunction(); 1656 if (!global && !function) 1657 return emitOpError( 1658 "must reference a global defined by 'llvm.mlir.global' or 'llvm.func'"); 1659 1660 LLVMPointerType type = getType(); 1661 if (global && global.getAddrSpace() != type.getAddressSpace()) 1662 return emitOpError("pointer address space must match address space of the " 1663 "referenced global"); 1664 1665 if (type.isOpaque()) 1666 return success(); 1667 1668 if (global && type.getElementType() != global.getType()) 1669 return emitOpError( 1670 "the type must be a pointer to the type of the referenced global"); 1671 1672 if (function && type.getElementType() != function.getFunctionType()) 1673 return emitOpError( 1674 "the type must be a pointer to the type of the referenced function"); 1675 1676 return success(); 1677 } 1678 1679 //===----------------------------------------------------------------------===// 1680 // Builder, printer and verifier for LLVM::GlobalOp. 1681 //===----------------------------------------------------------------------===// 1682 1683 void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type, 1684 bool isConstant, Linkage linkage, StringRef name, 1685 Attribute value, uint64_t alignment, unsigned addrSpace, 1686 bool dsoLocal, bool threadLocal, 1687 ArrayRef<NamedAttribute> attrs) { 1688 result.addAttribute(getSymNameAttrName(result.name), 1689 builder.getStringAttr(name)); 1690 result.addAttribute(getGlobalTypeAttrName(result.name), TypeAttr::get(type)); 1691 if (isConstant) 1692 result.addAttribute(getConstantAttrName(result.name), 1693 builder.getUnitAttr()); 1694 if (value) 1695 result.addAttribute(getValueAttrName(result.name), value); 1696 if (dsoLocal) 1697 result.addAttribute(getDsoLocalAttrName(result.name), 1698 builder.getUnitAttr()); 1699 if (threadLocal) 1700 result.addAttribute(getThreadLocal_AttrName(result.name), 1701 builder.getUnitAttr()); 1702 1703 // Only add an alignment attribute if the "alignment" input 1704 // is different from 0. The value must also be a power of two, but 1705 // this is tested in GlobalOp::verify, not here. 1706 if (alignment != 0) 1707 result.addAttribute(getAlignmentAttrName(result.name), 1708 builder.getI64IntegerAttr(alignment)); 1709 1710 result.addAttribute(getLinkageAttrName(result.name), 1711 LinkageAttr::get(builder.getContext(), linkage)); 1712 if (addrSpace != 0) 1713 result.addAttribute(getAddrSpaceAttrName(result.name), 1714 builder.getI32IntegerAttr(addrSpace)); 1715 result.attributes.append(attrs.begin(), attrs.end()); 1716 result.addRegion(); 1717 } 1718 1719 void GlobalOp::print(OpAsmPrinter &p) { 1720 p << ' ' << stringifyLinkage(getLinkage()) << ' '; 1721 if (auto unnamedAddr = getUnnamedAddr()) { 1722 StringRef str = stringifyUnnamedAddr(*unnamedAddr); 1723 if (!str.empty()) 1724 p << str << ' '; 1725 } 1726 if (getThreadLocal_()) 1727 p << "thread_local "; 1728 if (getConstant()) 1729 p << "constant "; 1730 p.printSymbolName(getSymName()); 1731 p << '('; 1732 if (auto value = getValueOrNull()) 1733 p.printAttribute(value); 1734 p << ')'; 1735 // Note that the alignment attribute is printed using the 1736 // default syntax here, even though it is an inherent attribute 1737 // (as defined in https://mlir.llvm.org/docs/LangRef/#attributes) 1738 p.printOptionalAttrDict( 1739 (*this)->getAttrs(), 1740 {SymbolTable::getSymbolAttrName(), getGlobalTypeAttrName(), 1741 getConstantAttrName(), getValueAttrName(), getLinkageAttrName(), 1742 getUnnamedAddrAttrName(), getThreadLocal_AttrName()}); 1743 1744 // Print the trailing type unless it's a string global. 1745 if (getValueOrNull().dyn_cast_or_null<StringAttr>()) 1746 return; 1747 p << " : " << getType(); 1748 1749 Region &initializer = getInitializerRegion(); 1750 if (!initializer.empty()) { 1751 p << ' '; 1752 p.printRegion(initializer, /*printEntryBlockArgs=*/false); 1753 } 1754 } 1755 1756 // Parses one of the keywords provided in the list `keywords` and returns the 1757 // position of the parsed keyword in the list. If none of the keywords from the 1758 // list is parsed, returns -1. 1759 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 1760 ArrayRef<StringRef> keywords) { 1761 for (const auto &en : llvm::enumerate(keywords)) { 1762 if (succeeded(parser.parseOptionalKeyword(en.value()))) 1763 return en.index(); 1764 } 1765 return -1; 1766 } 1767 1768 namespace { 1769 template <typename Ty> 1770 struct EnumTraits {}; 1771 1772 #define REGISTER_ENUM_TYPE(Ty) \ 1773 template <> \ 1774 struct EnumTraits<Ty> { \ 1775 static StringRef stringify(Ty value) { return stringify##Ty(value); } \ 1776 static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ 1777 } 1778 1779 REGISTER_ENUM_TYPE(Linkage); 1780 REGISTER_ENUM_TYPE(UnnamedAddr); 1781 } // namespace 1782 1783 /// Parse an enum from the keyword, or default to the provided default value. 1784 /// The return type is the enum type by default, unless overriden with the 1785 /// second template argument. 1786 template <typename EnumTy, typename RetTy = EnumTy> 1787 static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser, 1788 OperationState &result, 1789 EnumTy defaultValue) { 1790 SmallVector<StringRef, 10> names; 1791 for (unsigned i = 0, e = EnumTraits<EnumTy>::getMaxEnumVal(); i <= e; ++i) 1792 names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); 1793 1794 int index = parseOptionalKeywordAlternative(parser, names); 1795 if (index == -1) 1796 return static_cast<RetTy>(defaultValue); 1797 return static_cast<RetTy>(index); 1798 } 1799 1800 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier 1801 // `(` attribute? `)` align? attribute-list? (`:` type)? region? 1802 // align ::= `align` `=` UINT64 1803 // 1804 // The type can be omitted for string attributes, in which case it will be 1805 // inferred from the value of the string as [strlen(value) x i8]. 1806 ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) { 1807 MLIRContext *ctx = parser.getContext(); 1808 // Parse optional linkage, default to External. 1809 result.addAttribute(getLinkageAttrName(result.name), 1810 LLVM::LinkageAttr::get( 1811 ctx, parseOptionalLLVMKeyword<Linkage>( 1812 parser, result, LLVM::Linkage::External))); 1813 1814 if (succeeded(parser.parseOptionalKeyword("thread_local"))) 1815 result.addAttribute(getThreadLocal_AttrName(result.name), 1816 parser.getBuilder().getUnitAttr()); 1817 1818 // Parse optional UnnamedAddr, default to None. 1819 result.addAttribute(getUnnamedAddrAttrName(result.name), 1820 parser.getBuilder().getI64IntegerAttr( 1821 parseOptionalLLVMKeyword<UnnamedAddr, int64_t>( 1822 parser, result, LLVM::UnnamedAddr::None))); 1823 1824 if (succeeded(parser.parseOptionalKeyword("constant"))) 1825 result.addAttribute(getConstantAttrName(result.name), 1826 parser.getBuilder().getUnitAttr()); 1827 1828 StringAttr name; 1829 if (parser.parseSymbolName(name, getSymNameAttrName(result.name), 1830 result.attributes) || 1831 parser.parseLParen()) 1832 return failure(); 1833 1834 Attribute value; 1835 if (parser.parseOptionalRParen()) { 1836 if (parser.parseAttribute(value, getValueAttrName(result.name), 1837 result.attributes) || 1838 parser.parseRParen()) 1839 return failure(); 1840 } 1841 1842 SmallVector<Type, 1> types; 1843 if (parser.parseOptionalAttrDict(result.attributes) || 1844 parser.parseOptionalColonTypeList(types)) 1845 return failure(); 1846 1847 if (types.size() > 1) 1848 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1849 1850 Region &initRegion = *result.addRegion(); 1851 if (types.empty()) { 1852 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1853 MLIRContext *context = parser.getContext(); 1854 auto arrayType = LLVM::LLVMArrayType::get(IntegerType::get(context, 8), 1855 strAttr.getValue().size()); 1856 types.push_back(arrayType); 1857 } else { 1858 return parser.emitError(parser.getNameLoc(), 1859 "type can only be omitted for string globals"); 1860 } 1861 } else { 1862 OptionalParseResult parseResult = 1863 parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1864 /*argTypes=*/{}); 1865 if (parseResult.hasValue() && failed(*parseResult)) 1866 return failure(); 1867 } 1868 1869 result.addAttribute(getGlobalTypeAttrName(result.name), 1870 TypeAttr::get(types[0])); 1871 return success(); 1872 } 1873 1874 static bool isZeroAttribute(Attribute value) { 1875 if (auto intValue = value.dyn_cast<IntegerAttr>()) 1876 return intValue.getValue().isNullValue(); 1877 if (auto fpValue = value.dyn_cast<FloatAttr>()) 1878 return fpValue.getValue().isZero(); 1879 if (auto splatValue = value.dyn_cast<SplatElementsAttr>()) 1880 return isZeroAttribute(splatValue.getSplatValue<Attribute>()); 1881 if (auto elementsValue = value.dyn_cast<ElementsAttr>()) 1882 return llvm::all_of(elementsValue.getValues<Attribute>(), isZeroAttribute); 1883 if (auto arrayValue = value.dyn_cast<ArrayAttr>()) 1884 return llvm::all_of(arrayValue.getValue(), isZeroAttribute); 1885 return false; 1886 } 1887 1888 LogicalResult GlobalOp::verify() { 1889 if (!LLVMPointerType::isValidElementType(getType())) 1890 return emitOpError( 1891 "expects type to be a valid element type for an LLVM pointer"); 1892 if ((*this)->getParentOp() && !satisfiesLLVMModule((*this)->getParentOp())) 1893 return emitOpError("must appear at the module level"); 1894 1895 if (auto strAttr = getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1896 auto type = getType().dyn_cast<LLVMArrayType>(); 1897 IntegerType elementType = 1898 type ? type.getElementType().dyn_cast<IntegerType>() : nullptr; 1899 if (!elementType || elementType.getWidth() != 8 || 1900 type.getNumElements() != strAttr.getValue().size()) 1901 return emitOpError( 1902 "requires an i8 array type of the length equal to that of the string " 1903 "attribute"); 1904 } 1905 1906 if (getLinkage() == Linkage::Common) { 1907 if (Attribute value = getValueOrNull()) { 1908 if (!isZeroAttribute(value)) { 1909 return emitOpError() 1910 << "expected zero value for '" 1911 << stringifyLinkage(Linkage::Common) << "' linkage"; 1912 } 1913 } 1914 } 1915 1916 if (getLinkage() == Linkage::Appending) { 1917 if (!getType().isa<LLVMArrayType>()) { 1918 return emitOpError() << "expected array type for '" 1919 << stringifyLinkage(Linkage::Appending) 1920 << "' linkage"; 1921 } 1922 } 1923 1924 Optional<uint64_t> alignAttr = getAlignment(); 1925 if (alignAttr.hasValue()) { 1926 uint64_t value = alignAttr.getValue(); 1927 if (!llvm::isPowerOf2_64(value)) 1928 return emitError() << "alignment attribute is not a power of 2"; 1929 } 1930 1931 return success(); 1932 } 1933 1934 LogicalResult GlobalOp::verifyRegions() { 1935 if (Block *b = getInitializerBlock()) { 1936 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1937 if (ret.operand_type_begin() == ret.operand_type_end()) 1938 return emitOpError("initializer region cannot return void"); 1939 if (*ret.operand_type_begin() != getType()) 1940 return emitOpError("initializer region type ") 1941 << *ret.operand_type_begin() << " does not match global type " 1942 << getType(); 1943 1944 for (Operation &op : *b) { 1945 auto iface = dyn_cast<MemoryEffectOpInterface>(op); 1946 if (!iface || !iface.hasNoEffect()) 1947 return op.emitError() 1948 << "ops with side effects not allowed in global initializers"; 1949 } 1950 1951 if (getValueOrNull()) 1952 return emitOpError("cannot have both initializer value and region"); 1953 } 1954 1955 return success(); 1956 } 1957 1958 //===----------------------------------------------------------------------===// 1959 // LLVM::GlobalCtorsOp 1960 //===----------------------------------------------------------------------===// 1961 1962 LogicalResult 1963 GlobalCtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) { 1964 for (Attribute ctor : getCtors()) { 1965 if (failed(verifySymbolAttrUse(ctor.cast<FlatSymbolRefAttr>(), *this, 1966 symbolTable))) 1967 return failure(); 1968 } 1969 return success(); 1970 } 1971 1972 LogicalResult GlobalCtorsOp::verify() { 1973 if (getCtors().size() != getPriorities().size()) 1974 return emitError( 1975 "mismatch between the number of ctors and the number of priorities"); 1976 return success(); 1977 } 1978 1979 //===----------------------------------------------------------------------===// 1980 // LLVM::GlobalDtorsOp 1981 //===----------------------------------------------------------------------===// 1982 1983 LogicalResult 1984 GlobalDtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) { 1985 for (Attribute dtor : getDtors()) { 1986 if (failed(verifySymbolAttrUse(dtor.cast<FlatSymbolRefAttr>(), *this, 1987 symbolTable))) 1988 return failure(); 1989 } 1990 return success(); 1991 } 1992 1993 LogicalResult GlobalDtorsOp::verify() { 1994 if (getDtors().size() != getPriorities().size()) 1995 return emitError( 1996 "mismatch between the number of dtors and the number of priorities"); 1997 return success(); 1998 } 1999 2000 //===----------------------------------------------------------------------===// 2001 // Printing/parsing for LLVM::ShuffleVectorOp. 2002 //===----------------------------------------------------------------------===// 2003 // Expects vector to be of wrapped LLVM vector type and position to be of 2004 // wrapped LLVM i32 type. 2005 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 2006 Value v1, Value v2, ArrayAttr mask, 2007 ArrayRef<NamedAttribute> attrs) { 2008 auto containerType = v1.getType(); 2009 auto vType = LLVM::getVectorType( 2010 LLVM::getVectorElementType(containerType), mask.size(), 2011 containerType.cast<VectorType>().isScalable()); 2012 build(b, result, vType, v1, v2, mask); 2013 result.addAttributes(attrs); 2014 } 2015 2016 void ShuffleVectorOp::print(OpAsmPrinter &p) { 2017 p << ' ' << getV1() << ", " << getV2() << " " << getMask(); 2018 p.printOptionalAttrDict((*this)->getAttrs(), {"mask"}); 2019 p << " : " << getV1().getType() << ", " << getV2().getType(); 2020 } 2021 2022 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 2023 // `[` integer-literal (`,` integer-literal)* `]` 2024 // attribute-dict? `:` type 2025 ParseResult ShuffleVectorOp::parse(OpAsmParser &parser, 2026 OperationState &result) { 2027 SMLoc loc; 2028 OpAsmParser::UnresolvedOperand v1, v2; 2029 ArrayAttr maskAttr; 2030 Type typeV1, typeV2; 2031 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 2032 parser.parseComma() || parser.parseOperand(v2) || 2033 parser.parseAttribute(maskAttr, "mask", result.attributes) || 2034 parser.parseOptionalAttrDict(result.attributes) || 2035 parser.parseColonType(typeV1) || parser.parseComma() || 2036 parser.parseType(typeV2) || 2037 parser.resolveOperand(v1, typeV1, result.operands) || 2038 parser.resolveOperand(v2, typeV2, result.operands)) 2039 return failure(); 2040 if (!LLVM::isCompatibleVectorType(typeV1)) 2041 return parser.emitError( 2042 loc, "expected LLVM IR dialect vector type for operand #1"); 2043 auto vType = 2044 LLVM::getVectorType(LLVM::getVectorElementType(typeV1), maskAttr.size(), 2045 typeV1.cast<VectorType>().isScalable()); 2046 result.addTypes(vType); 2047 return success(); 2048 } 2049 2050 LogicalResult ShuffleVectorOp::verify() { 2051 Type type1 = getV1().getType(); 2052 Type type2 = getV2().getType(); 2053 if (LLVM::getVectorElementType(type1) != LLVM::getVectorElementType(type2)) 2054 return emitOpError("expected matching LLVM IR Dialect element types"); 2055 if (LLVM::isScalableVectorType(type1)) 2056 if (llvm::any_of(getMask(), [](Attribute attr) { 2057 return attr.cast<IntegerAttr>().getInt() != 0; 2058 })) 2059 return emitOpError("expected a splat operation for scalable vectors"); 2060 return success(); 2061 } 2062 2063 //===----------------------------------------------------------------------===// 2064 // Implementations for LLVM::LLVMFuncOp. 2065 //===----------------------------------------------------------------------===// 2066 2067 // Add the entry block to the function. 2068 Block *LLVMFuncOp::addEntryBlock() { 2069 assert(empty() && "function already has an entry block"); 2070 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 2071 2072 auto *entry = new Block; 2073 push_back(entry); 2074 2075 // FIXME: Allow passing in proper locations for the entry arguments. 2076 LLVMFunctionType type = getFunctionType(); 2077 for (unsigned i = 0, e = type.getNumParams(); i < e; ++i) 2078 entry->addArgument(type.getParamType(i), getLoc()); 2079 return entry; 2080 } 2081 2082 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 2083 StringRef name, Type type, LLVM::Linkage linkage, 2084 bool dsoLocal, ArrayRef<NamedAttribute> attrs, 2085 ArrayRef<DictionaryAttr> argAttrs) { 2086 result.addRegion(); 2087 result.addAttribute(SymbolTable::getSymbolAttrName(), 2088 builder.getStringAttr(name)); 2089 result.addAttribute(getFunctionTypeAttrName(result.name), 2090 TypeAttr::get(type)); 2091 result.addAttribute(getLinkageAttrName(result.name), 2092 LinkageAttr::get(builder.getContext(), linkage)); 2093 result.attributes.append(attrs.begin(), attrs.end()); 2094 if (dsoLocal) 2095 result.addAttribute("dso_local", builder.getUnitAttr()); 2096 if (argAttrs.empty()) 2097 return; 2098 2099 assert(type.cast<LLVMFunctionType>().getNumParams() == argAttrs.size() && 2100 "expected as many argument attribute lists as arguments"); 2101 function_interface_impl::addArgAndResultAttrs(builder, result, argAttrs, 2102 /*resultAttrs=*/llvm::None); 2103 } 2104 2105 // Builds an LLVM function type from the given lists of input and output types. 2106 // Returns a null type if any of the types provided are non-LLVM types, or if 2107 // there is more than one output type. 2108 static Type 2109 buildLLVMFunctionType(OpAsmParser &parser, SMLoc loc, ArrayRef<Type> inputs, 2110 ArrayRef<Type> outputs, 2111 function_interface_impl::VariadicFlag variadicFlag) { 2112 Builder &b = parser.getBuilder(); 2113 if (outputs.size() > 1) { 2114 parser.emitError(loc, "failed to construct function type: expected zero or " 2115 "one function result"); 2116 return {}; 2117 } 2118 2119 // Convert inputs to LLVM types, exit early on error. 2120 SmallVector<Type, 4> llvmInputs; 2121 for (auto t : inputs) { 2122 if (!isCompatibleType(t)) { 2123 parser.emitError(loc, "failed to construct function type: expected LLVM " 2124 "type for function arguments"); 2125 return {}; 2126 } 2127 llvmInputs.push_back(t); 2128 } 2129 2130 // No output is denoted as "void" in LLVM type system. 2131 Type llvmOutput = 2132 outputs.empty() ? LLVMVoidType::get(b.getContext()) : outputs.front(); 2133 if (!isCompatibleType(llvmOutput)) { 2134 parser.emitError(loc, "failed to construct function type: expected LLVM " 2135 "type for function results") 2136 << llvmOutput; 2137 return {}; 2138 } 2139 return LLVMFunctionType::get(llvmOutput, llvmInputs, 2140 variadicFlag.isVariadic()); 2141 } 2142 2143 // Parses an LLVM function. 2144 // 2145 // operation ::= `llvm.func` linkage? function-signature function-attributes? 2146 // function-body 2147 // 2148 ParseResult LLVMFuncOp::parse(OpAsmParser &parser, OperationState &result) { 2149 // Default to external linkage if no keyword is provided. 2150 result.addAttribute( 2151 getLinkageAttrName(result.name), 2152 LinkageAttr::get(parser.getContext(), 2153 parseOptionalLLVMKeyword<Linkage>( 2154 parser, result, LLVM::Linkage::External))); 2155 2156 StringAttr nameAttr; 2157 SmallVector<OpAsmParser::Argument> entryArgs; 2158 SmallVector<DictionaryAttr> resultAttrs; 2159 SmallVector<Type> resultTypes; 2160 bool isVariadic; 2161 2162 auto signatureLocation = parser.getCurrentLocation(); 2163 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 2164 result.attributes) || 2165 function_interface_impl::parseFunctionSignature( 2166 parser, /*allowVariadic=*/true, entryArgs, isVariadic, resultTypes, 2167 resultAttrs)) 2168 return failure(); 2169 2170 SmallVector<Type> argTypes; 2171 for (auto &arg : entryArgs) 2172 argTypes.push_back(arg.type); 2173 auto type = 2174 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 2175 function_interface_impl::VariadicFlag(isVariadic)); 2176 if (!type) 2177 return failure(); 2178 result.addAttribute(FunctionOpInterface::getTypeAttrName(), 2179 TypeAttr::get(type)); 2180 2181 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 2182 return failure(); 2183 function_interface_impl::addArgAndResultAttrs(parser.getBuilder(), result, 2184 entryArgs, resultAttrs); 2185 2186 auto *body = result.addRegion(); 2187 OptionalParseResult parseResult = 2188 parser.parseOptionalRegion(*body, entryArgs); 2189 return failure(parseResult.hasValue() && failed(*parseResult)); 2190 } 2191 2192 // Print the LLVMFuncOp. Collects argument and result types and passes them to 2193 // helper functions. Drops "void" result since it cannot be parsed back. Skips 2194 // the external linkage since it is the default value. 2195 void LLVMFuncOp::print(OpAsmPrinter &p) { 2196 p << ' '; 2197 if (getLinkage() != LLVM::Linkage::External) 2198 p << stringifyLinkage(getLinkage()) << ' '; 2199 p.printSymbolName(getName()); 2200 2201 LLVMFunctionType fnType = getFunctionType(); 2202 SmallVector<Type, 8> argTypes; 2203 SmallVector<Type, 1> resTypes; 2204 argTypes.reserve(fnType.getNumParams()); 2205 for (unsigned i = 0, e = fnType.getNumParams(); i < e; ++i) 2206 argTypes.push_back(fnType.getParamType(i)); 2207 2208 Type returnType = fnType.getReturnType(); 2209 if (!returnType.isa<LLVMVoidType>()) 2210 resTypes.push_back(returnType); 2211 2212 function_interface_impl::printFunctionSignature(p, *this, argTypes, 2213 isVarArg(), resTypes); 2214 function_interface_impl::printFunctionAttributes( 2215 p, *this, argTypes.size(), resTypes.size(), {getLinkageAttrName()}); 2216 2217 // Print the body if this is not an external function. 2218 Region &body = getBody(); 2219 if (!body.empty()) { 2220 p << ' '; 2221 p.printRegion(body, /*printEntryBlockArgs=*/false, 2222 /*printBlockTerminators=*/true); 2223 } 2224 } 2225 2226 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 2227 // - functions don't have 'common' linkage 2228 // - external functions have 'external' or 'extern_weak' linkage; 2229 // - vararg is (currently) only supported for external functions; 2230 LogicalResult LLVMFuncOp::verify() { 2231 if (getLinkage() == LLVM::Linkage::Common) 2232 return emitOpError() << "functions cannot have '" 2233 << stringifyLinkage(LLVM::Linkage::Common) 2234 << "' linkage"; 2235 2236 // Check to see if this function has a void return with a result attribute to 2237 // it. It isn't clear what semantics we would assign to that. 2238 if (getFunctionType().getReturnType().isa<LLVMVoidType>() && 2239 !getResultAttrs(0).empty()) { 2240 return emitOpError() 2241 << "cannot attach result attributes to functions with a void return"; 2242 } 2243 2244 if (isExternal()) { 2245 if (getLinkage() != LLVM::Linkage::External && 2246 getLinkage() != LLVM::Linkage::ExternWeak) 2247 return emitOpError() << "external functions must have '" 2248 << stringifyLinkage(LLVM::Linkage::External) 2249 << "' or '" 2250 << stringifyLinkage(LLVM::Linkage::ExternWeak) 2251 << "' linkage"; 2252 return success(); 2253 } 2254 2255 if (isVarArg()) 2256 return emitOpError("only external functions can be variadic"); 2257 2258 return success(); 2259 } 2260 2261 /// Verifies LLVM- and implementation-specific properties of the LLVM func Op: 2262 /// - entry block arguments are of LLVM types. 2263 LogicalResult LLVMFuncOp::verifyRegions() { 2264 if (isExternal()) 2265 return success(); 2266 2267 unsigned numArguments = getFunctionType().getNumParams(); 2268 Block &entryBlock = front(); 2269 for (unsigned i = 0; i < numArguments; ++i) { 2270 Type argType = entryBlock.getArgument(i).getType(); 2271 if (!isCompatibleType(argType)) 2272 return emitOpError("entry block argument #") 2273 << i << " is not of LLVM type"; 2274 } 2275 2276 return success(); 2277 } 2278 2279 //===----------------------------------------------------------------------===// 2280 // Verification for LLVM::ConstantOp. 2281 //===----------------------------------------------------------------------===// 2282 2283 LogicalResult LLVM::ConstantOp::verify() { 2284 if (StringAttr sAttr = getValue().dyn_cast<StringAttr>()) { 2285 auto arrayType = getType().dyn_cast<LLVMArrayType>(); 2286 if (!arrayType || arrayType.getNumElements() != sAttr.getValue().size() || 2287 !arrayType.getElementType().isInteger(8)) { 2288 return emitOpError() << "expected array type of " 2289 << sAttr.getValue().size() 2290 << " i8 elements for the string constant"; 2291 } 2292 return success(); 2293 } 2294 if (auto structType = getType().dyn_cast<LLVMStructType>()) { 2295 if (structType.getBody().size() != 2 || 2296 structType.getBody()[0] != structType.getBody()[1]) { 2297 return emitError() << "expected struct type with two elements of the " 2298 "same type, the type of a complex constant"; 2299 } 2300 2301 auto arrayAttr = getValue().dyn_cast<ArrayAttr>(); 2302 if (!arrayAttr || arrayAttr.size() != 2 || 2303 arrayAttr[0].getType() != arrayAttr[1].getType()) { 2304 return emitOpError() << "expected array attribute with two elements, " 2305 "representing a complex constant"; 2306 } 2307 2308 Type elementType = structType.getBody()[0]; 2309 if (!elementType 2310 .isa<IntegerType, Float16Type, Float32Type, Float64Type>()) { 2311 return emitError() 2312 << "expected struct element types to be floating point type or " 2313 "integer type"; 2314 } 2315 return success(); 2316 } 2317 if (!getValue().isa<IntegerAttr, ArrayAttr, FloatAttr, ElementsAttr>()) 2318 return emitOpError() 2319 << "only supports integer, float, string or elements attributes"; 2320 return success(); 2321 } 2322 2323 // Constant op constant-folds to its value. 2324 OpFoldResult LLVM::ConstantOp::fold(ArrayRef<Attribute>) { return getValue(); } 2325 2326 //===----------------------------------------------------------------------===// 2327 // Utility functions for parsing atomic ops 2328 //===----------------------------------------------------------------------===// 2329 2330 // Helper function to parse a keyword into the specified attribute named by 2331 // `attrName`. The keyword must match one of the string values defined by the 2332 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 2333 // state. 2334 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 2335 StringRef attrName) { 2336 SMLoc loc; 2337 StringRef keyword; 2338 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 2339 return failure(); 2340 2341 // Replace the keyword `keyword` with an integer attribute. 2342 auto kind = symbolizeAtomicBinOp(keyword); 2343 if (!kind) { 2344 return parser.emitError(loc) 2345 << "'" << keyword << "' is an incorrect value of the '" << attrName 2346 << "' attribute"; 2347 } 2348 2349 auto value = static_cast<int64_t>(kind.getValue()); 2350 auto attr = parser.getBuilder().getI64IntegerAttr(value); 2351 result.addAttribute(attrName, attr); 2352 2353 return success(); 2354 } 2355 2356 // Helper function to parse a keyword into the specified attribute named by 2357 // `attrName`. The keyword must match one of the string values defined by the 2358 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 2359 // state. 2360 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 2361 OperationState &result, 2362 StringRef attrName) { 2363 SMLoc loc; 2364 StringRef ordering; 2365 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 2366 return failure(); 2367 2368 // Replace the keyword `ordering` with an integer attribute. 2369 auto kind = symbolizeAtomicOrdering(ordering); 2370 if (!kind) { 2371 return parser.emitError(loc) 2372 << "'" << ordering << "' is an incorrect value of the '" << attrName 2373 << "' attribute"; 2374 } 2375 2376 auto value = static_cast<int64_t>(kind.getValue()); 2377 auto attr = parser.getBuilder().getI64IntegerAttr(value); 2378 result.addAttribute(attrName, attr); 2379 2380 return success(); 2381 } 2382 2383 //===----------------------------------------------------------------------===// 2384 // Printer, parser and verifier for LLVM::AtomicRMWOp. 2385 //===----------------------------------------------------------------------===// 2386 2387 void AtomicRMWOp::print(OpAsmPrinter &p) { 2388 p << ' ' << stringifyAtomicBinOp(getBinOp()) << ' ' << getPtr() << ", " 2389 << getVal() << ' ' << stringifyAtomicOrdering(getOrdering()) << ' '; 2390 p.printOptionalAttrDict((*this)->getAttrs(), {"bin_op", "ordering"}); 2391 p << " : " << getRes().getType(); 2392 } 2393 2394 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 2395 // attribute-dict? `:` type 2396 ParseResult AtomicRMWOp::parse(OpAsmParser &parser, OperationState &result) { 2397 Type type; 2398 OpAsmParser::UnresolvedOperand ptr, val; 2399 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 2400 parser.parseComma() || parser.parseOperand(val) || 2401 parseAtomicOrdering(parser, result, "ordering") || 2402 parser.parseOptionalAttrDict(result.attributes) || 2403 parser.parseColonType(type) || 2404 parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type), 2405 result.operands) || 2406 parser.resolveOperand(val, type, result.operands)) 2407 return failure(); 2408 2409 result.addTypes(type); 2410 return success(); 2411 } 2412 2413 LogicalResult AtomicRMWOp::verify() { 2414 auto ptrType = getPtr().getType().cast<LLVM::LLVMPointerType>(); 2415 auto valType = getVal().getType(); 2416 if (valType != ptrType.getElementType()) 2417 return emitOpError("expected LLVM IR element type for operand #0 to " 2418 "match type for operand #1"); 2419 auto resType = getRes().getType(); 2420 if (resType != valType) 2421 return emitOpError( 2422 "expected LLVM IR result type to match type for operand #1"); 2423 if (getBinOp() == AtomicBinOp::fadd || getBinOp() == AtomicBinOp::fsub) { 2424 if (!mlir::LLVM::isCompatibleFloatingPointType(valType)) 2425 return emitOpError("expected LLVM IR floating point type"); 2426 } else if (getBinOp() == AtomicBinOp::xchg) { 2427 auto intType = valType.dyn_cast<IntegerType>(); 2428 unsigned intBitWidth = intType ? intType.getWidth() : 0; 2429 if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 && 2430 intBitWidth != 64 && !valType.isa<BFloat16Type>() && 2431 !valType.isa<Float16Type>() && !valType.isa<Float32Type>() && 2432 !valType.isa<Float64Type>()) 2433 return emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 2434 } else { 2435 auto intType = valType.dyn_cast<IntegerType>(); 2436 unsigned intBitWidth = intType ? intType.getWidth() : 0; 2437 if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 && 2438 intBitWidth != 64) 2439 return emitOpError("expected LLVM IR integer type"); 2440 } 2441 2442 if (static_cast<unsigned>(getOrdering()) < 2443 static_cast<unsigned>(AtomicOrdering::monotonic)) 2444 return emitOpError() << "expected at least '" 2445 << stringifyAtomicOrdering(AtomicOrdering::monotonic) 2446 << "' ordering"; 2447 2448 return success(); 2449 } 2450 2451 //===----------------------------------------------------------------------===// 2452 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 2453 //===----------------------------------------------------------------------===// 2454 2455 void AtomicCmpXchgOp::print(OpAsmPrinter &p) { 2456 p << ' ' << getPtr() << ", " << getCmp() << ", " << getVal() << ' ' 2457 << stringifyAtomicOrdering(getSuccessOrdering()) << ' ' 2458 << stringifyAtomicOrdering(getFailureOrdering()); 2459 p.printOptionalAttrDict((*this)->getAttrs(), 2460 {"success_ordering", "failure_ordering"}); 2461 p << " : " << getVal().getType(); 2462 } 2463 2464 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 2465 // keyword keyword attribute-dict? `:` type 2466 ParseResult AtomicCmpXchgOp::parse(OpAsmParser &parser, 2467 OperationState &result) { 2468 auto &builder = parser.getBuilder(); 2469 Type type; 2470 OpAsmParser::UnresolvedOperand ptr, cmp, val; 2471 if (parser.parseOperand(ptr) || parser.parseComma() || 2472 parser.parseOperand(cmp) || parser.parseComma() || 2473 parser.parseOperand(val) || 2474 parseAtomicOrdering(parser, result, "success_ordering") || 2475 parseAtomicOrdering(parser, result, "failure_ordering") || 2476 parser.parseOptionalAttrDict(result.attributes) || 2477 parser.parseColonType(type) || 2478 parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type), 2479 result.operands) || 2480 parser.resolveOperand(cmp, type, result.operands) || 2481 parser.resolveOperand(val, type, result.operands)) 2482 return failure(); 2483 2484 auto boolType = IntegerType::get(builder.getContext(), 1); 2485 auto resultType = 2486 LLVMStructType::getLiteral(builder.getContext(), {type, boolType}); 2487 result.addTypes(resultType); 2488 2489 return success(); 2490 } 2491 2492 LogicalResult AtomicCmpXchgOp::verify() { 2493 auto ptrType = getPtr().getType().cast<LLVM::LLVMPointerType>(); 2494 if (!ptrType) 2495 return emitOpError("expected LLVM IR pointer type for operand #0"); 2496 auto cmpType = getCmp().getType(); 2497 auto valType = getVal().getType(); 2498 if (cmpType != ptrType.getElementType() || cmpType != valType) 2499 return emitOpError("expected LLVM IR element type for operand #0 to " 2500 "match type for all other operands"); 2501 auto intType = valType.dyn_cast<IntegerType>(); 2502 unsigned intBitWidth = intType ? intType.getWidth() : 0; 2503 if (!valType.isa<LLVMPointerType>() && intBitWidth != 8 && 2504 intBitWidth != 16 && intBitWidth != 32 && intBitWidth != 64 && 2505 !valType.isa<BFloat16Type>() && !valType.isa<Float16Type>() && 2506 !valType.isa<Float32Type>() && !valType.isa<Float64Type>()) 2507 return emitOpError("unexpected LLVM IR type"); 2508 if (getSuccessOrdering() < AtomicOrdering::monotonic || 2509 getFailureOrdering() < AtomicOrdering::monotonic) 2510 return emitOpError("ordering must be at least 'monotonic'"); 2511 if (getFailureOrdering() == AtomicOrdering::release || 2512 getFailureOrdering() == AtomicOrdering::acq_rel) 2513 return emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 2514 return success(); 2515 } 2516 2517 //===----------------------------------------------------------------------===// 2518 // Printer, parser and verifier for LLVM::FenceOp. 2519 //===----------------------------------------------------------------------===// 2520 2521 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 2522 // attribute-dict? 2523 ParseResult FenceOp::parse(OpAsmParser &parser, OperationState &result) { 2524 StringAttr sScope; 2525 StringRef syncscopeKeyword = "syncscope"; 2526 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 2527 if (parser.parseLParen() || 2528 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 2529 parser.parseRParen()) 2530 return failure(); 2531 } else { 2532 result.addAttribute(syncscopeKeyword, 2533 parser.getBuilder().getStringAttr("")); 2534 } 2535 if (parseAtomicOrdering(parser, result, "ordering") || 2536 parser.parseOptionalAttrDict(result.attributes)) 2537 return failure(); 2538 return success(); 2539 } 2540 2541 void FenceOp::print(OpAsmPrinter &p) { 2542 StringRef syncscopeKeyword = "syncscope"; 2543 p << ' '; 2544 if (!(*this)->getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 2545 p << "syncscope(" << (*this)->getAttr(syncscopeKeyword) << ") "; 2546 p << stringifyAtomicOrdering(getOrdering()); 2547 } 2548 2549 LogicalResult FenceOp::verify() { 2550 if (getOrdering() == AtomicOrdering::not_atomic || 2551 getOrdering() == AtomicOrdering::unordered || 2552 getOrdering() == AtomicOrdering::monotonic) 2553 return emitOpError("can be given only acquire, release, acq_rel, " 2554 "and seq_cst orderings"); 2555 return success(); 2556 } 2557 2558 //===----------------------------------------------------------------------===// 2559 // Folder for LLVM::BitcastOp 2560 //===----------------------------------------------------------------------===// 2561 2562 OpFoldResult LLVM::BitcastOp::fold(ArrayRef<Attribute> operands) { 2563 // bitcast(x : T0, T0) -> x 2564 if (getArg().getType() == getType()) 2565 return getArg(); 2566 // bitcast(bitcast(x : T0, T1), T0) -> x 2567 if (auto prev = getArg().getDefiningOp<BitcastOp>()) 2568 if (prev.getArg().getType() == getType()) 2569 return prev.getArg(); 2570 return {}; 2571 } 2572 2573 //===----------------------------------------------------------------------===// 2574 // Folder for LLVM::AddrSpaceCastOp 2575 //===----------------------------------------------------------------------===// 2576 2577 OpFoldResult LLVM::AddrSpaceCastOp::fold(ArrayRef<Attribute> operands) { 2578 // addrcast(x : T0, T0) -> x 2579 if (getArg().getType() == getType()) 2580 return getArg(); 2581 // addrcast(addrcast(x : T0, T1), T0) -> x 2582 if (auto prev = getArg().getDefiningOp<AddrSpaceCastOp>()) 2583 if (prev.getArg().getType() == getType()) 2584 return prev.getArg(); 2585 return {}; 2586 } 2587 2588 //===----------------------------------------------------------------------===// 2589 // Folder for LLVM::GEPOp 2590 //===----------------------------------------------------------------------===// 2591 2592 OpFoldResult LLVM::GEPOp::fold(ArrayRef<Attribute> operands) { 2593 // gep %x:T, 0 -> %x 2594 if (getBase().getType() == getType() && getIndices().size() == 1 && 2595 matchPattern(getIndices()[0], m_Zero())) 2596 return getBase(); 2597 return {}; 2598 } 2599 2600 //===----------------------------------------------------------------------===// 2601 // LLVMDialect initialization, type parsing, and registration. 2602 //===----------------------------------------------------------------------===// 2603 2604 void LLVMDialect::initialize() { 2605 addAttributes<FMFAttr, LinkageAttr, LoopOptionsAttr>(); 2606 2607 // clang-format off 2608 addTypes<LLVMVoidType, 2609 LLVMPPCFP128Type, 2610 LLVMX86MMXType, 2611 LLVMTokenType, 2612 LLVMLabelType, 2613 LLVMMetadataType, 2614 LLVMFunctionType, 2615 LLVMPointerType, 2616 LLVMFixedVectorType, 2617 LLVMScalableVectorType, 2618 LLVMArrayType, 2619 LLVMStructType>(); 2620 // clang-format on 2621 addOperations< 2622 #define GET_OP_LIST 2623 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 2624 , 2625 #define GET_OP_LIST 2626 #include "mlir/Dialect/LLVMIR/LLVMIntrinsicOps.cpp.inc" 2627 >(); 2628 2629 // Support unknown operations because not all LLVM operations are registered. 2630 allowUnknownOperations(); 2631 } 2632 2633 #define GET_OP_CLASSES 2634 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 2635 2636 /// Parse a type registered to this dialect. 2637 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 2638 return detail::parseType(parser); 2639 } 2640 2641 /// Print a type registered to this dialect. 2642 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 2643 return detail::printType(type, os); 2644 } 2645 2646 LogicalResult LLVMDialect::verifyDataLayoutString( 2647 StringRef descr, llvm::function_ref<void(const Twine &)> reportError) { 2648 llvm::Expected<llvm::DataLayout> maybeDataLayout = 2649 llvm::DataLayout::parse(descr); 2650 if (maybeDataLayout) 2651 return success(); 2652 2653 std::string message; 2654 llvm::raw_string_ostream messageStream(message); 2655 llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream); 2656 reportError("invalid data layout descriptor: " + messageStream.str()); 2657 return failure(); 2658 } 2659 2660 /// Verify LLVM dialect attributes. 2661 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op, 2662 NamedAttribute attr) { 2663 // If the `llvm.loop` attribute is present, enforce the following structure, 2664 // which the module translation can assume. 2665 if (attr.getName() == LLVMDialect::getLoopAttrName()) { 2666 auto loopAttr = attr.getValue().dyn_cast<DictionaryAttr>(); 2667 if (!loopAttr) 2668 return op->emitOpError() << "expected '" << LLVMDialect::getLoopAttrName() 2669 << "' to be a dictionary attribute"; 2670 Optional<NamedAttribute> parallelAccessGroup = 2671 loopAttr.getNamed(LLVMDialect::getParallelAccessAttrName()); 2672 if (parallelAccessGroup.hasValue()) { 2673 auto accessGroups = parallelAccessGroup->getValue().dyn_cast<ArrayAttr>(); 2674 if (!accessGroups) 2675 return op->emitOpError() 2676 << "expected '" << LLVMDialect::getParallelAccessAttrName() 2677 << "' to be an array attribute"; 2678 for (Attribute attr : accessGroups) { 2679 auto accessGroupRef = attr.dyn_cast<SymbolRefAttr>(); 2680 if (!accessGroupRef) 2681 return op->emitOpError() 2682 << "expected '" << attr << "' to be a symbol reference"; 2683 StringAttr metadataName = accessGroupRef.getRootReference(); 2684 auto metadataOp = 2685 SymbolTable::lookupNearestSymbolFrom<LLVM::MetadataOp>( 2686 op->getParentOp(), metadataName); 2687 if (!metadataOp) 2688 return op->emitOpError() 2689 << "expected '" << attr << "' to reference a metadata op"; 2690 StringAttr accessGroupName = accessGroupRef.getLeafReference(); 2691 Operation *accessGroupOp = 2692 SymbolTable::lookupNearestSymbolFrom(metadataOp, accessGroupName); 2693 if (!accessGroupOp) 2694 return op->emitOpError() 2695 << "expected '" << attr << "' to reference an access_group op"; 2696 } 2697 } 2698 2699 Optional<NamedAttribute> loopOptions = 2700 loopAttr.getNamed(LLVMDialect::getLoopOptionsAttrName()); 2701 if (loopOptions.hasValue() && 2702 !loopOptions->getValue().isa<LoopOptionsAttr>()) 2703 return op->emitOpError() 2704 << "expected '" << LLVMDialect::getLoopOptionsAttrName() 2705 << "' to be a `loopopts` attribute"; 2706 } 2707 2708 if (attr.getName() == LLVMDialect::getStructAttrsAttrName()) { 2709 return op->emitOpError() 2710 << "'" << LLVM::LLVMDialect::getStructAttrsAttrName() 2711 << "' is permitted only in argument or result attributes"; 2712 } 2713 2714 // If the data layout attribute is present, it must use the LLVM data layout 2715 // syntax. Try parsing it and report errors in case of failure. Users of this 2716 // attribute may assume it is well-formed and can pass it to the (asserting) 2717 // llvm::DataLayout constructor. 2718 if (attr.getName() != LLVM::LLVMDialect::getDataLayoutAttrName()) 2719 return success(); 2720 if (auto stringAttr = attr.getValue().dyn_cast<StringAttr>()) 2721 return verifyDataLayoutString( 2722 stringAttr.getValue(), 2723 [op](const Twine &message) { op->emitOpError() << message.str(); }); 2724 2725 return op->emitOpError() << "expected '" 2726 << LLVM::LLVMDialect::getDataLayoutAttrName() 2727 << "' to be a string attributes"; 2728 } 2729 2730 LogicalResult LLVMDialect::verifyStructAttr(Operation *op, Attribute attr, 2731 Type annotatedType) { 2732 auto structType = annotatedType.dyn_cast<LLVMStructType>(); 2733 if (!structType) { 2734 const auto emitIncorrectAnnotatedType = [&op]() { 2735 return op->emitError() 2736 << "expected '" << LLVMDialect::getStructAttrsAttrName() 2737 << "' to annotate '!llvm.struct' or '!llvm.ptr<struct<...>>'"; 2738 }; 2739 const auto ptrType = annotatedType.dyn_cast<LLVMPointerType>(); 2740 if (!ptrType) 2741 return emitIncorrectAnnotatedType(); 2742 structType = ptrType.getElementType().dyn_cast<LLVMStructType>(); 2743 if (!structType) 2744 return emitIncorrectAnnotatedType(); 2745 } 2746 2747 const auto arrAttrs = attr.dyn_cast<ArrayAttr>(); 2748 if (!arrAttrs) 2749 return op->emitError() << "expected '" 2750 << LLVMDialect::getStructAttrsAttrName() 2751 << "' to be an array attribute"; 2752 2753 if (structType.getBody().size() != arrAttrs.size()) 2754 return op->emitError() 2755 << "size of '" << LLVMDialect::getStructAttrsAttrName() 2756 << "' must match the size of the annotated '!llvm.struct'"; 2757 return success(); 2758 } 2759 2760 static LogicalResult verifyFuncOpInterfaceStructAttr( 2761 Operation *op, Attribute attr, 2762 const std::function<Type(FunctionOpInterface)> &getAnnotatedType) { 2763 if (auto funcOp = dyn_cast<FunctionOpInterface>(op)) 2764 return LLVMDialect::verifyStructAttr(op, attr, getAnnotatedType(funcOp)); 2765 return op->emitError() << "expected '" 2766 << LLVMDialect::getStructAttrsAttrName() 2767 << "' to be used on function-like operations"; 2768 } 2769 2770 /// Verify LLVMIR function argument attributes. 2771 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 2772 unsigned regionIdx, 2773 unsigned argIdx, 2774 NamedAttribute argAttr) { 2775 // Check that llvm.noalias is a unit attribute. 2776 if (argAttr.getName() == LLVMDialect::getNoAliasAttrName() && 2777 !argAttr.getValue().isa<UnitAttr>()) 2778 return op->emitError() 2779 << "expected llvm.noalias argument attribute to be a unit attribute"; 2780 // Check that llvm.align is an integer attribute. 2781 if (argAttr.getName() == LLVMDialect::getAlignAttrName() && 2782 !argAttr.getValue().isa<IntegerAttr>()) 2783 return op->emitError() 2784 << "llvm.align argument attribute of non integer type"; 2785 if (argAttr.getName() == LLVMDialect::getStructAttrsAttrName()) { 2786 return verifyFuncOpInterfaceStructAttr( 2787 op, argAttr.getValue(), [argIdx](FunctionOpInterface funcOp) { 2788 return funcOp.getArgumentTypes()[argIdx]; 2789 }); 2790 } 2791 return success(); 2792 } 2793 2794 LogicalResult LLVMDialect::verifyRegionResultAttribute(Operation *op, 2795 unsigned regionIdx, 2796 unsigned resIdx, 2797 NamedAttribute resAttr) { 2798 if (resAttr.getName() == LLVMDialect::getStructAttrsAttrName()) { 2799 return verifyFuncOpInterfaceStructAttr( 2800 op, resAttr.getValue(), [resIdx](FunctionOpInterface funcOp) { 2801 return funcOp.getResultTypes()[resIdx]; 2802 }); 2803 } 2804 return success(); 2805 } 2806 2807 //===----------------------------------------------------------------------===// 2808 // Utility functions. 2809 //===----------------------------------------------------------------------===// 2810 2811 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 2812 StringRef name, StringRef value, 2813 LLVM::Linkage linkage) { 2814 assert(builder.getInsertionBlock() && 2815 builder.getInsertionBlock()->getParentOp() && 2816 "expected builder to point to a block constrained in an op"); 2817 auto module = 2818 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 2819 assert(module && "builder points to an op outside of a module"); 2820 2821 // Create the global at the entry of the module. 2822 OpBuilder moduleBuilder(module.getBodyRegion(), builder.getListener()); 2823 MLIRContext *ctx = builder.getContext(); 2824 auto type = LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), value.size()); 2825 auto global = moduleBuilder.create<LLVM::GlobalOp>( 2826 loc, type, /*isConstant=*/true, linkage, name, 2827 builder.getStringAttr(value), /*alignment=*/0); 2828 2829 // Get the pointer to the first character in the global string. 2830 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 2831 Value cst0 = builder.create<LLVM::ConstantOp>( 2832 loc, IntegerType::get(ctx, 64), 2833 builder.getIntegerAttr(builder.getIndexType(), 0)); 2834 return builder.create<LLVM::GEPOp>( 2835 loc, LLVM::LLVMPointerType::get(IntegerType::get(ctx, 8)), globalPtr, 2836 ValueRange{cst0, cst0}); 2837 } 2838 2839 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 2840 return op->hasTrait<OpTrait::SymbolTable>() && 2841 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 2842 } 2843 2844 static constexpr const FastmathFlags fastmathFlagsList[] = { 2845 // clang-format off 2846 FastmathFlags::nnan, 2847 FastmathFlags::ninf, 2848 FastmathFlags::nsz, 2849 FastmathFlags::arcp, 2850 FastmathFlags::contract, 2851 FastmathFlags::afn, 2852 FastmathFlags::reassoc, 2853 FastmathFlags::fast, 2854 // clang-format on 2855 }; 2856 2857 void FMFAttr::print(AsmPrinter &printer) const { 2858 printer << "<"; 2859 auto flags = llvm::make_filter_range(fastmathFlagsList, [&](auto flag) { 2860 return bitEnumContains(this->getFlags(), flag); 2861 }); 2862 llvm::interleaveComma(flags, printer, 2863 [&](auto flag) { printer << stringifyEnum(flag); }); 2864 printer << ">"; 2865 } 2866 2867 Attribute FMFAttr::parse(AsmParser &parser, Type type) { 2868 if (failed(parser.parseLess())) 2869 return {}; 2870 2871 FastmathFlags flags = {}; 2872 if (failed(parser.parseOptionalGreater())) { 2873 auto parseFlags = [&]() -> ParseResult { 2874 StringRef elemName; 2875 if (failed(parser.parseKeyword(&elemName))) 2876 return failure(); 2877 2878 auto elem = symbolizeFastmathFlags(elemName); 2879 if (!elem) 2880 return parser.emitError(parser.getNameLoc(), "Unknown fastmath flag: ") 2881 << elemName; 2882 2883 flags = flags | *elem; 2884 return success(); 2885 }; 2886 if (failed(parser.parseCommaSeparatedList(parseFlags)) || 2887 parser.parseGreater()) 2888 return {}; 2889 } 2890 2891 return FMFAttr::get(parser.getContext(), flags); 2892 } 2893 2894 void LinkageAttr::print(AsmPrinter &printer) const { 2895 printer << "<"; 2896 if (static_cast<uint64_t>(getLinkage()) <= getMaxEnumValForLinkage()) 2897 printer << stringifyEnum(getLinkage()); 2898 else 2899 printer << static_cast<uint64_t>(getLinkage()); 2900 printer << ">"; 2901 } 2902 2903 Attribute LinkageAttr::parse(AsmParser &parser, Type type) { 2904 StringRef elemName; 2905 if (parser.parseLess() || parser.parseKeyword(&elemName) || 2906 parser.parseGreater()) 2907 return {}; 2908 auto elem = linkage::symbolizeLinkage(elemName); 2909 if (!elem) { 2910 parser.emitError(parser.getNameLoc(), "Unknown linkage: ") << elemName; 2911 return {}; 2912 } 2913 Linkage linkage = *elem; 2914 return LinkageAttr::get(parser.getContext(), linkage); 2915 } 2916 2917 LoopOptionsAttrBuilder::LoopOptionsAttrBuilder(LoopOptionsAttr attr) 2918 : options(attr.getOptions().begin(), attr.getOptions().end()) {} 2919 2920 template <typename T> 2921 LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setOption(LoopOptionCase tag, 2922 Optional<T> value) { 2923 auto option = llvm::find_if( 2924 options, [tag](auto option) { return option.first == tag; }); 2925 if (option != options.end()) { 2926 if (value.hasValue()) 2927 option->second = *value; 2928 else 2929 options.erase(option); 2930 } else { 2931 options.push_back(LoopOptionsAttr::OptionValuePair(tag, *value)); 2932 } 2933 return *this; 2934 } 2935 2936 LoopOptionsAttrBuilder & 2937 LoopOptionsAttrBuilder::setDisableLICM(Optional<bool> value) { 2938 return setOption(LoopOptionCase::disable_licm, value); 2939 } 2940 2941 /// Set the `interleave_count` option to the provided value. If no value 2942 /// is provided the option is deleted. 2943 LoopOptionsAttrBuilder & 2944 LoopOptionsAttrBuilder::setInterleaveCount(Optional<uint64_t> count) { 2945 return setOption(LoopOptionCase::interleave_count, count); 2946 } 2947 2948 /// Set the `disable_unroll` option to the provided value. If no value 2949 /// is provided the option is deleted. 2950 LoopOptionsAttrBuilder & 2951 LoopOptionsAttrBuilder::setDisableUnroll(Optional<bool> value) { 2952 return setOption(LoopOptionCase::disable_unroll, value); 2953 } 2954 2955 /// Set the `disable_pipeline` option to the provided value. If no value 2956 /// is provided the option is deleted. 2957 LoopOptionsAttrBuilder & 2958 LoopOptionsAttrBuilder::setDisablePipeline(Optional<bool> value) { 2959 return setOption(LoopOptionCase::disable_pipeline, value); 2960 } 2961 2962 /// Set the `pipeline_initiation_interval` option to the provided value. 2963 /// If no value is provided the option is deleted. 2964 LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setPipelineInitiationInterval( 2965 Optional<uint64_t> count) { 2966 return setOption(LoopOptionCase::pipeline_initiation_interval, count); 2967 } 2968 2969 template <typename T> 2970 static Optional<T> 2971 getOption(ArrayRef<std::pair<LoopOptionCase, int64_t>> options, 2972 LoopOptionCase option) { 2973 auto it = 2974 lower_bound(options, option, [](auto optionPair, LoopOptionCase option) { 2975 return optionPair.first < option; 2976 }); 2977 if (it == options.end()) 2978 return {}; 2979 return static_cast<T>(it->second); 2980 } 2981 2982 Optional<bool> LoopOptionsAttr::disableUnroll() { 2983 return getOption<bool>(getOptions(), LoopOptionCase::disable_unroll); 2984 } 2985 2986 Optional<bool> LoopOptionsAttr::disableLICM() { 2987 return getOption<bool>(getOptions(), LoopOptionCase::disable_licm); 2988 } 2989 2990 Optional<int64_t> LoopOptionsAttr::interleaveCount() { 2991 return getOption<int64_t>(getOptions(), LoopOptionCase::interleave_count); 2992 } 2993 2994 /// Build the LoopOptions Attribute from a sorted array of individual options. 2995 LoopOptionsAttr LoopOptionsAttr::get( 2996 MLIRContext *context, 2997 ArrayRef<std::pair<LoopOptionCase, int64_t>> sortedOptions) { 2998 assert(llvm::is_sorted(sortedOptions, llvm::less_first()) && 2999 "LoopOptionsAttr ctor expects a sorted options array"); 3000 return Base::get(context, sortedOptions); 3001 } 3002 3003 /// Build the LoopOptions Attribute from a sorted array of individual options. 3004 LoopOptionsAttr LoopOptionsAttr::get(MLIRContext *context, 3005 LoopOptionsAttrBuilder &optionBuilders) { 3006 llvm::sort(optionBuilders.options, llvm::less_first()); 3007 return Base::get(context, optionBuilders.options); 3008 } 3009 3010 void LoopOptionsAttr::print(AsmPrinter &printer) const { 3011 printer << "<"; 3012 llvm::interleaveComma(getOptions(), printer, [&](auto option) { 3013 printer << stringifyEnum(option.first) << " = "; 3014 switch (option.first) { 3015 case LoopOptionCase::disable_licm: 3016 case LoopOptionCase::disable_unroll: 3017 case LoopOptionCase::disable_pipeline: 3018 printer << (option.second ? "true" : "false"); 3019 break; 3020 case LoopOptionCase::interleave_count: 3021 case LoopOptionCase::pipeline_initiation_interval: 3022 printer << option.second; 3023 break; 3024 } 3025 }); 3026 printer << ">"; 3027 } 3028 3029 Attribute LoopOptionsAttr::parse(AsmParser &parser, Type type) { 3030 if (failed(parser.parseLess())) 3031 return {}; 3032 3033 SmallVector<std::pair<LoopOptionCase, int64_t>> options; 3034 llvm::SmallDenseSet<LoopOptionCase> seenOptions; 3035 auto parseLoopOptions = [&]() -> ParseResult { 3036 StringRef optionName; 3037 if (parser.parseKeyword(&optionName)) 3038 return failure(); 3039 3040 auto option = symbolizeLoopOptionCase(optionName); 3041 if (!option) 3042 return parser.emitError(parser.getNameLoc(), "unknown loop option: ") 3043 << optionName; 3044 if (!seenOptions.insert(*option).second) 3045 return parser.emitError(parser.getNameLoc(), "loop option present twice"); 3046 if (failed(parser.parseEqual())) 3047 return failure(); 3048 3049 int64_t value; 3050 switch (*option) { 3051 case LoopOptionCase::disable_licm: 3052 case LoopOptionCase::disable_unroll: 3053 case LoopOptionCase::disable_pipeline: 3054 if (succeeded(parser.parseOptionalKeyword("true"))) 3055 value = 1; 3056 else if (succeeded(parser.parseOptionalKeyword("false"))) 3057 value = 0; 3058 else { 3059 return parser.emitError(parser.getNameLoc(), 3060 "expected boolean value 'true' or 'false'"); 3061 } 3062 break; 3063 case LoopOptionCase::interleave_count: 3064 case LoopOptionCase::pipeline_initiation_interval: 3065 if (failed(parser.parseInteger(value))) 3066 return parser.emitError(parser.getNameLoc(), "expected integer value"); 3067 break; 3068 } 3069 options.push_back(std::make_pair(*option, value)); 3070 return success(); 3071 }; 3072 if (parser.parseCommaSeparatedList(parseLoopOptions) || parser.parseGreater()) 3073 return {}; 3074 3075 llvm::sort(options, llvm::less_first()); 3076 return get(parser.getContext(), options); 3077 } 3078