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/IR/Builders.h" 15 #include "mlir/IR/DialectImplementation.h" 16 #include "mlir/IR/FunctionImplementation.h" 17 #include "mlir/IR/MLIRContext.h" 18 #include "mlir/IR/Module.h" 19 #include "mlir/IR/StandardTypes.h" 20 21 #include "llvm/ADT/StringSwitch.h" 22 #include "llvm/AsmParser/Parser.h" 23 #include "llvm/Bitcode/BitcodeReader.h" 24 #include "llvm/Bitcode/BitcodeWriter.h" 25 #include "llvm/IR/Attributes.h" 26 #include "llvm/IR/Function.h" 27 #include "llvm/IR/Type.h" 28 #include "llvm/Support/Mutex.h" 29 #include "llvm/Support/SourceMgr.h" 30 31 using namespace mlir; 32 using namespace mlir::LLVM; 33 34 static constexpr const char kVolatileAttrName[] = "volatile_"; 35 static constexpr const char kNonTemporalAttrName[] = "nontemporal"; 36 37 #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc" 38 39 //===----------------------------------------------------------------------===// 40 // Printing/parsing for LLVM::CmpOp. 41 //===----------------------------------------------------------------------===// 42 static void printICmpOp(OpAsmPrinter &p, ICmpOp &op) { 43 p << op.getOperationName() << " \"" << stringifyICmpPredicate(op.predicate()) 44 << "\" " << op.getOperand(0) << ", " << op.getOperand(1); 45 p.printOptionalAttrDict(op.getAttrs(), {"predicate"}); 46 p << " : " << op.lhs().getType(); 47 } 48 49 static void printFCmpOp(OpAsmPrinter &p, FCmpOp &op) { 50 p << op.getOperationName() << " \"" << stringifyFCmpPredicate(op.predicate()) 51 << "\" " << op.getOperand(0) << ", " << op.getOperand(1); 52 p.printOptionalAttrDict(op.getAttrs(), {"predicate"}); 53 p << " : " << op.lhs().getType(); 54 } 55 56 // <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use 57 // attribute-dict? `:` type 58 // <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use 59 // attribute-dict? `:` type 60 template <typename CmpPredicateType> 61 static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result) { 62 Builder &builder = parser.getBuilder(); 63 64 StringAttr predicateAttr; 65 OpAsmParser::OperandType lhs, rhs; 66 Type type; 67 llvm::SMLoc predicateLoc, trailingTypeLoc; 68 if (parser.getCurrentLocation(&predicateLoc) || 69 parser.parseAttribute(predicateAttr, "predicate", result.attributes) || 70 parser.parseOperand(lhs) || parser.parseComma() || 71 parser.parseOperand(rhs) || 72 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 73 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type) || 74 parser.resolveOperand(lhs, type, result.operands) || 75 parser.resolveOperand(rhs, type, result.operands)) 76 return failure(); 77 78 // Replace the string attribute `predicate` with an integer attribute. 79 int64_t predicateValue = 0; 80 if (std::is_same<CmpPredicateType, ICmpPredicate>()) { 81 Optional<ICmpPredicate> predicate = 82 symbolizeICmpPredicate(predicateAttr.getValue()); 83 if (!predicate) 84 return parser.emitError(predicateLoc) 85 << "'" << predicateAttr.getValue() 86 << "' is an incorrect value of the 'predicate' attribute"; 87 predicateValue = static_cast<int64_t>(predicate.getValue()); 88 } else { 89 Optional<FCmpPredicate> predicate = 90 symbolizeFCmpPredicate(predicateAttr.getValue()); 91 if (!predicate) 92 return parser.emitError(predicateLoc) 93 << "'" << predicateAttr.getValue() 94 << "' is an incorrect value of the 'predicate' attribute"; 95 predicateValue = static_cast<int64_t>(predicate.getValue()); 96 } 97 98 result.attributes.set("predicate", 99 parser.getBuilder().getI64IntegerAttr(predicateValue)); 100 101 // The result type is either i1 or a vector type <? x i1> if the inputs are 102 // vectors. 103 auto *dialect = builder.getContext()->getRegisteredDialect<LLVMDialect>(); 104 auto resultType = LLVMType::getInt1Ty(dialect); 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()->getSExtValue() != 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(ArrayRef<Type>{}); 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 auto *llvmDialect = 396 builder.getContext()->getRegisteredDialect<LLVM::LLVMDialect>(); 397 LLVM::LLVMType llvmResultType; 398 if (funcType.getNumResults() == 0) { 399 llvmResultType = LLVM::LLVMType::getVoidTy(llvmDialect); 400 } else { 401 llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>(); 402 if (!llvmResultType) 403 return parser.emitError(trailingTypeLoc, 404 "expected result to have LLVM type"); 405 } 406 407 SmallVector<LLVM::LLVMType, 8> argTypes; 408 argTypes.reserve(funcType.getNumInputs()); 409 for (Type ty : funcType.getInputs()) { 410 if (auto argType = ty.dyn_cast<LLVM::LLVMType>()) 411 argTypes.push_back(argType); 412 else 413 return parser.emitError(trailingTypeLoc, 414 "expected LLVM types as inputs"); 415 } 416 417 auto llvmFuncType = LLVM::LLVMType::getFunctionTy(llvmResultType, argTypes, 418 /*isVarArg=*/false); 419 auto wrappedFuncType = llvmFuncType.getPointerTo(); 420 421 auto funcArguments = llvm::makeArrayRef(operands).drop_front(); 422 423 // Make sure that the first operand (indirect callee) matches the wrapped 424 // LLVM IR function type, and that the types of the other call operands 425 // match the types of the function arguments. 426 if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || 427 parser.resolveOperands(funcArguments, funcType.getInputs(), 428 parser.getNameLoc(), result.operands)) 429 return failure(); 430 431 result.addTypes(llvmResultType); 432 } 433 result.addSuccessors({normalDest, unwindDest}); 434 result.addOperands(normalOperands); 435 result.addOperands(unwindOperands); 436 437 result.addAttribute( 438 InvokeOp::getOperandSegmentSizeAttr(), 439 builder.getI32VectorAttr({static_cast<int32_t>(operands.size()), 440 static_cast<int32_t>(normalOperands.size()), 441 static_cast<int32_t>(unwindOperands.size())})); 442 return success(); 443 } 444 445 ///===----------------------------------------------------------------------===// 446 /// Verifying/Printing/Parsing for LLVM::LandingpadOp. 447 ///===----------------------------------------------------------------------===// 448 449 static LogicalResult verify(LandingpadOp op) { 450 Value value; 451 if (LLVMFuncOp func = op.getParentOfType<LLVMFuncOp>()) { 452 if (!func.personality().hasValue()) 453 return op.emitError( 454 "llvm.landingpad needs to be in a function with a personality"); 455 } 456 457 if (!op.cleanup() && op.getOperands().empty()) 458 return op.emitError("landingpad instruction expects at least one clause or " 459 "cleanup attribute"); 460 461 for (unsigned idx = 0, ie = op.getNumOperands(); idx < ie; idx++) { 462 value = op.getOperand(idx); 463 bool isFilter = value.getType().cast<LLVMType>().isArrayTy(); 464 if (isFilter) { 465 // FIXME: Verify filter clauses when arrays are appropriately handled 466 } else { 467 // catch - global addresses only. 468 // Bitcast ops should have global addresses as their args. 469 if (auto bcOp = value.getDefiningOp<BitcastOp>()) { 470 if (auto addrOp = bcOp.arg().getDefiningOp<AddressOfOp>()) 471 continue; 472 return op.emitError("constant clauses expected") 473 .attachNote(bcOp.getLoc()) 474 << "global addresses expected as operand to " 475 "bitcast used in clauses for landingpad"; 476 } 477 // NullOp and AddressOfOp allowed 478 if (value.getDefiningOp<NullOp>()) 479 continue; 480 if (value.getDefiningOp<AddressOfOp>()) 481 continue; 482 return op.emitError("clause #") 483 << idx << " is not a known constant - null, addressof, bitcast"; 484 } 485 } 486 return success(); 487 } 488 489 static void printLandingpadOp(OpAsmPrinter &p, LandingpadOp &op) { 490 p << op.getOperationName() << (op.cleanup() ? " cleanup " : " "); 491 492 // Clauses 493 for (auto value : op.getOperands()) { 494 // Similar to llvm - if clause is an array type then it is filter 495 // clause else catch clause 496 bool isArrayTy = value.getType().cast<LLVMType>().isArrayTy(); 497 p << '(' << (isArrayTy ? "filter " : "catch ") << value << " : " 498 << value.getType() << ") "; 499 } 500 501 p.printOptionalAttrDict(op.getAttrs(), {"cleanup"}); 502 503 p << ": " << op.getType(); 504 } 505 506 /// <operation> ::= `llvm.landingpad` `cleanup`? 507 /// ((`catch` | `filter`) operand-type ssa-use)* attribute-dict? 508 static ParseResult parseLandingpadOp(OpAsmParser &parser, 509 OperationState &result) { 510 // Check for cleanup 511 if (succeeded(parser.parseOptionalKeyword("cleanup"))) 512 result.addAttribute("cleanup", parser.getBuilder().getUnitAttr()); 513 514 // Parse clauses with types 515 while (succeeded(parser.parseOptionalLParen()) && 516 (succeeded(parser.parseOptionalKeyword("filter")) || 517 succeeded(parser.parseOptionalKeyword("catch")))) { 518 OpAsmParser::OperandType operand; 519 Type ty; 520 if (parser.parseOperand(operand) || parser.parseColon() || 521 parser.parseType(ty) || 522 parser.resolveOperand(operand, ty, result.operands) || 523 parser.parseRParen()) 524 return failure(); 525 } 526 527 Type type; 528 if (parser.parseColon() || parser.parseType(type)) 529 return failure(); 530 531 result.addTypes(type); 532 return success(); 533 } 534 535 //===----------------------------------------------------------------------===// 536 // Printing/parsing for LLVM::CallOp. 537 //===----------------------------------------------------------------------===// 538 539 static void printCallOp(OpAsmPrinter &p, CallOp &op) { 540 auto callee = op.callee(); 541 bool isDirect = callee.hasValue(); 542 543 // Print the direct callee if present as a function attribute, or an indirect 544 // callee (first operand) otherwise. 545 p << op.getOperationName() << ' '; 546 if (isDirect) 547 p.printSymbolName(callee.getValue()); 548 else 549 p << op.getOperand(0); 550 551 p << '(' << op.getOperands().drop_front(isDirect ? 0 : 1) << ')'; 552 p.printOptionalAttrDict(op.getAttrs(), {"callee"}); 553 554 // Reconstruct the function MLIR function type from operand and result types. 555 SmallVector<Type, 8> argTypes( 556 llvm::drop_begin(op.getOperandTypes(), isDirect ? 0 : 1)); 557 558 p << " : " 559 << FunctionType::get(argTypes, op.getResultTypes(), op.getContext()); 560 } 561 562 // <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)` 563 // attribute-dict? `:` function-type 564 static ParseResult parseCallOp(OpAsmParser &parser, OperationState &result) { 565 SmallVector<OpAsmParser::OperandType, 8> operands; 566 Type type; 567 SymbolRefAttr funcAttr; 568 llvm::SMLoc trailingTypeLoc; 569 570 // Parse an operand list that will, in practice, contain 0 or 1 operand. In 571 // case of an indirect call, there will be 1 operand before `(`. In case of a 572 // direct call, there will be no operands and the parser will stop at the 573 // function identifier without complaining. 574 if (parser.parseOperandList(operands)) 575 return failure(); 576 bool isDirect = operands.empty(); 577 578 // Optionally parse a function identifier. 579 if (isDirect) 580 if (parser.parseAttribute(funcAttr, "callee", result.attributes)) 581 return failure(); 582 583 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || 584 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 585 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 586 return failure(); 587 588 auto funcType = type.dyn_cast<FunctionType>(); 589 if (!funcType) 590 return parser.emitError(trailingTypeLoc, "expected function type"); 591 if (isDirect) { 592 // Make sure types match. 593 if (parser.resolveOperands(operands, funcType.getInputs(), 594 parser.getNameLoc(), result.operands)) 595 return failure(); 596 result.addTypes(funcType.getResults()); 597 } else { 598 // Construct the LLVM IR Dialect function type that the first operand 599 // should match. 600 if (funcType.getNumResults() > 1) 601 return parser.emitError(trailingTypeLoc, 602 "expected function with 0 or 1 result"); 603 604 Builder &builder = parser.getBuilder(); 605 auto *llvmDialect = 606 builder.getContext()->getRegisteredDialect<LLVM::LLVMDialect>(); 607 LLVM::LLVMType llvmResultType; 608 if (funcType.getNumResults() == 0) { 609 llvmResultType = LLVM::LLVMType::getVoidTy(llvmDialect); 610 } else { 611 llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>(); 612 if (!llvmResultType) 613 return parser.emitError(trailingTypeLoc, 614 "expected result to have LLVM type"); 615 } 616 617 SmallVector<LLVM::LLVMType, 8> argTypes; 618 argTypes.reserve(funcType.getNumInputs()); 619 for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) { 620 auto argType = funcType.getInput(i).dyn_cast<LLVM::LLVMType>(); 621 if (!argType) 622 return parser.emitError(trailingTypeLoc, 623 "expected LLVM types as inputs"); 624 argTypes.push_back(argType); 625 } 626 auto llvmFuncType = LLVM::LLVMType::getFunctionTy(llvmResultType, argTypes, 627 /*isVarArg=*/false); 628 auto wrappedFuncType = llvmFuncType.getPointerTo(); 629 630 auto funcArguments = 631 ArrayRef<OpAsmParser::OperandType>(operands).drop_front(); 632 633 // Make sure that the first operand (indirect callee) matches the wrapped 634 // LLVM IR function type, and that the types of the other call operands 635 // match the types of the function arguments. 636 if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || 637 parser.resolveOperands(funcArguments, funcType.getInputs(), 638 parser.getNameLoc(), result.operands)) 639 return failure(); 640 641 result.addTypes(llvmResultType); 642 } 643 644 return success(); 645 } 646 647 //===----------------------------------------------------------------------===// 648 // Printing/parsing for LLVM::ExtractElementOp. 649 //===----------------------------------------------------------------------===// 650 // Expects vector to be of wrapped LLVM vector type and position to be of 651 // wrapped LLVM i32 type. 652 void LLVM::ExtractElementOp::build(OpBuilder &b, OperationState &result, 653 Value vector, Value position, 654 ArrayRef<NamedAttribute> attrs) { 655 auto wrappedVectorType = vector.getType().cast<LLVM::LLVMType>(); 656 auto llvmType = wrappedVectorType.getVectorElementType(); 657 build(b, result, llvmType, vector, position); 658 result.addAttributes(attrs); 659 } 660 661 static void printExtractElementOp(OpAsmPrinter &p, ExtractElementOp &op) { 662 p << op.getOperationName() << ' ' << op.vector() << "[" << op.position() 663 << " : " << op.position().getType() << "]"; 664 p.printOptionalAttrDict(op.getAttrs()); 665 p << " : " << op.vector().getType(); 666 } 667 668 // <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use 669 // attribute-dict? `:` type 670 static ParseResult parseExtractElementOp(OpAsmParser &parser, 671 OperationState &result) { 672 llvm::SMLoc loc; 673 OpAsmParser::OperandType vector, position; 674 Type type, positionType; 675 if (parser.getCurrentLocation(&loc) || parser.parseOperand(vector) || 676 parser.parseLSquare() || parser.parseOperand(position) || 677 parser.parseColonType(positionType) || parser.parseRSquare() || 678 parser.parseOptionalAttrDict(result.attributes) || 679 parser.parseColonType(type) || 680 parser.resolveOperand(vector, type, result.operands) || 681 parser.resolveOperand(position, positionType, result.operands)) 682 return failure(); 683 auto wrappedVectorType = type.dyn_cast<LLVM::LLVMType>(); 684 if (!wrappedVectorType || !wrappedVectorType.isVectorTy()) 685 return parser.emitError( 686 loc, "expected LLVM IR dialect vector type for operand #1"); 687 result.addTypes(wrappedVectorType.getVectorElementType()); 688 return success(); 689 } 690 691 //===----------------------------------------------------------------------===// 692 // Printing/parsing for LLVM::ExtractValueOp. 693 //===----------------------------------------------------------------------===// 694 695 static void printExtractValueOp(OpAsmPrinter &p, ExtractValueOp &op) { 696 p << op.getOperationName() << ' ' << op.container() << op.position(); 697 p.printOptionalAttrDict(op.getAttrs(), {"position"}); 698 p << " : " << op.container().getType(); 699 } 700 701 // Extract the type at `position` in the wrapped LLVM IR aggregate type 702 // `containerType`. Position is an integer array attribute where each value 703 // is a zero-based position of the element in the aggregate type. Return the 704 // resulting type wrapped in MLIR, or nullptr on error. 705 static LLVM::LLVMType getInsertExtractValueElementType(OpAsmParser &parser, 706 Type containerType, 707 ArrayAttr positionAttr, 708 llvm::SMLoc attributeLoc, 709 llvm::SMLoc typeLoc) { 710 auto wrappedContainerType = containerType.dyn_cast<LLVM::LLVMType>(); 711 if (!wrappedContainerType) 712 return parser.emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr; 713 714 // Infer the element type from the structure type: iteratively step inside the 715 // type by taking the element type, indexed by the position attribute for 716 // structures. Check the position index before accessing, it is supposed to 717 // be in bounds. 718 for (Attribute subAttr : positionAttr) { 719 auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>(); 720 if (!positionElementAttr) 721 return parser.emitError(attributeLoc, 722 "expected an array of integer literals"), 723 nullptr; 724 int position = positionElementAttr.getInt(); 725 if (wrappedContainerType.isArrayTy()) { 726 if (position < 0 || static_cast<unsigned>(position) >= 727 wrappedContainerType.getArrayNumElements()) 728 return parser.emitError(attributeLoc, "position out of bounds"), 729 nullptr; 730 wrappedContainerType = wrappedContainerType.getArrayElementType(); 731 } else if (wrappedContainerType.isStructTy()) { 732 if (position < 0 || static_cast<unsigned>(position) >= 733 wrappedContainerType.getStructNumElements()) 734 return parser.emitError(attributeLoc, "position out of bounds"), 735 nullptr; 736 wrappedContainerType = 737 wrappedContainerType.getStructElementType(position); 738 } else { 739 return parser.emitError(typeLoc, 740 "expected wrapped LLVM IR structure/array type"), 741 nullptr; 742 } 743 } 744 return wrappedContainerType; 745 } 746 747 // <operation> ::= `llvm.extractvalue` ssa-use 748 // `[` integer-literal (`,` integer-literal)* `]` 749 // attribute-dict? `:` type 750 static ParseResult parseExtractValueOp(OpAsmParser &parser, 751 OperationState &result) { 752 OpAsmParser::OperandType container; 753 Type containerType; 754 ArrayAttr positionAttr; 755 llvm::SMLoc attributeLoc, trailingTypeLoc; 756 757 if (parser.parseOperand(container) || 758 parser.getCurrentLocation(&attributeLoc) || 759 parser.parseAttribute(positionAttr, "position", result.attributes) || 760 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 761 parser.getCurrentLocation(&trailingTypeLoc) || 762 parser.parseType(containerType) || 763 parser.resolveOperand(container, containerType, result.operands)) 764 return failure(); 765 766 auto elementType = getInsertExtractValueElementType( 767 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 768 if (!elementType) 769 return failure(); 770 771 result.addTypes(elementType); 772 return success(); 773 } 774 775 //===----------------------------------------------------------------------===// 776 // Printing/parsing for LLVM::InsertElementOp. 777 //===----------------------------------------------------------------------===// 778 779 static void printInsertElementOp(OpAsmPrinter &p, InsertElementOp &op) { 780 p << op.getOperationName() << ' ' << op.value() << ", " << op.vector() << "[" 781 << op.position() << " : " << op.position().getType() << "]"; 782 p.printOptionalAttrDict(op.getAttrs()); 783 p << " : " << op.vector().getType(); 784 } 785 786 // <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use 787 // attribute-dict? `:` type 788 static ParseResult parseInsertElementOp(OpAsmParser &parser, 789 OperationState &result) { 790 llvm::SMLoc loc; 791 OpAsmParser::OperandType vector, value, position; 792 Type vectorType, positionType; 793 if (parser.getCurrentLocation(&loc) || parser.parseOperand(value) || 794 parser.parseComma() || parser.parseOperand(vector) || 795 parser.parseLSquare() || parser.parseOperand(position) || 796 parser.parseColonType(positionType) || parser.parseRSquare() || 797 parser.parseOptionalAttrDict(result.attributes) || 798 parser.parseColonType(vectorType)) 799 return failure(); 800 801 auto wrappedVectorType = vectorType.dyn_cast<LLVM::LLVMType>(); 802 if (!wrappedVectorType || !wrappedVectorType.isVectorTy()) 803 return parser.emitError( 804 loc, "expected LLVM IR dialect vector type for operand #1"); 805 auto valueType = wrappedVectorType.getVectorElementType(); 806 if (!valueType) 807 return failure(); 808 809 if (parser.resolveOperand(vector, vectorType, result.operands) || 810 parser.resolveOperand(value, valueType, result.operands) || 811 parser.resolveOperand(position, positionType, result.operands)) 812 return failure(); 813 814 result.addTypes(vectorType); 815 return success(); 816 } 817 818 //===----------------------------------------------------------------------===// 819 // Printing/parsing for LLVM::InsertValueOp. 820 //===----------------------------------------------------------------------===// 821 822 static void printInsertValueOp(OpAsmPrinter &p, InsertValueOp &op) { 823 p << op.getOperationName() << ' ' << op.value() << ", " << op.container() 824 << op.position(); 825 p.printOptionalAttrDict(op.getAttrs(), {"position"}); 826 p << " : " << op.container().getType(); 827 } 828 829 // <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use 830 // `[` integer-literal (`,` integer-literal)* `]` 831 // attribute-dict? `:` type 832 static ParseResult parseInsertValueOp(OpAsmParser &parser, 833 OperationState &result) { 834 OpAsmParser::OperandType container, value; 835 Type containerType; 836 ArrayAttr positionAttr; 837 llvm::SMLoc attributeLoc, trailingTypeLoc; 838 839 if (parser.parseOperand(value) || parser.parseComma() || 840 parser.parseOperand(container) || 841 parser.getCurrentLocation(&attributeLoc) || 842 parser.parseAttribute(positionAttr, "position", result.attributes) || 843 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 844 parser.getCurrentLocation(&trailingTypeLoc) || 845 parser.parseType(containerType)) 846 return failure(); 847 848 auto valueType = getInsertExtractValueElementType( 849 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 850 if (!valueType) 851 return failure(); 852 853 if (parser.resolveOperand(container, containerType, result.operands) || 854 parser.resolveOperand(value, valueType, result.operands)) 855 return failure(); 856 857 result.addTypes(containerType); 858 return success(); 859 } 860 861 //===----------------------------------------------------------------------===// 862 // Printing/parsing for LLVM::ReturnOp. 863 //===----------------------------------------------------------------------===// 864 865 static void printReturnOp(OpAsmPrinter &p, ReturnOp &op) { 866 p << op.getOperationName(); 867 p.printOptionalAttrDict(op.getAttrs()); 868 assert(op.getNumOperands() <= 1); 869 870 if (op.getNumOperands() == 0) 871 return; 872 873 p << ' ' << op.getOperand(0) << " : " << op.getOperand(0).getType(); 874 } 875 876 // <operation> ::= `llvm.return` ssa-use-list attribute-dict? `:` 877 // type-list-no-parens 878 static ParseResult parseReturnOp(OpAsmParser &parser, OperationState &result) { 879 SmallVector<OpAsmParser::OperandType, 1> operands; 880 Type type; 881 882 if (parser.parseOperandList(operands) || 883 parser.parseOptionalAttrDict(result.attributes)) 884 return failure(); 885 if (operands.empty()) 886 return success(); 887 888 if (parser.parseColonType(type) || 889 parser.resolveOperand(operands[0], type, result.operands)) 890 return failure(); 891 return success(); 892 } 893 894 //===----------------------------------------------------------------------===// 895 // Verifier for LLVM::AddressOfOp. 896 //===----------------------------------------------------------------------===// 897 898 template <typename OpTy> 899 static OpTy lookupSymbolInModule(Operation *parent, StringRef name) { 900 Operation *module = parent; 901 while (module && !satisfiesLLVMModule(module)) 902 module = module->getParentOp(); 903 assert(module && "unexpected operation outside of a module"); 904 return dyn_cast_or_null<OpTy>( 905 mlir::SymbolTable::lookupSymbolIn(module, name)); 906 } 907 908 GlobalOp AddressOfOp::getGlobal() { 909 return lookupSymbolInModule<LLVM::GlobalOp>(getParentOp(), global_name()); 910 } 911 912 LLVMFuncOp AddressOfOp::getFunction() { 913 return lookupSymbolInModule<LLVM::LLVMFuncOp>(getParentOp(), global_name()); 914 } 915 916 static LogicalResult verify(AddressOfOp op) { 917 auto global = op.getGlobal(); 918 auto function = op.getFunction(); 919 if (!global && !function) 920 return op.emitOpError( 921 "must reference a global defined by 'llvm.mlir.global' or 'llvm.func'"); 922 923 if (global && 924 global.getType().getPointerTo(global.addr_space().getZExtValue()) != 925 op.getResult().getType()) 926 return op.emitOpError( 927 "the type must be a pointer to the type of the referenced global"); 928 929 if (function && function.getType().getPointerTo() != op.getResult().getType()) 930 return op.emitOpError( 931 "the type must be a pointer to the type of the referenced function"); 932 933 return success(); 934 } 935 936 //===----------------------------------------------------------------------===// 937 // Builder, printer and verifier for LLVM::GlobalOp. 938 //===----------------------------------------------------------------------===// 939 940 /// Returns the name used for the linkage attribute. This *must* correspond to 941 /// the name of the attribute in ODS. 942 static StringRef getLinkageAttrName() { return "linkage"; } 943 944 void GlobalOp::build(OpBuilder &builder, OperationState &result, LLVMType type, 945 bool isConstant, Linkage linkage, StringRef name, 946 Attribute value, unsigned addrSpace, 947 ArrayRef<NamedAttribute> attrs) { 948 result.addAttribute(SymbolTable::getSymbolAttrName(), 949 builder.getStringAttr(name)); 950 result.addAttribute("type", TypeAttr::get(type)); 951 if (isConstant) 952 result.addAttribute("constant", builder.getUnitAttr()); 953 if (value) 954 result.addAttribute("value", value); 955 result.addAttribute(getLinkageAttrName(), 956 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 957 if (addrSpace != 0) 958 result.addAttribute("addr_space", builder.getI32IntegerAttr(addrSpace)); 959 result.attributes.append(attrs.begin(), attrs.end()); 960 result.addRegion(); 961 } 962 963 static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) { 964 p << op.getOperationName() << ' ' << stringifyLinkage(op.linkage()) << ' '; 965 if (op.constant()) 966 p << "constant "; 967 p.printSymbolName(op.sym_name()); 968 p << '('; 969 if (auto value = op.getValueOrNull()) 970 p.printAttribute(value); 971 p << ')'; 972 p.printOptionalAttrDict(op.getAttrs(), 973 {SymbolTable::getSymbolAttrName(), "type", "constant", 974 "value", getLinkageAttrName()}); 975 976 // Print the trailing type unless it's a string global. 977 if (op.getValueOrNull().dyn_cast_or_null<StringAttr>()) 978 return; 979 p << " : " << op.type(); 980 981 Region &initializer = op.getInitializerRegion(); 982 if (!initializer.empty()) 983 p.printRegion(initializer, /*printEntryBlockArgs=*/false); 984 } 985 986 //===----------------------------------------------------------------------===// 987 // Verifier for LLVM::DialectCastOp. 988 //===----------------------------------------------------------------------===// 989 990 static LogicalResult verify(DialectCastOp op) { 991 auto verifyMLIRCastType = [&op](Type type) -> LogicalResult { 992 if (auto llvmType = type.dyn_cast<LLVM::LLVMType>()) { 993 if (llvmType.isVectorTy()) 994 llvmType = llvmType.getVectorElementType(); 995 if (llvmType.isIntegerTy() || llvmType.isBFloatTy() || 996 llvmType.isHalfTy() || llvmType.isFloatTy() || 997 llvmType.isDoubleTy()) { 998 return success(); 999 } 1000 return op.emitOpError("type must be non-index integer types, float " 1001 "types, or vector of mentioned types."); 1002 } 1003 if (auto vectorType = type.dyn_cast<VectorType>()) { 1004 if (vectorType.getShape().size() > 1) 1005 return op.emitOpError("only 1-d vector is allowed"); 1006 type = vectorType.getElementType(); 1007 } 1008 if (type.isSignlessIntOrFloat()) 1009 return success(); 1010 // Note that memrefs are not supported. We currently don't have a use case 1011 // for it, but even if we do, there are challenges: 1012 // * if we allow memrefs to cast from/to memref descriptors, then the 1013 // semantics of the cast op depends on the implementation detail of the 1014 // descriptor. 1015 // * if we allow memrefs to cast from/to bare pointers, some users might 1016 // alternatively want metadata that only present in the descriptor. 1017 // 1018 // TODO: re-evaluate the memref cast design when it's needed. 1019 return op.emitOpError("type must be non-index integer types, float types, " 1020 "or vector of mentioned types."); 1021 }; 1022 return failure(failed(verifyMLIRCastType(op.in().getType())) || 1023 failed(verifyMLIRCastType(op.getType()))); 1024 } 1025 1026 // Parses one of the keywords provided in the list `keywords` and returns the 1027 // position of the parsed keyword in the list. If none of the keywords from the 1028 // list is parsed, returns -1. 1029 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 1030 ArrayRef<StringRef> keywords) { 1031 for (auto en : llvm::enumerate(keywords)) { 1032 if (succeeded(parser.parseOptionalKeyword(en.value()))) 1033 return en.index(); 1034 } 1035 return -1; 1036 } 1037 1038 namespace { 1039 template <typename Ty> struct EnumTraits {}; 1040 1041 #define REGISTER_ENUM_TYPE(Ty) \ 1042 template <> struct EnumTraits<Ty> { \ 1043 static StringRef stringify(Ty value) { return stringify##Ty(value); } \ 1044 static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ 1045 } 1046 1047 REGISTER_ENUM_TYPE(Linkage); 1048 } // end namespace 1049 1050 template <typename EnumTy> 1051 static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser, 1052 OperationState &result, 1053 StringRef name) { 1054 SmallVector<StringRef, 10> names; 1055 for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i) 1056 names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); 1057 1058 int index = parseOptionalKeywordAlternative(parser, names); 1059 if (index == -1) 1060 return failure(); 1061 result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index)); 1062 return success(); 1063 } 1064 1065 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier 1066 // `(` attribute? `)` attribute-list? (`:` type)? region? 1067 // 1068 // The type can be omitted for string attributes, in which case it will be 1069 // inferred from the value of the string as [strlen(value) x i8]. 1070 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) { 1071 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1072 getLinkageAttrName()))) 1073 result.addAttribute(getLinkageAttrName(), 1074 parser.getBuilder().getI64IntegerAttr( 1075 static_cast<int64_t>(LLVM::Linkage::External))); 1076 1077 if (succeeded(parser.parseOptionalKeyword("constant"))) 1078 result.addAttribute("constant", parser.getBuilder().getUnitAttr()); 1079 1080 StringAttr name; 1081 if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), 1082 result.attributes) || 1083 parser.parseLParen()) 1084 return failure(); 1085 1086 Attribute value; 1087 if (parser.parseOptionalRParen()) { 1088 if (parser.parseAttribute(value, "value", result.attributes) || 1089 parser.parseRParen()) 1090 return failure(); 1091 } 1092 1093 SmallVector<Type, 1> types; 1094 if (parser.parseOptionalAttrDict(result.attributes) || 1095 parser.parseOptionalColonTypeList(types)) 1096 return failure(); 1097 1098 if (types.size() > 1) 1099 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1100 1101 Region &initRegion = *result.addRegion(); 1102 if (types.empty()) { 1103 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1104 MLIRContext *context = parser.getBuilder().getContext(); 1105 auto *dialect = context->getRegisteredDialect<LLVMDialect>(); 1106 auto arrayType = LLVM::LLVMType::getArrayTy( 1107 LLVM::LLVMType::getInt8Ty(dialect), strAttr.getValue().size()); 1108 types.push_back(arrayType); 1109 } else { 1110 return parser.emitError(parser.getNameLoc(), 1111 "type can only be omitted for string globals"); 1112 } 1113 } else if (parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1114 /*argTypes=*/{})) { 1115 return failure(); 1116 } 1117 1118 result.addAttribute("type", TypeAttr::get(types[0])); 1119 return success(); 1120 } 1121 1122 static LogicalResult verify(GlobalOp op) { 1123 if (!LLVMType::isValidPointerElementType(op.getType())) 1124 return op.emitOpError( 1125 "expects type to be a valid element type for an LLVM pointer"); 1126 if (op.getParentOp() && !satisfiesLLVMModule(op.getParentOp())) 1127 return op.emitOpError("must appear at the module level"); 1128 1129 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1130 auto type = op.getType(); 1131 if (!type.isArrayTy() || !type.getArrayElementType().isIntegerTy(8) || 1132 type.getArrayNumElements() != strAttr.getValue().size()) 1133 return op.emitOpError( 1134 "requires an i8 array type of the length equal to that of the string " 1135 "attribute"); 1136 } 1137 1138 if (Block *b = op.getInitializerBlock()) { 1139 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1140 if (ret.operand_type_begin() == ret.operand_type_end()) 1141 return op.emitOpError("initializer region cannot return void"); 1142 if (*ret.operand_type_begin() != op.getType()) 1143 return op.emitOpError("initializer region type ") 1144 << *ret.operand_type_begin() << " does not match global type " 1145 << op.getType(); 1146 1147 if (op.getValueOrNull()) 1148 return op.emitOpError("cannot have both initializer value and region"); 1149 } 1150 return success(); 1151 } 1152 1153 //===----------------------------------------------------------------------===// 1154 // Printing/parsing for LLVM::ShuffleVectorOp. 1155 //===----------------------------------------------------------------------===// 1156 // Expects vector to be of wrapped LLVM vector type and position to be of 1157 // wrapped LLVM i32 type. 1158 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 1159 Value v1, Value v2, ArrayAttr mask, 1160 ArrayRef<NamedAttribute> attrs) { 1161 auto wrappedContainerType1 = v1.getType().cast<LLVM::LLVMType>(); 1162 auto vType = LLVMType::getVectorTy( 1163 wrappedContainerType1.getVectorElementType(), mask.size()); 1164 build(b, result, vType, v1, v2, mask); 1165 result.addAttributes(attrs); 1166 } 1167 1168 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1169 p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " " 1170 << op.mask(); 1171 p.printOptionalAttrDict(op.getAttrs(), {"mask"}); 1172 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1173 } 1174 1175 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1176 // `[` integer-literal (`,` integer-literal)* `]` 1177 // attribute-dict? `:` type 1178 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1179 OperationState &result) { 1180 llvm::SMLoc loc; 1181 OpAsmParser::OperandType v1, v2; 1182 ArrayAttr maskAttr; 1183 Type typeV1, typeV2; 1184 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1185 parser.parseComma() || parser.parseOperand(v2) || 1186 parser.parseAttribute(maskAttr, "mask", result.attributes) || 1187 parser.parseOptionalAttrDict(result.attributes) || 1188 parser.parseColonType(typeV1) || parser.parseComma() || 1189 parser.parseType(typeV2) || 1190 parser.resolveOperand(v1, typeV1, result.operands) || 1191 parser.resolveOperand(v2, typeV2, result.operands)) 1192 return failure(); 1193 auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>(); 1194 if (!wrappedContainerType1 || !wrappedContainerType1.isVectorTy()) 1195 return parser.emitError( 1196 loc, "expected LLVM IR dialect vector type for operand #1"); 1197 auto vType = LLVMType::getVectorTy( 1198 wrappedContainerType1.getVectorElementType(), maskAttr.size()); 1199 result.addTypes(vType); 1200 return success(); 1201 } 1202 1203 //===----------------------------------------------------------------------===// 1204 // Implementations for LLVM::LLVMFuncOp. 1205 //===----------------------------------------------------------------------===// 1206 1207 // Add the entry block to the function. 1208 Block *LLVMFuncOp::addEntryBlock() { 1209 assert(empty() && "function already has an entry block"); 1210 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1211 1212 auto *entry = new Block; 1213 push_back(entry); 1214 1215 LLVMType type = getType(); 1216 for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i) 1217 entry->addArgument(type.getFunctionParamType(i)); 1218 return entry; 1219 } 1220 1221 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 1222 StringRef name, LLVMType type, LLVM::Linkage linkage, 1223 ArrayRef<NamedAttribute> attrs, 1224 ArrayRef<MutableDictionaryAttr> argAttrs) { 1225 result.addRegion(); 1226 result.addAttribute(SymbolTable::getSymbolAttrName(), 1227 builder.getStringAttr(name)); 1228 result.addAttribute("type", TypeAttr::get(type)); 1229 result.addAttribute(getLinkageAttrName(), 1230 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1231 result.attributes.append(attrs.begin(), attrs.end()); 1232 if (argAttrs.empty()) 1233 return; 1234 1235 unsigned numInputs = type.getFunctionNumParams(); 1236 assert(numInputs == argAttrs.size() && 1237 "expected as many argument attribute lists as arguments"); 1238 SmallString<8> argAttrName; 1239 for (unsigned i = 0; i < numInputs; ++i) 1240 if (auto argDict = argAttrs[i].getDictionary(builder.getContext())) 1241 result.addAttribute(getArgAttrName(i, argAttrName), argDict); 1242 } 1243 1244 // Builds an LLVM function type from the given lists of input and output types. 1245 // Returns a null type if any of the types provided are non-LLVM types, or if 1246 // there is more than one output type. 1247 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1248 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1249 impl::VariadicFlag variadicFlag) { 1250 Builder &b = parser.getBuilder(); 1251 if (outputs.size() > 1) { 1252 parser.emitError(loc, "failed to construct function type: expected zero or " 1253 "one function result"); 1254 return {}; 1255 } 1256 1257 // Convert inputs to LLVM types, exit early on error. 1258 SmallVector<LLVMType, 4> llvmInputs; 1259 for (auto t : inputs) { 1260 auto llvmTy = t.dyn_cast<LLVMType>(); 1261 if (!llvmTy) { 1262 parser.emitError(loc, "failed to construct function type: expected LLVM " 1263 "type for function arguments"); 1264 return {}; 1265 } 1266 llvmInputs.push_back(llvmTy); 1267 } 1268 1269 // Get the dialect from the input type, if any exist. Look it up in the 1270 // context otherwise. 1271 LLVMDialect *dialect = 1272 llvmInputs.empty() ? b.getContext()->getRegisteredDialect<LLVMDialect>() 1273 : &llvmInputs.front().getDialect(); 1274 1275 // No output is denoted as "void" in LLVM type system. 1276 LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(dialect) 1277 : outputs.front().dyn_cast<LLVMType>(); 1278 if (!llvmOutput) { 1279 parser.emitError(loc, "failed to construct function type: expected LLVM " 1280 "type for function results"); 1281 return {}; 1282 } 1283 return LLVMType::getFunctionTy(llvmOutput, llvmInputs, 1284 variadicFlag.isVariadic()); 1285 } 1286 1287 // Parses an LLVM function. 1288 // 1289 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1290 // function-body 1291 // 1292 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1293 OperationState &result) { 1294 // Default to external linkage if no keyword is provided. 1295 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1296 getLinkageAttrName()))) 1297 result.addAttribute(getLinkageAttrName(), 1298 parser.getBuilder().getI64IntegerAttr( 1299 static_cast<int64_t>(LLVM::Linkage::External))); 1300 1301 StringAttr nameAttr; 1302 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1303 SmallVector<NamedAttrList, 1> argAttrs; 1304 SmallVector<NamedAttrList, 1> resultAttrs; 1305 SmallVector<Type, 8> argTypes; 1306 SmallVector<Type, 4> resultTypes; 1307 bool isVariadic; 1308 1309 auto signatureLocation = parser.getCurrentLocation(); 1310 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1311 result.attributes) || 1312 impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs, 1313 argTypes, argAttrs, isVariadic, resultTypes, 1314 resultAttrs)) 1315 return failure(); 1316 1317 auto type = 1318 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1319 impl::VariadicFlag(isVariadic)); 1320 if (!type) 1321 return failure(); 1322 result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type)); 1323 1324 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1325 return failure(); 1326 impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs, 1327 resultAttrs); 1328 1329 auto *body = result.addRegion(); 1330 return parser.parseOptionalRegion( 1331 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1332 } 1333 1334 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1335 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1336 // the external linkage since it is the default value. 1337 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1338 p << op.getOperationName() << ' '; 1339 if (op.linkage() != LLVM::Linkage::External) 1340 p << stringifyLinkage(op.linkage()) << ' '; 1341 p.printSymbolName(op.getName()); 1342 1343 LLVMType fnType = op.getType(); 1344 SmallVector<Type, 8> argTypes; 1345 SmallVector<Type, 1> resTypes; 1346 argTypes.reserve(fnType.getFunctionNumParams()); 1347 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i) 1348 argTypes.push_back(fnType.getFunctionParamType(i)); 1349 1350 LLVMType returnType = fnType.getFunctionResultType(); 1351 if (!returnType.isVoidTy()) 1352 resTypes.push_back(returnType); 1353 1354 impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes); 1355 impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(), 1356 {getLinkageAttrName()}); 1357 1358 // Print the body if this is not an external function. 1359 Region &body = op.body(); 1360 if (!body.empty()) 1361 p.printRegion(body, /*printEntryBlockArgs=*/false, 1362 /*printBlockTerminators=*/true); 1363 } 1364 1365 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1366 // attribute is present. This can check for preconditions of the 1367 // getNumArguments hook not failing. 1368 LogicalResult LLVMFuncOp::verifyType() { 1369 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>(); 1370 if (!llvmType || !llvmType.isFunctionTy()) 1371 return emitOpError("requires '" + getTypeAttrName() + 1372 "' attribute of wrapped LLVM function type"); 1373 1374 return success(); 1375 } 1376 1377 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1378 // Depends on the type attribute being correct as checked by verifyType 1379 unsigned LLVMFuncOp::getNumFuncArguments() { 1380 return getType().getFunctionNumParams(); 1381 } 1382 1383 // Hook for OpTrait::FunctionLike, returns the number of function results. 1384 // Depends on the type attribute being correct as checked by verifyType 1385 unsigned LLVMFuncOp::getNumFuncResults() { 1386 // We model LLVM functions that return void as having zero results, 1387 // and all others as having one result. 1388 // If we modeled a void return as one result, then it would be possible to 1389 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1390 // would assign to that. 1391 if (getType().getFunctionResultType().isVoidTy()) 1392 return 0; 1393 return 1; 1394 } 1395 1396 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1397 // - functions don't have 'common' linkage 1398 // - external functions have 'external' or 'extern_weak' linkage; 1399 // - vararg is (currently) only supported for external functions; 1400 // - entry block arguments are of LLVM types and match the function signature. 1401 static LogicalResult verify(LLVMFuncOp op) { 1402 if (op.linkage() == LLVM::Linkage::Common) 1403 return op.emitOpError() 1404 << "functions cannot have '" 1405 << stringifyLinkage(LLVM::Linkage::Common) << "' linkage"; 1406 1407 if (op.isExternal()) { 1408 if (op.linkage() != LLVM::Linkage::External && 1409 op.linkage() != LLVM::Linkage::ExternWeak) 1410 return op.emitOpError() 1411 << "external functions must have '" 1412 << stringifyLinkage(LLVM::Linkage::External) << "' or '" 1413 << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage"; 1414 return success(); 1415 } 1416 1417 if (op.isVarArg()) 1418 return op.emitOpError("only external functions can be variadic"); 1419 1420 unsigned numArguments = op.getType().getFunctionNumParams(); 1421 Block &entryBlock = op.front(); 1422 for (unsigned i = 0; i < numArguments; ++i) { 1423 Type argType = entryBlock.getArgument(i).getType(); 1424 auto argLLVMType = argType.dyn_cast<LLVMType>(); 1425 if (!argLLVMType) 1426 return op.emitOpError("entry block argument #") 1427 << i << " is not of LLVM type"; 1428 if (op.getType().getFunctionParamType(i) != argLLVMType) 1429 return op.emitOpError("the type of entry block argument #") 1430 << i << " does not match the function signature"; 1431 } 1432 1433 return success(); 1434 } 1435 1436 //===----------------------------------------------------------------------===// 1437 // Verification for LLVM::NullOp. 1438 //===----------------------------------------------------------------------===// 1439 1440 // Only LLVM pointer types are supported. 1441 static LogicalResult verify(LLVM::NullOp op) { 1442 auto llvmType = op.getType().dyn_cast<LLVM::LLVMType>(); 1443 if (!llvmType || !llvmType.isPointerTy()) 1444 return op.emitOpError("expected LLVM IR pointer type"); 1445 return success(); 1446 } 1447 1448 //===----------------------------------------------------------------------===// 1449 // Verification for LLVM::ConstantOp. 1450 //===----------------------------------------------------------------------===// 1451 1452 static LogicalResult verify(LLVM::ConstantOp op) { 1453 if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() || 1454 op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>())) 1455 return op.emitOpError() 1456 << "only supports integer, float, string or elements attributes"; 1457 return success(); 1458 } 1459 1460 //===----------------------------------------------------------------------===// 1461 // Utility functions for parsing atomic ops 1462 //===----------------------------------------------------------------------===// 1463 1464 // Helper function to parse a keyword into the specified attribute named by 1465 // `attrName`. The keyword must match one of the string values defined by the 1466 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 1467 // state. 1468 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 1469 StringRef attrName) { 1470 llvm::SMLoc loc; 1471 StringRef keyword; 1472 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 1473 return failure(); 1474 1475 // Replace the keyword `keyword` with an integer attribute. 1476 auto kind = symbolizeAtomicBinOp(keyword); 1477 if (!kind) { 1478 return parser.emitError(loc) 1479 << "'" << keyword << "' is an incorrect value of the '" << attrName 1480 << "' attribute"; 1481 } 1482 1483 auto value = static_cast<int64_t>(kind.getValue()); 1484 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1485 result.addAttribute(attrName, attr); 1486 1487 return success(); 1488 } 1489 1490 // Helper function to parse a keyword into the specified attribute named by 1491 // `attrName`. The keyword must match one of the string values defined by the 1492 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 1493 // state. 1494 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 1495 OperationState &result, 1496 StringRef attrName) { 1497 llvm::SMLoc loc; 1498 StringRef ordering; 1499 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 1500 return failure(); 1501 1502 // Replace the keyword `ordering` with an integer attribute. 1503 auto kind = symbolizeAtomicOrdering(ordering); 1504 if (!kind) { 1505 return parser.emitError(loc) 1506 << "'" << ordering << "' is an incorrect value of the '" << attrName 1507 << "' attribute"; 1508 } 1509 1510 auto value = static_cast<int64_t>(kind.getValue()); 1511 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1512 result.addAttribute(attrName, attr); 1513 1514 return success(); 1515 } 1516 1517 //===----------------------------------------------------------------------===// 1518 // Printer, parser and verifier for LLVM::AtomicRMWOp. 1519 //===----------------------------------------------------------------------===// 1520 1521 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) { 1522 p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' 1523 << op.ptr() << ", " << op.val() << ' ' 1524 << stringifyAtomicOrdering(op.ordering()) << ' '; 1525 p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"}); 1526 p << " : " << op.res().getType(); 1527 } 1528 1529 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 1530 // attribute-dict? `:` type 1531 static ParseResult parseAtomicRMWOp(OpAsmParser &parser, 1532 OperationState &result) { 1533 LLVMType type; 1534 OpAsmParser::OperandType ptr, val; 1535 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 1536 parser.parseComma() || parser.parseOperand(val) || 1537 parseAtomicOrdering(parser, result, "ordering") || 1538 parser.parseOptionalAttrDict(result.attributes) || 1539 parser.parseColonType(type) || 1540 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1541 parser.resolveOperand(val, type, result.operands)) 1542 return failure(); 1543 1544 result.addTypes(type); 1545 return success(); 1546 } 1547 1548 static LogicalResult verify(AtomicRMWOp op) { 1549 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1550 if (!ptrType.isPointerTy()) 1551 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1552 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1553 if (valType != ptrType.getPointerElementTy()) 1554 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1555 "match type for operand #1"); 1556 auto resType = op.res().getType().cast<LLVM::LLVMType>(); 1557 if (resType != valType) 1558 return op.emitOpError( 1559 "expected LLVM IR result type to match type for operand #1"); 1560 if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) { 1561 if (!valType.isFloatingPointTy()) 1562 return op.emitOpError("expected LLVM IR floating point type"); 1563 } else if (op.bin_op() == AtomicBinOp::xchg) { 1564 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1565 !valType.isIntegerTy(32) && !valType.isIntegerTy(64) && 1566 !valType.isBFloatTy() && !valType.isHalfTy() && !valType.isFloatTy() && 1567 !valType.isDoubleTy()) 1568 return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 1569 } else { 1570 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1571 !valType.isIntegerTy(32) && !valType.isIntegerTy(64)) 1572 return op.emitOpError("expected LLVM IR integer type"); 1573 } 1574 return success(); 1575 } 1576 1577 //===----------------------------------------------------------------------===// 1578 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 1579 //===----------------------------------------------------------------------===// 1580 1581 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) { 1582 p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", " 1583 << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' ' 1584 << stringifyAtomicOrdering(op.failure_ordering()); 1585 p.printOptionalAttrDict(op.getAttrs(), 1586 {"success_ordering", "failure_ordering"}); 1587 p << " : " << op.val().getType(); 1588 } 1589 1590 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 1591 // keyword keyword attribute-dict? `:` type 1592 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser, 1593 OperationState &result) { 1594 auto &builder = parser.getBuilder(); 1595 LLVMType type; 1596 OpAsmParser::OperandType ptr, cmp, val; 1597 if (parser.parseOperand(ptr) || parser.parseComma() || 1598 parser.parseOperand(cmp) || parser.parseComma() || 1599 parser.parseOperand(val) || 1600 parseAtomicOrdering(parser, result, "success_ordering") || 1601 parseAtomicOrdering(parser, result, "failure_ordering") || 1602 parser.parseOptionalAttrDict(result.attributes) || 1603 parser.parseColonType(type) || 1604 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1605 parser.resolveOperand(cmp, type, result.operands) || 1606 parser.resolveOperand(val, type, result.operands)) 1607 return failure(); 1608 1609 auto *dialect = builder.getContext()->getRegisteredDialect<LLVMDialect>(); 1610 auto boolType = LLVMType::getInt1Ty(dialect); 1611 auto resultType = LLVMType::getStructTy(type, boolType); 1612 result.addTypes(resultType); 1613 1614 return success(); 1615 } 1616 1617 static LogicalResult verify(AtomicCmpXchgOp op) { 1618 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1619 if (!ptrType.isPointerTy()) 1620 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1621 auto cmpType = op.cmp().getType().cast<LLVM::LLVMType>(); 1622 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1623 if (cmpType != ptrType.getPointerElementTy() || cmpType != valType) 1624 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1625 "match type for all other operands"); 1626 if (!valType.isPointerTy() && !valType.isIntegerTy(8) && 1627 !valType.isIntegerTy(16) && !valType.isIntegerTy(32) && 1628 !valType.isIntegerTy(64) && !valType.isBFloatTy() && 1629 !valType.isHalfTy() && !valType.isFloatTy() && !valType.isDoubleTy()) 1630 return op.emitOpError("unexpected LLVM IR type"); 1631 if (op.success_ordering() < AtomicOrdering::monotonic || 1632 op.failure_ordering() < AtomicOrdering::monotonic) 1633 return op.emitOpError("ordering must be at least 'monotonic'"); 1634 if (op.failure_ordering() == AtomicOrdering::release || 1635 op.failure_ordering() == AtomicOrdering::acq_rel) 1636 return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 1637 return success(); 1638 } 1639 1640 //===----------------------------------------------------------------------===// 1641 // Printer, parser and verifier for LLVM::FenceOp. 1642 //===----------------------------------------------------------------------===// 1643 1644 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 1645 // attribute-dict? 1646 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) { 1647 StringAttr sScope; 1648 StringRef syncscopeKeyword = "syncscope"; 1649 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 1650 if (parser.parseLParen() || 1651 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 1652 parser.parseRParen()) 1653 return failure(); 1654 } else { 1655 result.addAttribute(syncscopeKeyword, 1656 parser.getBuilder().getStringAttr("")); 1657 } 1658 if (parseAtomicOrdering(parser, result, "ordering") || 1659 parser.parseOptionalAttrDict(result.attributes)) 1660 return failure(); 1661 return success(); 1662 } 1663 1664 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) { 1665 StringRef syncscopeKeyword = "syncscope"; 1666 p << op.getOperationName() << ' '; 1667 if (!op.getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 1668 p << "syncscope(" << op.getAttr(syncscopeKeyword) << ") "; 1669 p << stringifyAtomicOrdering(op.ordering()); 1670 } 1671 1672 static LogicalResult verify(FenceOp &op) { 1673 if (op.ordering() == AtomicOrdering::not_atomic || 1674 op.ordering() == AtomicOrdering::unordered || 1675 op.ordering() == AtomicOrdering::monotonic) 1676 return op.emitOpError("can be given only acquire, release, acq_rel, " 1677 "and seq_cst orderings"); 1678 return success(); 1679 } 1680 1681 //===----------------------------------------------------------------------===// 1682 // LLVMDialect initialization, type parsing, and registration. 1683 //===----------------------------------------------------------------------===// 1684 1685 namespace mlir { 1686 namespace LLVM { 1687 namespace detail { 1688 struct LLVMDialectImpl { 1689 LLVMDialectImpl() : module("LLVMDialectModule", llvmContext) {} 1690 1691 llvm::LLVMContext llvmContext; 1692 llvm::Module module; 1693 1694 /// A set of LLVMTypes that are cached on construction to avoid any lookups or 1695 /// locking. 1696 LLVMType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty; 1697 LLVMType doubleTy, floatTy, bfloatTy, halfTy, fp128Ty, x86_fp80Ty; 1698 LLVMType voidTy; 1699 1700 /// A smart mutex to lock access to the llvm context. Unlike MLIR, LLVM is not 1701 /// multi-threaded and requires locked access to prevent race conditions. 1702 llvm::sys::SmartMutex<true> mutex; 1703 }; 1704 } // end namespace detail 1705 } // end namespace LLVM 1706 } // end namespace mlir 1707 1708 LLVMDialect::LLVMDialect(MLIRContext *context) 1709 : Dialect(getDialectNamespace(), context), 1710 impl(new detail::LLVMDialectImpl()) { 1711 addTypes<LLVMType>(); 1712 addOperations< 1713 #define GET_OP_LIST 1714 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1715 >(); 1716 1717 // Support unknown operations because not all LLVM operations are registered. 1718 allowUnknownOperations(); 1719 1720 // Cache some of the common LLVM types to avoid the need for lookups/locking. 1721 auto &llvmContext = impl->llvmContext; 1722 /// Integer Types. 1723 impl->int1Ty = LLVMType::get(context, llvm::Type::getInt1Ty(llvmContext)); 1724 impl->int8Ty = LLVMType::get(context, llvm::Type::getInt8Ty(llvmContext)); 1725 impl->int16Ty = LLVMType::get(context, llvm::Type::getInt16Ty(llvmContext)); 1726 impl->int32Ty = LLVMType::get(context, llvm::Type::getInt32Ty(llvmContext)); 1727 impl->int64Ty = LLVMType::get(context, llvm::Type::getInt64Ty(llvmContext)); 1728 impl->int128Ty = LLVMType::get(context, llvm::Type::getInt128Ty(llvmContext)); 1729 /// Float Types. 1730 impl->doubleTy = LLVMType::get(context, llvm::Type::getDoubleTy(llvmContext)); 1731 impl->floatTy = LLVMType::get(context, llvm::Type::getFloatTy(llvmContext)); 1732 impl->bfloatTy = LLVMType::get(context, llvm::Type::getBFloatTy(llvmContext)); 1733 impl->halfTy = LLVMType::get(context, llvm::Type::getHalfTy(llvmContext)); 1734 impl->fp128Ty = LLVMType::get(context, llvm::Type::getFP128Ty(llvmContext)); 1735 impl->x86_fp80Ty = 1736 LLVMType::get(context, llvm::Type::getX86_FP80Ty(llvmContext)); 1737 /// Other Types. 1738 impl->voidTy = LLVMType::get(context, llvm::Type::getVoidTy(llvmContext)); 1739 } 1740 1741 LLVMDialect::~LLVMDialect() {} 1742 1743 #define GET_OP_CLASSES 1744 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1745 1746 llvm::LLVMContext &LLVMDialect::getLLVMContext() { return impl->llvmContext; } 1747 llvm::Module &LLVMDialect::getLLVMModule() { return impl->module; } 1748 llvm::sys::SmartMutex<true> &LLVMDialect::getLLVMContextMutex() { 1749 return impl->mutex; 1750 } 1751 1752 /// Parse a type registered to this dialect. 1753 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 1754 StringRef tyData = parser.getFullSymbolSpec(); 1755 1756 // LLVM is not thread-safe, so lock access to it. 1757 llvm::sys::SmartScopedLock<true> lock(impl->mutex); 1758 1759 llvm::SMDiagnostic errorMessage; 1760 llvm::Type *type = llvm::parseType(tyData, errorMessage, impl->module); 1761 if (!type) 1762 return (parser.emitError(parser.getNameLoc(), errorMessage.getMessage()), 1763 nullptr); 1764 return LLVMType::get(getContext(), type); 1765 } 1766 1767 /// Print a type registered to this dialect. 1768 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 1769 auto llvmType = type.dyn_cast<LLVMType>(); 1770 assert(llvmType && "printing wrong type"); 1771 assert(llvmType.getUnderlyingType() && "no underlying LLVM type"); 1772 llvmType.getUnderlyingType()->print(os.getStream()); 1773 } 1774 1775 /// Verify LLVMIR function argument attributes. 1776 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 1777 unsigned regionIdx, 1778 unsigned argIdx, 1779 NamedAttribute argAttr) { 1780 // Check that llvm.noalias is a boolean attribute. 1781 if (argAttr.first == "llvm.noalias" && !argAttr.second.isa<BoolAttr>()) 1782 return op->emitError() 1783 << "llvm.noalias argument attribute of non boolean type"; 1784 // Check that llvm.align is an integer attribute. 1785 if (argAttr.first == "llvm.align" && !argAttr.second.isa<IntegerAttr>()) 1786 return op->emitError() 1787 << "llvm.align argument attribute of non integer type"; 1788 return success(); 1789 } 1790 1791 //===----------------------------------------------------------------------===// 1792 // LLVMType. 1793 //===----------------------------------------------------------------------===// 1794 1795 namespace mlir { 1796 namespace LLVM { 1797 namespace detail { 1798 struct LLVMTypeStorage : public ::mlir::TypeStorage { 1799 LLVMTypeStorage(llvm::Type *ty) : underlyingType(ty) {} 1800 1801 // LLVM types are pointer-unique. 1802 using KeyTy = llvm::Type *; 1803 bool operator==(const KeyTy &key) const { return key == underlyingType; } 1804 1805 static LLVMTypeStorage *construct(TypeStorageAllocator &allocator, 1806 llvm::Type *ty) { 1807 return new (allocator.allocate<LLVMTypeStorage>()) LLVMTypeStorage(ty); 1808 } 1809 1810 llvm::Type *underlyingType; 1811 }; 1812 } // end namespace detail 1813 } // end namespace LLVM 1814 } // end namespace mlir 1815 1816 LLVMType LLVMType::get(MLIRContext *context, llvm::Type *llvmType) { 1817 return Base::get(context, FIRST_LLVM_TYPE, llvmType); 1818 } 1819 1820 /// Get an LLVMType with an llvm type that may cause changes to the underlying 1821 /// llvm context when constructed. 1822 LLVMType LLVMType::getLocked(LLVMDialect *dialect, 1823 function_ref<llvm::Type *()> typeBuilder) { 1824 // Lock access to the llvm context and build the type. 1825 llvm::sys::SmartScopedLock<true> lock(dialect->impl->mutex); 1826 return get(dialect->getContext(), typeBuilder()); 1827 } 1828 1829 LLVMDialect &LLVMType::getDialect() { 1830 return static_cast<LLVMDialect &>(Type::getDialect()); 1831 } 1832 1833 llvm::Type *LLVMType::getUnderlyingType() const { 1834 return getImpl()->underlyingType; 1835 } 1836 1837 void LLVMType::getUnderlyingTypes(ArrayRef<LLVMType> types, 1838 SmallVectorImpl<llvm::Type *> &result) { 1839 result.reserve(result.size() + types.size()); 1840 for (LLVMType ty : types) 1841 result.push_back(ty.getUnderlyingType()); 1842 } 1843 1844 /// Array type utilities. 1845 LLVMType LLVMType::getArrayElementType() { 1846 return get(getContext(), getUnderlyingType()->getArrayElementType()); 1847 } 1848 unsigned LLVMType::getArrayNumElements() { 1849 return getUnderlyingType()->getArrayNumElements(); 1850 } 1851 bool LLVMType::isArrayTy() { return getUnderlyingType()->isArrayTy(); } 1852 1853 /// Vector type utilities. 1854 LLVMType LLVMType::getVectorElementType() { 1855 return get( 1856 getContext(), 1857 llvm::cast<llvm::VectorType>(getUnderlyingType())->getElementType()); 1858 } 1859 unsigned LLVMType::getVectorNumElements() { 1860 return llvm::cast<llvm::FixedVectorType>(getUnderlyingType()) 1861 ->getNumElements(); 1862 } 1863 llvm::ElementCount LLVMType::getVectorElementCount() { 1864 return llvm::cast<llvm::VectorType>(getUnderlyingType())->getElementCount(); 1865 } 1866 bool LLVMType::isVectorTy() { return getUnderlyingType()->isVectorTy(); } 1867 1868 /// Function type utilities. 1869 LLVMType LLVMType::getFunctionParamType(unsigned argIdx) { 1870 return get(getContext(), getUnderlyingType()->getFunctionParamType(argIdx)); 1871 } 1872 unsigned LLVMType::getFunctionNumParams() { 1873 return getUnderlyingType()->getFunctionNumParams(); 1874 } 1875 LLVMType LLVMType::getFunctionResultType() { 1876 return get( 1877 getContext(), 1878 llvm::cast<llvm::FunctionType>(getUnderlyingType())->getReturnType()); 1879 } 1880 bool LLVMType::isFunctionTy() { return getUnderlyingType()->isFunctionTy(); } 1881 bool LLVMType::isFunctionVarArg() { 1882 return getUnderlyingType()->isFunctionVarArg(); 1883 } 1884 1885 /// Pointer type utilities. 1886 LLVMType LLVMType::getPointerTo(unsigned addrSpace) { 1887 // Lock access to the dialect as this may modify the LLVM context. 1888 return getLocked(&getDialect(), [=] { 1889 return getUnderlyingType()->getPointerTo(addrSpace); 1890 }); 1891 } 1892 LLVMType LLVMType::getPointerElementTy() { 1893 return get(getContext(), getUnderlyingType()->getPointerElementType()); 1894 } 1895 bool LLVMType::isPointerTy() { return getUnderlyingType()->isPointerTy(); } 1896 bool LLVMType::isValidPointerElementType(LLVMType type) { 1897 return llvm::PointerType::isValidElementType(type.getUnderlyingType()); 1898 } 1899 1900 /// Struct type utilities. 1901 LLVMType LLVMType::getStructElementType(unsigned i) { 1902 return get(getContext(), getUnderlyingType()->getStructElementType(i)); 1903 } 1904 unsigned LLVMType::getStructNumElements() { 1905 return getUnderlyingType()->getStructNumElements(); 1906 } 1907 bool LLVMType::isStructTy() { return getUnderlyingType()->isStructTy(); } 1908 1909 /// Utilities used to generate floating point types. 1910 LLVMType LLVMType::getDoubleTy(LLVMDialect *dialect) { 1911 return dialect->impl->doubleTy; 1912 } 1913 LLVMType LLVMType::getFloatTy(LLVMDialect *dialect) { 1914 return dialect->impl->floatTy; 1915 } 1916 LLVMType LLVMType::getBFloatTy(LLVMDialect *dialect) { 1917 return dialect->impl->bfloatTy; 1918 } 1919 LLVMType LLVMType::getHalfTy(LLVMDialect *dialect) { 1920 return dialect->impl->halfTy; 1921 } 1922 LLVMType LLVMType::getFP128Ty(LLVMDialect *dialect) { 1923 return dialect->impl->fp128Ty; 1924 } 1925 LLVMType LLVMType::getX86_FP80Ty(LLVMDialect *dialect) { 1926 return dialect->impl->x86_fp80Ty; 1927 } 1928 1929 /// Utilities used to generate integer types. 1930 LLVMType LLVMType::getIntNTy(LLVMDialect *dialect, unsigned numBits) { 1931 switch (numBits) { 1932 case 1: 1933 return dialect->impl->int1Ty; 1934 case 8: 1935 return dialect->impl->int8Ty; 1936 case 16: 1937 return dialect->impl->int16Ty; 1938 case 32: 1939 return dialect->impl->int32Ty; 1940 case 64: 1941 return dialect->impl->int64Ty; 1942 case 128: 1943 return dialect->impl->int128Ty; 1944 default: 1945 break; 1946 } 1947 1948 // Lock access to the dialect as this may modify the LLVM context. 1949 return getLocked(dialect, [=] { 1950 return llvm::Type::getIntNTy(dialect->getLLVMContext(), numBits); 1951 }); 1952 } 1953 1954 /// Utilities used to generate other miscellaneous types. 1955 LLVMType LLVMType::getArrayTy(LLVMType elementType, uint64_t numElements) { 1956 // Lock access to the dialect as this may modify the LLVM context. 1957 return getLocked(&elementType.getDialect(), [=] { 1958 return llvm::ArrayType::get(elementType.getUnderlyingType(), numElements); 1959 }); 1960 } 1961 LLVMType LLVMType::getFunctionTy(LLVMType result, ArrayRef<LLVMType> params, 1962 bool isVarArg) { 1963 SmallVector<llvm::Type *, 8> llvmParams; 1964 for (auto param : params) 1965 llvmParams.push_back(param.getUnderlyingType()); 1966 1967 // Lock access to the dialect as this may modify the LLVM context. 1968 return getLocked(&result.getDialect(), [=] { 1969 return llvm::FunctionType::get(result.getUnderlyingType(), llvmParams, 1970 isVarArg); 1971 }); 1972 } 1973 LLVMType LLVMType::getStructTy(LLVMDialect *dialect, 1974 ArrayRef<LLVMType> elements, bool isPacked) { 1975 SmallVector<llvm::Type *, 8> llvmElements; 1976 for (auto elt : elements) 1977 llvmElements.push_back(elt.getUnderlyingType()); 1978 1979 // Lock access to the dialect as this may modify the LLVM context. 1980 return getLocked(dialect, [=] { 1981 return llvm::StructType::get(dialect->getLLVMContext(), llvmElements, 1982 isPacked); 1983 }); 1984 } 1985 LLVMType LLVMType::createStructTy(LLVMDialect *dialect, 1986 ArrayRef<LLVMType> elements, 1987 Optional<StringRef> name, bool isPacked) { 1988 StringRef sr = name.hasValue() ? *name : ""; 1989 SmallVector<llvm::Type *, 8> llvmElements; 1990 getUnderlyingTypes(elements, llvmElements); 1991 return getLocked(dialect, [=] { 1992 auto *rv = llvm::StructType::create(dialect->getLLVMContext(), sr); 1993 if (!llvmElements.empty()) 1994 rv->setBody(llvmElements, isPacked); 1995 return rv; 1996 }); 1997 } 1998 LLVMType LLVMType::setStructTyBody(LLVMType structType, 1999 ArrayRef<LLVMType> elements, bool isPacked) { 2000 llvm::StructType *st = 2001 llvm::cast<llvm::StructType>(structType.getUnderlyingType()); 2002 SmallVector<llvm::Type *, 8> llvmElements; 2003 getUnderlyingTypes(elements, llvmElements); 2004 return getLocked(&structType.getDialect(), [=] { 2005 st->setBody(llvmElements, isPacked); 2006 return st; 2007 }); 2008 } 2009 LLVMType LLVMType::getVectorTy(LLVMType elementType, unsigned numElements) { 2010 // Lock access to the dialect as this may modify the LLVM context. 2011 return getLocked(&elementType.getDialect(), [=] { 2012 return llvm::FixedVectorType::get(elementType.getUnderlyingType(), 2013 numElements); 2014 }); 2015 } 2016 2017 LLVMType LLVMType::getVoidTy(LLVMDialect *dialect) { 2018 return dialect->impl->voidTy; 2019 } 2020 2021 bool LLVMType::isVoidTy() { return getUnderlyingType()->isVoidTy(); } 2022 2023 llvm::Type *mlir::LLVM::convertLLVMType(LLVMType type) { 2024 return type.getUnderlyingType(); 2025 } 2026 2027 //===----------------------------------------------------------------------===// 2028 // Utility functions. 2029 //===----------------------------------------------------------------------===// 2030 2031 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 2032 StringRef name, StringRef value, 2033 LLVM::Linkage linkage, 2034 LLVM::LLVMDialect *llvmDialect) { 2035 assert(builder.getInsertionBlock() && 2036 builder.getInsertionBlock()->getParentOp() && 2037 "expected builder to point to a block constrained in an op"); 2038 auto module = 2039 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 2040 assert(module && "builder points to an op outside of a module"); 2041 2042 // Create the global at the entry of the module. 2043 OpBuilder moduleBuilder(module.getBodyRegion()); 2044 auto type = LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(llvmDialect), 2045 value.size()); 2046 auto global = moduleBuilder.create<LLVM::GlobalOp>( 2047 loc, type, /*isConstant=*/true, linkage, name, 2048 builder.getStringAttr(value)); 2049 2050 // Get the pointer to the first character in the global string. 2051 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 2052 Value cst0 = builder.create<LLVM::ConstantOp>( 2053 loc, LLVM::LLVMType::getInt64Ty(llvmDialect), 2054 builder.getIntegerAttr(builder.getIndexType(), 0)); 2055 return builder.create<LLVM::GEPOp>(loc, 2056 LLVM::LLVMType::getInt8PtrTy(llvmDialect), 2057 globalPtr, ArrayRef<Value>({cst0, cst0})); 2058 } 2059 2060 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 2061 return op->hasTrait<OpTrait::SymbolTable>() && 2062 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 2063 } 2064 2065 std::unique_ptr<llvm::Module> 2066 mlir::LLVM::cloneModuleIntoNewContext(llvm::LLVMContext *context, 2067 llvm::Module *module) { 2068 SmallVector<char, 1> buffer; 2069 { 2070 llvm::raw_svector_ostream os(buffer); 2071 WriteBitcodeToFile(*module, os); 2072 } 2073 llvm::MemoryBufferRef bufferRef(StringRef(buffer.data(), buffer.size()), 2074 "cloned module buffer"); 2075 return cantFail(parseBitcodeFile(bufferRef, *context)); 2076 } 2077