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/DialectImplementation.h" 17 #include "mlir/IR/FunctionImplementation.h" 18 #include "mlir/IR/MLIRContext.h" 19 #include "mlir/IR/Module.h" 20 #include "mlir/IR/StandardTypes.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 if (parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1191 /*argTypes=*/{})) { 1192 return failure(); 1193 } 1194 1195 result.addAttribute("type", TypeAttr::get(types[0])); 1196 return success(); 1197 } 1198 1199 static LogicalResult verify(GlobalOp op) { 1200 if (!LLVMPointerType::isValidElementType(op.getType())) 1201 return op.emitOpError( 1202 "expects type to be a valid element type for an LLVM pointer"); 1203 if (op.getParentOp() && !satisfiesLLVMModule(op.getParentOp())) 1204 return op.emitOpError("must appear at the module level"); 1205 1206 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1207 auto type = op.getType(); 1208 if (!type.isArrayTy() || !type.getArrayElementType().isIntegerTy(8) || 1209 type.getArrayNumElements() != strAttr.getValue().size()) 1210 return op.emitOpError( 1211 "requires an i8 array type of the length equal to that of the string " 1212 "attribute"); 1213 } 1214 1215 if (Block *b = op.getInitializerBlock()) { 1216 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1217 if (ret.operand_type_begin() == ret.operand_type_end()) 1218 return op.emitOpError("initializer region cannot return void"); 1219 if (*ret.operand_type_begin() != op.getType()) 1220 return op.emitOpError("initializer region type ") 1221 << *ret.operand_type_begin() << " does not match global type " 1222 << op.getType(); 1223 1224 if (op.getValueOrNull()) 1225 return op.emitOpError("cannot have both initializer value and region"); 1226 } 1227 return success(); 1228 } 1229 1230 //===----------------------------------------------------------------------===// 1231 // Printing/parsing for LLVM::ShuffleVectorOp. 1232 //===----------------------------------------------------------------------===// 1233 // Expects vector to be of wrapped LLVM vector type and position to be of 1234 // wrapped LLVM i32 type. 1235 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 1236 Value v1, Value v2, ArrayAttr mask, 1237 ArrayRef<NamedAttribute> attrs) { 1238 auto wrappedContainerType1 = v1.getType().cast<LLVM::LLVMType>(); 1239 auto vType = LLVMType::getVectorTy( 1240 wrappedContainerType1.getVectorElementType(), mask.size()); 1241 build(b, result, vType, v1, v2, mask); 1242 result.addAttributes(attrs); 1243 } 1244 1245 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1246 p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " " 1247 << op.mask(); 1248 p.printOptionalAttrDict(op.getAttrs(), {"mask"}); 1249 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1250 } 1251 1252 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1253 // `[` integer-literal (`,` integer-literal)* `]` 1254 // attribute-dict? `:` type 1255 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1256 OperationState &result) { 1257 llvm::SMLoc loc; 1258 OpAsmParser::OperandType v1, v2; 1259 ArrayAttr maskAttr; 1260 Type typeV1, typeV2; 1261 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1262 parser.parseComma() || parser.parseOperand(v2) || 1263 parser.parseAttribute(maskAttr, "mask", result.attributes) || 1264 parser.parseOptionalAttrDict(result.attributes) || 1265 parser.parseColonType(typeV1) || parser.parseComma() || 1266 parser.parseType(typeV2) || 1267 parser.resolveOperand(v1, typeV1, result.operands) || 1268 parser.resolveOperand(v2, typeV2, result.operands)) 1269 return failure(); 1270 auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>(); 1271 if (!wrappedContainerType1 || !wrappedContainerType1.isVectorTy()) 1272 return parser.emitError( 1273 loc, "expected LLVM IR dialect vector type for operand #1"); 1274 auto vType = LLVMType::getVectorTy( 1275 wrappedContainerType1.getVectorElementType(), maskAttr.size()); 1276 result.addTypes(vType); 1277 return success(); 1278 } 1279 1280 //===----------------------------------------------------------------------===// 1281 // Implementations for LLVM::LLVMFuncOp. 1282 //===----------------------------------------------------------------------===// 1283 1284 // Add the entry block to the function. 1285 Block *LLVMFuncOp::addEntryBlock() { 1286 assert(empty() && "function already has an entry block"); 1287 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1288 1289 auto *entry = new Block; 1290 push_back(entry); 1291 1292 LLVMType type = getType(); 1293 for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i) 1294 entry->addArgument(type.getFunctionParamType(i)); 1295 return entry; 1296 } 1297 1298 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 1299 StringRef name, LLVMType type, LLVM::Linkage linkage, 1300 ArrayRef<NamedAttribute> attrs, 1301 ArrayRef<MutableDictionaryAttr> argAttrs) { 1302 result.addRegion(); 1303 result.addAttribute(SymbolTable::getSymbolAttrName(), 1304 builder.getStringAttr(name)); 1305 result.addAttribute("type", TypeAttr::get(type)); 1306 result.addAttribute(getLinkageAttrName(), 1307 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1308 result.attributes.append(attrs.begin(), attrs.end()); 1309 if (argAttrs.empty()) 1310 return; 1311 1312 unsigned numInputs = type.getFunctionNumParams(); 1313 assert(numInputs == argAttrs.size() && 1314 "expected as many argument attribute lists as arguments"); 1315 SmallString<8> argAttrName; 1316 for (unsigned i = 0; i < numInputs; ++i) 1317 if (auto argDict = argAttrs[i].getDictionary(builder.getContext())) 1318 result.addAttribute(getArgAttrName(i, argAttrName), argDict); 1319 } 1320 1321 // Builds an LLVM function type from the given lists of input and output types. 1322 // Returns a null type if any of the types provided are non-LLVM types, or if 1323 // there is more than one output type. 1324 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1325 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1326 impl::VariadicFlag variadicFlag) { 1327 Builder &b = parser.getBuilder(); 1328 if (outputs.size() > 1) { 1329 parser.emitError(loc, "failed to construct function type: expected zero or " 1330 "one function result"); 1331 return {}; 1332 } 1333 1334 // Convert inputs to LLVM types, exit early on error. 1335 SmallVector<LLVMType, 4> llvmInputs; 1336 for (auto t : inputs) { 1337 auto llvmTy = t.dyn_cast<LLVMType>(); 1338 if (!llvmTy) { 1339 parser.emitError(loc, "failed to construct function type: expected LLVM " 1340 "type for function arguments"); 1341 return {}; 1342 } 1343 llvmInputs.push_back(llvmTy); 1344 } 1345 1346 // No output is denoted as "void" in LLVM type system. 1347 LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(b.getContext()) 1348 : outputs.front().dyn_cast<LLVMType>(); 1349 if (!llvmOutput) { 1350 parser.emitError(loc, "failed to construct function type: expected LLVM " 1351 "type for function results"); 1352 return {}; 1353 } 1354 return LLVMType::getFunctionTy(llvmOutput, llvmInputs, 1355 variadicFlag.isVariadic()); 1356 } 1357 1358 // Parses an LLVM function. 1359 // 1360 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1361 // function-body 1362 // 1363 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1364 OperationState &result) { 1365 // Default to external linkage if no keyword is provided. 1366 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1367 getLinkageAttrName()))) 1368 result.addAttribute(getLinkageAttrName(), 1369 parser.getBuilder().getI64IntegerAttr( 1370 static_cast<int64_t>(LLVM::Linkage::External))); 1371 1372 StringAttr nameAttr; 1373 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1374 SmallVector<NamedAttrList, 1> argAttrs; 1375 SmallVector<NamedAttrList, 1> resultAttrs; 1376 SmallVector<Type, 8> argTypes; 1377 SmallVector<Type, 4> resultTypes; 1378 bool isVariadic; 1379 1380 auto signatureLocation = parser.getCurrentLocation(); 1381 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1382 result.attributes) || 1383 impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs, 1384 argTypes, argAttrs, isVariadic, resultTypes, 1385 resultAttrs)) 1386 return failure(); 1387 1388 auto type = 1389 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1390 impl::VariadicFlag(isVariadic)); 1391 if (!type) 1392 return failure(); 1393 result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type)); 1394 1395 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1396 return failure(); 1397 impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs, 1398 resultAttrs); 1399 1400 auto *body = result.addRegion(); 1401 return parser.parseOptionalRegion( 1402 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1403 } 1404 1405 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1406 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1407 // the external linkage since it is the default value. 1408 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1409 p << op.getOperationName() << ' '; 1410 if (op.linkage() != LLVM::Linkage::External) 1411 p << stringifyLinkage(op.linkage()) << ' '; 1412 p.printSymbolName(op.getName()); 1413 1414 LLVMType fnType = op.getType(); 1415 SmallVector<Type, 8> argTypes; 1416 SmallVector<Type, 1> resTypes; 1417 argTypes.reserve(fnType.getFunctionNumParams()); 1418 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i) 1419 argTypes.push_back(fnType.getFunctionParamType(i)); 1420 1421 LLVMType returnType = fnType.getFunctionResultType(); 1422 if (!returnType.isVoidTy()) 1423 resTypes.push_back(returnType); 1424 1425 impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes); 1426 impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(), 1427 {getLinkageAttrName()}); 1428 1429 // Print the body if this is not an external function. 1430 Region &body = op.body(); 1431 if (!body.empty()) 1432 p.printRegion(body, /*printEntryBlockArgs=*/false, 1433 /*printBlockTerminators=*/true); 1434 } 1435 1436 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1437 // attribute is present. This can check for preconditions of the 1438 // getNumArguments hook not failing. 1439 LogicalResult LLVMFuncOp::verifyType() { 1440 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>(); 1441 if (!llvmType || !llvmType.isFunctionTy()) 1442 return emitOpError("requires '" + getTypeAttrName() + 1443 "' attribute of wrapped LLVM function type"); 1444 1445 return success(); 1446 } 1447 1448 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1449 // Depends on the type attribute being correct as checked by verifyType 1450 unsigned LLVMFuncOp::getNumFuncArguments() { 1451 return getType().getFunctionNumParams(); 1452 } 1453 1454 // Hook for OpTrait::FunctionLike, returns the number of function results. 1455 // Depends on the type attribute being correct as checked by verifyType 1456 unsigned LLVMFuncOp::getNumFuncResults() { 1457 // We model LLVM functions that return void as having zero results, 1458 // and all others as having one result. 1459 // If we modeled a void return as one result, then it would be possible to 1460 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1461 // would assign to that. 1462 if (getType().getFunctionResultType().isVoidTy()) 1463 return 0; 1464 return 1; 1465 } 1466 1467 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1468 // - functions don't have 'common' linkage 1469 // - external functions have 'external' or 'extern_weak' linkage; 1470 // - vararg is (currently) only supported for external functions; 1471 // - entry block arguments are of LLVM types and match the function signature. 1472 static LogicalResult verify(LLVMFuncOp op) { 1473 if (op.linkage() == LLVM::Linkage::Common) 1474 return op.emitOpError() 1475 << "functions cannot have '" 1476 << stringifyLinkage(LLVM::Linkage::Common) << "' linkage"; 1477 1478 if (op.isExternal()) { 1479 if (op.linkage() != LLVM::Linkage::External && 1480 op.linkage() != LLVM::Linkage::ExternWeak) 1481 return op.emitOpError() 1482 << "external functions must have '" 1483 << stringifyLinkage(LLVM::Linkage::External) << "' or '" 1484 << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage"; 1485 return success(); 1486 } 1487 1488 if (op.isVarArg()) 1489 return op.emitOpError("only external functions can be variadic"); 1490 1491 unsigned numArguments = op.getType().getFunctionNumParams(); 1492 Block &entryBlock = op.front(); 1493 for (unsigned i = 0; i < numArguments; ++i) { 1494 Type argType = entryBlock.getArgument(i).getType(); 1495 auto argLLVMType = argType.dyn_cast<LLVMType>(); 1496 if (!argLLVMType) 1497 return op.emitOpError("entry block argument #") 1498 << i << " is not of LLVM type"; 1499 if (op.getType().getFunctionParamType(i) != argLLVMType) 1500 return op.emitOpError("the type of entry block argument #") 1501 << i << " does not match the function signature"; 1502 } 1503 1504 return success(); 1505 } 1506 1507 //===----------------------------------------------------------------------===// 1508 // Verification for LLVM::NullOp. 1509 //===----------------------------------------------------------------------===// 1510 1511 // Only LLVM pointer types are supported. 1512 static LogicalResult verify(LLVM::NullOp op) { 1513 auto llvmType = op.getType().dyn_cast<LLVM::LLVMType>(); 1514 if (!llvmType || !llvmType.isPointerTy()) 1515 return op.emitOpError("expected LLVM IR pointer type"); 1516 return success(); 1517 } 1518 1519 //===----------------------------------------------------------------------===// 1520 // Verification for LLVM::ConstantOp. 1521 //===----------------------------------------------------------------------===// 1522 1523 static LogicalResult verify(LLVM::ConstantOp op) { 1524 if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() || 1525 op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>())) 1526 return op.emitOpError() 1527 << "only supports integer, float, string or elements attributes"; 1528 return success(); 1529 } 1530 1531 //===----------------------------------------------------------------------===// 1532 // Utility functions for parsing atomic ops 1533 //===----------------------------------------------------------------------===// 1534 1535 // Helper function to parse a keyword into the specified attribute named by 1536 // `attrName`. The keyword must match one of the string values defined by the 1537 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 1538 // state. 1539 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 1540 StringRef attrName) { 1541 llvm::SMLoc loc; 1542 StringRef keyword; 1543 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 1544 return failure(); 1545 1546 // Replace the keyword `keyword` with an integer attribute. 1547 auto kind = symbolizeAtomicBinOp(keyword); 1548 if (!kind) { 1549 return parser.emitError(loc) 1550 << "'" << keyword << "' is an incorrect value of the '" << attrName 1551 << "' attribute"; 1552 } 1553 1554 auto value = static_cast<int64_t>(kind.getValue()); 1555 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1556 result.addAttribute(attrName, attr); 1557 1558 return success(); 1559 } 1560 1561 // Helper function to parse a keyword into the specified attribute named by 1562 // `attrName`. The keyword must match one of the string values defined by the 1563 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 1564 // state. 1565 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 1566 OperationState &result, 1567 StringRef attrName) { 1568 llvm::SMLoc loc; 1569 StringRef ordering; 1570 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 1571 return failure(); 1572 1573 // Replace the keyword `ordering` with an integer attribute. 1574 auto kind = symbolizeAtomicOrdering(ordering); 1575 if (!kind) { 1576 return parser.emitError(loc) 1577 << "'" << ordering << "' is an incorrect value of the '" << attrName 1578 << "' attribute"; 1579 } 1580 1581 auto value = static_cast<int64_t>(kind.getValue()); 1582 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1583 result.addAttribute(attrName, attr); 1584 1585 return success(); 1586 } 1587 1588 //===----------------------------------------------------------------------===// 1589 // Printer, parser and verifier for LLVM::AtomicRMWOp. 1590 //===----------------------------------------------------------------------===// 1591 1592 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) { 1593 p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' 1594 << op.ptr() << ", " << op.val() << ' ' 1595 << stringifyAtomicOrdering(op.ordering()) << ' '; 1596 p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"}); 1597 p << " : " << op.res().getType(); 1598 } 1599 1600 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 1601 // attribute-dict? `:` type 1602 static ParseResult parseAtomicRMWOp(OpAsmParser &parser, 1603 OperationState &result) { 1604 LLVMType type; 1605 OpAsmParser::OperandType ptr, val; 1606 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 1607 parser.parseComma() || parser.parseOperand(val) || 1608 parseAtomicOrdering(parser, result, "ordering") || 1609 parser.parseOptionalAttrDict(result.attributes) || 1610 parser.parseColonType(type) || 1611 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1612 parser.resolveOperand(val, type, result.operands)) 1613 return failure(); 1614 1615 result.addTypes(type); 1616 return success(); 1617 } 1618 1619 static LogicalResult verify(AtomicRMWOp op) { 1620 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1621 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1622 if (valType != ptrType.getPointerElementTy()) 1623 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1624 "match type for operand #1"); 1625 auto resType = op.res().getType().cast<LLVM::LLVMType>(); 1626 if (resType != valType) 1627 return op.emitOpError( 1628 "expected LLVM IR result type to match type for operand #1"); 1629 if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) { 1630 if (!valType.isFloatingPointTy()) 1631 return op.emitOpError("expected LLVM IR floating point type"); 1632 } else if (op.bin_op() == AtomicBinOp::xchg) { 1633 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1634 !valType.isIntegerTy(32) && !valType.isIntegerTy(64) && 1635 !valType.isBFloatTy() && !valType.isHalfTy() && !valType.isFloatTy() && 1636 !valType.isDoubleTy()) 1637 return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 1638 } else { 1639 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1640 !valType.isIntegerTy(32) && !valType.isIntegerTy(64)) 1641 return op.emitOpError("expected LLVM IR integer type"); 1642 } 1643 return success(); 1644 } 1645 1646 //===----------------------------------------------------------------------===// 1647 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 1648 //===----------------------------------------------------------------------===// 1649 1650 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) { 1651 p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", " 1652 << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' ' 1653 << stringifyAtomicOrdering(op.failure_ordering()); 1654 p.printOptionalAttrDict(op.getAttrs(), 1655 {"success_ordering", "failure_ordering"}); 1656 p << " : " << op.val().getType(); 1657 } 1658 1659 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 1660 // keyword keyword attribute-dict? `:` type 1661 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser, 1662 OperationState &result) { 1663 auto &builder = parser.getBuilder(); 1664 LLVMType type; 1665 OpAsmParser::OperandType ptr, cmp, val; 1666 if (parser.parseOperand(ptr) || parser.parseComma() || 1667 parser.parseOperand(cmp) || parser.parseComma() || 1668 parser.parseOperand(val) || 1669 parseAtomicOrdering(parser, result, "success_ordering") || 1670 parseAtomicOrdering(parser, result, "failure_ordering") || 1671 parser.parseOptionalAttrDict(result.attributes) || 1672 parser.parseColonType(type) || 1673 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1674 parser.resolveOperand(cmp, type, result.operands) || 1675 parser.resolveOperand(val, type, result.operands)) 1676 return failure(); 1677 1678 auto boolType = LLVMType::getInt1Ty(builder.getContext()); 1679 auto resultType = LLVMType::getStructTy(type, boolType); 1680 result.addTypes(resultType); 1681 1682 return success(); 1683 } 1684 1685 static LogicalResult verify(AtomicCmpXchgOp op) { 1686 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1687 if (!ptrType.isPointerTy()) 1688 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1689 auto cmpType = op.cmp().getType().cast<LLVM::LLVMType>(); 1690 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1691 if (cmpType != ptrType.getPointerElementTy() || cmpType != valType) 1692 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1693 "match type for all other operands"); 1694 if (!valType.isPointerTy() && !valType.isIntegerTy(8) && 1695 !valType.isIntegerTy(16) && !valType.isIntegerTy(32) && 1696 !valType.isIntegerTy(64) && !valType.isBFloatTy() && 1697 !valType.isHalfTy() && !valType.isFloatTy() && !valType.isDoubleTy()) 1698 return op.emitOpError("unexpected LLVM IR type"); 1699 if (op.success_ordering() < AtomicOrdering::monotonic || 1700 op.failure_ordering() < AtomicOrdering::monotonic) 1701 return op.emitOpError("ordering must be at least 'monotonic'"); 1702 if (op.failure_ordering() == AtomicOrdering::release || 1703 op.failure_ordering() == AtomicOrdering::acq_rel) 1704 return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 1705 return success(); 1706 } 1707 1708 //===----------------------------------------------------------------------===// 1709 // Printer, parser and verifier for LLVM::FenceOp. 1710 //===----------------------------------------------------------------------===// 1711 1712 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 1713 // attribute-dict? 1714 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) { 1715 StringAttr sScope; 1716 StringRef syncscopeKeyword = "syncscope"; 1717 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 1718 if (parser.parseLParen() || 1719 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 1720 parser.parseRParen()) 1721 return failure(); 1722 } else { 1723 result.addAttribute(syncscopeKeyword, 1724 parser.getBuilder().getStringAttr("")); 1725 } 1726 if (parseAtomicOrdering(parser, result, "ordering") || 1727 parser.parseOptionalAttrDict(result.attributes)) 1728 return failure(); 1729 return success(); 1730 } 1731 1732 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) { 1733 StringRef syncscopeKeyword = "syncscope"; 1734 p << op.getOperationName() << ' '; 1735 if (!op.getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 1736 p << "syncscope(" << op.getAttr(syncscopeKeyword) << ") "; 1737 p << stringifyAtomicOrdering(op.ordering()); 1738 } 1739 1740 static LogicalResult verify(FenceOp &op) { 1741 if (op.ordering() == AtomicOrdering::not_atomic || 1742 op.ordering() == AtomicOrdering::unordered || 1743 op.ordering() == AtomicOrdering::monotonic) 1744 return op.emitOpError("can be given only acquire, release, acq_rel, " 1745 "and seq_cst orderings"); 1746 return success(); 1747 } 1748 1749 //===----------------------------------------------------------------------===// 1750 // LLVMDialect initialization, type parsing, and registration. 1751 //===----------------------------------------------------------------------===// 1752 1753 void LLVMDialect::initialize() { 1754 // clang-format off 1755 addTypes<LLVMVoidType, 1756 LLVMHalfType, 1757 LLVMBFloatType, 1758 LLVMFloatType, 1759 LLVMDoubleType, 1760 LLVMFP128Type, 1761 LLVMX86FP80Type, 1762 LLVMPPCFP128Type, 1763 LLVMX86MMXType, 1764 LLVMTokenType, 1765 LLVMLabelType, 1766 LLVMMetadataType, 1767 LLVMFunctionType, 1768 LLVMIntegerType, 1769 LLVMPointerType, 1770 LLVMFixedVectorType, 1771 LLVMScalableVectorType, 1772 LLVMArrayType, 1773 LLVMStructType>(); 1774 // clang-format on 1775 addOperations< 1776 #define GET_OP_LIST 1777 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1778 >(); 1779 1780 // Support unknown operations because not all LLVM operations are registered. 1781 allowUnknownOperations(); 1782 } 1783 1784 #define GET_OP_CLASSES 1785 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1786 1787 /// Parse a type registered to this dialect. 1788 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 1789 return detail::parseType(parser); 1790 } 1791 1792 /// Print a type registered to this dialect. 1793 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 1794 return detail::printType(type.cast<LLVMType>(), os); 1795 } 1796 1797 LogicalResult LLVMDialect::verifyDataLayoutString( 1798 StringRef descr, llvm::function_ref<void(const Twine &)> reportError) { 1799 llvm::Expected<llvm::DataLayout> maybeDataLayout = 1800 llvm::DataLayout::parse(descr); 1801 if (maybeDataLayout) 1802 return success(); 1803 1804 std::string message; 1805 llvm::raw_string_ostream messageStream(message); 1806 llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream); 1807 reportError("invalid data layout descriptor: " + messageStream.str()); 1808 return failure(); 1809 } 1810 1811 /// Verify LLVM dialect attributes. 1812 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op, 1813 NamedAttribute attr) { 1814 // If the data layout attribute is present, it must use the LLVM data layout 1815 // syntax. Try parsing it and report errors in case of failure. Users of this 1816 // attribute may assume it is well-formed and can pass it to the (asserting) 1817 // llvm::DataLayout constructor. 1818 if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName()) 1819 return success(); 1820 if (auto stringAttr = attr.second.dyn_cast<StringAttr>()) 1821 return verifyDataLayoutString( 1822 stringAttr.getValue(), 1823 [op](const Twine &message) { op->emitOpError() << message.str(); }); 1824 1825 return op->emitOpError() << "expected '" 1826 << LLVM::LLVMDialect::getDataLayoutAttrName() 1827 << "' to be a string attribute"; 1828 } 1829 1830 /// Verify LLVMIR function argument attributes. 1831 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 1832 unsigned regionIdx, 1833 unsigned argIdx, 1834 NamedAttribute argAttr) { 1835 // Check that llvm.noalias is a boolean attribute. 1836 if (argAttr.first == "llvm.noalias" && !argAttr.second.isa<BoolAttr>()) 1837 return op->emitError() 1838 << "llvm.noalias argument attribute of non boolean type"; 1839 // Check that llvm.align is an integer attribute. 1840 if (argAttr.first == "llvm.align" && !argAttr.second.isa<IntegerAttr>()) 1841 return op->emitError() 1842 << "llvm.align argument attribute of non integer type"; 1843 return success(); 1844 } 1845 1846 //===----------------------------------------------------------------------===// 1847 // Utility functions. 1848 //===----------------------------------------------------------------------===// 1849 1850 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 1851 StringRef name, StringRef value, 1852 LLVM::Linkage linkage) { 1853 assert(builder.getInsertionBlock() && 1854 builder.getInsertionBlock()->getParentOp() && 1855 "expected builder to point to a block constrained in an op"); 1856 auto module = 1857 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 1858 assert(module && "builder points to an op outside of a module"); 1859 1860 // Create the global at the entry of the module. 1861 OpBuilder moduleBuilder(module.getBodyRegion()); 1862 MLIRContext *ctx = builder.getContext(); 1863 auto type = 1864 LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(ctx), value.size()); 1865 auto global = moduleBuilder.create<LLVM::GlobalOp>( 1866 loc, type, /*isConstant=*/true, linkage, name, 1867 builder.getStringAttr(value)); 1868 1869 // Get the pointer to the first character in the global string. 1870 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 1871 Value cst0 = builder.create<LLVM::ConstantOp>( 1872 loc, LLVM::LLVMType::getInt64Ty(ctx), 1873 builder.getIntegerAttr(builder.getIndexType(), 0)); 1874 return builder.create<LLVM::GEPOp>(loc, LLVM::LLVMType::getInt8PtrTy(ctx), 1875 globalPtr, ValueRange{cst0, cst0}); 1876 } 1877 1878 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 1879 return op->hasTrait<OpTrait::SymbolTable>() && 1880 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 1881 } 1882