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 (op.unnamed_addr()) 1414 p << stringifyUnnamedAddr(*op.unnamed_addr()) << ' '; 1415 if (op.constant()) 1416 p << "constant "; 1417 p.printSymbolName(op.sym_name()); 1418 p << '('; 1419 if (auto value = op.getValueOrNull()) 1420 p.printAttribute(value); 1421 p << ')'; 1422 // Note that the alignment attribute is printed using the 1423 // default syntax here, even though it is an inherent attribute 1424 // (as defined in https://mlir.llvm.org/docs/LangRef/#attributes) 1425 p.printOptionalAttrDict(op->getAttrs(), 1426 {SymbolTable::getSymbolAttrName(), "type", "constant", 1427 "value", getLinkageAttrName(), 1428 getUnnamedAddrAttrName()}); 1429 1430 // Print the trailing type unless it's a string global. 1431 if (op.getValueOrNull().dyn_cast_or_null<StringAttr>()) 1432 return; 1433 p << " : " << op.type(); 1434 1435 Region &initializer = op.getInitializerRegion(); 1436 if (!initializer.empty()) 1437 p.printRegion(initializer, /*printEntryBlockArgs=*/false); 1438 } 1439 1440 // Parses one of the keywords provided in the list `keywords` and returns the 1441 // position of the parsed keyword in the list. If none of the keywords from the 1442 // list is parsed, returns -1. 1443 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 1444 ArrayRef<StringRef> keywords) { 1445 for (auto en : llvm::enumerate(keywords)) { 1446 if (succeeded(parser.parseOptionalKeyword(en.value()))) 1447 return en.index(); 1448 } 1449 return -1; 1450 } 1451 1452 namespace { 1453 template <typename Ty> 1454 struct EnumTraits {}; 1455 1456 #define REGISTER_ENUM_TYPE(Ty) \ 1457 template <> \ 1458 struct EnumTraits<Ty> { \ 1459 static StringRef stringify(Ty value) { return stringify##Ty(value); } \ 1460 static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ 1461 } 1462 1463 REGISTER_ENUM_TYPE(Linkage); 1464 REGISTER_ENUM_TYPE(UnnamedAddr); 1465 } // end namespace 1466 1467 /// Parse an enum from the keyword, or default to the provided default value. 1468 /// The return type is the enum type by default, unless overriden with the 1469 /// second template argument. 1470 template <typename EnumTy, typename RetTy = EnumTy> 1471 static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser, 1472 OperationState &result, 1473 EnumTy defaultValue) { 1474 SmallVector<StringRef, 10> names; 1475 for (unsigned i = 0, e = EnumTraits<EnumTy>::getMaxEnumVal(); i <= e; ++i) 1476 names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); 1477 1478 int index = parseOptionalKeywordAlternative(parser, names); 1479 if (index == -1) 1480 return static_cast<RetTy>(defaultValue); 1481 return static_cast<RetTy>(index); 1482 } 1483 1484 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier 1485 // `(` attribute? `)` align? attribute-list? (`:` type)? region? 1486 // align ::= `align` `=` UINT64 1487 // 1488 // The type can be omitted for string attributes, in which case it will be 1489 // inferred from the value of the string as [strlen(value) x i8]. 1490 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) { 1491 MLIRContext *ctx = parser.getBuilder().getContext(); 1492 // Parse optional linkage, default to External. 1493 result.addAttribute(getLinkageAttrName(), 1494 LLVM::LinkageAttr::get( 1495 ctx, parseOptionalLLVMKeyword<Linkage>( 1496 parser, result, LLVM::Linkage::External))); 1497 // Parse optional UnnamedAddr, default to None. 1498 result.addAttribute(getUnnamedAddrAttrName(), 1499 parser.getBuilder().getI64IntegerAttr( 1500 parseOptionalLLVMKeyword<UnnamedAddr, int64_t>( 1501 parser, result, LLVM::UnnamedAddr::None))); 1502 1503 if (succeeded(parser.parseOptionalKeyword("constant"))) 1504 result.addAttribute("constant", parser.getBuilder().getUnitAttr()); 1505 1506 StringAttr name; 1507 if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), 1508 result.attributes) || 1509 parser.parseLParen()) 1510 return failure(); 1511 1512 Attribute value; 1513 if (parser.parseOptionalRParen()) { 1514 if (parser.parseAttribute(value, "value", result.attributes) || 1515 parser.parseRParen()) 1516 return failure(); 1517 } 1518 1519 SmallVector<Type, 1> types; 1520 if (parser.parseOptionalAttrDict(result.attributes) || 1521 parser.parseOptionalColonTypeList(types)) 1522 return failure(); 1523 1524 if (types.size() > 1) 1525 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1526 1527 Region &initRegion = *result.addRegion(); 1528 if (types.empty()) { 1529 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1530 MLIRContext *context = parser.getBuilder().getContext(); 1531 auto arrayType = LLVM::LLVMArrayType::get(IntegerType::get(context, 8), 1532 strAttr.getValue().size()); 1533 types.push_back(arrayType); 1534 } else { 1535 return parser.emitError(parser.getNameLoc(), 1536 "type can only be omitted for string globals"); 1537 } 1538 } else { 1539 OptionalParseResult parseResult = 1540 parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1541 /*argTypes=*/{}); 1542 if (parseResult.hasValue() && failed(*parseResult)) 1543 return failure(); 1544 } 1545 1546 result.addAttribute("type", TypeAttr::get(types[0])); 1547 return success(); 1548 } 1549 1550 static bool isZeroAttribute(Attribute value) { 1551 if (auto intValue = value.dyn_cast<IntegerAttr>()) 1552 return intValue.getValue().isNullValue(); 1553 if (auto fpValue = value.dyn_cast<FloatAttr>()) 1554 return fpValue.getValue().isZero(); 1555 if (auto splatValue = value.dyn_cast<SplatElementsAttr>()) 1556 return isZeroAttribute(splatValue.getSplatValue()); 1557 if (auto elementsValue = value.dyn_cast<ElementsAttr>()) 1558 return llvm::all_of(elementsValue.getValues<Attribute>(), isZeroAttribute); 1559 if (auto arrayValue = value.dyn_cast<ArrayAttr>()) 1560 return llvm::all_of(arrayValue.getValue(), isZeroAttribute); 1561 return false; 1562 } 1563 1564 static LogicalResult verify(GlobalOp op) { 1565 if (!LLVMPointerType::isValidElementType(op.getType())) 1566 return op.emitOpError( 1567 "expects type to be a valid element type for an LLVM pointer"); 1568 if (op->getParentOp() && !satisfiesLLVMModule(op->getParentOp())) 1569 return op.emitOpError("must appear at the module level"); 1570 1571 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1572 auto type = op.getType().dyn_cast<LLVMArrayType>(); 1573 IntegerType elementType = 1574 type ? type.getElementType().dyn_cast<IntegerType>() : nullptr; 1575 if (!elementType || elementType.getWidth() != 8 || 1576 type.getNumElements() != strAttr.getValue().size()) 1577 return op.emitOpError( 1578 "requires an i8 array type of the length equal to that of the string " 1579 "attribute"); 1580 } 1581 1582 if (Block *b = op.getInitializerBlock()) { 1583 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1584 if (ret.operand_type_begin() == ret.operand_type_end()) 1585 return op.emitOpError("initializer region cannot return void"); 1586 if (*ret.operand_type_begin() != op.getType()) 1587 return op.emitOpError("initializer region type ") 1588 << *ret.operand_type_begin() << " does not match global type " 1589 << op.getType(); 1590 1591 if (op.getValueOrNull()) 1592 return op.emitOpError("cannot have both initializer value and region"); 1593 } 1594 1595 if (op.linkage() == Linkage::Common) { 1596 if (Attribute value = op.getValueOrNull()) { 1597 if (!isZeroAttribute(value)) { 1598 return op.emitOpError() 1599 << "expected zero value for '" 1600 << stringifyLinkage(Linkage::Common) << "' linkage"; 1601 } 1602 } 1603 } 1604 1605 if (op.linkage() == Linkage::Appending) { 1606 if (!op.getType().isa<LLVMArrayType>()) { 1607 return op.emitOpError() 1608 << "expected array type for '" 1609 << stringifyLinkage(Linkage::Appending) << "' linkage"; 1610 } 1611 } 1612 1613 Optional<uint64_t> alignAttr = op.alignment(); 1614 if (alignAttr.hasValue()) { 1615 uint64_t value = alignAttr.getValue(); 1616 if (!llvm::isPowerOf2_64(value)) 1617 return op->emitError() << "alignment attribute is not a power of 2"; 1618 } 1619 1620 return success(); 1621 } 1622 1623 //===----------------------------------------------------------------------===// 1624 // Printing/parsing for LLVM::ShuffleVectorOp. 1625 //===----------------------------------------------------------------------===// 1626 // Expects vector to be of wrapped LLVM vector type and position to be of 1627 // wrapped LLVM i32 type. 1628 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 1629 Value v1, Value v2, ArrayAttr mask, 1630 ArrayRef<NamedAttribute> attrs) { 1631 auto containerType = v1.getType(); 1632 auto vType = LLVM::getFixedVectorType( 1633 LLVM::getVectorElementType(containerType), mask.size()); 1634 build(b, result, vType, v1, v2, mask); 1635 result.addAttributes(attrs); 1636 } 1637 1638 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1639 p << ' ' << op.v1() << ", " << op.v2() << " " << op.mask(); 1640 p.printOptionalAttrDict(op->getAttrs(), {"mask"}); 1641 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1642 } 1643 1644 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1645 // `[` integer-literal (`,` integer-literal)* `]` 1646 // attribute-dict? `:` type 1647 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1648 OperationState &result) { 1649 llvm::SMLoc loc; 1650 OpAsmParser::OperandType v1, v2; 1651 ArrayAttr maskAttr; 1652 Type typeV1, typeV2; 1653 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1654 parser.parseComma() || parser.parseOperand(v2) || 1655 parser.parseAttribute(maskAttr, "mask", result.attributes) || 1656 parser.parseOptionalAttrDict(result.attributes) || 1657 parser.parseColonType(typeV1) || parser.parseComma() || 1658 parser.parseType(typeV2) || 1659 parser.resolveOperand(v1, typeV1, result.operands) || 1660 parser.resolveOperand(v2, typeV2, result.operands)) 1661 return failure(); 1662 if (!LLVM::isCompatibleVectorType(typeV1)) 1663 return parser.emitError( 1664 loc, "expected LLVM IR dialect vector type for operand #1"); 1665 auto vType = LLVM::getFixedVectorType(LLVM::getVectorElementType(typeV1), 1666 maskAttr.size()); 1667 result.addTypes(vType); 1668 return success(); 1669 } 1670 1671 //===----------------------------------------------------------------------===// 1672 // Implementations for LLVM::LLVMFuncOp. 1673 //===----------------------------------------------------------------------===// 1674 1675 // Add the entry block to the function. 1676 Block *LLVMFuncOp::addEntryBlock() { 1677 assert(empty() && "function already has an entry block"); 1678 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1679 1680 auto *entry = new Block; 1681 push_back(entry); 1682 1683 LLVMFunctionType type = getType(); 1684 for (unsigned i = 0, e = type.getNumParams(); i < e; ++i) 1685 entry->addArgument(type.getParamType(i)); 1686 return entry; 1687 } 1688 1689 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 1690 StringRef name, Type type, LLVM::Linkage linkage, 1691 bool dsoLocal, ArrayRef<NamedAttribute> attrs, 1692 ArrayRef<DictionaryAttr> argAttrs) { 1693 result.addRegion(); 1694 result.addAttribute(SymbolTable::getSymbolAttrName(), 1695 builder.getStringAttr(name)); 1696 result.addAttribute("type", TypeAttr::get(type)); 1697 result.addAttribute(getLinkageAttrName(), 1698 LinkageAttr::get(builder.getContext(), linkage)); 1699 result.attributes.append(attrs.begin(), attrs.end()); 1700 if (dsoLocal) 1701 result.addAttribute("dso_local", builder.getUnitAttr()); 1702 if (argAttrs.empty()) 1703 return; 1704 1705 assert(type.cast<LLVMFunctionType>().getNumParams() == argAttrs.size() && 1706 "expected as many argument attribute lists as arguments"); 1707 function_like_impl::addArgAndResultAttrs(builder, result, argAttrs, 1708 /*resultAttrs=*/llvm::None); 1709 } 1710 1711 // Builds an LLVM function type from the given lists of input and output types. 1712 // Returns a null type if any of the types provided are non-LLVM types, or if 1713 // there is more than one output type. 1714 static Type 1715 buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1716 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1717 function_like_impl::VariadicFlag variadicFlag) { 1718 Builder &b = parser.getBuilder(); 1719 if (outputs.size() > 1) { 1720 parser.emitError(loc, "failed to construct function type: expected zero or " 1721 "one function result"); 1722 return {}; 1723 } 1724 1725 // Convert inputs to LLVM types, exit early on error. 1726 SmallVector<Type, 4> llvmInputs; 1727 for (auto t : inputs) { 1728 if (!isCompatibleType(t)) { 1729 parser.emitError(loc, "failed to construct function type: expected LLVM " 1730 "type for function arguments"); 1731 return {}; 1732 } 1733 llvmInputs.push_back(t); 1734 } 1735 1736 // No output is denoted as "void" in LLVM type system. 1737 Type llvmOutput = 1738 outputs.empty() ? LLVMVoidType::get(b.getContext()) : outputs.front(); 1739 if (!isCompatibleType(llvmOutput)) { 1740 parser.emitError(loc, "failed to construct function type: expected LLVM " 1741 "type for function results") 1742 << llvmOutput; 1743 return {}; 1744 } 1745 return LLVMFunctionType::get(llvmOutput, llvmInputs, 1746 variadicFlag.isVariadic()); 1747 } 1748 1749 // Parses an LLVM function. 1750 // 1751 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1752 // function-body 1753 // 1754 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1755 OperationState &result) { 1756 // Default to external linkage if no keyword is provided. 1757 result.addAttribute( 1758 getLinkageAttrName(), 1759 LinkageAttr::get(parser.getBuilder().getContext(), 1760 parseOptionalLLVMKeyword<Linkage>( 1761 parser, result, LLVM::Linkage::External))); 1762 1763 StringAttr nameAttr; 1764 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1765 SmallVector<NamedAttrList, 1> argAttrs; 1766 SmallVector<NamedAttrList, 1> resultAttrs; 1767 SmallVector<Type, 8> argTypes; 1768 SmallVector<Type, 4> resultTypes; 1769 bool isVariadic; 1770 1771 auto signatureLocation = parser.getCurrentLocation(); 1772 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1773 result.attributes) || 1774 function_like_impl::parseFunctionSignature( 1775 parser, /*allowVariadic=*/true, entryArgs, argTypes, argAttrs, 1776 isVariadic, resultTypes, resultAttrs)) 1777 return failure(); 1778 1779 auto type = 1780 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1781 function_like_impl::VariadicFlag(isVariadic)); 1782 if (!type) 1783 return failure(); 1784 result.addAttribute(function_like_impl::getTypeAttrName(), 1785 TypeAttr::get(type)); 1786 1787 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1788 return failure(); 1789 function_like_impl::addArgAndResultAttrs(parser.getBuilder(), result, 1790 argAttrs, resultAttrs); 1791 1792 auto *body = result.addRegion(); 1793 OptionalParseResult parseResult = parser.parseOptionalRegion( 1794 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1795 return failure(parseResult.hasValue() && failed(*parseResult)); 1796 } 1797 1798 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1799 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1800 // the external linkage since it is the default value. 1801 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1802 p << ' '; 1803 if (op.linkage() != LLVM::Linkage::External) 1804 p << stringifyLinkage(op.linkage()) << ' '; 1805 p.printSymbolName(op.getName()); 1806 1807 LLVMFunctionType fnType = op.getType(); 1808 SmallVector<Type, 8> argTypes; 1809 SmallVector<Type, 1> resTypes; 1810 argTypes.reserve(fnType.getNumParams()); 1811 for (unsigned i = 0, e = fnType.getNumParams(); i < e; ++i) 1812 argTypes.push_back(fnType.getParamType(i)); 1813 1814 Type returnType = fnType.getReturnType(); 1815 if (!returnType.isa<LLVMVoidType>()) 1816 resTypes.push_back(returnType); 1817 1818 function_like_impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), 1819 resTypes); 1820 function_like_impl::printFunctionAttributes( 1821 p, op, argTypes.size(), resTypes.size(), {getLinkageAttrName()}); 1822 1823 // Print the body if this is not an external function. 1824 Region &body = op.body(); 1825 if (!body.empty()) 1826 p.printRegion(body, /*printEntryBlockArgs=*/false, 1827 /*printBlockTerminators=*/true); 1828 } 1829 1830 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1831 // attribute is present. This can check for preconditions of the 1832 // getNumArguments hook not failing. 1833 LogicalResult LLVMFuncOp::verifyType() { 1834 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMFunctionType>(); 1835 if (!llvmType) 1836 return emitOpError("requires '" + getTypeAttrName() + 1837 "' attribute of wrapped LLVM function type"); 1838 1839 return success(); 1840 } 1841 1842 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1843 // Depends on the type attribute being correct as checked by verifyType 1844 unsigned LLVMFuncOp::getNumFuncArguments() { return getType().getNumParams(); } 1845 1846 // Hook for OpTrait::FunctionLike, returns the number of function results. 1847 // Depends on the type attribute being correct as checked by verifyType 1848 unsigned LLVMFuncOp::getNumFuncResults() { 1849 // We model LLVM functions that return void as having zero results, 1850 // and all others as having one result. 1851 // If we modeled a void return as one result, then it would be possible to 1852 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1853 // would assign to that. 1854 if (getType().getReturnType().isa<LLVMVoidType>()) 1855 return 0; 1856 return 1; 1857 } 1858 1859 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1860 // - functions don't have 'common' linkage 1861 // - external functions have 'external' or 'extern_weak' linkage; 1862 // - vararg is (currently) only supported for external functions; 1863 // - entry block arguments are of LLVM types and match the function signature. 1864 static LogicalResult verify(LLVMFuncOp op) { 1865 if (op.linkage() == LLVM::Linkage::Common) 1866 return op.emitOpError() 1867 << "functions cannot have '" 1868 << stringifyLinkage(LLVM::Linkage::Common) << "' linkage"; 1869 1870 if (op.isExternal()) { 1871 if (op.linkage() != LLVM::Linkage::External && 1872 op.linkage() != LLVM::Linkage::ExternWeak) 1873 return op.emitOpError() 1874 << "external functions must have '" 1875 << stringifyLinkage(LLVM::Linkage::External) << "' or '" 1876 << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage"; 1877 return success(); 1878 } 1879 1880 if (op.isVarArg()) 1881 return op.emitOpError("only external functions can be variadic"); 1882 1883 unsigned numArguments = op.getType().getNumParams(); 1884 Block &entryBlock = op.front(); 1885 for (unsigned i = 0; i < numArguments; ++i) { 1886 Type argType = entryBlock.getArgument(i).getType(); 1887 if (!isCompatibleType(argType)) 1888 return op.emitOpError("entry block argument #") 1889 << i << " is not of LLVM type"; 1890 if (op.getType().getParamType(i) != argType) 1891 return op.emitOpError("the type of entry block argument #") 1892 << i << " does not match the function signature"; 1893 } 1894 1895 return success(); 1896 } 1897 1898 //===----------------------------------------------------------------------===// 1899 // Verification for LLVM::ConstantOp. 1900 //===----------------------------------------------------------------------===// 1901 1902 static LogicalResult verify(LLVM::ConstantOp op) { 1903 if (StringAttr sAttr = op.value().dyn_cast<StringAttr>()) { 1904 auto arrayType = op.getType().dyn_cast<LLVMArrayType>(); 1905 if (!arrayType || arrayType.getNumElements() != sAttr.getValue().size() || 1906 !arrayType.getElementType().isInteger(8)) { 1907 return op->emitOpError() 1908 << "expected array type of " << sAttr.getValue().size() 1909 << " i8 elements for the string constant"; 1910 } 1911 return success(); 1912 } 1913 if (auto structType = op.getType().dyn_cast<LLVMStructType>()) { 1914 if (structType.getBody().size() != 2 || 1915 structType.getBody()[0] != structType.getBody()[1]) { 1916 return op.emitError() << "expected struct type with two elements of the " 1917 "same type, the type of a complex constant"; 1918 } 1919 1920 auto arrayAttr = op.value().dyn_cast<ArrayAttr>(); 1921 if (!arrayAttr || arrayAttr.size() != 2 || 1922 arrayAttr[0].getType() != arrayAttr[1].getType()) { 1923 return op.emitOpError() << "expected array attribute with two elements, " 1924 "representing a complex constant"; 1925 } 1926 1927 Type elementType = structType.getBody()[0]; 1928 if (!elementType 1929 .isa<IntegerType, Float16Type, Float32Type, Float64Type>()) { 1930 return op.emitError() 1931 << "expected struct element types to be floating point type or " 1932 "integer type"; 1933 } 1934 return success(); 1935 } 1936 if (!op.value().isa<IntegerAttr, ArrayAttr, FloatAttr, ElementsAttr>()) 1937 return op.emitOpError() 1938 << "only supports integer, float, string or elements attributes"; 1939 return success(); 1940 } 1941 1942 //===----------------------------------------------------------------------===// 1943 // Utility functions for parsing atomic ops 1944 //===----------------------------------------------------------------------===// 1945 1946 // Helper function to parse a keyword into the specified attribute named by 1947 // `attrName`. The keyword must match one of the string values defined by the 1948 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 1949 // state. 1950 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 1951 StringRef attrName) { 1952 llvm::SMLoc loc; 1953 StringRef keyword; 1954 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 1955 return failure(); 1956 1957 // Replace the keyword `keyword` with an integer attribute. 1958 auto kind = symbolizeAtomicBinOp(keyword); 1959 if (!kind) { 1960 return parser.emitError(loc) 1961 << "'" << keyword << "' is an incorrect value of the '" << attrName 1962 << "' attribute"; 1963 } 1964 1965 auto value = static_cast<int64_t>(kind.getValue()); 1966 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1967 result.addAttribute(attrName, attr); 1968 1969 return success(); 1970 } 1971 1972 // Helper function to parse a keyword into the specified attribute named by 1973 // `attrName`. The keyword must match one of the string values defined by the 1974 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 1975 // state. 1976 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 1977 OperationState &result, 1978 StringRef attrName) { 1979 llvm::SMLoc loc; 1980 StringRef ordering; 1981 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 1982 return failure(); 1983 1984 // Replace the keyword `ordering` with an integer attribute. 1985 auto kind = symbolizeAtomicOrdering(ordering); 1986 if (!kind) { 1987 return parser.emitError(loc) 1988 << "'" << ordering << "' is an incorrect value of the '" << attrName 1989 << "' attribute"; 1990 } 1991 1992 auto value = static_cast<int64_t>(kind.getValue()); 1993 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1994 result.addAttribute(attrName, attr); 1995 1996 return success(); 1997 } 1998 1999 //===----------------------------------------------------------------------===// 2000 // Printer, parser and verifier for LLVM::AtomicRMWOp. 2001 //===----------------------------------------------------------------------===// 2002 2003 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) { 2004 p << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' << op.ptr() << ", " 2005 << op.val() << ' ' << stringifyAtomicOrdering(op.ordering()) << ' '; 2006 p.printOptionalAttrDict(op->getAttrs(), {"bin_op", "ordering"}); 2007 p << " : " << op.res().getType(); 2008 } 2009 2010 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 2011 // attribute-dict? `:` type 2012 static ParseResult parseAtomicRMWOp(OpAsmParser &parser, 2013 OperationState &result) { 2014 Type type; 2015 OpAsmParser::OperandType ptr, val; 2016 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 2017 parser.parseComma() || parser.parseOperand(val) || 2018 parseAtomicOrdering(parser, result, "ordering") || 2019 parser.parseOptionalAttrDict(result.attributes) || 2020 parser.parseColonType(type) || 2021 parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type), 2022 result.operands) || 2023 parser.resolveOperand(val, type, result.operands)) 2024 return failure(); 2025 2026 result.addTypes(type); 2027 return success(); 2028 } 2029 2030 static LogicalResult verify(AtomicRMWOp op) { 2031 auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>(); 2032 auto valType = op.val().getType(); 2033 if (valType != ptrType.getElementType()) 2034 return op.emitOpError("expected LLVM IR element type for operand #0 to " 2035 "match type for operand #1"); 2036 auto resType = op.res().getType(); 2037 if (resType != valType) 2038 return op.emitOpError( 2039 "expected LLVM IR result type to match type for operand #1"); 2040 if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) { 2041 if (!mlir::LLVM::isCompatibleFloatingPointType(valType)) 2042 return op.emitOpError("expected LLVM IR floating point type"); 2043 } else if (op.bin_op() == AtomicBinOp::xchg) { 2044 auto intType = valType.dyn_cast<IntegerType>(); 2045 unsigned intBitWidth = intType ? intType.getWidth() : 0; 2046 if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 && 2047 intBitWidth != 64 && !valType.isa<BFloat16Type>() && 2048 !valType.isa<Float16Type>() && !valType.isa<Float32Type>() && 2049 !valType.isa<Float64Type>()) 2050 return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 2051 } else { 2052 auto intType = valType.dyn_cast<IntegerType>(); 2053 unsigned intBitWidth = intType ? intType.getWidth() : 0; 2054 if (intBitWidth != 8 && intBitWidth != 16 && intBitWidth != 32 && 2055 intBitWidth != 64) 2056 return op.emitOpError("expected LLVM IR integer type"); 2057 } 2058 2059 if (static_cast<unsigned>(op.ordering()) < 2060 static_cast<unsigned>(AtomicOrdering::monotonic)) 2061 return op.emitOpError() 2062 << "expected at least '" 2063 << stringifyAtomicOrdering(AtomicOrdering::monotonic) 2064 << "' ordering"; 2065 2066 return success(); 2067 } 2068 2069 //===----------------------------------------------------------------------===// 2070 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 2071 //===----------------------------------------------------------------------===// 2072 2073 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) { 2074 p << ' ' << op.ptr() << ", " << op.cmp() << ", " << op.val() << ' ' 2075 << stringifyAtomicOrdering(op.success_ordering()) << ' ' 2076 << stringifyAtomicOrdering(op.failure_ordering()); 2077 p.printOptionalAttrDict(op->getAttrs(), 2078 {"success_ordering", "failure_ordering"}); 2079 p << " : " << op.val().getType(); 2080 } 2081 2082 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 2083 // keyword keyword attribute-dict? `:` type 2084 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser, 2085 OperationState &result) { 2086 auto &builder = parser.getBuilder(); 2087 Type type; 2088 OpAsmParser::OperandType ptr, cmp, val; 2089 if (parser.parseOperand(ptr) || parser.parseComma() || 2090 parser.parseOperand(cmp) || parser.parseComma() || 2091 parser.parseOperand(val) || 2092 parseAtomicOrdering(parser, result, "success_ordering") || 2093 parseAtomicOrdering(parser, result, "failure_ordering") || 2094 parser.parseOptionalAttrDict(result.attributes) || 2095 parser.parseColonType(type) || 2096 parser.resolveOperand(ptr, LLVM::LLVMPointerType::get(type), 2097 result.operands) || 2098 parser.resolveOperand(cmp, type, result.operands) || 2099 parser.resolveOperand(val, type, result.operands)) 2100 return failure(); 2101 2102 auto boolType = IntegerType::get(builder.getContext(), 1); 2103 auto resultType = 2104 LLVMStructType::getLiteral(builder.getContext(), {type, boolType}); 2105 result.addTypes(resultType); 2106 2107 return success(); 2108 } 2109 2110 static LogicalResult verify(AtomicCmpXchgOp op) { 2111 auto ptrType = op.ptr().getType().cast<LLVM::LLVMPointerType>(); 2112 if (!ptrType) 2113 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 2114 auto cmpType = op.cmp().getType(); 2115 auto valType = op.val().getType(); 2116 if (cmpType != ptrType.getElementType() || cmpType != valType) 2117 return op.emitOpError("expected LLVM IR element type for operand #0 to " 2118 "match type for all other operands"); 2119 auto intType = valType.dyn_cast<IntegerType>(); 2120 unsigned intBitWidth = intType ? intType.getWidth() : 0; 2121 if (!valType.isa<LLVMPointerType>() && intBitWidth != 8 && 2122 intBitWidth != 16 && intBitWidth != 32 && intBitWidth != 64 && 2123 !valType.isa<BFloat16Type>() && !valType.isa<Float16Type>() && 2124 !valType.isa<Float32Type>() && !valType.isa<Float64Type>()) 2125 return op.emitOpError("unexpected LLVM IR type"); 2126 if (op.success_ordering() < AtomicOrdering::monotonic || 2127 op.failure_ordering() < AtomicOrdering::monotonic) 2128 return op.emitOpError("ordering must be at least 'monotonic'"); 2129 if (op.failure_ordering() == AtomicOrdering::release || 2130 op.failure_ordering() == AtomicOrdering::acq_rel) 2131 return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 2132 return success(); 2133 } 2134 2135 //===----------------------------------------------------------------------===// 2136 // Printer, parser and verifier for LLVM::FenceOp. 2137 //===----------------------------------------------------------------------===// 2138 2139 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 2140 // attribute-dict? 2141 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) { 2142 StringAttr sScope; 2143 StringRef syncscopeKeyword = "syncscope"; 2144 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 2145 if (parser.parseLParen() || 2146 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 2147 parser.parseRParen()) 2148 return failure(); 2149 } else { 2150 result.addAttribute(syncscopeKeyword, 2151 parser.getBuilder().getStringAttr("")); 2152 } 2153 if (parseAtomicOrdering(parser, result, "ordering") || 2154 parser.parseOptionalAttrDict(result.attributes)) 2155 return failure(); 2156 return success(); 2157 } 2158 2159 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) { 2160 StringRef syncscopeKeyword = "syncscope"; 2161 p << ' '; 2162 if (!op->getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 2163 p << "syncscope(" << op->getAttr(syncscopeKeyword) << ") "; 2164 p << stringifyAtomicOrdering(op.ordering()); 2165 } 2166 2167 static LogicalResult verify(FenceOp &op) { 2168 if (op.ordering() == AtomicOrdering::not_atomic || 2169 op.ordering() == AtomicOrdering::unordered || 2170 op.ordering() == AtomicOrdering::monotonic) 2171 return op.emitOpError("can be given only acquire, release, acq_rel, " 2172 "and seq_cst orderings"); 2173 return success(); 2174 } 2175 2176 //===----------------------------------------------------------------------===// 2177 // LLVMDialect initialization, type parsing, and registration. 2178 //===----------------------------------------------------------------------===// 2179 2180 void LLVMDialect::initialize() { 2181 addAttributes<FMFAttr, LinkageAttr, LoopOptionsAttr>(); 2182 2183 // clang-format off 2184 addTypes<LLVMVoidType, 2185 LLVMPPCFP128Type, 2186 LLVMX86MMXType, 2187 LLVMTokenType, 2188 LLVMLabelType, 2189 LLVMMetadataType, 2190 LLVMFunctionType, 2191 LLVMPointerType, 2192 LLVMFixedVectorType, 2193 LLVMScalableVectorType, 2194 LLVMArrayType, 2195 LLVMStructType>(); 2196 // clang-format on 2197 addOperations< 2198 #define GET_OP_LIST 2199 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 2200 >(); 2201 2202 // Support unknown operations because not all LLVM operations are registered. 2203 allowUnknownOperations(); 2204 } 2205 2206 #define GET_OP_CLASSES 2207 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 2208 2209 /// Parse a type registered to this dialect. 2210 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 2211 return detail::parseType(parser); 2212 } 2213 2214 /// Print a type registered to this dialect. 2215 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 2216 return detail::printType(type, os); 2217 } 2218 2219 LogicalResult LLVMDialect::verifyDataLayoutString( 2220 StringRef descr, llvm::function_ref<void(const Twine &)> reportError) { 2221 llvm::Expected<llvm::DataLayout> maybeDataLayout = 2222 llvm::DataLayout::parse(descr); 2223 if (maybeDataLayout) 2224 return success(); 2225 2226 std::string message; 2227 llvm::raw_string_ostream messageStream(message); 2228 llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream); 2229 reportError("invalid data layout descriptor: " + messageStream.str()); 2230 return failure(); 2231 } 2232 2233 /// Verify LLVM dialect attributes. 2234 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op, 2235 NamedAttribute attr) { 2236 // If the `llvm.loop` attribute is present, enforce the following structure, 2237 // which the module translation can assume. 2238 if (attr.first.strref() == LLVMDialect::getLoopAttrName()) { 2239 auto loopAttr = attr.second.dyn_cast<DictionaryAttr>(); 2240 if (!loopAttr) 2241 return op->emitOpError() << "expected '" << LLVMDialect::getLoopAttrName() 2242 << "' to be a dictionary attribute"; 2243 Optional<NamedAttribute> parallelAccessGroup = 2244 loopAttr.getNamed(LLVMDialect::getParallelAccessAttrName()); 2245 if (parallelAccessGroup.hasValue()) { 2246 auto accessGroups = parallelAccessGroup->second.dyn_cast<ArrayAttr>(); 2247 if (!accessGroups) 2248 return op->emitOpError() 2249 << "expected '" << LLVMDialect::getParallelAccessAttrName() 2250 << "' to be an array attribute"; 2251 for (Attribute attr : accessGroups) { 2252 auto accessGroupRef = attr.dyn_cast<SymbolRefAttr>(); 2253 if (!accessGroupRef) 2254 return op->emitOpError() 2255 << "expected '" << attr << "' to be a symbol reference"; 2256 StringAttr metadataName = accessGroupRef.getRootReference(); 2257 auto metadataOp = 2258 SymbolTable::lookupNearestSymbolFrom<LLVM::MetadataOp>( 2259 op->getParentOp(), metadataName); 2260 if (!metadataOp) 2261 return op->emitOpError() 2262 << "expected '" << attr << "' to reference a metadata op"; 2263 StringAttr accessGroupName = accessGroupRef.getLeafReference(); 2264 Operation *accessGroupOp = 2265 SymbolTable::lookupNearestSymbolFrom(metadataOp, accessGroupName); 2266 if (!accessGroupOp) 2267 return op->emitOpError() 2268 << "expected '" << attr << "' to reference an access_group op"; 2269 } 2270 } 2271 2272 Optional<NamedAttribute> loopOptions = 2273 loopAttr.getNamed(LLVMDialect::getLoopOptionsAttrName()); 2274 if (loopOptions.hasValue() && !loopOptions->second.isa<LoopOptionsAttr>()) 2275 return op->emitOpError() 2276 << "expected '" << LLVMDialect::getLoopOptionsAttrName() 2277 << "' to be a `loopopts` attribute"; 2278 } 2279 2280 // If the data layout attribute is present, it must use the LLVM data layout 2281 // syntax. Try parsing it and report errors in case of failure. Users of this 2282 // attribute may assume it is well-formed and can pass it to the (asserting) 2283 // llvm::DataLayout constructor. 2284 if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName()) 2285 return success(); 2286 if (auto stringAttr = attr.second.dyn_cast<StringAttr>()) 2287 return verifyDataLayoutString( 2288 stringAttr.getValue(), 2289 [op](const Twine &message) { op->emitOpError() << message.str(); }); 2290 2291 return op->emitOpError() << "expected '" 2292 << LLVM::LLVMDialect::getDataLayoutAttrName() 2293 << "' to be a string attribute"; 2294 } 2295 2296 /// Verify LLVMIR function argument attributes. 2297 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 2298 unsigned regionIdx, 2299 unsigned argIdx, 2300 NamedAttribute argAttr) { 2301 // Check that llvm.noalias is a unit attribute. 2302 if (argAttr.first == LLVMDialect::getNoAliasAttrName() && 2303 !argAttr.second.isa<UnitAttr>()) 2304 return op->emitError() 2305 << "expected llvm.noalias argument attribute to be a unit attribute"; 2306 // Check that llvm.align is an integer attribute. 2307 if (argAttr.first == LLVMDialect::getAlignAttrName() && 2308 !argAttr.second.isa<IntegerAttr>()) 2309 return op->emitError() 2310 << "llvm.align argument attribute of non integer type"; 2311 return success(); 2312 } 2313 2314 //===----------------------------------------------------------------------===// 2315 // Utility functions. 2316 //===----------------------------------------------------------------------===// 2317 2318 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 2319 StringRef name, StringRef value, 2320 LLVM::Linkage linkage) { 2321 assert(builder.getInsertionBlock() && 2322 builder.getInsertionBlock()->getParentOp() && 2323 "expected builder to point to a block constrained in an op"); 2324 auto module = 2325 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 2326 assert(module && "builder points to an op outside of a module"); 2327 2328 // Create the global at the entry of the module. 2329 OpBuilder moduleBuilder(module.getBodyRegion(), builder.getListener()); 2330 MLIRContext *ctx = builder.getContext(); 2331 auto type = LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), value.size()); 2332 auto global = moduleBuilder.create<LLVM::GlobalOp>( 2333 loc, type, /*isConstant=*/true, linkage, name, 2334 builder.getStringAttr(value), /*alignment=*/0); 2335 2336 // Get the pointer to the first character in the global string. 2337 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 2338 Value cst0 = builder.create<LLVM::ConstantOp>( 2339 loc, IntegerType::get(ctx, 64), 2340 builder.getIntegerAttr(builder.getIndexType(), 0)); 2341 return builder.create<LLVM::GEPOp>( 2342 loc, LLVM::LLVMPointerType::get(IntegerType::get(ctx, 8)), globalPtr, 2343 ValueRange{cst0, cst0}); 2344 } 2345 2346 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 2347 return op->hasTrait<OpTrait::SymbolTable>() && 2348 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 2349 } 2350 2351 static constexpr const FastmathFlags FastmathFlagsList[] = { 2352 // clang-format off 2353 FastmathFlags::nnan, 2354 FastmathFlags::ninf, 2355 FastmathFlags::nsz, 2356 FastmathFlags::arcp, 2357 FastmathFlags::contract, 2358 FastmathFlags::afn, 2359 FastmathFlags::reassoc, 2360 FastmathFlags::fast, 2361 // clang-format on 2362 }; 2363 2364 void FMFAttr::print(DialectAsmPrinter &printer) const { 2365 printer << "fastmath<"; 2366 auto flags = llvm::make_filter_range(FastmathFlagsList, [&](auto flag) { 2367 return bitEnumContains(this->getFlags(), flag); 2368 }); 2369 llvm::interleaveComma(flags, printer, 2370 [&](auto flag) { printer << stringifyEnum(flag); }); 2371 printer << ">"; 2372 } 2373 2374 Attribute FMFAttr::parse(MLIRContext *context, DialectAsmParser &parser, 2375 Type type) { 2376 if (failed(parser.parseLess())) 2377 return {}; 2378 2379 FastmathFlags flags = {}; 2380 if (failed(parser.parseOptionalGreater())) { 2381 do { 2382 StringRef elemName; 2383 if (failed(parser.parseKeyword(&elemName))) 2384 return {}; 2385 2386 auto elem = symbolizeFastmathFlags(elemName); 2387 if (!elem) { 2388 parser.emitError(parser.getNameLoc(), "Unknown fastmath flag: ") 2389 << elemName; 2390 return {}; 2391 } 2392 2393 flags = flags | *elem; 2394 } while (succeeded(parser.parseOptionalComma())); 2395 2396 if (failed(parser.parseGreater())) 2397 return {}; 2398 } 2399 2400 return FMFAttr::get(parser.getBuilder().getContext(), flags); 2401 } 2402 2403 void LinkageAttr::print(DialectAsmPrinter &printer) const { 2404 printer << "linkage<"; 2405 if (static_cast<uint64_t>(getLinkage()) <= getMaxEnumValForLinkage()) 2406 printer << stringifyEnum(getLinkage()); 2407 else 2408 printer << static_cast<uint64_t>(getLinkage()); 2409 printer << ">"; 2410 } 2411 2412 Attribute LinkageAttr::parse(MLIRContext *context, DialectAsmParser &parser, 2413 Type type) { 2414 StringRef elemName; 2415 if (parser.parseLess() || parser.parseKeyword(&elemName) || 2416 parser.parseGreater()) 2417 return {}; 2418 auto elem = linkage::symbolizeLinkage(elemName); 2419 if (!elem) { 2420 parser.emitError(parser.getNameLoc(), "Unknown linkage: ") << elemName; 2421 return {}; 2422 } 2423 Linkage linkage = *elem; 2424 return LinkageAttr::get(context, linkage); 2425 } 2426 2427 LoopOptionsAttrBuilder::LoopOptionsAttrBuilder(LoopOptionsAttr attr) 2428 : options(attr.getOptions().begin(), attr.getOptions().end()) {} 2429 2430 template <typename T> 2431 LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setOption(LoopOptionCase tag, 2432 Optional<T> value) { 2433 auto option = llvm::find_if( 2434 options, [tag](auto option) { return option.first == tag; }); 2435 if (option != options.end()) { 2436 if (value.hasValue()) 2437 option->second = *value; 2438 else 2439 options.erase(option); 2440 } else { 2441 options.push_back(LoopOptionsAttr::OptionValuePair(tag, *value)); 2442 } 2443 return *this; 2444 } 2445 2446 LoopOptionsAttrBuilder & 2447 LoopOptionsAttrBuilder::setDisableLICM(Optional<bool> value) { 2448 return setOption(LoopOptionCase::disable_licm, value); 2449 } 2450 2451 /// Set the `interleave_count` option to the provided value. If no value 2452 /// is provided the option is deleted. 2453 LoopOptionsAttrBuilder & 2454 LoopOptionsAttrBuilder::setInterleaveCount(Optional<uint64_t> count) { 2455 return setOption(LoopOptionCase::interleave_count, count); 2456 } 2457 2458 /// Set the `disable_unroll` option to the provided value. If no value 2459 /// is provided the option is deleted. 2460 LoopOptionsAttrBuilder & 2461 LoopOptionsAttrBuilder::setDisableUnroll(Optional<bool> value) { 2462 return setOption(LoopOptionCase::disable_unroll, value); 2463 } 2464 2465 /// Set the `disable_pipeline` option to the provided value. If no value 2466 /// is provided the option is deleted. 2467 LoopOptionsAttrBuilder & 2468 LoopOptionsAttrBuilder::setDisablePipeline(Optional<bool> value) { 2469 return setOption(LoopOptionCase::disable_pipeline, value); 2470 } 2471 2472 /// Set the `pipeline_initiation_interval` option to the provided value. 2473 /// If no value is provided the option is deleted. 2474 LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setPipelineInitiationInterval( 2475 Optional<uint64_t> count) { 2476 return setOption(LoopOptionCase::pipeline_initiation_interval, count); 2477 } 2478 2479 template <typename T> 2480 static Optional<T> 2481 getOption(ArrayRef<std::pair<LoopOptionCase, int64_t>> options, 2482 LoopOptionCase option) { 2483 auto it = 2484 lower_bound(options, option, [](auto optionPair, LoopOptionCase option) { 2485 return optionPair.first < option; 2486 }); 2487 if (it == options.end()) 2488 return {}; 2489 return static_cast<T>(it->second); 2490 } 2491 2492 Optional<bool> LoopOptionsAttr::disableUnroll() { 2493 return getOption<bool>(getOptions(), LoopOptionCase::disable_unroll); 2494 } 2495 2496 Optional<bool> LoopOptionsAttr::disableLICM() { 2497 return getOption<bool>(getOptions(), LoopOptionCase::disable_licm); 2498 } 2499 2500 Optional<int64_t> LoopOptionsAttr::interleaveCount() { 2501 return getOption<int64_t>(getOptions(), LoopOptionCase::interleave_count); 2502 } 2503 2504 /// Build the LoopOptions Attribute from a sorted array of individual options. 2505 LoopOptionsAttr LoopOptionsAttr::get( 2506 MLIRContext *context, 2507 ArrayRef<std::pair<LoopOptionCase, int64_t>> sortedOptions) { 2508 assert(llvm::is_sorted(sortedOptions, llvm::less_first()) && 2509 "LoopOptionsAttr ctor expects a sorted options array"); 2510 return Base::get(context, sortedOptions); 2511 } 2512 2513 /// Build the LoopOptions Attribute from a sorted array of individual options. 2514 LoopOptionsAttr LoopOptionsAttr::get(MLIRContext *context, 2515 LoopOptionsAttrBuilder &optionBuilders) { 2516 llvm::sort(optionBuilders.options, llvm::less_first()); 2517 return Base::get(context, optionBuilders.options); 2518 } 2519 2520 void LoopOptionsAttr::print(DialectAsmPrinter &printer) const { 2521 printer << getMnemonic() << "<"; 2522 llvm::interleaveComma(getOptions(), printer, [&](auto option) { 2523 printer << stringifyEnum(option.first) << " = "; 2524 switch (option.first) { 2525 case LoopOptionCase::disable_licm: 2526 case LoopOptionCase::disable_unroll: 2527 case LoopOptionCase::disable_pipeline: 2528 printer << (option.second ? "true" : "false"); 2529 break; 2530 case LoopOptionCase::interleave_count: 2531 case LoopOptionCase::pipeline_initiation_interval: 2532 printer << option.second; 2533 break; 2534 } 2535 }); 2536 printer << ">"; 2537 } 2538 2539 Attribute LoopOptionsAttr::parse(MLIRContext *context, DialectAsmParser &parser, 2540 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.getBuilder().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 = 2608 generatedAttributeParser(getContext(), parser, attrKind, type, attr); 2609 if (parseResult.hasValue()) 2610 return attr; 2611 } 2612 parser.emitError(parser.getNameLoc(), "unknown attribute type: ") << attrKind; 2613 return {}; 2614 } 2615 2616 void LLVMDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const { 2617 if (succeeded(generatedAttributePrinter(attr, os))) 2618 return; 2619 llvm_unreachable("Unknown attribute type"); 2620 } 2621