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 "mlir/Dialect/LLVMIR/LLVMTypes.h" 15 #include "mlir/IR/Builders.h" 16 #include "mlir/IR/BuiltinOps.h" 17 #include "mlir/IR/BuiltinTypes.h" 18 #include "mlir/IR/DialectImplementation.h" 19 #include "mlir/IR/FunctionImplementation.h" 20 #include "mlir/IR/MLIRContext.h" 21 22 #include "llvm/ADT/StringSwitch.h" 23 #include "llvm/AsmParser/Parser.h" 24 #include "llvm/Bitcode/BitcodeReader.h" 25 #include "llvm/Bitcode/BitcodeWriter.h" 26 #include "llvm/IR/Attributes.h" 27 #include "llvm/IR/Function.h" 28 #include "llvm/IR/Type.h" 29 #include "llvm/Support/Mutex.h" 30 #include "llvm/Support/SourceMgr.h" 31 32 using namespace mlir; 33 using namespace mlir::LLVM; 34 35 static constexpr const char kVolatileAttrName[] = "volatile_"; 36 static constexpr const char kNonTemporalAttrName[] = "nontemporal"; 37 38 #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc" 39 40 //===----------------------------------------------------------------------===// 41 // Printing/parsing for LLVM::CmpOp. 42 //===----------------------------------------------------------------------===// 43 static void printICmpOp(OpAsmPrinter &p, ICmpOp &op) { 44 p << op.getOperationName() << " \"" << stringifyICmpPredicate(op.predicate()) 45 << "\" " << op.getOperand(0) << ", " << op.getOperand(1); 46 p.printOptionalAttrDict(op.getAttrs(), {"predicate"}); 47 p << " : " << op.lhs().getType(); 48 } 49 50 static void printFCmpOp(OpAsmPrinter &p, FCmpOp &op) { 51 p << op.getOperationName() << " \"" << stringifyFCmpPredicate(op.predicate()) 52 << "\" " << op.getOperand(0) << ", " << op.getOperand(1); 53 p.printOptionalAttrDict(op.getAttrs(), {"predicate"}); 54 p << " : " << op.lhs().getType(); 55 } 56 57 // <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use 58 // attribute-dict? `:` type 59 // <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use 60 // attribute-dict? `:` type 61 template <typename CmpPredicateType> 62 static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result) { 63 Builder &builder = parser.getBuilder(); 64 65 StringAttr predicateAttr; 66 OpAsmParser::OperandType lhs, rhs; 67 Type type; 68 llvm::SMLoc predicateLoc, trailingTypeLoc; 69 if (parser.getCurrentLocation(&predicateLoc) || 70 parser.parseAttribute(predicateAttr, "predicate", result.attributes) || 71 parser.parseOperand(lhs) || parser.parseComma() || 72 parser.parseOperand(rhs) || 73 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 74 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) || 75 parser.resolveOperand(lhs, type, result.operands) || 76 parser.resolveOperand(rhs, type, result.operands)) 77 return failure(); 78 79 // Replace the string attribute `predicate` with an integer attribute. 80 int64_t predicateValue = 0; 81 if (std::is_same<CmpPredicateType, ICmpPredicate>()) { 82 Optional<ICmpPredicate> predicate = 83 symbolizeICmpPredicate(predicateAttr.getValue()); 84 if (!predicate) 85 return parser.emitError(predicateLoc) 86 << "'" << predicateAttr.getValue() 87 << "' is an incorrect value of the 'predicate' attribute"; 88 predicateValue = static_cast<int64_t>(predicate.getValue()); 89 } else { 90 Optional<FCmpPredicate> predicate = 91 symbolizeFCmpPredicate(predicateAttr.getValue()); 92 if (!predicate) 93 return parser.emitError(predicateLoc) 94 << "'" << predicateAttr.getValue() 95 << "' is an incorrect value of the 'predicate' attribute"; 96 predicateValue = static_cast<int64_t>(predicate.getValue()); 97 } 98 99 result.attributes.set("predicate", 100 parser.getBuilder().getI64IntegerAttr(predicateValue)); 101 102 // The result type is either i1 or a vector type <? x i1> if the inputs are 103 // vectors. 104 auto resultType = LLVMType::getInt1Ty(builder.getContext()); 105 auto argType = type.dyn_cast<LLVM::LLVMType>(); 106 if (!argType) 107 return parser.emitError(trailingTypeLoc, "expected LLVM IR dialect type"); 108 if (argType.isVectorTy()) 109 resultType = 110 LLVMType::getVectorTy(resultType, argType.getVectorNumElements()); 111 112 result.addTypes({resultType}); 113 return success(); 114 } 115 116 //===----------------------------------------------------------------------===// 117 // Printing/parsing for LLVM::AllocaOp. 118 //===----------------------------------------------------------------------===// 119 120 static void printAllocaOp(OpAsmPrinter &p, AllocaOp &op) { 121 auto elemTy = op.getType().cast<LLVM::LLVMType>().getPointerElementTy(); 122 123 auto funcTy = FunctionType::get({op.arraySize().getType()}, {op.getType()}, 124 op.getContext()); 125 126 p << op.getOperationName() << ' ' << op.arraySize() << " x " << elemTy; 127 if (op.alignment().hasValue() && *op.alignment() != 0) 128 p.printOptionalAttrDict(op.getAttrs()); 129 else 130 p.printOptionalAttrDict(op.getAttrs(), {"alignment"}); 131 p << " : " << funcTy; 132 } 133 134 // <operation> ::= `llvm.alloca` ssa-use `x` type attribute-dict? 135 // `:` type `,` type 136 static ParseResult parseAllocaOp(OpAsmParser &parser, OperationState &result) { 137 OpAsmParser::OperandType arraySize; 138 Type type, elemType; 139 llvm::SMLoc trailingTypeLoc; 140 if (parser.parseOperand(arraySize) || parser.parseKeyword("x") || 141 parser.parseType(elemType) || 142 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 143 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 144 return failure(); 145 146 Optional<NamedAttribute> alignmentAttr = 147 result.attributes.getNamed("alignment"); 148 if (alignmentAttr.hasValue()) { 149 auto alignmentInt = alignmentAttr.getValue().second.dyn_cast<IntegerAttr>(); 150 if (!alignmentInt) 151 return parser.emitError(parser.getNameLoc(), 152 "expected integer alignment"); 153 if (alignmentInt.getValue().isNullValue()) 154 result.attributes.erase("alignment"); 155 } 156 157 // Extract the result type from the trailing function type. 158 auto funcType = type.dyn_cast<FunctionType>(); 159 if (!funcType || funcType.getNumInputs() != 1 || 160 funcType.getNumResults() != 1) 161 return parser.emitError( 162 trailingTypeLoc, 163 "expected trailing function type with one argument and one result"); 164 165 if (parser.resolveOperand(arraySize, funcType.getInput(0), result.operands)) 166 return failure(); 167 168 result.addTypes({funcType.getResult(0)}); 169 return success(); 170 } 171 172 //===----------------------------------------------------------------------===// 173 // LLVM::BrOp 174 //===----------------------------------------------------------------------===// 175 176 Optional<MutableOperandRange> 177 BrOp::getMutableSuccessorOperands(unsigned index) { 178 assert(index == 0 && "invalid successor index"); 179 return destOperandsMutable(); 180 } 181 182 //===----------------------------------------------------------------------===// 183 // LLVM::CondBrOp 184 //===----------------------------------------------------------------------===// 185 186 Optional<MutableOperandRange> 187 CondBrOp::getMutableSuccessorOperands(unsigned index) { 188 assert(index < getNumSuccessors() && "invalid successor index"); 189 return index == 0 ? trueDestOperandsMutable() : falseDestOperandsMutable(); 190 } 191 192 //===----------------------------------------------------------------------===// 193 // Builder, printer and parser for for LLVM::LoadOp. 194 //===----------------------------------------------------------------------===// 195 196 void LoadOp::build(OpBuilder &builder, OperationState &result, Type t, 197 Value addr, unsigned alignment, bool isVolatile, 198 bool isNonTemporal) { 199 result.addOperands(addr); 200 result.addTypes(t); 201 if (isVolatile) 202 result.addAttribute(kVolatileAttrName, builder.getUnitAttr()); 203 if (isNonTemporal) 204 result.addAttribute(kNonTemporalAttrName, builder.getUnitAttr()); 205 if (alignment != 0) 206 result.addAttribute("alignment", builder.getI64IntegerAttr(alignment)); 207 } 208 209 static void printLoadOp(OpAsmPrinter &p, LoadOp &op) { 210 p << op.getOperationName() << ' '; 211 if (op.volatile_()) 212 p << "volatile "; 213 p << op.addr(); 214 p.printOptionalAttrDict(op.getAttrs(), {kVolatileAttrName}); 215 p << " : " << op.addr().getType(); 216 } 217 218 // Extract the pointee type from the LLVM pointer type wrapped in MLIR. Return 219 // the resulting type wrapped in MLIR, or nullptr on error. 220 static Type getLoadStoreElementType(OpAsmParser &parser, Type type, 221 llvm::SMLoc trailingTypeLoc) { 222 auto llvmTy = type.dyn_cast<LLVM::LLVMType>(); 223 if (!llvmTy) 224 return parser.emitError(trailingTypeLoc, "expected LLVM IR dialect type"), 225 nullptr; 226 if (!llvmTy.isPointerTy()) 227 return parser.emitError(trailingTypeLoc, "expected LLVM pointer type"), 228 nullptr; 229 return llvmTy.getPointerElementTy(); 230 } 231 232 // <operation> ::= `llvm.load` `volatile` ssa-use attribute-dict? `:` type 233 static ParseResult parseLoadOp(OpAsmParser &parser, OperationState &result) { 234 OpAsmParser::OperandType addr; 235 Type type; 236 llvm::SMLoc trailingTypeLoc; 237 238 if (succeeded(parser.parseOptionalKeyword("volatile"))) 239 result.addAttribute(kVolatileAttrName, parser.getBuilder().getUnitAttr()); 240 241 if (parser.parseOperand(addr) || 242 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 243 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) || 244 parser.resolveOperand(addr, type, result.operands)) 245 return failure(); 246 247 Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc); 248 249 result.addTypes(elemTy); 250 return success(); 251 } 252 253 //===----------------------------------------------------------------------===// 254 // Builder, printer and parser for LLVM::StoreOp. 255 //===----------------------------------------------------------------------===// 256 257 void StoreOp::build(OpBuilder &builder, OperationState &result, Value value, 258 Value addr, unsigned alignment, bool isVolatile, 259 bool isNonTemporal) { 260 result.addOperands({value, addr}); 261 result.addTypes({}); 262 if (isVolatile) 263 result.addAttribute(kVolatileAttrName, builder.getUnitAttr()); 264 if (isNonTemporal) 265 result.addAttribute(kNonTemporalAttrName, builder.getUnitAttr()); 266 if (alignment != 0) 267 result.addAttribute("alignment", builder.getI64IntegerAttr(alignment)); 268 } 269 270 static void printStoreOp(OpAsmPrinter &p, StoreOp &op) { 271 p << op.getOperationName() << ' '; 272 if (op.volatile_()) 273 p << "volatile "; 274 p << op.value() << ", " << op.addr(); 275 p.printOptionalAttrDict(op.getAttrs(), {kVolatileAttrName}); 276 p << " : " << op.addr().getType(); 277 } 278 279 // <operation> ::= `llvm.store` `volatile` ssa-use `,` ssa-use 280 // attribute-dict? `:` type 281 static ParseResult parseStoreOp(OpAsmParser &parser, OperationState &result) { 282 OpAsmParser::OperandType addr, value; 283 Type type; 284 llvm::SMLoc trailingTypeLoc; 285 286 if (succeeded(parser.parseOptionalKeyword("volatile"))) 287 result.addAttribute(kVolatileAttrName, parser.getBuilder().getUnitAttr()); 288 289 if (parser.parseOperand(value) || parser.parseComma() || 290 parser.parseOperand(addr) || 291 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 292 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 293 return failure(); 294 295 Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc); 296 if (!elemTy) 297 return failure(); 298 299 if (parser.resolveOperand(value, elemTy, result.operands) || 300 parser.resolveOperand(addr, type, result.operands)) 301 return failure(); 302 303 return success(); 304 } 305 306 ///===---------------------------------------------------------------------===// 307 /// LLVM::InvokeOp 308 ///===---------------------------------------------------------------------===// 309 310 Optional<MutableOperandRange> 311 InvokeOp::getMutableSuccessorOperands(unsigned index) { 312 assert(index < getNumSuccessors() && "invalid successor index"); 313 return index == 0 ? normalDestOperandsMutable() : unwindDestOperandsMutable(); 314 } 315 316 static LogicalResult verify(InvokeOp op) { 317 if (op.getNumResults() > 1) 318 return op.emitOpError("must have 0 or 1 result"); 319 320 Block *unwindDest = op.unwindDest(); 321 if (unwindDest->empty()) 322 return op.emitError( 323 "must have at least one operation in unwind destination"); 324 325 // In unwind destination, first operation must be LandingpadOp 326 if (!isa<LandingpadOp>(unwindDest->front())) 327 return op.emitError("first operation in unwind destination should be a " 328 "llvm.landingpad operation"); 329 330 return success(); 331 } 332 333 static void printInvokeOp(OpAsmPrinter &p, InvokeOp op) { 334 auto callee = op.callee(); 335 bool isDirect = callee.hasValue(); 336 337 p << op.getOperationName() << ' '; 338 339 // Either function name or pointer 340 if (isDirect) 341 p.printSymbolName(callee.getValue()); 342 else 343 p << op.getOperand(0); 344 345 p << '(' << op.getOperands().drop_front(isDirect ? 0 : 1) << ')'; 346 p << " to "; 347 p.printSuccessorAndUseList(op.normalDest(), op.normalDestOperands()); 348 p << " unwind "; 349 p.printSuccessorAndUseList(op.unwindDest(), op.unwindDestOperands()); 350 351 p.printOptionalAttrDict(op.getAttrs(), 352 {InvokeOp::getOperandSegmentSizeAttr(), "callee"}); 353 p << " : "; 354 p.printFunctionalType( 355 llvm::drop_begin(op.getOperandTypes(), isDirect ? 0 : 1), 356 op.getResultTypes()); 357 } 358 359 /// <operation> ::= `llvm.invoke` (function-id | ssa-use) `(` ssa-use-list `)` 360 /// `to` bb-id (`[` ssa-use-and-type-list `]`)? 361 /// `unwind` bb-id (`[` ssa-use-and-type-list `]`)? 362 /// attribute-dict? `:` function-type 363 static ParseResult parseInvokeOp(OpAsmParser &parser, OperationState &result) { 364 SmallVector<OpAsmParser::OperandType, 8> operands; 365 FunctionType funcType; 366 SymbolRefAttr funcAttr; 367 llvm::SMLoc trailingTypeLoc; 368 Block *normalDest, *unwindDest; 369 SmallVector<Value, 4> normalOperands, unwindOperands; 370 Builder &builder = parser.getBuilder(); 371 372 // Parse an operand list that will, in practice, contain 0 or 1 operand. In 373 // case of an indirect call, there will be 1 operand before `(`. In case of a 374 // direct call, there will be no operands and the parser will stop at the 375 // function identifier without complaining. 376 if (parser.parseOperandList(operands)) 377 return failure(); 378 bool isDirect = operands.empty(); 379 380 // Optionally parse a function identifier. 381 if (isDirect && parser.parseAttribute(funcAttr, "callee", result.attributes)) 382 return failure(); 383 384 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || 385 parser.parseKeyword("to") || 386 parser.parseSuccessorAndUseList(normalDest, normalOperands) || 387 parser.parseKeyword("unwind") || 388 parser.parseSuccessorAndUseList(unwindDest, unwindOperands) || 389 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 390 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(funcType)) 391 return failure(); 392 393 if (isDirect) { 394 // Make sure types match. 395 if (parser.resolveOperands(operands, funcType.getInputs(), 396 parser.getNameLoc(), result.operands)) 397 return failure(); 398 result.addTypes(funcType.getResults()); 399 } else { 400 // Construct the LLVM IR Dialect function type that the first operand 401 // should match. 402 if (funcType.getNumResults() > 1) 403 return parser.emitError(trailingTypeLoc, 404 "expected function with 0 or 1 result"); 405 406 LLVM::LLVMType llvmResultType; 407 if (funcType.getNumResults() == 0) { 408 llvmResultType = LLVM::LLVMType::getVoidTy(builder.getContext()); 409 } else { 410 llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>(); 411 if (!llvmResultType) 412 return parser.emitError(trailingTypeLoc, 413 "expected result to have LLVM type"); 414 } 415 416 SmallVector<LLVM::LLVMType, 8> argTypes; 417 argTypes.reserve(funcType.getNumInputs()); 418 for (Type ty : funcType.getInputs()) { 419 if (auto argType = ty.dyn_cast<LLVM::LLVMType>()) 420 argTypes.push_back(argType); 421 else 422 return parser.emitError(trailingTypeLoc, 423 "expected LLVM types as inputs"); 424 } 425 426 auto llvmFuncType = LLVM::LLVMType::getFunctionTy(llvmResultType, argTypes, 427 /*isVarArg=*/false); 428 auto wrappedFuncType = llvmFuncType.getPointerTo(); 429 430 auto funcArguments = llvm::makeArrayRef(operands).drop_front(); 431 432 // Make sure that the first operand (indirect callee) matches the wrapped 433 // LLVM IR function type, and that the types of the other call operands 434 // match the types of the function arguments. 435 if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || 436 parser.resolveOperands(funcArguments, funcType.getInputs(), 437 parser.getNameLoc(), result.operands)) 438 return failure(); 439 440 result.addTypes(llvmResultType); 441 } 442 result.addSuccessors({normalDest, unwindDest}); 443 result.addOperands(normalOperands); 444 result.addOperands(unwindOperands); 445 446 result.addAttribute( 447 InvokeOp::getOperandSegmentSizeAttr(), 448 builder.getI32VectorAttr({static_cast<int32_t>(operands.size()), 449 static_cast<int32_t>(normalOperands.size()), 450 static_cast<int32_t>(unwindOperands.size())})); 451 return success(); 452 } 453 454 ///===----------------------------------------------------------------------===// 455 /// Verifying/Printing/Parsing for LLVM::LandingpadOp. 456 ///===----------------------------------------------------------------------===// 457 458 static LogicalResult verify(LandingpadOp op) { 459 Value value; 460 if (LLVMFuncOp func = op.getParentOfType<LLVMFuncOp>()) { 461 if (!func.personality().hasValue()) 462 return op.emitError( 463 "llvm.landingpad needs to be in a function with a personality"); 464 } 465 466 if (!op.cleanup() && op.getOperands().empty()) 467 return op.emitError("landingpad instruction expects at least one clause or " 468 "cleanup attribute"); 469 470 for (unsigned idx = 0, ie = op.getNumOperands(); idx < ie; idx++) { 471 value = op.getOperand(idx); 472 bool isFilter = value.getType().cast<LLVMType>().isArrayTy(); 473 if (isFilter) { 474 // FIXME: Verify filter clauses when arrays are appropriately handled 475 } else { 476 // catch - global addresses only. 477 // Bitcast ops should have global addresses as their args. 478 if (auto bcOp = value.getDefiningOp<BitcastOp>()) { 479 if (auto addrOp = bcOp.arg().getDefiningOp<AddressOfOp>()) 480 continue; 481 return op.emitError("constant clauses expected") 482 .attachNote(bcOp.getLoc()) 483 << "global addresses expected as operand to " 484 "bitcast used in clauses for landingpad"; 485 } 486 // NullOp and AddressOfOp allowed 487 if (value.getDefiningOp<NullOp>()) 488 continue; 489 if (value.getDefiningOp<AddressOfOp>()) 490 continue; 491 return op.emitError("clause #") 492 << idx << " is not a known constant - null, addressof, bitcast"; 493 } 494 } 495 return success(); 496 } 497 498 static void printLandingpadOp(OpAsmPrinter &p, LandingpadOp &op) { 499 p << op.getOperationName() << (op.cleanup() ? " cleanup " : " "); 500 501 // Clauses 502 for (auto value : op.getOperands()) { 503 // Similar to llvm - if clause is an array type then it is filter 504 // clause else catch clause 505 bool isArrayTy = value.getType().cast<LLVMType>().isArrayTy(); 506 p << '(' << (isArrayTy ? "filter " : "catch ") << value << " : " 507 << value.getType() << ") "; 508 } 509 510 p.printOptionalAttrDict(op.getAttrs(), {"cleanup"}); 511 512 p << ": " << op.getType(); 513 } 514 515 /// <operation> ::= `llvm.landingpad` `cleanup`? 516 /// ((`catch` | `filter`) operand-type ssa-use)* attribute-dict? 517 static ParseResult parseLandingpadOp(OpAsmParser &parser, 518 OperationState &result) { 519 // Check for cleanup 520 if (succeeded(parser.parseOptionalKeyword("cleanup"))) 521 result.addAttribute("cleanup", parser.getBuilder().getUnitAttr()); 522 523 // Parse clauses with types 524 while (succeeded(parser.parseOptionalLParen()) && 525 (succeeded(parser.parseOptionalKeyword("filter")) || 526 succeeded(parser.parseOptionalKeyword("catch")))) { 527 OpAsmParser::OperandType operand; 528 Type ty; 529 if (parser.parseOperand(operand) || parser.parseColon() || 530 parser.parseType(ty) || 531 parser.resolveOperand(operand, ty, result.operands) || 532 parser.parseRParen()) 533 return failure(); 534 } 535 536 Type type; 537 if (parser.parseColon() || parser.parseType(type)) 538 return failure(); 539 540 result.addTypes(type); 541 return success(); 542 } 543 544 //===----------------------------------------------------------------------===// 545 // Verifying/Printing/parsing for LLVM::CallOp. 546 //===----------------------------------------------------------------------===// 547 548 static LogicalResult verify(CallOp &op) { 549 if (op.getNumResults() > 1) 550 return op.emitOpError("must have 0 or 1 result"); 551 552 // Type for the callee, we'll get it differently depending if it is a direct 553 // or indirect call. 554 LLVMType fnType; 555 556 bool isIndirect = false; 557 558 // If this is an indirect call, the callee attribute is missing. 559 Optional<StringRef> calleeName = op.callee(); 560 if (!calleeName) { 561 isIndirect = true; 562 if (!op.getNumOperands()) 563 return op.emitOpError( 564 "must have either a `callee` attribute or at least an operand"); 565 fnType = op.getOperand(0).getType().dyn_cast<LLVMType>(); 566 if (!fnType) 567 return op.emitOpError("indirect call to a non-llvm type: ") 568 << op.getOperand(0).getType(); 569 auto ptrType = fnType.dyn_cast<LLVMPointerType>(); 570 if (!ptrType) 571 return op.emitOpError("indirect call expects a pointer as callee: ") 572 << fnType; 573 fnType = ptrType.getElementType(); 574 } else { 575 Operation *callee = SymbolTable::lookupNearestSymbolFrom(op, *calleeName); 576 if (!callee) 577 return op.emitOpError() 578 << "'" << *calleeName 579 << "' does not reference a symbol in the current scope"; 580 auto fn = dyn_cast<LLVMFuncOp>(callee); 581 if (!fn) 582 return op.emitOpError() << "'" << *calleeName 583 << "' does not reference a valid LLVM function"; 584 585 fnType = fn.getType(); 586 } 587 if (!fnType.isFunctionTy()) 588 return op.emitOpError("callee does not have a functional type: ") << fnType; 589 590 // Verify that the operand and result types match the callee. 591 592 if (!fnType.isFunctionVarArg() && 593 fnType.getFunctionNumParams() != (op.getNumOperands() - isIndirect)) 594 return op.emitOpError() 595 << "incorrect number of operands (" 596 << (op.getNumOperands() - isIndirect) 597 << ") for callee (expecting: " << fnType.getFunctionNumParams() 598 << ")"; 599 600 if (fnType.getFunctionNumParams() > (op.getNumOperands() - isIndirect)) 601 return op.emitOpError() << "incorrect number of operands (" 602 << (op.getNumOperands() - isIndirect) 603 << ") for varargs callee (expecting at least: " 604 << fnType.getFunctionNumParams() << ")"; 605 606 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i != e; ++i) 607 if (op.getOperand(i + isIndirect).getType() != 608 fnType.getFunctionParamType(i)) 609 return op.emitOpError() << "operand type mismatch for operand " << i 610 << ": " << op.getOperand(i + isIndirect).getType() 611 << " != " << fnType.getFunctionParamType(i); 612 613 if (op.getNumResults() && 614 op.getResult(0).getType() != fnType.getFunctionResultType()) 615 return op.emitOpError() 616 << "result type mismatch: " << op.getResult(0).getType() 617 << " != " << fnType.getFunctionResultType(); 618 619 return success(); 620 } 621 622 static void printCallOp(OpAsmPrinter &p, CallOp &op) { 623 auto callee = op.callee(); 624 bool isDirect = callee.hasValue(); 625 626 // Print the direct callee if present as a function attribute, or an indirect 627 // callee (first operand) otherwise. 628 p << op.getOperationName() << ' '; 629 if (isDirect) 630 p.printSymbolName(callee.getValue()); 631 else 632 p << op.getOperand(0); 633 634 auto args = op.getOperands().drop_front(isDirect ? 0 : 1); 635 p << '(' << args << ')'; 636 p.printOptionalAttrDict(op.getAttrs(), {"callee"}); 637 638 // Reconstruct the function MLIR function type from operand and result types. 639 p << " : " 640 << FunctionType::get(args.getTypes(), op.getResultTypes(), op.getContext()); 641 } 642 643 // <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)` 644 // attribute-dict? `:` function-type 645 static ParseResult parseCallOp(OpAsmParser &parser, OperationState &result) { 646 SmallVector<OpAsmParser::OperandType, 8> operands; 647 Type type; 648 SymbolRefAttr funcAttr; 649 llvm::SMLoc trailingTypeLoc; 650 651 // Parse an operand list that will, in practice, contain 0 or 1 operand. In 652 // case of an indirect call, there will be 1 operand before `(`. In case of a 653 // direct call, there will be no operands and the parser will stop at the 654 // function identifier without complaining. 655 if (parser.parseOperandList(operands)) 656 return failure(); 657 bool isDirect = operands.empty(); 658 659 // Optionally parse a function identifier. 660 if (isDirect) 661 if (parser.parseAttribute(funcAttr, "callee", result.attributes)) 662 return failure(); 663 664 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || 665 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 666 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 667 return failure(); 668 669 auto funcType = type.dyn_cast<FunctionType>(); 670 if (!funcType) 671 return parser.emitError(trailingTypeLoc, "expected function type"); 672 if (isDirect) { 673 // Make sure types match. 674 if (parser.resolveOperands(operands, funcType.getInputs(), 675 parser.getNameLoc(), result.operands)) 676 return failure(); 677 result.addTypes(funcType.getResults()); 678 } else { 679 // Construct the LLVM IR Dialect function type that the first operand 680 // should match. 681 if (funcType.getNumResults() > 1) 682 return parser.emitError(trailingTypeLoc, 683 "expected function with 0 or 1 result"); 684 685 Builder &builder = parser.getBuilder(); 686 LLVM::LLVMType llvmResultType; 687 if (funcType.getNumResults() == 0) { 688 llvmResultType = LLVM::LLVMType::getVoidTy(builder.getContext()); 689 } else { 690 llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>(); 691 if (!llvmResultType) 692 return parser.emitError(trailingTypeLoc, 693 "expected result to have LLVM type"); 694 } 695 696 SmallVector<LLVM::LLVMType, 8> argTypes; 697 argTypes.reserve(funcType.getNumInputs()); 698 for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) { 699 auto argType = funcType.getInput(i).dyn_cast<LLVM::LLVMType>(); 700 if (!argType) 701 return parser.emitError(trailingTypeLoc, 702 "expected LLVM types as inputs"); 703 argTypes.push_back(argType); 704 } 705 auto llvmFuncType = LLVM::LLVMType::getFunctionTy(llvmResultType, argTypes, 706 /*isVarArg=*/false); 707 auto wrappedFuncType = llvmFuncType.getPointerTo(); 708 709 auto funcArguments = 710 ArrayRef<OpAsmParser::OperandType>(operands).drop_front(); 711 712 // Make sure that the first operand (indirect callee) matches the wrapped 713 // LLVM IR function type, and that the types of the other call operands 714 // match the types of the function arguments. 715 if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || 716 parser.resolveOperands(funcArguments, funcType.getInputs(), 717 parser.getNameLoc(), result.operands)) 718 return failure(); 719 720 result.addTypes(llvmResultType); 721 } 722 723 return success(); 724 } 725 726 //===----------------------------------------------------------------------===// 727 // Printing/parsing for LLVM::ExtractElementOp. 728 //===----------------------------------------------------------------------===// 729 // Expects vector to be of wrapped LLVM vector type and position to be of 730 // wrapped LLVM i32 type. 731 void LLVM::ExtractElementOp::build(OpBuilder &b, OperationState &result, 732 Value vector, Value position, 733 ArrayRef<NamedAttribute> attrs) { 734 auto wrappedVectorType = vector.getType().cast<LLVM::LLVMType>(); 735 auto llvmType = wrappedVectorType.getVectorElementType(); 736 build(b, result, llvmType, vector, position); 737 result.addAttributes(attrs); 738 } 739 740 static void printExtractElementOp(OpAsmPrinter &p, ExtractElementOp &op) { 741 p << op.getOperationName() << ' ' << op.vector() << "[" << op.position() 742 << " : " << op.position().getType() << "]"; 743 p.printOptionalAttrDict(op.getAttrs()); 744 p << " : " << op.vector().getType(); 745 } 746 747 // <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use 748 // attribute-dict? `:` type 749 static ParseResult parseExtractElementOp(OpAsmParser &parser, 750 OperationState &result) { 751 llvm::SMLoc loc; 752 OpAsmParser::OperandType vector, position; 753 Type type, positionType; 754 if (parser.getCurrentLocation(&loc) || parser.parseOperand(vector) || 755 parser.parseLSquare() || parser.parseOperand(position) || 756 parser.parseColonType(positionType) || parser.parseRSquare() || 757 parser.parseOptionalAttrDict(result.attributes) || 758 parser.parseColonType(type) || 759 parser.resolveOperand(vector, type, result.operands) || 760 parser.resolveOperand(position, positionType, result.operands)) 761 return failure(); 762 auto wrappedVectorType = type.dyn_cast<LLVM::LLVMType>(); 763 if (!wrappedVectorType || !wrappedVectorType.isVectorTy()) 764 return parser.emitError( 765 loc, "expected LLVM IR dialect vector type for operand #1"); 766 result.addTypes(wrappedVectorType.getVectorElementType()); 767 return success(); 768 } 769 770 //===----------------------------------------------------------------------===// 771 // Printing/parsing for LLVM::ExtractValueOp. 772 //===----------------------------------------------------------------------===// 773 774 static void printExtractValueOp(OpAsmPrinter &p, ExtractValueOp &op) { 775 p << op.getOperationName() << ' ' << op.container() << op.position(); 776 p.printOptionalAttrDict(op.getAttrs(), {"position"}); 777 p << " : " << op.container().getType(); 778 } 779 780 // Extract the type at `position` in the wrapped LLVM IR aggregate type 781 // `containerType`. Position is an integer array attribute where each value 782 // is a zero-based position of the element in the aggregate type. Return the 783 // resulting type wrapped in MLIR, or nullptr on error. 784 static LLVM::LLVMType getInsertExtractValueElementType(OpAsmParser &parser, 785 Type containerType, 786 ArrayAttr positionAttr, 787 llvm::SMLoc attributeLoc, 788 llvm::SMLoc typeLoc) { 789 auto wrappedContainerType = containerType.dyn_cast<LLVM::LLVMType>(); 790 if (!wrappedContainerType) 791 return parser.emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr; 792 793 // Infer the element type from the structure type: iteratively step inside the 794 // type by taking the element type, indexed by the position attribute for 795 // structures. Check the position index before accessing, it is supposed to 796 // be in bounds. 797 for (Attribute subAttr : positionAttr) { 798 auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>(); 799 if (!positionElementAttr) 800 return parser.emitError(attributeLoc, 801 "expected an array of integer literals"), 802 nullptr; 803 int position = positionElementAttr.getInt(); 804 if (wrappedContainerType.isArrayTy()) { 805 if (position < 0 || static_cast<unsigned>(position) >= 806 wrappedContainerType.getArrayNumElements()) 807 return parser.emitError(attributeLoc, "position out of bounds"), 808 nullptr; 809 wrappedContainerType = wrappedContainerType.getArrayElementType(); 810 } else if (wrappedContainerType.isStructTy()) { 811 if (position < 0 || static_cast<unsigned>(position) >= 812 wrappedContainerType.getStructNumElements()) 813 return parser.emitError(attributeLoc, "position out of bounds"), 814 nullptr; 815 wrappedContainerType = 816 wrappedContainerType.getStructElementType(position); 817 } else { 818 return parser.emitError(typeLoc, 819 "expected wrapped LLVM IR structure/array type"), 820 nullptr; 821 } 822 } 823 return wrappedContainerType; 824 } 825 826 // <operation> ::= `llvm.extractvalue` ssa-use 827 // `[` integer-literal (`,` integer-literal)* `]` 828 // attribute-dict? `:` type 829 static ParseResult parseExtractValueOp(OpAsmParser &parser, 830 OperationState &result) { 831 OpAsmParser::OperandType container; 832 Type containerType; 833 ArrayAttr positionAttr; 834 llvm::SMLoc attributeLoc, trailingTypeLoc; 835 836 if (parser.parseOperand(container) || 837 parser.getCurrentLocation(&attributeLoc) || 838 parser.parseAttribute(positionAttr, "position", result.attributes) || 839 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 840 parser.getCurrentLocation(&trailingTypeLoc) || 841 parser.parseType(containerType) || 842 parser.resolveOperand(container, containerType, result.operands)) 843 return failure(); 844 845 auto elementType = getInsertExtractValueElementType( 846 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 847 if (!elementType) 848 return failure(); 849 850 result.addTypes(elementType); 851 return success(); 852 } 853 854 //===----------------------------------------------------------------------===// 855 // Printing/parsing for LLVM::InsertElementOp. 856 //===----------------------------------------------------------------------===// 857 858 static void printInsertElementOp(OpAsmPrinter &p, InsertElementOp &op) { 859 p << op.getOperationName() << ' ' << op.value() << ", " << op.vector() << "[" 860 << op.position() << " : " << op.position().getType() << "]"; 861 p.printOptionalAttrDict(op.getAttrs()); 862 p << " : " << op.vector().getType(); 863 } 864 865 // <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use 866 // attribute-dict? `:` type 867 static ParseResult parseInsertElementOp(OpAsmParser &parser, 868 OperationState &result) { 869 llvm::SMLoc loc; 870 OpAsmParser::OperandType vector, value, position; 871 Type vectorType, positionType; 872 if (parser.getCurrentLocation(&loc) || parser.parseOperand(value) || 873 parser.parseComma() || parser.parseOperand(vector) || 874 parser.parseLSquare() || parser.parseOperand(position) || 875 parser.parseColonType(positionType) || parser.parseRSquare() || 876 parser.parseOptionalAttrDict(result.attributes) || 877 parser.parseColonType(vectorType)) 878 return failure(); 879 880 auto wrappedVectorType = vectorType.dyn_cast<LLVM::LLVMType>(); 881 if (!wrappedVectorType || !wrappedVectorType.isVectorTy()) 882 return parser.emitError( 883 loc, "expected LLVM IR dialect vector type for operand #1"); 884 auto valueType = wrappedVectorType.getVectorElementType(); 885 if (!valueType) 886 return failure(); 887 888 if (parser.resolveOperand(vector, vectorType, result.operands) || 889 parser.resolveOperand(value, valueType, result.operands) || 890 parser.resolveOperand(position, positionType, result.operands)) 891 return failure(); 892 893 result.addTypes(vectorType); 894 return success(); 895 } 896 897 //===----------------------------------------------------------------------===// 898 // Printing/parsing for LLVM::InsertValueOp. 899 //===----------------------------------------------------------------------===// 900 901 static void printInsertValueOp(OpAsmPrinter &p, InsertValueOp &op) { 902 p << op.getOperationName() << ' ' << op.value() << ", " << op.container() 903 << op.position(); 904 p.printOptionalAttrDict(op.getAttrs(), {"position"}); 905 p << " : " << op.container().getType(); 906 } 907 908 // <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use 909 // `[` integer-literal (`,` integer-literal)* `]` 910 // attribute-dict? `:` type 911 static ParseResult parseInsertValueOp(OpAsmParser &parser, 912 OperationState &result) { 913 OpAsmParser::OperandType container, value; 914 Type containerType; 915 ArrayAttr positionAttr; 916 llvm::SMLoc attributeLoc, trailingTypeLoc; 917 918 if (parser.parseOperand(value) || parser.parseComma() || 919 parser.parseOperand(container) || 920 parser.getCurrentLocation(&attributeLoc) || 921 parser.parseAttribute(positionAttr, "position", result.attributes) || 922 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 923 parser.getCurrentLocation(&trailingTypeLoc) || 924 parser.parseType(containerType)) 925 return failure(); 926 927 auto valueType = getInsertExtractValueElementType( 928 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 929 if (!valueType) 930 return failure(); 931 932 if (parser.resolveOperand(container, containerType, result.operands) || 933 parser.resolveOperand(value, valueType, result.operands)) 934 return failure(); 935 936 result.addTypes(containerType); 937 return success(); 938 } 939 940 //===----------------------------------------------------------------------===// 941 // Printing/parsing for LLVM::ReturnOp. 942 //===----------------------------------------------------------------------===// 943 944 static void printReturnOp(OpAsmPrinter &p, ReturnOp &op) { 945 p << op.getOperationName(); 946 p.printOptionalAttrDict(op.getAttrs()); 947 assert(op.getNumOperands() <= 1); 948 949 if (op.getNumOperands() == 0) 950 return; 951 952 p << ' ' << op.getOperand(0) << " : " << op.getOperand(0).getType(); 953 } 954 955 // <operation> ::= `llvm.return` ssa-use-list attribute-dict? `:` 956 // type-list-no-parens 957 static ParseResult parseReturnOp(OpAsmParser &parser, OperationState &result) { 958 SmallVector<OpAsmParser::OperandType, 1> operands; 959 Type type; 960 961 if (parser.parseOperandList(operands) || 962 parser.parseOptionalAttrDict(result.attributes)) 963 return failure(); 964 if (operands.empty()) 965 return success(); 966 967 if (parser.parseColonType(type) || 968 parser.resolveOperand(operands[0], type, result.operands)) 969 return failure(); 970 return success(); 971 } 972 973 //===----------------------------------------------------------------------===// 974 // Verifier for LLVM::AddressOfOp. 975 //===----------------------------------------------------------------------===// 976 977 template <typename OpTy> 978 static OpTy lookupSymbolInModule(Operation *parent, StringRef name) { 979 Operation *module = parent; 980 while (module && !satisfiesLLVMModule(module)) 981 module = module->getParentOp(); 982 assert(module && "unexpected operation outside of a module"); 983 return dyn_cast_or_null<OpTy>( 984 mlir::SymbolTable::lookupSymbolIn(module, name)); 985 } 986 987 GlobalOp AddressOfOp::getGlobal() { 988 return lookupSymbolInModule<LLVM::GlobalOp>(getParentOp(), global_name()); 989 } 990 991 LLVMFuncOp AddressOfOp::getFunction() { 992 return lookupSymbolInModule<LLVM::LLVMFuncOp>(getParentOp(), global_name()); 993 } 994 995 static LogicalResult verify(AddressOfOp op) { 996 auto global = op.getGlobal(); 997 auto function = op.getFunction(); 998 if (!global && !function) 999 return op.emitOpError( 1000 "must reference a global defined by 'llvm.mlir.global' or 'llvm.func'"); 1001 1002 if (global && global.getType().getPointerTo(global.addr_space()) != 1003 op.getResult().getType()) 1004 return op.emitOpError( 1005 "the type must be a pointer to the type of the referenced global"); 1006 1007 if (function && function.getType().getPointerTo() != op.getResult().getType()) 1008 return op.emitOpError( 1009 "the type must be a pointer to the type of the referenced function"); 1010 1011 return success(); 1012 } 1013 1014 //===----------------------------------------------------------------------===// 1015 // Builder, printer and verifier for LLVM::GlobalOp. 1016 //===----------------------------------------------------------------------===// 1017 1018 /// Returns the name used for the linkage attribute. This *must* correspond to 1019 /// the name of the attribute in ODS. 1020 static StringRef getLinkageAttrName() { return "linkage"; } 1021 1022 void GlobalOp::build(OpBuilder &builder, OperationState &result, LLVMType type, 1023 bool isConstant, Linkage linkage, StringRef name, 1024 Attribute value, unsigned addrSpace, 1025 ArrayRef<NamedAttribute> attrs) { 1026 result.addAttribute(SymbolTable::getSymbolAttrName(), 1027 builder.getStringAttr(name)); 1028 result.addAttribute("type", TypeAttr::get(type)); 1029 if (isConstant) 1030 result.addAttribute("constant", builder.getUnitAttr()); 1031 if (value) 1032 result.addAttribute("value", value); 1033 result.addAttribute(getLinkageAttrName(), 1034 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1035 if (addrSpace != 0) 1036 result.addAttribute("addr_space", builder.getI32IntegerAttr(addrSpace)); 1037 result.attributes.append(attrs.begin(), attrs.end()); 1038 result.addRegion(); 1039 } 1040 1041 static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) { 1042 p << op.getOperationName() << ' ' << stringifyLinkage(op.linkage()) << ' '; 1043 if (op.constant()) 1044 p << "constant "; 1045 p.printSymbolName(op.sym_name()); 1046 p << '('; 1047 if (auto value = op.getValueOrNull()) 1048 p.printAttribute(value); 1049 p << ')'; 1050 p.printOptionalAttrDict(op.getAttrs(), 1051 {SymbolTable::getSymbolAttrName(), "type", "constant", 1052 "value", getLinkageAttrName()}); 1053 1054 // Print the trailing type unless it's a string global. 1055 if (op.getValueOrNull().dyn_cast_or_null<StringAttr>()) 1056 return; 1057 p << " : " << op.type(); 1058 1059 Region &initializer = op.getInitializerRegion(); 1060 if (!initializer.empty()) 1061 p.printRegion(initializer, /*printEntryBlockArgs=*/false); 1062 } 1063 1064 //===----------------------------------------------------------------------===// 1065 // Verifier for LLVM::DialectCastOp. 1066 //===----------------------------------------------------------------------===// 1067 1068 static LogicalResult verify(DialectCastOp op) { 1069 auto verifyMLIRCastType = [&op](Type type) -> LogicalResult { 1070 if (auto llvmType = type.dyn_cast<LLVM::LLVMType>()) { 1071 if (llvmType.isVectorTy()) 1072 llvmType = llvmType.getVectorElementType(); 1073 if (llvmType.isIntegerTy() || llvmType.isBFloatTy() || 1074 llvmType.isHalfTy() || llvmType.isFloatTy() || 1075 llvmType.isDoubleTy()) { 1076 return success(); 1077 } 1078 return op.emitOpError("type must be non-index integer types, float " 1079 "types, or vector of mentioned types."); 1080 } 1081 if (auto vectorType = type.dyn_cast<VectorType>()) { 1082 if (vectorType.getShape().size() > 1) 1083 return op.emitOpError("only 1-d vector is allowed"); 1084 type = vectorType.getElementType(); 1085 } 1086 if (type.isSignlessIntOrFloat()) 1087 return success(); 1088 // Note that memrefs are not supported. We currently don't have a use case 1089 // for it, but even if we do, there are challenges: 1090 // * if we allow memrefs to cast from/to memref descriptors, then the 1091 // semantics of the cast op depends on the implementation detail of the 1092 // descriptor. 1093 // * if we allow memrefs to cast from/to bare pointers, some users might 1094 // alternatively want metadata that only present in the descriptor. 1095 // 1096 // TODO: re-evaluate the memref cast design when it's needed. 1097 return op.emitOpError("type must be non-index integer types, float types, " 1098 "or vector of mentioned types."); 1099 }; 1100 return failure(failed(verifyMLIRCastType(op.in().getType())) || 1101 failed(verifyMLIRCastType(op.getType()))); 1102 } 1103 1104 // Parses one of the keywords provided in the list `keywords` and returns the 1105 // position of the parsed keyword in the list. If none of the keywords from the 1106 // list is parsed, returns -1. 1107 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 1108 ArrayRef<StringRef> keywords) { 1109 for (auto en : llvm::enumerate(keywords)) { 1110 if (succeeded(parser.parseOptionalKeyword(en.value()))) 1111 return en.index(); 1112 } 1113 return -1; 1114 } 1115 1116 namespace { 1117 template <typename Ty> struct EnumTraits {}; 1118 1119 #define REGISTER_ENUM_TYPE(Ty) \ 1120 template <> struct EnumTraits<Ty> { \ 1121 static StringRef stringify(Ty value) { return stringify##Ty(value); } \ 1122 static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ 1123 } 1124 1125 REGISTER_ENUM_TYPE(Linkage); 1126 } // end namespace 1127 1128 template <typename EnumTy> 1129 static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser, 1130 OperationState &result, 1131 StringRef name) { 1132 SmallVector<StringRef, 10> names; 1133 for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i) 1134 names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); 1135 1136 int index = parseOptionalKeywordAlternative(parser, names); 1137 if (index == -1) 1138 return failure(); 1139 result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index)); 1140 return success(); 1141 } 1142 1143 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier 1144 // `(` attribute? `)` attribute-list? (`:` type)? region? 1145 // 1146 // The type can be omitted for string attributes, in which case it will be 1147 // inferred from the value of the string as [strlen(value) x i8]. 1148 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) { 1149 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1150 getLinkageAttrName()))) 1151 result.addAttribute(getLinkageAttrName(), 1152 parser.getBuilder().getI64IntegerAttr( 1153 static_cast<int64_t>(LLVM::Linkage::External))); 1154 1155 if (succeeded(parser.parseOptionalKeyword("constant"))) 1156 result.addAttribute("constant", parser.getBuilder().getUnitAttr()); 1157 1158 StringAttr name; 1159 if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), 1160 result.attributes) || 1161 parser.parseLParen()) 1162 return failure(); 1163 1164 Attribute value; 1165 if (parser.parseOptionalRParen()) { 1166 if (parser.parseAttribute(value, "value", result.attributes) || 1167 parser.parseRParen()) 1168 return failure(); 1169 } 1170 1171 SmallVector<Type, 1> types; 1172 if (parser.parseOptionalAttrDict(result.attributes) || 1173 parser.parseOptionalColonTypeList(types)) 1174 return failure(); 1175 1176 if (types.size() > 1) 1177 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1178 1179 Region &initRegion = *result.addRegion(); 1180 if (types.empty()) { 1181 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1182 MLIRContext *context = parser.getBuilder().getContext(); 1183 auto arrayType = LLVM::LLVMType::getArrayTy( 1184 LLVM::LLVMType::getInt8Ty(context), strAttr.getValue().size()); 1185 types.push_back(arrayType); 1186 } else { 1187 return parser.emitError(parser.getNameLoc(), 1188 "type can only be omitted for string globals"); 1189 } 1190 } else { 1191 OptionalParseResult parseResult = 1192 parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1193 /*argTypes=*/{}); 1194 if (parseResult.hasValue() && failed(*parseResult)) 1195 return failure(); 1196 } 1197 1198 result.addAttribute("type", TypeAttr::get(types[0])); 1199 return success(); 1200 } 1201 1202 static LogicalResult verify(GlobalOp op) { 1203 if (!LLVMPointerType::isValidElementType(op.getType())) 1204 return op.emitOpError( 1205 "expects type to be a valid element type for an LLVM pointer"); 1206 if (op.getParentOp() && !satisfiesLLVMModule(op.getParentOp())) 1207 return op.emitOpError("must appear at the module level"); 1208 1209 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1210 auto type = op.getType(); 1211 if (!type.isArrayTy() || !type.getArrayElementType().isIntegerTy(8) || 1212 type.getArrayNumElements() != strAttr.getValue().size()) 1213 return op.emitOpError( 1214 "requires an i8 array type of the length equal to that of the string " 1215 "attribute"); 1216 } 1217 1218 if (Block *b = op.getInitializerBlock()) { 1219 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1220 if (ret.operand_type_begin() == ret.operand_type_end()) 1221 return op.emitOpError("initializer region cannot return void"); 1222 if (*ret.operand_type_begin() != op.getType()) 1223 return op.emitOpError("initializer region type ") 1224 << *ret.operand_type_begin() << " does not match global type " 1225 << op.getType(); 1226 1227 if (op.getValueOrNull()) 1228 return op.emitOpError("cannot have both initializer value and region"); 1229 } 1230 return success(); 1231 } 1232 1233 //===----------------------------------------------------------------------===// 1234 // Printing/parsing for LLVM::ShuffleVectorOp. 1235 //===----------------------------------------------------------------------===// 1236 // Expects vector to be of wrapped LLVM vector type and position to be of 1237 // wrapped LLVM i32 type. 1238 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 1239 Value v1, Value v2, ArrayAttr mask, 1240 ArrayRef<NamedAttribute> attrs) { 1241 auto wrappedContainerType1 = v1.getType().cast<LLVM::LLVMType>(); 1242 auto vType = LLVMType::getVectorTy( 1243 wrappedContainerType1.getVectorElementType(), mask.size()); 1244 build(b, result, vType, v1, v2, mask); 1245 result.addAttributes(attrs); 1246 } 1247 1248 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1249 p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " " 1250 << op.mask(); 1251 p.printOptionalAttrDict(op.getAttrs(), {"mask"}); 1252 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1253 } 1254 1255 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1256 // `[` integer-literal (`,` integer-literal)* `]` 1257 // attribute-dict? `:` type 1258 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1259 OperationState &result) { 1260 llvm::SMLoc loc; 1261 OpAsmParser::OperandType v1, v2; 1262 ArrayAttr maskAttr; 1263 Type typeV1, typeV2; 1264 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1265 parser.parseComma() || parser.parseOperand(v2) || 1266 parser.parseAttribute(maskAttr, "mask", result.attributes) || 1267 parser.parseOptionalAttrDict(result.attributes) || 1268 parser.parseColonType(typeV1) || parser.parseComma() || 1269 parser.parseType(typeV2) || 1270 parser.resolveOperand(v1, typeV1, result.operands) || 1271 parser.resolveOperand(v2, typeV2, result.operands)) 1272 return failure(); 1273 auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>(); 1274 if (!wrappedContainerType1 || !wrappedContainerType1.isVectorTy()) 1275 return parser.emitError( 1276 loc, "expected LLVM IR dialect vector type for operand #1"); 1277 auto vType = LLVMType::getVectorTy( 1278 wrappedContainerType1.getVectorElementType(), maskAttr.size()); 1279 result.addTypes(vType); 1280 return success(); 1281 } 1282 1283 //===----------------------------------------------------------------------===// 1284 // Implementations for LLVM::LLVMFuncOp. 1285 //===----------------------------------------------------------------------===// 1286 1287 // Add the entry block to the function. 1288 Block *LLVMFuncOp::addEntryBlock() { 1289 assert(empty() && "function already has an entry block"); 1290 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1291 1292 auto *entry = new Block; 1293 push_back(entry); 1294 1295 LLVMType type = getType(); 1296 for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i) 1297 entry->addArgument(type.getFunctionParamType(i)); 1298 return entry; 1299 } 1300 1301 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 1302 StringRef name, LLVMType type, LLVM::Linkage linkage, 1303 ArrayRef<NamedAttribute> attrs, 1304 ArrayRef<MutableDictionaryAttr> argAttrs) { 1305 result.addRegion(); 1306 result.addAttribute(SymbolTable::getSymbolAttrName(), 1307 builder.getStringAttr(name)); 1308 result.addAttribute("type", TypeAttr::get(type)); 1309 result.addAttribute(getLinkageAttrName(), 1310 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1311 result.attributes.append(attrs.begin(), attrs.end()); 1312 if (argAttrs.empty()) 1313 return; 1314 1315 unsigned numInputs = type.getFunctionNumParams(); 1316 assert(numInputs == argAttrs.size() && 1317 "expected as many argument attribute lists as arguments"); 1318 SmallString<8> argAttrName; 1319 for (unsigned i = 0; i < numInputs; ++i) 1320 if (auto argDict = argAttrs[i].getDictionary(builder.getContext())) 1321 result.addAttribute(getArgAttrName(i, argAttrName), argDict); 1322 } 1323 1324 // Builds an LLVM function type from the given lists of input and output types. 1325 // Returns a null type if any of the types provided are non-LLVM types, or if 1326 // there is more than one output type. 1327 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1328 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1329 impl::VariadicFlag variadicFlag) { 1330 Builder &b = parser.getBuilder(); 1331 if (outputs.size() > 1) { 1332 parser.emitError(loc, "failed to construct function type: expected zero or " 1333 "one function result"); 1334 return {}; 1335 } 1336 1337 // Convert inputs to LLVM types, exit early on error. 1338 SmallVector<LLVMType, 4> llvmInputs; 1339 for (auto t : inputs) { 1340 auto llvmTy = t.dyn_cast<LLVMType>(); 1341 if (!llvmTy) { 1342 parser.emitError(loc, "failed to construct function type: expected LLVM " 1343 "type for function arguments"); 1344 return {}; 1345 } 1346 llvmInputs.push_back(llvmTy); 1347 } 1348 1349 // No output is denoted as "void" in LLVM type system. 1350 LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(b.getContext()) 1351 : outputs.front().dyn_cast<LLVMType>(); 1352 if (!llvmOutput) { 1353 parser.emitError(loc, "failed to construct function type: expected LLVM " 1354 "type for function results"); 1355 return {}; 1356 } 1357 return LLVMType::getFunctionTy(llvmOutput, llvmInputs, 1358 variadicFlag.isVariadic()); 1359 } 1360 1361 // Parses an LLVM function. 1362 // 1363 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1364 // function-body 1365 // 1366 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1367 OperationState &result) { 1368 // Default to external linkage if no keyword is provided. 1369 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1370 getLinkageAttrName()))) 1371 result.addAttribute(getLinkageAttrName(), 1372 parser.getBuilder().getI64IntegerAttr( 1373 static_cast<int64_t>(LLVM::Linkage::External))); 1374 1375 StringAttr nameAttr; 1376 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1377 SmallVector<NamedAttrList, 1> argAttrs; 1378 SmallVector<NamedAttrList, 1> resultAttrs; 1379 SmallVector<Type, 8> argTypes; 1380 SmallVector<Type, 4> resultTypes; 1381 bool isVariadic; 1382 1383 auto signatureLocation = parser.getCurrentLocation(); 1384 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1385 result.attributes) || 1386 impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs, 1387 argTypes, argAttrs, isVariadic, resultTypes, 1388 resultAttrs)) 1389 return failure(); 1390 1391 auto type = 1392 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1393 impl::VariadicFlag(isVariadic)); 1394 if (!type) 1395 return failure(); 1396 result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type)); 1397 1398 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1399 return failure(); 1400 impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs, 1401 resultAttrs); 1402 1403 auto *body = result.addRegion(); 1404 OptionalParseResult parseResult = parser.parseOptionalRegion( 1405 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1406 return failure(parseResult.hasValue() && failed(*parseResult)); 1407 } 1408 1409 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1410 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1411 // the external linkage since it is the default value. 1412 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1413 p << op.getOperationName() << ' '; 1414 if (op.linkage() != LLVM::Linkage::External) 1415 p << stringifyLinkage(op.linkage()) << ' '; 1416 p.printSymbolName(op.getName()); 1417 1418 LLVMType fnType = op.getType(); 1419 SmallVector<Type, 8> argTypes; 1420 SmallVector<Type, 1> resTypes; 1421 argTypes.reserve(fnType.getFunctionNumParams()); 1422 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i) 1423 argTypes.push_back(fnType.getFunctionParamType(i)); 1424 1425 LLVMType returnType = fnType.getFunctionResultType(); 1426 if (!returnType.isVoidTy()) 1427 resTypes.push_back(returnType); 1428 1429 impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes); 1430 impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(), 1431 {getLinkageAttrName()}); 1432 1433 // Print the body if this is not an external function. 1434 Region &body = op.body(); 1435 if (!body.empty()) 1436 p.printRegion(body, /*printEntryBlockArgs=*/false, 1437 /*printBlockTerminators=*/true); 1438 } 1439 1440 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1441 // attribute is present. This can check for preconditions of the 1442 // getNumArguments hook not failing. 1443 LogicalResult LLVMFuncOp::verifyType() { 1444 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>(); 1445 if (!llvmType || !llvmType.isFunctionTy()) 1446 return emitOpError("requires '" + getTypeAttrName() + 1447 "' attribute of wrapped LLVM function type"); 1448 1449 return success(); 1450 } 1451 1452 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1453 // Depends on the type attribute being correct as checked by verifyType 1454 unsigned LLVMFuncOp::getNumFuncArguments() { 1455 return getType().getFunctionNumParams(); 1456 } 1457 1458 // Hook for OpTrait::FunctionLike, returns the number of function results. 1459 // Depends on the type attribute being correct as checked by verifyType 1460 unsigned LLVMFuncOp::getNumFuncResults() { 1461 // We model LLVM functions that return void as having zero results, 1462 // and all others as having one result. 1463 // If we modeled a void return as one result, then it would be possible to 1464 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1465 // would assign to that. 1466 if (getType().getFunctionResultType().isVoidTy()) 1467 return 0; 1468 return 1; 1469 } 1470 1471 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1472 // - functions don't have 'common' linkage 1473 // - external functions have 'external' or 'extern_weak' linkage; 1474 // - vararg is (currently) only supported for external functions; 1475 // - entry block arguments are of LLVM types and match the function signature. 1476 static LogicalResult verify(LLVMFuncOp op) { 1477 if (op.linkage() == LLVM::Linkage::Common) 1478 return op.emitOpError() 1479 << "functions cannot have '" 1480 << stringifyLinkage(LLVM::Linkage::Common) << "' linkage"; 1481 1482 if (op.isExternal()) { 1483 if (op.linkage() != LLVM::Linkage::External && 1484 op.linkage() != LLVM::Linkage::ExternWeak) 1485 return op.emitOpError() 1486 << "external functions must have '" 1487 << stringifyLinkage(LLVM::Linkage::External) << "' or '" 1488 << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage"; 1489 return success(); 1490 } 1491 1492 if (op.isVarArg()) 1493 return op.emitOpError("only external functions can be variadic"); 1494 1495 unsigned numArguments = op.getType().getFunctionNumParams(); 1496 Block &entryBlock = op.front(); 1497 for (unsigned i = 0; i < numArguments; ++i) { 1498 Type argType = entryBlock.getArgument(i).getType(); 1499 auto argLLVMType = argType.dyn_cast<LLVMType>(); 1500 if (!argLLVMType) 1501 return op.emitOpError("entry block argument #") 1502 << i << " is not of LLVM type"; 1503 if (op.getType().getFunctionParamType(i) != argLLVMType) 1504 return op.emitOpError("the type of entry block argument #") 1505 << i << " does not match the function signature"; 1506 } 1507 1508 return success(); 1509 } 1510 1511 //===----------------------------------------------------------------------===// 1512 // Verification for LLVM::NullOp. 1513 //===----------------------------------------------------------------------===// 1514 1515 // Only LLVM pointer types are supported. 1516 static LogicalResult verify(LLVM::NullOp op) { 1517 auto llvmType = op.getType().dyn_cast<LLVM::LLVMType>(); 1518 if (!llvmType || !llvmType.isPointerTy()) 1519 return op.emitOpError("expected LLVM IR pointer type"); 1520 return success(); 1521 } 1522 1523 //===----------------------------------------------------------------------===// 1524 // Verification for LLVM::ConstantOp. 1525 //===----------------------------------------------------------------------===// 1526 1527 static LogicalResult verify(LLVM::ConstantOp op) { 1528 if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() || 1529 op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>())) 1530 return op.emitOpError() 1531 << "only supports integer, float, string or elements attributes"; 1532 return success(); 1533 } 1534 1535 //===----------------------------------------------------------------------===// 1536 // Utility functions for parsing atomic ops 1537 //===----------------------------------------------------------------------===// 1538 1539 // Helper function to parse a keyword into the specified attribute named by 1540 // `attrName`. The keyword must match one of the string values defined by the 1541 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 1542 // state. 1543 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 1544 StringRef attrName) { 1545 llvm::SMLoc loc; 1546 StringRef keyword; 1547 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 1548 return failure(); 1549 1550 // Replace the keyword `keyword` with an integer attribute. 1551 auto kind = symbolizeAtomicBinOp(keyword); 1552 if (!kind) { 1553 return parser.emitError(loc) 1554 << "'" << keyword << "' is an incorrect value of the '" << attrName 1555 << "' attribute"; 1556 } 1557 1558 auto value = static_cast<int64_t>(kind.getValue()); 1559 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1560 result.addAttribute(attrName, attr); 1561 1562 return success(); 1563 } 1564 1565 // Helper function to parse a keyword into the specified attribute named by 1566 // `attrName`. The keyword must match one of the string values defined by the 1567 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 1568 // state. 1569 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 1570 OperationState &result, 1571 StringRef attrName) { 1572 llvm::SMLoc loc; 1573 StringRef ordering; 1574 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 1575 return failure(); 1576 1577 // Replace the keyword `ordering` with an integer attribute. 1578 auto kind = symbolizeAtomicOrdering(ordering); 1579 if (!kind) { 1580 return parser.emitError(loc) 1581 << "'" << ordering << "' is an incorrect value of the '" << attrName 1582 << "' attribute"; 1583 } 1584 1585 auto value = static_cast<int64_t>(kind.getValue()); 1586 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1587 result.addAttribute(attrName, attr); 1588 1589 return success(); 1590 } 1591 1592 //===----------------------------------------------------------------------===// 1593 // Printer, parser and verifier for LLVM::AtomicRMWOp. 1594 //===----------------------------------------------------------------------===// 1595 1596 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) { 1597 p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' 1598 << op.ptr() << ", " << op.val() << ' ' 1599 << stringifyAtomicOrdering(op.ordering()) << ' '; 1600 p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"}); 1601 p << " : " << op.res().getType(); 1602 } 1603 1604 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 1605 // attribute-dict? `:` type 1606 static ParseResult parseAtomicRMWOp(OpAsmParser &parser, 1607 OperationState &result) { 1608 LLVMType type; 1609 OpAsmParser::OperandType ptr, val; 1610 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 1611 parser.parseComma() || parser.parseOperand(val) || 1612 parseAtomicOrdering(parser, result, "ordering") || 1613 parser.parseOptionalAttrDict(result.attributes) || 1614 parser.parseColonType(type) || 1615 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1616 parser.resolveOperand(val, type, result.operands)) 1617 return failure(); 1618 1619 result.addTypes(type); 1620 return success(); 1621 } 1622 1623 static LogicalResult verify(AtomicRMWOp op) { 1624 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1625 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1626 if (valType != ptrType.getPointerElementTy()) 1627 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1628 "match type for operand #1"); 1629 auto resType = op.res().getType().cast<LLVM::LLVMType>(); 1630 if (resType != valType) 1631 return op.emitOpError( 1632 "expected LLVM IR result type to match type for operand #1"); 1633 if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) { 1634 if (!valType.isFloatingPointTy()) 1635 return op.emitOpError("expected LLVM IR floating point type"); 1636 } else if (op.bin_op() == AtomicBinOp::xchg) { 1637 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1638 !valType.isIntegerTy(32) && !valType.isIntegerTy(64) && 1639 !valType.isBFloatTy() && !valType.isHalfTy() && !valType.isFloatTy() && 1640 !valType.isDoubleTy()) 1641 return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 1642 } else { 1643 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1644 !valType.isIntegerTy(32) && !valType.isIntegerTy(64)) 1645 return op.emitOpError("expected LLVM IR integer type"); 1646 } 1647 return success(); 1648 } 1649 1650 //===----------------------------------------------------------------------===// 1651 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 1652 //===----------------------------------------------------------------------===// 1653 1654 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) { 1655 p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", " 1656 << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' ' 1657 << stringifyAtomicOrdering(op.failure_ordering()); 1658 p.printOptionalAttrDict(op.getAttrs(), 1659 {"success_ordering", "failure_ordering"}); 1660 p << " : " << op.val().getType(); 1661 } 1662 1663 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 1664 // keyword keyword attribute-dict? `:` type 1665 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser, 1666 OperationState &result) { 1667 auto &builder = parser.getBuilder(); 1668 LLVMType type; 1669 OpAsmParser::OperandType ptr, cmp, val; 1670 if (parser.parseOperand(ptr) || parser.parseComma() || 1671 parser.parseOperand(cmp) || parser.parseComma() || 1672 parser.parseOperand(val) || 1673 parseAtomicOrdering(parser, result, "success_ordering") || 1674 parseAtomicOrdering(parser, result, "failure_ordering") || 1675 parser.parseOptionalAttrDict(result.attributes) || 1676 parser.parseColonType(type) || 1677 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1678 parser.resolveOperand(cmp, type, result.operands) || 1679 parser.resolveOperand(val, type, result.operands)) 1680 return failure(); 1681 1682 auto boolType = LLVMType::getInt1Ty(builder.getContext()); 1683 auto resultType = LLVMType::getStructTy(type, boolType); 1684 result.addTypes(resultType); 1685 1686 return success(); 1687 } 1688 1689 static LogicalResult verify(AtomicCmpXchgOp op) { 1690 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1691 if (!ptrType.isPointerTy()) 1692 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1693 auto cmpType = op.cmp().getType().cast<LLVM::LLVMType>(); 1694 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1695 if (cmpType != ptrType.getPointerElementTy() || cmpType != valType) 1696 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1697 "match type for all other operands"); 1698 if (!valType.isPointerTy() && !valType.isIntegerTy(8) && 1699 !valType.isIntegerTy(16) && !valType.isIntegerTy(32) && 1700 !valType.isIntegerTy(64) && !valType.isBFloatTy() && 1701 !valType.isHalfTy() && !valType.isFloatTy() && !valType.isDoubleTy()) 1702 return op.emitOpError("unexpected LLVM IR type"); 1703 if (op.success_ordering() < AtomicOrdering::monotonic || 1704 op.failure_ordering() < AtomicOrdering::monotonic) 1705 return op.emitOpError("ordering must be at least 'monotonic'"); 1706 if (op.failure_ordering() == AtomicOrdering::release || 1707 op.failure_ordering() == AtomicOrdering::acq_rel) 1708 return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 1709 return success(); 1710 } 1711 1712 //===----------------------------------------------------------------------===// 1713 // Printer, parser and verifier for LLVM::FenceOp. 1714 //===----------------------------------------------------------------------===// 1715 1716 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 1717 // attribute-dict? 1718 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) { 1719 StringAttr sScope; 1720 StringRef syncscopeKeyword = "syncscope"; 1721 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 1722 if (parser.parseLParen() || 1723 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 1724 parser.parseRParen()) 1725 return failure(); 1726 } else { 1727 result.addAttribute(syncscopeKeyword, 1728 parser.getBuilder().getStringAttr("")); 1729 } 1730 if (parseAtomicOrdering(parser, result, "ordering") || 1731 parser.parseOptionalAttrDict(result.attributes)) 1732 return failure(); 1733 return success(); 1734 } 1735 1736 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) { 1737 StringRef syncscopeKeyword = "syncscope"; 1738 p << op.getOperationName() << ' '; 1739 if (!op.getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 1740 p << "syncscope(" << op.getAttr(syncscopeKeyword) << ") "; 1741 p << stringifyAtomicOrdering(op.ordering()); 1742 } 1743 1744 static LogicalResult verify(FenceOp &op) { 1745 if (op.ordering() == AtomicOrdering::not_atomic || 1746 op.ordering() == AtomicOrdering::unordered || 1747 op.ordering() == AtomicOrdering::monotonic) 1748 return op.emitOpError("can be given only acquire, release, acq_rel, " 1749 "and seq_cst orderings"); 1750 return success(); 1751 } 1752 1753 //===----------------------------------------------------------------------===// 1754 // LLVMDialect initialization, type parsing, and registration. 1755 //===----------------------------------------------------------------------===// 1756 1757 void LLVMDialect::initialize() { 1758 // clang-format off 1759 addTypes<LLVMVoidType, 1760 LLVMHalfType, 1761 LLVMBFloatType, 1762 LLVMFloatType, 1763 LLVMDoubleType, 1764 LLVMFP128Type, 1765 LLVMX86FP80Type, 1766 LLVMPPCFP128Type, 1767 LLVMX86MMXType, 1768 LLVMTokenType, 1769 LLVMLabelType, 1770 LLVMMetadataType, 1771 LLVMFunctionType, 1772 LLVMIntegerType, 1773 LLVMPointerType, 1774 LLVMFixedVectorType, 1775 LLVMScalableVectorType, 1776 LLVMArrayType, 1777 LLVMStructType>(); 1778 // clang-format on 1779 addOperations< 1780 #define GET_OP_LIST 1781 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1782 >(); 1783 1784 // Support unknown operations because not all LLVM operations are registered. 1785 allowUnknownOperations(); 1786 } 1787 1788 #define GET_OP_CLASSES 1789 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1790 1791 /// Parse a type registered to this dialect. 1792 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 1793 return detail::parseType(parser); 1794 } 1795 1796 /// Print a type registered to this dialect. 1797 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 1798 return detail::printType(type.cast<LLVMType>(), os); 1799 } 1800 1801 LogicalResult LLVMDialect::verifyDataLayoutString( 1802 StringRef descr, llvm::function_ref<void(const Twine &)> reportError) { 1803 llvm::Expected<llvm::DataLayout> maybeDataLayout = 1804 llvm::DataLayout::parse(descr); 1805 if (maybeDataLayout) 1806 return success(); 1807 1808 std::string message; 1809 llvm::raw_string_ostream messageStream(message); 1810 llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream); 1811 reportError("invalid data layout descriptor: " + messageStream.str()); 1812 return failure(); 1813 } 1814 1815 /// Verify LLVM dialect attributes. 1816 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op, 1817 NamedAttribute attr) { 1818 // If the data layout attribute is present, it must use the LLVM data layout 1819 // syntax. Try parsing it and report errors in case of failure. Users of this 1820 // attribute may assume it is well-formed and can pass it to the (asserting) 1821 // llvm::DataLayout constructor. 1822 if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName()) 1823 return success(); 1824 if (auto stringAttr = attr.second.dyn_cast<StringAttr>()) 1825 return verifyDataLayoutString( 1826 stringAttr.getValue(), 1827 [op](const Twine &message) { op->emitOpError() << message.str(); }); 1828 1829 return op->emitOpError() << "expected '" 1830 << LLVM::LLVMDialect::getDataLayoutAttrName() 1831 << "' to be a string attribute"; 1832 } 1833 1834 /// Verify LLVMIR function argument attributes. 1835 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 1836 unsigned regionIdx, 1837 unsigned argIdx, 1838 NamedAttribute argAttr) { 1839 // Check that llvm.noalias is a boolean attribute. 1840 if (argAttr.first == LLVMDialect::getNoAliasAttrName() && 1841 !argAttr.second.isa<BoolAttr>()) 1842 return op->emitError() 1843 << "llvm.noalias argument attribute of non boolean type"; 1844 // Check that llvm.align is an integer attribute. 1845 if (argAttr.first == LLVMDialect::getAlignAttrName() && 1846 !argAttr.second.isa<IntegerAttr>()) 1847 return op->emitError() 1848 << "llvm.align argument attribute of non integer type"; 1849 return success(); 1850 } 1851 1852 //===----------------------------------------------------------------------===// 1853 // Utility functions. 1854 //===----------------------------------------------------------------------===// 1855 1856 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 1857 StringRef name, StringRef value, 1858 LLVM::Linkage linkage) { 1859 assert(builder.getInsertionBlock() && 1860 builder.getInsertionBlock()->getParentOp() && 1861 "expected builder to point to a block constrained in an op"); 1862 auto module = 1863 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 1864 assert(module && "builder points to an op outside of a module"); 1865 1866 // Create the global at the entry of the module. 1867 OpBuilder moduleBuilder(module.getBodyRegion()); 1868 MLIRContext *ctx = builder.getContext(); 1869 auto type = 1870 LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(ctx), value.size()); 1871 auto global = moduleBuilder.create<LLVM::GlobalOp>( 1872 loc, type, /*isConstant=*/true, linkage, name, 1873 builder.getStringAttr(value)); 1874 1875 // Get the pointer to the first character in the global string. 1876 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 1877 Value cst0 = builder.create<LLVM::ConstantOp>( 1878 loc, LLVM::LLVMType::getInt64Ty(ctx), 1879 builder.getIntegerAttr(builder.getIndexType(), 0)); 1880 return builder.create<LLVM::GEPOp>(loc, LLVM::LLVMType::getInt8PtrTy(ctx), 1881 globalPtr, ValueRange{cst0, cst0}); 1882 } 1883 1884 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 1885 return op->hasTrait<OpTrait::SymbolTable>() && 1886 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 1887 } 1888