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