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