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