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