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>((*this)->getParentOp(), 989 global_name()); 990 } 991 992 LLVMFuncOp AddressOfOp::getFunction() { 993 return lookupSymbolInModule<LLVM::LLVMFuncOp>((*this)->getParentOp(), 994 global_name()); 995 } 996 997 static LogicalResult verify(AddressOfOp op) { 998 auto global = op.getGlobal(); 999 auto function = op.getFunction(); 1000 if (!global && !function) 1001 return op.emitOpError( 1002 "must reference a global defined by 'llvm.mlir.global' or 'llvm.func'"); 1003 1004 if (global && global.getType().getPointerTo(global.addr_space()) != 1005 op.getResult().getType()) 1006 return op.emitOpError( 1007 "the type must be a pointer to the type of the referenced global"); 1008 1009 if (function && function.getType().getPointerTo() != op.getResult().getType()) 1010 return op.emitOpError( 1011 "the type must be a pointer to the type of the referenced function"); 1012 1013 return success(); 1014 } 1015 1016 //===----------------------------------------------------------------------===// 1017 // Builder, printer and verifier for LLVM::GlobalOp. 1018 //===----------------------------------------------------------------------===// 1019 1020 /// Returns the name used for the linkage attribute. This *must* correspond to 1021 /// the name of the attribute in ODS. 1022 static StringRef getLinkageAttrName() { return "linkage"; } 1023 1024 void GlobalOp::build(OpBuilder &builder, OperationState &result, LLVMType type, 1025 bool isConstant, Linkage linkage, StringRef name, 1026 Attribute value, unsigned addrSpace, 1027 ArrayRef<NamedAttribute> attrs) { 1028 result.addAttribute(SymbolTable::getSymbolAttrName(), 1029 builder.getStringAttr(name)); 1030 result.addAttribute("type", TypeAttr::get(type)); 1031 if (isConstant) 1032 result.addAttribute("constant", builder.getUnitAttr()); 1033 if (value) 1034 result.addAttribute("value", value); 1035 result.addAttribute(getLinkageAttrName(), 1036 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1037 if (addrSpace != 0) 1038 result.addAttribute("addr_space", builder.getI32IntegerAttr(addrSpace)); 1039 result.attributes.append(attrs.begin(), attrs.end()); 1040 result.addRegion(); 1041 } 1042 1043 static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) { 1044 p << op.getOperationName() << ' ' << stringifyLinkage(op.linkage()) << ' '; 1045 if (op.constant()) 1046 p << "constant "; 1047 p.printSymbolName(op.sym_name()); 1048 p << '('; 1049 if (auto value = op.getValueOrNull()) 1050 p.printAttribute(value); 1051 p << ')'; 1052 p.printOptionalAttrDict(op.getAttrs(), 1053 {SymbolTable::getSymbolAttrName(), "type", "constant", 1054 "value", getLinkageAttrName()}); 1055 1056 // Print the trailing type unless it's a string global. 1057 if (op.getValueOrNull().dyn_cast_or_null<StringAttr>()) 1058 return; 1059 p << " : " << op.type(); 1060 1061 Region &initializer = op.getInitializerRegion(); 1062 if (!initializer.empty()) 1063 p.printRegion(initializer, /*printEntryBlockArgs=*/false); 1064 } 1065 1066 //===----------------------------------------------------------------------===// 1067 // Verifier for LLVM::DialectCastOp. 1068 //===----------------------------------------------------------------------===// 1069 1070 /// Checks if `llvmType` is dialect cast-compatible with `index` type. Does not 1071 /// report the error, the user is expected to produce an appropriate message. 1072 // TODO: make the size depend on data layout rather than on the conversion 1073 // pass option, and pull that information here. 1074 static LogicalResult verifyCastWithIndex(LLVMType llvmType) { 1075 return success(llvmType.isa<LLVMIntegerType>()); 1076 } 1077 1078 /// Checks if `llvmType` is dialect cast-compatible with built-in `type` and 1079 /// reports errors to the location of `op`. 1080 static LogicalResult verifyCast(DialectCastOp op, LLVMType llvmType, 1081 Type type) { 1082 // Index is compatible with any integer. 1083 if (type.isIndex()) { 1084 if (succeeded(verifyCastWithIndex(llvmType))) 1085 return success(); 1086 1087 return op.emitOpError("invalid cast between index and non-integer type"); 1088 } 1089 1090 // Simple one-to-one mappings for floating point types. 1091 if (type.isF16()) { 1092 if (llvmType.isa<LLVMHalfType>()) 1093 return success(); 1094 return op.emitOpError( 1095 "invalid cast between f16 and a type other than !llvm.half"); 1096 } 1097 if (type.isBF16()) { 1098 if (llvmType.isa<LLVMBFloatType>()) 1099 return success(); 1100 return op->emitOpError( 1101 "invalid cast between bf16 and a type other than !llvm.bfloat"); 1102 } 1103 if (type.isF32()) { 1104 if (llvmType.isa<LLVMFloatType>()) 1105 return success(); 1106 return op->emitOpError( 1107 "invalid cast between f32 and a type other than !llvm.float"); 1108 } 1109 if (type.isF64()) { 1110 if (llvmType.isa<LLVMDoubleType>()) 1111 return success(); 1112 return op->emitOpError( 1113 "invalid cast between f64 and a type other than !llvm.double"); 1114 } 1115 1116 // Singless integers are compatible with LLVM integer of the same bitwidth. 1117 if (type.isSignlessInteger()) { 1118 auto llvmInt = llvmType.dyn_cast<LLVMIntegerType>(); 1119 if (!llvmInt) 1120 return op->emitOpError( 1121 "invalid cast between integer and non-integer type"); 1122 if (llvmInt.getBitWidth() == type.getIntOrFloatBitWidth()) 1123 return success(); 1124 1125 return op->emitOpError( 1126 "invalid cast between integers with mismatching bitwidth"); 1127 } 1128 1129 // Vectors are compatible if they are 1D non-scalable, and their element types 1130 // are compatible. 1131 if (auto vectorType = type.dyn_cast<VectorType>()) { 1132 if (vectorType.getRank() != 1) 1133 return op->emitOpError("only 1-d vector is allowed"); 1134 1135 auto llvmVector = llvmType.dyn_cast<LLVMVectorType>(); 1136 if (llvmVector.isa<LLVMScalableVectorType>()) 1137 return op->emitOpError("only fixed-sized vector is allowed"); 1138 1139 if (vectorType.getDimSize(0) != llvmVector.getVectorNumElements()) 1140 return op->emitOpError( 1141 "invalid cast between vectors with mismatching sizes"); 1142 1143 return verifyCast(op, llvmVector.getElementType(), 1144 vectorType.getElementType()); 1145 } 1146 1147 if (auto memrefType = type.dyn_cast<MemRefType>()) { 1148 // Bare pointer convention: statically-shaped memref is compatible with an 1149 // LLVM pointer to the element type. 1150 if (auto ptrType = llvmType.dyn_cast<LLVMPointerType>()) { 1151 if (!memrefType.hasStaticShape()) 1152 return op->emitOpError( 1153 "unexpected bare pointer for dynamically shaped memref"); 1154 if (memrefType.getMemorySpace() != ptrType.getAddressSpace()) 1155 return op->emitError("invalid conversion between memref and pointer in " 1156 "different memory spaces"); 1157 1158 return verifyCast(op, ptrType.getElementType(), 1159 memrefType.getElementType()); 1160 } 1161 1162 // Otherwise, memrefs are convertible to a descriptor, which is a structure 1163 // type. 1164 auto structType = llvmType.dyn_cast<LLVMStructType>(); 1165 if (!structType) 1166 return op->emitOpError("invalid cast between a memref and a type other " 1167 "than pointer or memref descriptor"); 1168 1169 unsigned expectedNumElements = memrefType.getRank() == 0 ? 3 : 5; 1170 if (structType.getBody().size() != expectedNumElements) { 1171 return op->emitOpError() << "expected memref descriptor with " 1172 << expectedNumElements << " elements"; 1173 } 1174 1175 // The first two elements are pointers to the element type. 1176 auto allocatedPtr = structType.getBody()[0].dyn_cast<LLVMPointerType>(); 1177 if (!allocatedPtr || 1178 allocatedPtr.getAddressSpace() != memrefType.getMemorySpace()) 1179 return op->emitOpError("expected first element of a memref descriptor to " 1180 "be a pointer in the address space of the memref"); 1181 if (failed(verifyCast(op, allocatedPtr.getElementType(), 1182 memrefType.getElementType()))) 1183 return failure(); 1184 1185 auto alignedPtr = structType.getBody()[1].dyn_cast<LLVMPointerType>(); 1186 if (!alignedPtr || 1187 alignedPtr.getAddressSpace() != memrefType.getMemorySpace()) 1188 return op->emitOpError( 1189 "expected second element of a memref descriptor to " 1190 "be a pointer in the address space of the memref"); 1191 if (failed(verifyCast(op, alignedPtr.getElementType(), 1192 memrefType.getElementType()))) 1193 return failure(); 1194 1195 // The second element (offset) is an equivalent of index. 1196 if (failed(verifyCastWithIndex(structType.getBody()[2]))) 1197 return op->emitOpError("expected third element of a memref descriptor to " 1198 "be index-compatible integers"); 1199 1200 // 0D memrefs don't have sizes/strides. 1201 if (memrefType.getRank() == 0) 1202 return success(); 1203 1204 // Sizes and strides are rank-sized arrays of `index` equivalents. 1205 auto sizes = structType.getBody()[3].dyn_cast<LLVMArrayType>(); 1206 if (!sizes || failed(verifyCastWithIndex(sizes.getElementType())) || 1207 sizes.getNumElements() != memrefType.getRank()) 1208 return op->emitOpError( 1209 "expected fourth element of a memref descriptor " 1210 "to be an array of <rank> index-compatible integers"); 1211 1212 auto strides = structType.getBody()[4].dyn_cast<LLVMArrayType>(); 1213 if (!strides || failed(verifyCastWithIndex(strides.getElementType())) || 1214 strides.getNumElements() != memrefType.getRank()) 1215 return op->emitOpError( 1216 "expected fifth element of a memref descriptor " 1217 "to be an array of <rank> index-compatible integers"); 1218 1219 return success(); 1220 } 1221 1222 // Unranked memrefs are compatible with their descriptors. 1223 if (auto unrankedMemrefType = type.dyn_cast<UnrankedMemRefType>()) { 1224 auto structType = llvmType.dyn_cast<LLVMStructType>(); 1225 if (!structType || structType.getBody().size() != 2) 1226 return op->emitOpError( 1227 "expected descriptor to be a struct with two elements"); 1228 1229 if (failed(verifyCastWithIndex(structType.getBody()[0]))) 1230 return op->emitOpError("expected first element of a memref descriptor to " 1231 "be an index-compatible integer"); 1232 1233 auto ptrType = structType.getBody()[1].dyn_cast<LLVMPointerType>(); 1234 if (!ptrType || !ptrType.getPointerElementTy().isIntegerTy(8)) 1235 return op->emitOpError("expected second element of a memref descriptor " 1236 "to be an !llvm.ptr<i8>"); 1237 1238 return success(); 1239 } 1240 1241 // Everything else is not supported. 1242 return op->emitError("unsupported cast"); 1243 } 1244 1245 static LogicalResult verify(DialectCastOp op) { 1246 if (auto llvmType = op.getType().dyn_cast<LLVMType>()) 1247 return verifyCast(op, llvmType, op.in().getType()); 1248 1249 auto llvmType = op.in().getType().dyn_cast<LLVMType>(); 1250 if (!llvmType) 1251 return op->emitOpError("expected one LLVM type and one built-in type"); 1252 1253 return verifyCast(op, llvmType, op.getType()); 1254 } 1255 1256 // Parses one of the keywords provided in the list `keywords` and returns the 1257 // position of the parsed keyword in the list. If none of the keywords from the 1258 // list is parsed, returns -1. 1259 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 1260 ArrayRef<StringRef> keywords) { 1261 for (auto en : llvm::enumerate(keywords)) { 1262 if (succeeded(parser.parseOptionalKeyword(en.value()))) 1263 return en.index(); 1264 } 1265 return -1; 1266 } 1267 1268 namespace { 1269 template <typename Ty> struct EnumTraits {}; 1270 1271 #define REGISTER_ENUM_TYPE(Ty) \ 1272 template <> struct EnumTraits<Ty> { \ 1273 static StringRef stringify(Ty value) { return stringify##Ty(value); } \ 1274 static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ 1275 } 1276 1277 REGISTER_ENUM_TYPE(Linkage); 1278 } // end namespace 1279 1280 template <typename EnumTy> 1281 static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser, 1282 OperationState &result, 1283 StringRef name) { 1284 SmallVector<StringRef, 10> names; 1285 for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i) 1286 names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); 1287 1288 int index = parseOptionalKeywordAlternative(parser, names); 1289 if (index == -1) 1290 return failure(); 1291 result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index)); 1292 return success(); 1293 } 1294 1295 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier 1296 // `(` attribute? `)` attribute-list? (`:` type)? region? 1297 // 1298 // The type can be omitted for string attributes, in which case it will be 1299 // inferred from the value of the string as [strlen(value) x i8]. 1300 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) { 1301 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1302 getLinkageAttrName()))) 1303 result.addAttribute(getLinkageAttrName(), 1304 parser.getBuilder().getI64IntegerAttr( 1305 static_cast<int64_t>(LLVM::Linkage::External))); 1306 1307 if (succeeded(parser.parseOptionalKeyword("constant"))) 1308 result.addAttribute("constant", parser.getBuilder().getUnitAttr()); 1309 1310 StringAttr name; 1311 if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), 1312 result.attributes) || 1313 parser.parseLParen()) 1314 return failure(); 1315 1316 Attribute value; 1317 if (parser.parseOptionalRParen()) { 1318 if (parser.parseAttribute(value, "value", result.attributes) || 1319 parser.parseRParen()) 1320 return failure(); 1321 } 1322 1323 SmallVector<Type, 1> types; 1324 if (parser.parseOptionalAttrDict(result.attributes) || 1325 parser.parseOptionalColonTypeList(types)) 1326 return failure(); 1327 1328 if (types.size() > 1) 1329 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1330 1331 Region &initRegion = *result.addRegion(); 1332 if (types.empty()) { 1333 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1334 MLIRContext *context = parser.getBuilder().getContext(); 1335 auto arrayType = LLVM::LLVMType::getArrayTy( 1336 LLVM::LLVMType::getInt8Ty(context), strAttr.getValue().size()); 1337 types.push_back(arrayType); 1338 } else { 1339 return parser.emitError(parser.getNameLoc(), 1340 "type can only be omitted for string globals"); 1341 } 1342 } else { 1343 OptionalParseResult parseResult = 1344 parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1345 /*argTypes=*/{}); 1346 if (parseResult.hasValue() && failed(*parseResult)) 1347 return failure(); 1348 } 1349 1350 result.addAttribute("type", TypeAttr::get(types[0])); 1351 return success(); 1352 } 1353 1354 static LogicalResult verify(GlobalOp op) { 1355 if (!LLVMPointerType::isValidElementType(op.getType())) 1356 return op.emitOpError( 1357 "expects type to be a valid element type for an LLVM pointer"); 1358 if (op->getParentOp() && !satisfiesLLVMModule(op->getParentOp())) 1359 return op.emitOpError("must appear at the module level"); 1360 1361 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1362 auto type = op.getType(); 1363 if (!type.isArrayTy() || !type.getArrayElementType().isIntegerTy(8) || 1364 type.getArrayNumElements() != strAttr.getValue().size()) 1365 return op.emitOpError( 1366 "requires an i8 array type of the length equal to that of the string " 1367 "attribute"); 1368 } 1369 1370 if (Block *b = op.getInitializerBlock()) { 1371 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1372 if (ret.operand_type_begin() == ret.operand_type_end()) 1373 return op.emitOpError("initializer region cannot return void"); 1374 if (*ret.operand_type_begin() != op.getType()) 1375 return op.emitOpError("initializer region type ") 1376 << *ret.operand_type_begin() << " does not match global type " 1377 << op.getType(); 1378 1379 if (op.getValueOrNull()) 1380 return op.emitOpError("cannot have both initializer value and region"); 1381 } 1382 return success(); 1383 } 1384 1385 //===----------------------------------------------------------------------===// 1386 // Printing/parsing for LLVM::ShuffleVectorOp. 1387 //===----------------------------------------------------------------------===// 1388 // Expects vector to be of wrapped LLVM vector type and position to be of 1389 // wrapped LLVM i32 type. 1390 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 1391 Value v1, Value v2, ArrayAttr mask, 1392 ArrayRef<NamedAttribute> attrs) { 1393 auto wrappedContainerType1 = v1.getType().cast<LLVM::LLVMType>(); 1394 auto vType = LLVMType::getVectorTy( 1395 wrappedContainerType1.getVectorElementType(), mask.size()); 1396 build(b, result, vType, v1, v2, mask); 1397 result.addAttributes(attrs); 1398 } 1399 1400 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1401 p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " " 1402 << op.mask(); 1403 p.printOptionalAttrDict(op.getAttrs(), {"mask"}); 1404 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1405 } 1406 1407 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1408 // `[` integer-literal (`,` integer-literal)* `]` 1409 // attribute-dict? `:` type 1410 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1411 OperationState &result) { 1412 llvm::SMLoc loc; 1413 OpAsmParser::OperandType v1, v2; 1414 ArrayAttr maskAttr; 1415 Type typeV1, typeV2; 1416 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1417 parser.parseComma() || parser.parseOperand(v2) || 1418 parser.parseAttribute(maskAttr, "mask", result.attributes) || 1419 parser.parseOptionalAttrDict(result.attributes) || 1420 parser.parseColonType(typeV1) || parser.parseComma() || 1421 parser.parseType(typeV2) || 1422 parser.resolveOperand(v1, typeV1, result.operands) || 1423 parser.resolveOperand(v2, typeV2, result.operands)) 1424 return failure(); 1425 auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>(); 1426 if (!wrappedContainerType1 || !wrappedContainerType1.isVectorTy()) 1427 return parser.emitError( 1428 loc, "expected LLVM IR dialect vector type for operand #1"); 1429 auto vType = LLVMType::getVectorTy( 1430 wrappedContainerType1.getVectorElementType(), maskAttr.size()); 1431 result.addTypes(vType); 1432 return success(); 1433 } 1434 1435 //===----------------------------------------------------------------------===// 1436 // Implementations for LLVM::LLVMFuncOp. 1437 //===----------------------------------------------------------------------===// 1438 1439 // Add the entry block to the function. 1440 Block *LLVMFuncOp::addEntryBlock() { 1441 assert(empty() && "function already has an entry block"); 1442 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1443 1444 auto *entry = new Block; 1445 push_back(entry); 1446 1447 LLVMType type = getType(); 1448 for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i) 1449 entry->addArgument(type.getFunctionParamType(i)); 1450 return entry; 1451 } 1452 1453 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 1454 StringRef name, LLVMType type, LLVM::Linkage linkage, 1455 ArrayRef<NamedAttribute> attrs, 1456 ArrayRef<MutableDictionaryAttr> argAttrs) { 1457 result.addRegion(); 1458 result.addAttribute(SymbolTable::getSymbolAttrName(), 1459 builder.getStringAttr(name)); 1460 result.addAttribute("type", TypeAttr::get(type)); 1461 result.addAttribute(getLinkageAttrName(), 1462 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1463 result.attributes.append(attrs.begin(), attrs.end()); 1464 if (argAttrs.empty()) 1465 return; 1466 1467 unsigned numInputs = type.getFunctionNumParams(); 1468 assert(numInputs == argAttrs.size() && 1469 "expected as many argument attribute lists as arguments"); 1470 SmallString<8> argAttrName; 1471 for (unsigned i = 0; i < numInputs; ++i) 1472 if (auto argDict = argAttrs[i].getDictionary(builder.getContext())) 1473 result.addAttribute(getArgAttrName(i, argAttrName), argDict); 1474 } 1475 1476 // Builds an LLVM function type from the given lists of input and output types. 1477 // Returns a null type if any of the types provided are non-LLVM types, or if 1478 // there is more than one output type. 1479 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1480 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1481 impl::VariadicFlag variadicFlag) { 1482 Builder &b = parser.getBuilder(); 1483 if (outputs.size() > 1) { 1484 parser.emitError(loc, "failed to construct function type: expected zero or " 1485 "one function result"); 1486 return {}; 1487 } 1488 1489 // Convert inputs to LLVM types, exit early on error. 1490 SmallVector<LLVMType, 4> llvmInputs; 1491 for (auto t : inputs) { 1492 auto llvmTy = t.dyn_cast<LLVMType>(); 1493 if (!llvmTy) { 1494 parser.emitError(loc, "failed to construct function type: expected LLVM " 1495 "type for function arguments"); 1496 return {}; 1497 } 1498 llvmInputs.push_back(llvmTy); 1499 } 1500 1501 // No output is denoted as "void" in LLVM type system. 1502 LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(b.getContext()) 1503 : outputs.front().dyn_cast<LLVMType>(); 1504 if (!llvmOutput) { 1505 parser.emitError(loc, "failed to construct function type: expected LLVM " 1506 "type for function results"); 1507 return {}; 1508 } 1509 return LLVMType::getFunctionTy(llvmOutput, llvmInputs, 1510 variadicFlag.isVariadic()); 1511 } 1512 1513 // Parses an LLVM function. 1514 // 1515 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1516 // function-body 1517 // 1518 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1519 OperationState &result) { 1520 // Default to external linkage if no keyword is provided. 1521 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1522 getLinkageAttrName()))) 1523 result.addAttribute(getLinkageAttrName(), 1524 parser.getBuilder().getI64IntegerAttr( 1525 static_cast<int64_t>(LLVM::Linkage::External))); 1526 1527 StringAttr nameAttr; 1528 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1529 SmallVector<NamedAttrList, 1> argAttrs; 1530 SmallVector<NamedAttrList, 1> resultAttrs; 1531 SmallVector<Type, 8> argTypes; 1532 SmallVector<Type, 4> resultTypes; 1533 bool isVariadic; 1534 1535 auto signatureLocation = parser.getCurrentLocation(); 1536 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1537 result.attributes) || 1538 impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs, 1539 argTypes, argAttrs, isVariadic, resultTypes, 1540 resultAttrs)) 1541 return failure(); 1542 1543 auto type = 1544 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1545 impl::VariadicFlag(isVariadic)); 1546 if (!type) 1547 return failure(); 1548 result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type)); 1549 1550 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1551 return failure(); 1552 impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs, 1553 resultAttrs); 1554 1555 auto *body = result.addRegion(); 1556 OptionalParseResult parseResult = parser.parseOptionalRegion( 1557 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1558 return failure(parseResult.hasValue() && failed(*parseResult)); 1559 } 1560 1561 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1562 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1563 // the external linkage since it is the default value. 1564 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1565 p << op.getOperationName() << ' '; 1566 if (op.linkage() != LLVM::Linkage::External) 1567 p << stringifyLinkage(op.linkage()) << ' '; 1568 p.printSymbolName(op.getName()); 1569 1570 LLVMType fnType = op.getType(); 1571 SmallVector<Type, 8> argTypes; 1572 SmallVector<Type, 1> resTypes; 1573 argTypes.reserve(fnType.getFunctionNumParams()); 1574 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i) 1575 argTypes.push_back(fnType.getFunctionParamType(i)); 1576 1577 LLVMType returnType = fnType.getFunctionResultType(); 1578 if (!returnType.isVoidTy()) 1579 resTypes.push_back(returnType); 1580 1581 impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes); 1582 impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(), 1583 {getLinkageAttrName()}); 1584 1585 // Print the body if this is not an external function. 1586 Region &body = op.body(); 1587 if (!body.empty()) 1588 p.printRegion(body, /*printEntryBlockArgs=*/false, 1589 /*printBlockTerminators=*/true); 1590 } 1591 1592 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1593 // attribute is present. This can check for preconditions of the 1594 // getNumArguments hook not failing. 1595 LogicalResult LLVMFuncOp::verifyType() { 1596 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>(); 1597 if (!llvmType || !llvmType.isFunctionTy()) 1598 return emitOpError("requires '" + getTypeAttrName() + 1599 "' attribute of wrapped LLVM function type"); 1600 1601 return success(); 1602 } 1603 1604 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1605 // Depends on the type attribute being correct as checked by verifyType 1606 unsigned LLVMFuncOp::getNumFuncArguments() { 1607 return getType().getFunctionNumParams(); 1608 } 1609 1610 // Hook for OpTrait::FunctionLike, returns the number of function results. 1611 // Depends on the type attribute being correct as checked by verifyType 1612 unsigned LLVMFuncOp::getNumFuncResults() { 1613 // We model LLVM functions that return void as having zero results, 1614 // and all others as having one result. 1615 // If we modeled a void return as one result, then it would be possible to 1616 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1617 // would assign to that. 1618 if (getType().getFunctionResultType().isVoidTy()) 1619 return 0; 1620 return 1; 1621 } 1622 1623 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1624 // - functions don't have 'common' linkage 1625 // - external functions have 'external' or 'extern_weak' linkage; 1626 // - vararg is (currently) only supported for external functions; 1627 // - entry block arguments are of LLVM types and match the function signature. 1628 static LogicalResult verify(LLVMFuncOp op) { 1629 if (op.linkage() == LLVM::Linkage::Common) 1630 return op.emitOpError() 1631 << "functions cannot have '" 1632 << stringifyLinkage(LLVM::Linkage::Common) << "' linkage"; 1633 1634 if (op.isExternal()) { 1635 if (op.linkage() != LLVM::Linkage::External && 1636 op.linkage() != LLVM::Linkage::ExternWeak) 1637 return op.emitOpError() 1638 << "external functions must have '" 1639 << stringifyLinkage(LLVM::Linkage::External) << "' or '" 1640 << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage"; 1641 return success(); 1642 } 1643 1644 if (op.isVarArg()) 1645 return op.emitOpError("only external functions can be variadic"); 1646 1647 unsigned numArguments = op.getType().getFunctionNumParams(); 1648 Block &entryBlock = op.front(); 1649 for (unsigned i = 0; i < numArguments; ++i) { 1650 Type argType = entryBlock.getArgument(i).getType(); 1651 auto argLLVMType = argType.dyn_cast<LLVMType>(); 1652 if (!argLLVMType) 1653 return op.emitOpError("entry block argument #") 1654 << i << " is not of LLVM type"; 1655 if (op.getType().getFunctionParamType(i) != argLLVMType) 1656 return op.emitOpError("the type of entry block argument #") 1657 << i << " does not match the function signature"; 1658 } 1659 1660 return success(); 1661 } 1662 1663 //===----------------------------------------------------------------------===// 1664 // Verification for LLVM::ConstantOp. 1665 //===----------------------------------------------------------------------===// 1666 1667 static LogicalResult verify(LLVM::ConstantOp op) { 1668 if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() || 1669 op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>())) 1670 return op.emitOpError() 1671 << "only supports integer, float, string or elements attributes"; 1672 return success(); 1673 } 1674 1675 //===----------------------------------------------------------------------===// 1676 // Utility functions for parsing atomic ops 1677 //===----------------------------------------------------------------------===// 1678 1679 // Helper function to parse a keyword into the specified attribute named by 1680 // `attrName`. The keyword must match one of the string values defined by the 1681 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 1682 // state. 1683 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 1684 StringRef attrName) { 1685 llvm::SMLoc loc; 1686 StringRef keyword; 1687 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 1688 return failure(); 1689 1690 // Replace the keyword `keyword` with an integer attribute. 1691 auto kind = symbolizeAtomicBinOp(keyword); 1692 if (!kind) { 1693 return parser.emitError(loc) 1694 << "'" << keyword << "' is an incorrect value of the '" << attrName 1695 << "' attribute"; 1696 } 1697 1698 auto value = static_cast<int64_t>(kind.getValue()); 1699 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1700 result.addAttribute(attrName, attr); 1701 1702 return success(); 1703 } 1704 1705 // Helper function to parse a keyword into the specified attribute named by 1706 // `attrName`. The keyword must match one of the string values defined by the 1707 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 1708 // state. 1709 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 1710 OperationState &result, 1711 StringRef attrName) { 1712 llvm::SMLoc loc; 1713 StringRef ordering; 1714 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 1715 return failure(); 1716 1717 // Replace the keyword `ordering` with an integer attribute. 1718 auto kind = symbolizeAtomicOrdering(ordering); 1719 if (!kind) { 1720 return parser.emitError(loc) 1721 << "'" << ordering << "' is an incorrect value of the '" << attrName 1722 << "' attribute"; 1723 } 1724 1725 auto value = static_cast<int64_t>(kind.getValue()); 1726 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1727 result.addAttribute(attrName, attr); 1728 1729 return success(); 1730 } 1731 1732 //===----------------------------------------------------------------------===// 1733 // Printer, parser and verifier for LLVM::AtomicRMWOp. 1734 //===----------------------------------------------------------------------===// 1735 1736 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) { 1737 p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' 1738 << op.ptr() << ", " << op.val() << ' ' 1739 << stringifyAtomicOrdering(op.ordering()) << ' '; 1740 p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"}); 1741 p << " : " << op.res().getType(); 1742 } 1743 1744 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 1745 // attribute-dict? `:` type 1746 static ParseResult parseAtomicRMWOp(OpAsmParser &parser, 1747 OperationState &result) { 1748 LLVMType type; 1749 OpAsmParser::OperandType ptr, val; 1750 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 1751 parser.parseComma() || parser.parseOperand(val) || 1752 parseAtomicOrdering(parser, result, "ordering") || 1753 parser.parseOptionalAttrDict(result.attributes) || 1754 parser.parseColonType(type) || 1755 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1756 parser.resolveOperand(val, type, result.operands)) 1757 return failure(); 1758 1759 result.addTypes(type); 1760 return success(); 1761 } 1762 1763 static LogicalResult verify(AtomicRMWOp op) { 1764 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1765 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1766 if (valType != ptrType.getPointerElementTy()) 1767 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1768 "match type for operand #1"); 1769 auto resType = op.res().getType().cast<LLVM::LLVMType>(); 1770 if (resType != valType) 1771 return op.emitOpError( 1772 "expected LLVM IR result type to match type for operand #1"); 1773 if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) { 1774 if (!valType.isFloatingPointTy()) 1775 return op.emitOpError("expected LLVM IR floating point type"); 1776 } else if (op.bin_op() == AtomicBinOp::xchg) { 1777 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1778 !valType.isIntegerTy(32) && !valType.isIntegerTy(64) && 1779 !valType.isBFloatTy() && !valType.isHalfTy() && !valType.isFloatTy() && 1780 !valType.isDoubleTy()) 1781 return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 1782 } else { 1783 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1784 !valType.isIntegerTy(32) && !valType.isIntegerTy(64)) 1785 return op.emitOpError("expected LLVM IR integer type"); 1786 } 1787 return success(); 1788 } 1789 1790 //===----------------------------------------------------------------------===// 1791 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 1792 //===----------------------------------------------------------------------===// 1793 1794 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) { 1795 p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", " 1796 << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' ' 1797 << stringifyAtomicOrdering(op.failure_ordering()); 1798 p.printOptionalAttrDict(op.getAttrs(), 1799 {"success_ordering", "failure_ordering"}); 1800 p << " : " << op.val().getType(); 1801 } 1802 1803 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 1804 // keyword keyword attribute-dict? `:` type 1805 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser, 1806 OperationState &result) { 1807 auto &builder = parser.getBuilder(); 1808 LLVMType type; 1809 OpAsmParser::OperandType ptr, cmp, val; 1810 if (parser.parseOperand(ptr) || parser.parseComma() || 1811 parser.parseOperand(cmp) || parser.parseComma() || 1812 parser.parseOperand(val) || 1813 parseAtomicOrdering(parser, result, "success_ordering") || 1814 parseAtomicOrdering(parser, result, "failure_ordering") || 1815 parser.parseOptionalAttrDict(result.attributes) || 1816 parser.parseColonType(type) || 1817 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1818 parser.resolveOperand(cmp, type, result.operands) || 1819 parser.resolveOperand(val, type, result.operands)) 1820 return failure(); 1821 1822 auto boolType = LLVMType::getInt1Ty(builder.getContext()); 1823 auto resultType = LLVMType::getStructTy(type, boolType); 1824 result.addTypes(resultType); 1825 1826 return success(); 1827 } 1828 1829 static LogicalResult verify(AtomicCmpXchgOp op) { 1830 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1831 if (!ptrType.isPointerTy()) 1832 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1833 auto cmpType = op.cmp().getType().cast<LLVM::LLVMType>(); 1834 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1835 if (cmpType != ptrType.getPointerElementTy() || cmpType != valType) 1836 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1837 "match type for all other operands"); 1838 if (!valType.isPointerTy() && !valType.isIntegerTy(8) && 1839 !valType.isIntegerTy(16) && !valType.isIntegerTy(32) && 1840 !valType.isIntegerTy(64) && !valType.isBFloatTy() && 1841 !valType.isHalfTy() && !valType.isFloatTy() && !valType.isDoubleTy()) 1842 return op.emitOpError("unexpected LLVM IR type"); 1843 if (op.success_ordering() < AtomicOrdering::monotonic || 1844 op.failure_ordering() < AtomicOrdering::monotonic) 1845 return op.emitOpError("ordering must be at least 'monotonic'"); 1846 if (op.failure_ordering() == AtomicOrdering::release || 1847 op.failure_ordering() == AtomicOrdering::acq_rel) 1848 return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 1849 return success(); 1850 } 1851 1852 //===----------------------------------------------------------------------===// 1853 // Printer, parser and verifier for LLVM::FenceOp. 1854 //===----------------------------------------------------------------------===// 1855 1856 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 1857 // attribute-dict? 1858 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) { 1859 StringAttr sScope; 1860 StringRef syncscopeKeyword = "syncscope"; 1861 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 1862 if (parser.parseLParen() || 1863 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 1864 parser.parseRParen()) 1865 return failure(); 1866 } else { 1867 result.addAttribute(syncscopeKeyword, 1868 parser.getBuilder().getStringAttr("")); 1869 } 1870 if (parseAtomicOrdering(parser, result, "ordering") || 1871 parser.parseOptionalAttrDict(result.attributes)) 1872 return failure(); 1873 return success(); 1874 } 1875 1876 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) { 1877 StringRef syncscopeKeyword = "syncscope"; 1878 p << op.getOperationName() << ' '; 1879 if (!op->getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 1880 p << "syncscope(" << op->getAttr(syncscopeKeyword) << ") "; 1881 p << stringifyAtomicOrdering(op.ordering()); 1882 } 1883 1884 static LogicalResult verify(FenceOp &op) { 1885 if (op.ordering() == AtomicOrdering::not_atomic || 1886 op.ordering() == AtomicOrdering::unordered || 1887 op.ordering() == AtomicOrdering::monotonic) 1888 return op.emitOpError("can be given only acquire, release, acq_rel, " 1889 "and seq_cst orderings"); 1890 return success(); 1891 } 1892 1893 //===----------------------------------------------------------------------===// 1894 // LLVMDialect initialization, type parsing, and registration. 1895 //===----------------------------------------------------------------------===// 1896 1897 void LLVMDialect::initialize() { 1898 // clang-format off 1899 addTypes<LLVMVoidType, 1900 LLVMHalfType, 1901 LLVMBFloatType, 1902 LLVMFloatType, 1903 LLVMDoubleType, 1904 LLVMFP128Type, 1905 LLVMX86FP80Type, 1906 LLVMPPCFP128Type, 1907 LLVMX86MMXType, 1908 LLVMTokenType, 1909 LLVMLabelType, 1910 LLVMMetadataType, 1911 LLVMFunctionType, 1912 LLVMIntegerType, 1913 LLVMPointerType, 1914 LLVMFixedVectorType, 1915 LLVMScalableVectorType, 1916 LLVMArrayType, 1917 LLVMStructType>(); 1918 // clang-format on 1919 addOperations< 1920 #define GET_OP_LIST 1921 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1922 >(); 1923 1924 // Support unknown operations because not all LLVM operations are registered. 1925 allowUnknownOperations(); 1926 } 1927 1928 #define GET_OP_CLASSES 1929 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1930 1931 /// Parse a type registered to this dialect. 1932 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 1933 return detail::parseType(parser); 1934 } 1935 1936 /// Print a type registered to this dialect. 1937 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 1938 return detail::printType(type.cast<LLVMType>(), os); 1939 } 1940 1941 LogicalResult LLVMDialect::verifyDataLayoutString( 1942 StringRef descr, llvm::function_ref<void(const Twine &)> reportError) { 1943 llvm::Expected<llvm::DataLayout> maybeDataLayout = 1944 llvm::DataLayout::parse(descr); 1945 if (maybeDataLayout) 1946 return success(); 1947 1948 std::string message; 1949 llvm::raw_string_ostream messageStream(message); 1950 llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream); 1951 reportError("invalid data layout descriptor: " + messageStream.str()); 1952 return failure(); 1953 } 1954 1955 /// Verify LLVM dialect attributes. 1956 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op, 1957 NamedAttribute attr) { 1958 // If the data layout attribute is present, it must use the LLVM data layout 1959 // syntax. Try parsing it and report errors in case of failure. Users of this 1960 // attribute may assume it is well-formed and can pass it to the (asserting) 1961 // llvm::DataLayout constructor. 1962 if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName()) 1963 return success(); 1964 if (auto stringAttr = attr.second.dyn_cast<StringAttr>()) 1965 return verifyDataLayoutString( 1966 stringAttr.getValue(), 1967 [op](const Twine &message) { op->emitOpError() << message.str(); }); 1968 1969 return op->emitOpError() << "expected '" 1970 << LLVM::LLVMDialect::getDataLayoutAttrName() 1971 << "' to be a string attribute"; 1972 } 1973 1974 /// Verify LLVMIR function argument attributes. 1975 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 1976 unsigned regionIdx, 1977 unsigned argIdx, 1978 NamedAttribute argAttr) { 1979 // Check that llvm.noalias is a boolean attribute. 1980 if (argAttr.first == LLVMDialect::getNoAliasAttrName() && 1981 !argAttr.second.isa<BoolAttr>()) 1982 return op->emitError() 1983 << "llvm.noalias argument attribute of non boolean type"; 1984 // Check that llvm.align is an integer attribute. 1985 if (argAttr.first == LLVMDialect::getAlignAttrName() && 1986 !argAttr.second.isa<IntegerAttr>()) 1987 return op->emitError() 1988 << "llvm.align argument attribute of non integer type"; 1989 return success(); 1990 } 1991 1992 //===----------------------------------------------------------------------===// 1993 // Utility functions. 1994 //===----------------------------------------------------------------------===// 1995 1996 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 1997 StringRef name, StringRef value, 1998 LLVM::Linkage linkage) { 1999 assert(builder.getInsertionBlock() && 2000 builder.getInsertionBlock()->getParentOp() && 2001 "expected builder to point to a block constrained in an op"); 2002 auto module = 2003 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 2004 assert(module && "builder points to an op outside of a module"); 2005 2006 // Create the global at the entry of the module. 2007 OpBuilder moduleBuilder(module.getBodyRegion()); 2008 MLIRContext *ctx = builder.getContext(); 2009 auto type = 2010 LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(ctx), value.size()); 2011 auto global = moduleBuilder.create<LLVM::GlobalOp>( 2012 loc, type, /*isConstant=*/true, linkage, name, 2013 builder.getStringAttr(value)); 2014 2015 // Get the pointer to the first character in the global string. 2016 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 2017 Value cst0 = builder.create<LLVM::ConstantOp>( 2018 loc, LLVM::LLVMType::getInt64Ty(ctx), 2019 builder.getIntegerAttr(builder.getIndexType(), 0)); 2020 return builder.create<LLVM::GEPOp>(loc, LLVM::LLVMType::getInt8PtrTy(ctx), 2021 globalPtr, ValueRange{cst0, cst0}); 2022 } 2023 2024 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 2025 return op->hasTrait<OpTrait::SymbolTable>() && 2026 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 2027 } 2028