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