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(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 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 // Printing/parsing for LLVM::CallOp. 535 //===----------------------------------------------------------------------===// 536 537 static void printCallOp(OpAsmPrinter &p, CallOp &op) { 538 auto callee = op.callee(); 539 bool isDirect = callee.hasValue(); 540 541 // Print the direct callee if present as a function attribute, or an indirect 542 // callee (first operand) otherwise. 543 p << op.getOperationName() << ' '; 544 if (isDirect) 545 p.printSymbolName(callee.getValue()); 546 else 547 p << op.getOperand(0); 548 549 auto args = op.getOperands().drop_front(isDirect ? 0 : 1); 550 p << '(' << args << ')'; 551 p.printOptionalAttrDict(op.getAttrs(), {"callee"}); 552 553 // Reconstruct the function MLIR function type from operand and result types. 554 p << " : " 555 << FunctionType::get(args.getTypes(), op.getResultTypes(), op.getContext()); 556 } 557 558 // <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)` 559 // attribute-dict? `:` function-type 560 static ParseResult parseCallOp(OpAsmParser &parser, OperationState &result) { 561 SmallVector<OpAsmParser::OperandType, 8> operands; 562 Type type; 563 SymbolRefAttr funcAttr; 564 llvm::SMLoc trailingTypeLoc; 565 566 // Parse an operand list that will, in practice, contain 0 or 1 operand. In 567 // case of an indirect call, there will be 1 operand before `(`. In case of a 568 // direct call, there will be no operands and the parser will stop at the 569 // function identifier without complaining. 570 if (parser.parseOperandList(operands)) 571 return failure(); 572 bool isDirect = operands.empty(); 573 574 // Optionally parse a function identifier. 575 if (isDirect) 576 if (parser.parseAttribute(funcAttr, "callee", result.attributes)) 577 return failure(); 578 579 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || 580 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 581 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 582 return failure(); 583 584 auto funcType = type.dyn_cast<FunctionType>(); 585 if (!funcType) 586 return parser.emitError(trailingTypeLoc, "expected function type"); 587 if (isDirect) { 588 // Make sure types match. 589 if (parser.resolveOperands(operands, funcType.getInputs(), 590 parser.getNameLoc(), result.operands)) 591 return failure(); 592 result.addTypes(funcType.getResults()); 593 } else { 594 // Construct the LLVM IR Dialect function type that the first operand 595 // should match. 596 if (funcType.getNumResults() > 1) 597 return parser.emitError(trailingTypeLoc, 598 "expected function with 0 or 1 result"); 599 600 Builder &builder = parser.getBuilder(); 601 LLVM::LLVMType llvmResultType; 602 if (funcType.getNumResults() == 0) { 603 llvmResultType = LLVM::LLVMType::getVoidTy(builder.getContext()); 604 } else { 605 llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>(); 606 if (!llvmResultType) 607 return parser.emitError(trailingTypeLoc, 608 "expected result to have LLVM type"); 609 } 610 611 SmallVector<LLVM::LLVMType, 8> argTypes; 612 argTypes.reserve(funcType.getNumInputs()); 613 for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) { 614 auto argType = funcType.getInput(i).dyn_cast<LLVM::LLVMType>(); 615 if (!argType) 616 return parser.emitError(trailingTypeLoc, 617 "expected LLVM types as inputs"); 618 argTypes.push_back(argType); 619 } 620 auto llvmFuncType = LLVM::LLVMType::getFunctionTy(llvmResultType, argTypes, 621 /*isVarArg=*/false); 622 auto wrappedFuncType = llvmFuncType.getPointerTo(); 623 624 auto funcArguments = 625 ArrayRef<OpAsmParser::OperandType>(operands).drop_front(); 626 627 // Make sure that the first operand (indirect callee) matches the wrapped 628 // LLVM IR function type, and that the types of the other call operands 629 // match the types of the function arguments. 630 if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || 631 parser.resolveOperands(funcArguments, funcType.getInputs(), 632 parser.getNameLoc(), result.operands)) 633 return failure(); 634 635 result.addTypes(llvmResultType); 636 } 637 638 return success(); 639 } 640 641 //===----------------------------------------------------------------------===// 642 // Printing/parsing for LLVM::ExtractElementOp. 643 //===----------------------------------------------------------------------===// 644 // Expects vector to be of wrapped LLVM vector type and position to be of 645 // wrapped LLVM i32 type. 646 void LLVM::ExtractElementOp::build(OpBuilder &b, OperationState &result, 647 Value vector, Value position, 648 ArrayRef<NamedAttribute> attrs) { 649 auto wrappedVectorType = vector.getType().cast<LLVM::LLVMType>(); 650 auto llvmType = wrappedVectorType.getVectorElementType(); 651 build(b, result, llvmType, vector, position); 652 result.addAttributes(attrs); 653 } 654 655 static void printExtractElementOp(OpAsmPrinter &p, ExtractElementOp &op) { 656 p << op.getOperationName() << ' ' << op.vector() << "[" << op.position() 657 << " : " << op.position().getType() << "]"; 658 p.printOptionalAttrDict(op.getAttrs()); 659 p << " : " << op.vector().getType(); 660 } 661 662 // <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use 663 // attribute-dict? `:` type 664 static ParseResult parseExtractElementOp(OpAsmParser &parser, 665 OperationState &result) { 666 llvm::SMLoc loc; 667 OpAsmParser::OperandType vector, position; 668 Type type, positionType; 669 if (parser.getCurrentLocation(&loc) || parser.parseOperand(vector) || 670 parser.parseLSquare() || parser.parseOperand(position) || 671 parser.parseColonType(positionType) || parser.parseRSquare() || 672 parser.parseOptionalAttrDict(result.attributes) || 673 parser.parseColonType(type) || 674 parser.resolveOperand(vector, type, result.operands) || 675 parser.resolveOperand(position, positionType, result.operands)) 676 return failure(); 677 auto wrappedVectorType = type.dyn_cast<LLVM::LLVMType>(); 678 if (!wrappedVectorType || !wrappedVectorType.isVectorTy()) 679 return parser.emitError( 680 loc, "expected LLVM IR dialect vector type for operand #1"); 681 result.addTypes(wrappedVectorType.getVectorElementType()); 682 return success(); 683 } 684 685 //===----------------------------------------------------------------------===// 686 // Printing/parsing for LLVM::ExtractValueOp. 687 //===----------------------------------------------------------------------===// 688 689 static void printExtractValueOp(OpAsmPrinter &p, ExtractValueOp &op) { 690 p << op.getOperationName() << ' ' << op.container() << op.position(); 691 p.printOptionalAttrDict(op.getAttrs(), {"position"}); 692 p << " : " << op.container().getType(); 693 } 694 695 // Extract the type at `position` in the wrapped LLVM IR aggregate type 696 // `containerType`. Position is an integer array attribute where each value 697 // is a zero-based position of the element in the aggregate type. Return the 698 // resulting type wrapped in MLIR, or nullptr on error. 699 static LLVM::LLVMType getInsertExtractValueElementType(OpAsmParser &parser, 700 Type containerType, 701 ArrayAttr positionAttr, 702 llvm::SMLoc attributeLoc, 703 llvm::SMLoc typeLoc) { 704 auto wrappedContainerType = containerType.dyn_cast<LLVM::LLVMType>(); 705 if (!wrappedContainerType) 706 return parser.emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr; 707 708 // Infer the element type from the structure type: iteratively step inside the 709 // type by taking the element type, indexed by the position attribute for 710 // structures. Check the position index before accessing, it is supposed to 711 // be in bounds. 712 for (Attribute subAttr : positionAttr) { 713 auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>(); 714 if (!positionElementAttr) 715 return parser.emitError(attributeLoc, 716 "expected an array of integer literals"), 717 nullptr; 718 int position = positionElementAttr.getInt(); 719 if (wrappedContainerType.isArrayTy()) { 720 if (position < 0 || static_cast<unsigned>(position) >= 721 wrappedContainerType.getArrayNumElements()) 722 return parser.emitError(attributeLoc, "position out of bounds"), 723 nullptr; 724 wrappedContainerType = wrappedContainerType.getArrayElementType(); 725 } else if (wrappedContainerType.isStructTy()) { 726 if (position < 0 || static_cast<unsigned>(position) >= 727 wrappedContainerType.getStructNumElements()) 728 return parser.emitError(attributeLoc, "position out of bounds"), 729 nullptr; 730 wrappedContainerType = 731 wrappedContainerType.getStructElementType(position); 732 } else { 733 return parser.emitError(typeLoc, 734 "expected wrapped LLVM IR structure/array type"), 735 nullptr; 736 } 737 } 738 return wrappedContainerType; 739 } 740 741 // <operation> ::= `llvm.extractvalue` ssa-use 742 // `[` integer-literal (`,` integer-literal)* `]` 743 // attribute-dict? `:` type 744 static ParseResult parseExtractValueOp(OpAsmParser &parser, 745 OperationState &result) { 746 OpAsmParser::OperandType container; 747 Type containerType; 748 ArrayAttr positionAttr; 749 llvm::SMLoc attributeLoc, trailingTypeLoc; 750 751 if (parser.parseOperand(container) || 752 parser.getCurrentLocation(&attributeLoc) || 753 parser.parseAttribute(positionAttr, "position", result.attributes) || 754 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 755 parser.getCurrentLocation(&trailingTypeLoc) || 756 parser.parseType(containerType) || 757 parser.resolveOperand(container, containerType, result.operands)) 758 return failure(); 759 760 auto elementType = getInsertExtractValueElementType( 761 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 762 if (!elementType) 763 return failure(); 764 765 result.addTypes(elementType); 766 return success(); 767 } 768 769 //===----------------------------------------------------------------------===// 770 // Printing/parsing for LLVM::InsertElementOp. 771 //===----------------------------------------------------------------------===// 772 773 static void printInsertElementOp(OpAsmPrinter &p, InsertElementOp &op) { 774 p << op.getOperationName() << ' ' << op.value() << ", " << op.vector() << "[" 775 << op.position() << " : " << op.position().getType() << "]"; 776 p.printOptionalAttrDict(op.getAttrs()); 777 p << " : " << op.vector().getType(); 778 } 779 780 // <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use 781 // attribute-dict? `:` type 782 static ParseResult parseInsertElementOp(OpAsmParser &parser, 783 OperationState &result) { 784 llvm::SMLoc loc; 785 OpAsmParser::OperandType vector, value, position; 786 Type vectorType, positionType; 787 if (parser.getCurrentLocation(&loc) || parser.parseOperand(value) || 788 parser.parseComma() || parser.parseOperand(vector) || 789 parser.parseLSquare() || parser.parseOperand(position) || 790 parser.parseColonType(positionType) || parser.parseRSquare() || 791 parser.parseOptionalAttrDict(result.attributes) || 792 parser.parseColonType(vectorType)) 793 return failure(); 794 795 auto wrappedVectorType = vectorType.dyn_cast<LLVM::LLVMType>(); 796 if (!wrappedVectorType || !wrappedVectorType.isVectorTy()) 797 return parser.emitError( 798 loc, "expected LLVM IR dialect vector type for operand #1"); 799 auto valueType = wrappedVectorType.getVectorElementType(); 800 if (!valueType) 801 return failure(); 802 803 if (parser.resolveOperand(vector, vectorType, result.operands) || 804 parser.resolveOperand(value, valueType, result.operands) || 805 parser.resolveOperand(position, positionType, result.operands)) 806 return failure(); 807 808 result.addTypes(vectorType); 809 return success(); 810 } 811 812 //===----------------------------------------------------------------------===// 813 // Printing/parsing for LLVM::InsertValueOp. 814 //===----------------------------------------------------------------------===// 815 816 static void printInsertValueOp(OpAsmPrinter &p, InsertValueOp &op) { 817 p << op.getOperationName() << ' ' << op.value() << ", " << op.container() 818 << op.position(); 819 p.printOptionalAttrDict(op.getAttrs(), {"position"}); 820 p << " : " << op.container().getType(); 821 } 822 823 // <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use 824 // `[` integer-literal (`,` integer-literal)* `]` 825 // attribute-dict? `:` type 826 static ParseResult parseInsertValueOp(OpAsmParser &parser, 827 OperationState &result) { 828 OpAsmParser::OperandType container, value; 829 Type containerType; 830 ArrayAttr positionAttr; 831 llvm::SMLoc attributeLoc, trailingTypeLoc; 832 833 if (parser.parseOperand(value) || parser.parseComma() || 834 parser.parseOperand(container) || 835 parser.getCurrentLocation(&attributeLoc) || 836 parser.parseAttribute(positionAttr, "position", result.attributes) || 837 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 838 parser.getCurrentLocation(&trailingTypeLoc) || 839 parser.parseType(containerType)) 840 return failure(); 841 842 auto valueType = getInsertExtractValueElementType( 843 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 844 if (!valueType) 845 return failure(); 846 847 if (parser.resolveOperand(container, containerType, result.operands) || 848 parser.resolveOperand(value, valueType, result.operands)) 849 return failure(); 850 851 result.addTypes(containerType); 852 return success(); 853 } 854 855 //===----------------------------------------------------------------------===// 856 // Printing/parsing for LLVM::ReturnOp. 857 //===----------------------------------------------------------------------===// 858 859 static void printReturnOp(OpAsmPrinter &p, ReturnOp &op) { 860 p << op.getOperationName(); 861 p.printOptionalAttrDict(op.getAttrs()); 862 assert(op.getNumOperands() <= 1); 863 864 if (op.getNumOperands() == 0) 865 return; 866 867 p << ' ' << op.getOperand(0) << " : " << op.getOperand(0).getType(); 868 } 869 870 // <operation> ::= `llvm.return` ssa-use-list attribute-dict? `:` 871 // type-list-no-parens 872 static ParseResult parseReturnOp(OpAsmParser &parser, OperationState &result) { 873 SmallVector<OpAsmParser::OperandType, 1> operands; 874 Type type; 875 876 if (parser.parseOperandList(operands) || 877 parser.parseOptionalAttrDict(result.attributes)) 878 return failure(); 879 if (operands.empty()) 880 return success(); 881 882 if (parser.parseColonType(type) || 883 parser.resolveOperand(operands[0], type, result.operands)) 884 return failure(); 885 return success(); 886 } 887 888 //===----------------------------------------------------------------------===// 889 // Verifier for LLVM::AddressOfOp. 890 //===----------------------------------------------------------------------===// 891 892 template <typename OpTy> 893 static OpTy lookupSymbolInModule(Operation *parent, StringRef name) { 894 Operation *module = parent; 895 while (module && !satisfiesLLVMModule(module)) 896 module = module->getParentOp(); 897 assert(module && "unexpected operation outside of a module"); 898 return dyn_cast_or_null<OpTy>( 899 mlir::SymbolTable::lookupSymbolIn(module, name)); 900 } 901 902 GlobalOp AddressOfOp::getGlobal() { 903 return lookupSymbolInModule<LLVM::GlobalOp>(getParentOp(), global_name()); 904 } 905 906 LLVMFuncOp AddressOfOp::getFunction() { 907 return lookupSymbolInModule<LLVM::LLVMFuncOp>(getParentOp(), global_name()); 908 } 909 910 static LogicalResult verify(AddressOfOp op) { 911 auto global = op.getGlobal(); 912 auto function = op.getFunction(); 913 if (!global && !function) 914 return op.emitOpError( 915 "must reference a global defined by 'llvm.mlir.global' or 'llvm.func'"); 916 917 if (global && global.getType().getPointerTo(global.addr_space()) != 918 op.getResult().getType()) 919 return op.emitOpError( 920 "the type must be a pointer to the type of the referenced global"); 921 922 if (function && function.getType().getPointerTo() != op.getResult().getType()) 923 return op.emitOpError( 924 "the type must be a pointer to the type of the referenced function"); 925 926 return success(); 927 } 928 929 //===----------------------------------------------------------------------===// 930 // Builder, printer and verifier for LLVM::GlobalOp. 931 //===----------------------------------------------------------------------===// 932 933 /// Returns the name used for the linkage attribute. This *must* correspond to 934 /// the name of the attribute in ODS. 935 static StringRef getLinkageAttrName() { return "linkage"; } 936 937 void GlobalOp::build(OpBuilder &builder, OperationState &result, LLVMType type, 938 bool isConstant, Linkage linkage, StringRef name, 939 Attribute value, unsigned addrSpace, 940 ArrayRef<NamedAttribute> attrs) { 941 result.addAttribute(SymbolTable::getSymbolAttrName(), 942 builder.getStringAttr(name)); 943 result.addAttribute("type", TypeAttr::get(type)); 944 if (isConstant) 945 result.addAttribute("constant", builder.getUnitAttr()); 946 if (value) 947 result.addAttribute("value", value); 948 result.addAttribute(getLinkageAttrName(), 949 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 950 if (addrSpace != 0) 951 result.addAttribute("addr_space", builder.getI32IntegerAttr(addrSpace)); 952 result.attributes.append(attrs.begin(), attrs.end()); 953 result.addRegion(); 954 } 955 956 static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) { 957 p << op.getOperationName() << ' ' << stringifyLinkage(op.linkage()) << ' '; 958 if (op.constant()) 959 p << "constant "; 960 p.printSymbolName(op.sym_name()); 961 p << '('; 962 if (auto value = op.getValueOrNull()) 963 p.printAttribute(value); 964 p << ')'; 965 p.printOptionalAttrDict(op.getAttrs(), 966 {SymbolTable::getSymbolAttrName(), "type", "constant", 967 "value", getLinkageAttrName()}); 968 969 // Print the trailing type unless it's a string global. 970 if (op.getValueOrNull().dyn_cast_or_null<StringAttr>()) 971 return; 972 p << " : " << op.type(); 973 974 Region &initializer = op.getInitializerRegion(); 975 if (!initializer.empty()) 976 p.printRegion(initializer, /*printEntryBlockArgs=*/false); 977 } 978 979 //===----------------------------------------------------------------------===// 980 // Verifier for LLVM::DialectCastOp. 981 //===----------------------------------------------------------------------===// 982 983 static LogicalResult verify(DialectCastOp op) { 984 auto verifyMLIRCastType = [&op](Type type) -> LogicalResult { 985 if (auto llvmType = type.dyn_cast<LLVM::LLVMType>()) { 986 if (llvmType.isVectorTy()) 987 llvmType = llvmType.getVectorElementType(); 988 if (llvmType.isIntegerTy() || llvmType.isBFloatTy() || 989 llvmType.isHalfTy() || llvmType.isFloatTy() || 990 llvmType.isDoubleTy()) { 991 return success(); 992 } 993 return op.emitOpError("type must be non-index integer types, float " 994 "types, or vector of mentioned types."); 995 } 996 if (auto vectorType = type.dyn_cast<VectorType>()) { 997 if (vectorType.getShape().size() > 1) 998 return op.emitOpError("only 1-d vector is allowed"); 999 type = vectorType.getElementType(); 1000 } 1001 if (type.isSignlessIntOrFloat()) 1002 return success(); 1003 // Note that memrefs are not supported. We currently don't have a use case 1004 // for it, but even if we do, there are challenges: 1005 // * if we allow memrefs to cast from/to memref descriptors, then the 1006 // semantics of the cast op depends on the implementation detail of the 1007 // descriptor. 1008 // * if we allow memrefs to cast from/to bare pointers, some users might 1009 // alternatively want metadata that only present in the descriptor. 1010 // 1011 // TODO: re-evaluate the memref cast design when it's needed. 1012 return op.emitOpError("type must be non-index integer types, float types, " 1013 "or vector of mentioned types."); 1014 }; 1015 return failure(failed(verifyMLIRCastType(op.in().getType())) || 1016 failed(verifyMLIRCastType(op.getType()))); 1017 } 1018 1019 // Parses one of the keywords provided in the list `keywords` and returns the 1020 // position of the parsed keyword in the list. If none of the keywords from the 1021 // list is parsed, returns -1. 1022 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 1023 ArrayRef<StringRef> keywords) { 1024 for (auto en : llvm::enumerate(keywords)) { 1025 if (succeeded(parser.parseOptionalKeyword(en.value()))) 1026 return en.index(); 1027 } 1028 return -1; 1029 } 1030 1031 namespace { 1032 template <typename Ty> struct EnumTraits {}; 1033 1034 #define REGISTER_ENUM_TYPE(Ty) \ 1035 template <> struct EnumTraits<Ty> { \ 1036 static StringRef stringify(Ty value) { return stringify##Ty(value); } \ 1037 static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ 1038 } 1039 1040 REGISTER_ENUM_TYPE(Linkage); 1041 } // end namespace 1042 1043 template <typename EnumTy> 1044 static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser, 1045 OperationState &result, 1046 StringRef name) { 1047 SmallVector<StringRef, 10> names; 1048 for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i) 1049 names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); 1050 1051 int index = parseOptionalKeywordAlternative(parser, names); 1052 if (index == -1) 1053 return failure(); 1054 result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index)); 1055 return success(); 1056 } 1057 1058 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier 1059 // `(` attribute? `)` attribute-list? (`:` type)? region? 1060 // 1061 // The type can be omitted for string attributes, in which case it will be 1062 // inferred from the value of the string as [strlen(value) x i8]. 1063 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) { 1064 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1065 getLinkageAttrName()))) 1066 result.addAttribute(getLinkageAttrName(), 1067 parser.getBuilder().getI64IntegerAttr( 1068 static_cast<int64_t>(LLVM::Linkage::External))); 1069 1070 if (succeeded(parser.parseOptionalKeyword("constant"))) 1071 result.addAttribute("constant", parser.getBuilder().getUnitAttr()); 1072 1073 StringAttr name; 1074 if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), 1075 result.attributes) || 1076 parser.parseLParen()) 1077 return failure(); 1078 1079 Attribute value; 1080 if (parser.parseOptionalRParen()) { 1081 if (parser.parseAttribute(value, "value", result.attributes) || 1082 parser.parseRParen()) 1083 return failure(); 1084 } 1085 1086 SmallVector<Type, 1> types; 1087 if (parser.parseOptionalAttrDict(result.attributes) || 1088 parser.parseOptionalColonTypeList(types)) 1089 return failure(); 1090 1091 if (types.size() > 1) 1092 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1093 1094 Region &initRegion = *result.addRegion(); 1095 if (types.empty()) { 1096 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1097 MLIRContext *context = parser.getBuilder().getContext(); 1098 auto arrayType = LLVM::LLVMType::getArrayTy( 1099 LLVM::LLVMType::getInt8Ty(context), strAttr.getValue().size()); 1100 types.push_back(arrayType); 1101 } else { 1102 return parser.emitError(parser.getNameLoc(), 1103 "type can only be omitted for string globals"); 1104 } 1105 } else if (parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1106 /*argTypes=*/{})) { 1107 return failure(); 1108 } 1109 1110 result.addAttribute("type", TypeAttr::get(types[0])); 1111 return success(); 1112 } 1113 1114 static LogicalResult verify(GlobalOp op) { 1115 if (!LLVMPointerType::isValidElementType(op.getType())) 1116 return op.emitOpError( 1117 "expects type to be a valid element type for an LLVM pointer"); 1118 if (op.getParentOp() && !satisfiesLLVMModule(op.getParentOp())) 1119 return op.emitOpError("must appear at the module level"); 1120 1121 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1122 auto type = op.getType(); 1123 if (!type.isArrayTy() || !type.getArrayElementType().isIntegerTy(8) || 1124 type.getArrayNumElements() != strAttr.getValue().size()) 1125 return op.emitOpError( 1126 "requires an i8 array type of the length equal to that of the string " 1127 "attribute"); 1128 } 1129 1130 if (Block *b = op.getInitializerBlock()) { 1131 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1132 if (ret.operand_type_begin() == ret.operand_type_end()) 1133 return op.emitOpError("initializer region cannot return void"); 1134 if (*ret.operand_type_begin() != op.getType()) 1135 return op.emitOpError("initializer region type ") 1136 << *ret.operand_type_begin() << " does not match global type " 1137 << op.getType(); 1138 1139 if (op.getValueOrNull()) 1140 return op.emitOpError("cannot have both initializer value and region"); 1141 } 1142 return success(); 1143 } 1144 1145 //===----------------------------------------------------------------------===// 1146 // Printing/parsing for LLVM::ShuffleVectorOp. 1147 //===----------------------------------------------------------------------===// 1148 // Expects vector to be of wrapped LLVM vector type and position to be of 1149 // wrapped LLVM i32 type. 1150 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 1151 Value v1, Value v2, ArrayAttr mask, 1152 ArrayRef<NamedAttribute> attrs) { 1153 auto wrappedContainerType1 = v1.getType().cast<LLVM::LLVMType>(); 1154 auto vType = LLVMType::getVectorTy( 1155 wrappedContainerType1.getVectorElementType(), mask.size()); 1156 build(b, result, vType, v1, v2, mask); 1157 result.addAttributes(attrs); 1158 } 1159 1160 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1161 p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " " 1162 << op.mask(); 1163 p.printOptionalAttrDict(op.getAttrs(), {"mask"}); 1164 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1165 } 1166 1167 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1168 // `[` integer-literal (`,` integer-literal)* `]` 1169 // attribute-dict? `:` type 1170 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1171 OperationState &result) { 1172 llvm::SMLoc loc; 1173 OpAsmParser::OperandType v1, v2; 1174 ArrayAttr maskAttr; 1175 Type typeV1, typeV2; 1176 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1177 parser.parseComma() || parser.parseOperand(v2) || 1178 parser.parseAttribute(maskAttr, "mask", result.attributes) || 1179 parser.parseOptionalAttrDict(result.attributes) || 1180 parser.parseColonType(typeV1) || parser.parseComma() || 1181 parser.parseType(typeV2) || 1182 parser.resolveOperand(v1, typeV1, result.operands) || 1183 parser.resolveOperand(v2, typeV2, result.operands)) 1184 return failure(); 1185 auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>(); 1186 if (!wrappedContainerType1 || !wrappedContainerType1.isVectorTy()) 1187 return parser.emitError( 1188 loc, "expected LLVM IR dialect vector type for operand #1"); 1189 auto vType = LLVMType::getVectorTy( 1190 wrappedContainerType1.getVectorElementType(), maskAttr.size()); 1191 result.addTypes(vType); 1192 return success(); 1193 } 1194 1195 //===----------------------------------------------------------------------===// 1196 // Implementations for LLVM::LLVMFuncOp. 1197 //===----------------------------------------------------------------------===// 1198 1199 // Add the entry block to the function. 1200 Block *LLVMFuncOp::addEntryBlock() { 1201 assert(empty() && "function already has an entry block"); 1202 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1203 1204 auto *entry = new Block; 1205 push_back(entry); 1206 1207 LLVMType type = getType(); 1208 for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i) 1209 entry->addArgument(type.getFunctionParamType(i)); 1210 return entry; 1211 } 1212 1213 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 1214 StringRef name, LLVMType type, LLVM::Linkage linkage, 1215 ArrayRef<NamedAttribute> attrs, 1216 ArrayRef<MutableDictionaryAttr> argAttrs) { 1217 result.addRegion(); 1218 result.addAttribute(SymbolTable::getSymbolAttrName(), 1219 builder.getStringAttr(name)); 1220 result.addAttribute("type", TypeAttr::get(type)); 1221 result.addAttribute(getLinkageAttrName(), 1222 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1223 result.attributes.append(attrs.begin(), attrs.end()); 1224 if (argAttrs.empty()) 1225 return; 1226 1227 unsigned numInputs = type.getFunctionNumParams(); 1228 assert(numInputs == argAttrs.size() && 1229 "expected as many argument attribute lists as arguments"); 1230 SmallString<8> argAttrName; 1231 for (unsigned i = 0; i < numInputs; ++i) 1232 if (auto argDict = argAttrs[i].getDictionary(builder.getContext())) 1233 result.addAttribute(getArgAttrName(i, argAttrName), argDict); 1234 } 1235 1236 // Builds an LLVM function type from the given lists of input and output types. 1237 // Returns a null type if any of the types provided are non-LLVM types, or if 1238 // there is more than one output type. 1239 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1240 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1241 impl::VariadicFlag variadicFlag) { 1242 Builder &b = parser.getBuilder(); 1243 if (outputs.size() > 1) { 1244 parser.emitError(loc, "failed to construct function type: expected zero or " 1245 "one function result"); 1246 return {}; 1247 } 1248 1249 // Convert inputs to LLVM types, exit early on error. 1250 SmallVector<LLVMType, 4> llvmInputs; 1251 for (auto t : inputs) { 1252 auto llvmTy = t.dyn_cast<LLVMType>(); 1253 if (!llvmTy) { 1254 parser.emitError(loc, "failed to construct function type: expected LLVM " 1255 "type for function arguments"); 1256 return {}; 1257 } 1258 llvmInputs.push_back(llvmTy); 1259 } 1260 1261 // No output is denoted as "void" in LLVM type system. 1262 LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(b.getContext()) 1263 : outputs.front().dyn_cast<LLVMType>(); 1264 if (!llvmOutput) { 1265 parser.emitError(loc, "failed to construct function type: expected LLVM " 1266 "type for function results"); 1267 return {}; 1268 } 1269 return LLVMType::getFunctionTy(llvmOutput, llvmInputs, 1270 variadicFlag.isVariadic()); 1271 } 1272 1273 // Parses an LLVM function. 1274 // 1275 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1276 // function-body 1277 // 1278 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1279 OperationState &result) { 1280 // Default to external linkage if no keyword is provided. 1281 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1282 getLinkageAttrName()))) 1283 result.addAttribute(getLinkageAttrName(), 1284 parser.getBuilder().getI64IntegerAttr( 1285 static_cast<int64_t>(LLVM::Linkage::External))); 1286 1287 StringAttr nameAttr; 1288 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1289 SmallVector<NamedAttrList, 1> argAttrs; 1290 SmallVector<NamedAttrList, 1> resultAttrs; 1291 SmallVector<Type, 8> argTypes; 1292 SmallVector<Type, 4> resultTypes; 1293 bool isVariadic; 1294 1295 auto signatureLocation = parser.getCurrentLocation(); 1296 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1297 result.attributes) || 1298 impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs, 1299 argTypes, argAttrs, isVariadic, resultTypes, 1300 resultAttrs)) 1301 return failure(); 1302 1303 auto type = 1304 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1305 impl::VariadicFlag(isVariadic)); 1306 if (!type) 1307 return failure(); 1308 result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type)); 1309 1310 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1311 return failure(); 1312 impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs, 1313 resultAttrs); 1314 1315 auto *body = result.addRegion(); 1316 return parser.parseOptionalRegion( 1317 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1318 } 1319 1320 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1321 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1322 // the external linkage since it is the default value. 1323 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1324 p << op.getOperationName() << ' '; 1325 if (op.linkage() != LLVM::Linkage::External) 1326 p << stringifyLinkage(op.linkage()) << ' '; 1327 p.printSymbolName(op.getName()); 1328 1329 LLVMType fnType = op.getType(); 1330 SmallVector<Type, 8> argTypes; 1331 SmallVector<Type, 1> resTypes; 1332 argTypes.reserve(fnType.getFunctionNumParams()); 1333 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i) 1334 argTypes.push_back(fnType.getFunctionParamType(i)); 1335 1336 LLVMType returnType = fnType.getFunctionResultType(); 1337 if (!returnType.isVoidTy()) 1338 resTypes.push_back(returnType); 1339 1340 impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes); 1341 impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(), 1342 {getLinkageAttrName()}); 1343 1344 // Print the body if this is not an external function. 1345 Region &body = op.body(); 1346 if (!body.empty()) 1347 p.printRegion(body, /*printEntryBlockArgs=*/false, 1348 /*printBlockTerminators=*/true); 1349 } 1350 1351 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1352 // attribute is present. This can check for preconditions of the 1353 // getNumArguments hook not failing. 1354 LogicalResult LLVMFuncOp::verifyType() { 1355 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>(); 1356 if (!llvmType || !llvmType.isFunctionTy()) 1357 return emitOpError("requires '" + getTypeAttrName() + 1358 "' attribute of wrapped LLVM function type"); 1359 1360 return success(); 1361 } 1362 1363 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1364 // Depends on the type attribute being correct as checked by verifyType 1365 unsigned LLVMFuncOp::getNumFuncArguments() { 1366 return getType().getFunctionNumParams(); 1367 } 1368 1369 // Hook for OpTrait::FunctionLike, returns the number of function results. 1370 // Depends on the type attribute being correct as checked by verifyType 1371 unsigned LLVMFuncOp::getNumFuncResults() { 1372 // We model LLVM functions that return void as having zero results, 1373 // and all others as having one result. 1374 // If we modeled a void return as one result, then it would be possible to 1375 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1376 // would assign to that. 1377 if (getType().getFunctionResultType().isVoidTy()) 1378 return 0; 1379 return 1; 1380 } 1381 1382 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1383 // - functions don't have 'common' linkage 1384 // - external functions have 'external' or 'extern_weak' linkage; 1385 // - vararg is (currently) only supported for external functions; 1386 // - entry block arguments are of LLVM types and match the function signature. 1387 static LogicalResult verify(LLVMFuncOp op) { 1388 if (op.linkage() == LLVM::Linkage::Common) 1389 return op.emitOpError() 1390 << "functions cannot have '" 1391 << stringifyLinkage(LLVM::Linkage::Common) << "' linkage"; 1392 1393 if (op.isExternal()) { 1394 if (op.linkage() != LLVM::Linkage::External && 1395 op.linkage() != LLVM::Linkage::ExternWeak) 1396 return op.emitOpError() 1397 << "external functions must have '" 1398 << stringifyLinkage(LLVM::Linkage::External) << "' or '" 1399 << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage"; 1400 return success(); 1401 } 1402 1403 if (op.isVarArg()) 1404 return op.emitOpError("only external functions can be variadic"); 1405 1406 unsigned numArguments = op.getType().getFunctionNumParams(); 1407 Block &entryBlock = op.front(); 1408 for (unsigned i = 0; i < numArguments; ++i) { 1409 Type argType = entryBlock.getArgument(i).getType(); 1410 auto argLLVMType = argType.dyn_cast<LLVMType>(); 1411 if (!argLLVMType) 1412 return op.emitOpError("entry block argument #") 1413 << i << " is not of LLVM type"; 1414 if (op.getType().getFunctionParamType(i) != argLLVMType) 1415 return op.emitOpError("the type of entry block argument #") 1416 << i << " does not match the function signature"; 1417 } 1418 1419 return success(); 1420 } 1421 1422 //===----------------------------------------------------------------------===// 1423 // Verification for LLVM::NullOp. 1424 //===----------------------------------------------------------------------===// 1425 1426 // Only LLVM pointer types are supported. 1427 static LogicalResult verify(LLVM::NullOp op) { 1428 auto llvmType = op.getType().dyn_cast<LLVM::LLVMType>(); 1429 if (!llvmType || !llvmType.isPointerTy()) 1430 return op.emitOpError("expected LLVM IR pointer type"); 1431 return success(); 1432 } 1433 1434 //===----------------------------------------------------------------------===// 1435 // Verification for LLVM::ConstantOp. 1436 //===----------------------------------------------------------------------===// 1437 1438 static LogicalResult verify(LLVM::ConstantOp op) { 1439 if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() || 1440 op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>())) 1441 return op.emitOpError() 1442 << "only supports integer, float, string or elements attributes"; 1443 return success(); 1444 } 1445 1446 //===----------------------------------------------------------------------===// 1447 // Utility functions for parsing atomic ops 1448 //===----------------------------------------------------------------------===// 1449 1450 // Helper function to parse a keyword into the specified attribute named by 1451 // `attrName`. The keyword must match one of the string values defined by the 1452 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 1453 // state. 1454 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 1455 StringRef attrName) { 1456 llvm::SMLoc loc; 1457 StringRef keyword; 1458 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 1459 return failure(); 1460 1461 // Replace the keyword `keyword` with an integer attribute. 1462 auto kind = symbolizeAtomicBinOp(keyword); 1463 if (!kind) { 1464 return parser.emitError(loc) 1465 << "'" << keyword << "' is an incorrect value of the '" << attrName 1466 << "' attribute"; 1467 } 1468 1469 auto value = static_cast<int64_t>(kind.getValue()); 1470 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1471 result.addAttribute(attrName, attr); 1472 1473 return success(); 1474 } 1475 1476 // Helper function to parse a keyword into the specified attribute named by 1477 // `attrName`. The keyword must match one of the string values defined by the 1478 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 1479 // state. 1480 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 1481 OperationState &result, 1482 StringRef attrName) { 1483 llvm::SMLoc loc; 1484 StringRef ordering; 1485 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 1486 return failure(); 1487 1488 // Replace the keyword `ordering` with an integer attribute. 1489 auto kind = symbolizeAtomicOrdering(ordering); 1490 if (!kind) { 1491 return parser.emitError(loc) 1492 << "'" << ordering << "' is an incorrect value of the '" << attrName 1493 << "' attribute"; 1494 } 1495 1496 auto value = static_cast<int64_t>(kind.getValue()); 1497 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1498 result.addAttribute(attrName, attr); 1499 1500 return success(); 1501 } 1502 1503 //===----------------------------------------------------------------------===// 1504 // Printer, parser and verifier for LLVM::AtomicRMWOp. 1505 //===----------------------------------------------------------------------===// 1506 1507 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) { 1508 p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' 1509 << op.ptr() << ", " << op.val() << ' ' 1510 << stringifyAtomicOrdering(op.ordering()) << ' '; 1511 p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"}); 1512 p << " : " << op.res().getType(); 1513 } 1514 1515 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 1516 // attribute-dict? `:` type 1517 static ParseResult parseAtomicRMWOp(OpAsmParser &parser, 1518 OperationState &result) { 1519 LLVMType type; 1520 OpAsmParser::OperandType ptr, val; 1521 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 1522 parser.parseComma() || parser.parseOperand(val) || 1523 parseAtomicOrdering(parser, result, "ordering") || 1524 parser.parseOptionalAttrDict(result.attributes) || 1525 parser.parseColonType(type) || 1526 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1527 parser.resolveOperand(val, type, result.operands)) 1528 return failure(); 1529 1530 result.addTypes(type); 1531 return success(); 1532 } 1533 1534 static LogicalResult verify(AtomicRMWOp op) { 1535 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1536 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1537 if (valType != ptrType.getPointerElementTy()) 1538 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1539 "match type for operand #1"); 1540 auto resType = op.res().getType().cast<LLVM::LLVMType>(); 1541 if (resType != valType) 1542 return op.emitOpError( 1543 "expected LLVM IR result type to match type for operand #1"); 1544 if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) { 1545 if (!valType.isFloatingPointTy()) 1546 return op.emitOpError("expected LLVM IR floating point type"); 1547 } else if (op.bin_op() == AtomicBinOp::xchg) { 1548 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1549 !valType.isIntegerTy(32) && !valType.isIntegerTy(64) && 1550 !valType.isBFloatTy() && !valType.isHalfTy() && !valType.isFloatTy() && 1551 !valType.isDoubleTy()) 1552 return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 1553 } else { 1554 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1555 !valType.isIntegerTy(32) && !valType.isIntegerTy(64)) 1556 return op.emitOpError("expected LLVM IR integer type"); 1557 } 1558 return success(); 1559 } 1560 1561 //===----------------------------------------------------------------------===// 1562 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 1563 //===----------------------------------------------------------------------===// 1564 1565 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) { 1566 p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", " 1567 << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' ' 1568 << stringifyAtomicOrdering(op.failure_ordering()); 1569 p.printOptionalAttrDict(op.getAttrs(), 1570 {"success_ordering", "failure_ordering"}); 1571 p << " : " << op.val().getType(); 1572 } 1573 1574 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 1575 // keyword keyword attribute-dict? `:` type 1576 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser, 1577 OperationState &result) { 1578 auto &builder = parser.getBuilder(); 1579 LLVMType type; 1580 OpAsmParser::OperandType ptr, cmp, val; 1581 if (parser.parseOperand(ptr) || parser.parseComma() || 1582 parser.parseOperand(cmp) || parser.parseComma() || 1583 parser.parseOperand(val) || 1584 parseAtomicOrdering(parser, result, "success_ordering") || 1585 parseAtomicOrdering(parser, result, "failure_ordering") || 1586 parser.parseOptionalAttrDict(result.attributes) || 1587 parser.parseColonType(type) || 1588 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1589 parser.resolveOperand(cmp, type, result.operands) || 1590 parser.resolveOperand(val, type, result.operands)) 1591 return failure(); 1592 1593 auto boolType = LLVMType::getInt1Ty(builder.getContext()); 1594 auto resultType = LLVMType::getStructTy(type, boolType); 1595 result.addTypes(resultType); 1596 1597 return success(); 1598 } 1599 1600 static LogicalResult verify(AtomicCmpXchgOp op) { 1601 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1602 if (!ptrType.isPointerTy()) 1603 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1604 auto cmpType = op.cmp().getType().cast<LLVM::LLVMType>(); 1605 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1606 if (cmpType != ptrType.getPointerElementTy() || cmpType != valType) 1607 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1608 "match type for all other operands"); 1609 if (!valType.isPointerTy() && !valType.isIntegerTy(8) && 1610 !valType.isIntegerTy(16) && !valType.isIntegerTy(32) && 1611 !valType.isIntegerTy(64) && !valType.isBFloatTy() && 1612 !valType.isHalfTy() && !valType.isFloatTy() && !valType.isDoubleTy()) 1613 return op.emitOpError("unexpected LLVM IR type"); 1614 if (op.success_ordering() < AtomicOrdering::monotonic || 1615 op.failure_ordering() < AtomicOrdering::monotonic) 1616 return op.emitOpError("ordering must be at least 'monotonic'"); 1617 if (op.failure_ordering() == AtomicOrdering::release || 1618 op.failure_ordering() == AtomicOrdering::acq_rel) 1619 return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 1620 return success(); 1621 } 1622 1623 //===----------------------------------------------------------------------===// 1624 // Printer, parser and verifier for LLVM::FenceOp. 1625 //===----------------------------------------------------------------------===// 1626 1627 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 1628 // attribute-dict? 1629 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) { 1630 StringAttr sScope; 1631 StringRef syncscopeKeyword = "syncscope"; 1632 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 1633 if (parser.parseLParen() || 1634 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 1635 parser.parseRParen()) 1636 return failure(); 1637 } else { 1638 result.addAttribute(syncscopeKeyword, 1639 parser.getBuilder().getStringAttr("")); 1640 } 1641 if (parseAtomicOrdering(parser, result, "ordering") || 1642 parser.parseOptionalAttrDict(result.attributes)) 1643 return failure(); 1644 return success(); 1645 } 1646 1647 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) { 1648 StringRef syncscopeKeyword = "syncscope"; 1649 p << op.getOperationName() << ' '; 1650 if (!op.getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 1651 p << "syncscope(" << op.getAttr(syncscopeKeyword) << ") "; 1652 p << stringifyAtomicOrdering(op.ordering()); 1653 } 1654 1655 static LogicalResult verify(FenceOp &op) { 1656 if (op.ordering() == AtomicOrdering::not_atomic || 1657 op.ordering() == AtomicOrdering::unordered || 1658 op.ordering() == AtomicOrdering::monotonic) 1659 return op.emitOpError("can be given only acquire, release, acq_rel, " 1660 "and seq_cst orderings"); 1661 return success(); 1662 } 1663 1664 //===----------------------------------------------------------------------===// 1665 // LLVMDialect initialization, type parsing, and registration. 1666 //===----------------------------------------------------------------------===// 1667 1668 void LLVMDialect::initialize() { 1669 // clang-format off 1670 addTypes<LLVMVoidType, 1671 LLVMHalfType, 1672 LLVMBFloatType, 1673 LLVMFloatType, 1674 LLVMDoubleType, 1675 LLVMFP128Type, 1676 LLVMX86FP80Type, 1677 LLVMPPCFP128Type, 1678 LLVMX86MMXType, 1679 LLVMTokenType, 1680 LLVMLabelType, 1681 LLVMMetadataType, 1682 LLVMFunctionType, 1683 LLVMIntegerType, 1684 LLVMPointerType, 1685 LLVMFixedVectorType, 1686 LLVMScalableVectorType, 1687 LLVMArrayType, 1688 LLVMStructType>(); 1689 // clang-format on 1690 addOperations< 1691 #define GET_OP_LIST 1692 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1693 >(); 1694 1695 // Support unknown operations because not all LLVM operations are registered. 1696 allowUnknownOperations(); 1697 } 1698 1699 #define GET_OP_CLASSES 1700 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1701 1702 /// Parse a type registered to this dialect. 1703 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 1704 return detail::parseType(parser); 1705 } 1706 1707 /// Print a type registered to this dialect. 1708 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 1709 return detail::printType(type.cast<LLVMType>(), os); 1710 } 1711 1712 LogicalResult LLVMDialect::verifyDataLayoutString( 1713 StringRef descr, llvm::function_ref<void(const Twine &)> reportError) { 1714 llvm::Expected<llvm::DataLayout> maybeDataLayout = 1715 llvm::DataLayout::parse(descr); 1716 if (maybeDataLayout) 1717 return success(); 1718 1719 std::string message; 1720 llvm::raw_string_ostream messageStream(message); 1721 llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream); 1722 reportError("invalid data layout descriptor: " + messageStream.str()); 1723 return failure(); 1724 } 1725 1726 /// Verify LLVM dialect attributes. 1727 LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op, 1728 NamedAttribute attr) { 1729 // If the data layout attribute is present, it must use the LLVM data layout 1730 // syntax. Try parsing it and report errors in case of failure. Users of this 1731 // attribute may assume it is well-formed and can pass it to the (asserting) 1732 // llvm::DataLayout constructor. 1733 if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName()) 1734 return success(); 1735 if (auto stringAttr = attr.second.dyn_cast<StringAttr>()) 1736 return verifyDataLayoutString( 1737 stringAttr.getValue(), 1738 [op](const Twine &message) { op->emitOpError() << message.str(); }); 1739 1740 return op->emitOpError() << "expected '" 1741 << LLVM::LLVMDialect::getDataLayoutAttrName() 1742 << "' to be a string attribute"; 1743 } 1744 1745 /// Verify LLVMIR function argument attributes. 1746 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 1747 unsigned regionIdx, 1748 unsigned argIdx, 1749 NamedAttribute argAttr) { 1750 // Check that llvm.noalias is a boolean attribute. 1751 if (argAttr.first == "llvm.noalias" && !argAttr.second.isa<BoolAttr>()) 1752 return op->emitError() 1753 << "llvm.noalias argument attribute of non boolean type"; 1754 // Check that llvm.align is an integer attribute. 1755 if (argAttr.first == "llvm.align" && !argAttr.second.isa<IntegerAttr>()) 1756 return op->emitError() 1757 << "llvm.align argument attribute of non integer type"; 1758 return success(); 1759 } 1760 1761 //===----------------------------------------------------------------------===// 1762 // Utility functions. 1763 //===----------------------------------------------------------------------===// 1764 1765 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 1766 StringRef name, StringRef value, 1767 LLVM::Linkage linkage) { 1768 assert(builder.getInsertionBlock() && 1769 builder.getInsertionBlock()->getParentOp() && 1770 "expected builder to point to a block constrained in an op"); 1771 auto module = 1772 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 1773 assert(module && "builder points to an op outside of a module"); 1774 1775 // Create the global at the entry of the module. 1776 OpBuilder moduleBuilder(module.getBodyRegion()); 1777 MLIRContext *ctx = builder.getContext(); 1778 auto type = 1779 LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(ctx), value.size()); 1780 auto global = moduleBuilder.create<LLVM::GlobalOp>( 1781 loc, type, /*isConstant=*/true, linkage, name, 1782 builder.getStringAttr(value)); 1783 1784 // Get the pointer to the first character in the global string. 1785 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 1786 Value cst0 = builder.create<LLVM::ConstantOp>( 1787 loc, LLVM::LLVMType::getInt64Ty(ctx), 1788 builder.getIntegerAttr(builder.getIndexType(), 0)); 1789 return builder.create<LLVM::GEPOp>(loc, LLVM::LLVMType::getInt8PtrTy(ctx), 1790 globalPtr, ArrayRef<Value>({cst0, cst0})); 1791 } 1792 1793 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 1794 return op->hasTrait<OpTrait::SymbolTable>() && 1795 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 1796 } 1797