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()->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 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 && 918 global.getType().getPointerTo(global.addr_space().getZExtValue()) != 919 op.getResult().getType()) 920 return op.emitOpError( 921 "the type must be a pointer to the type of the referenced global"); 922 923 if (function && function.getType().getPointerTo() != op.getResult().getType()) 924 return op.emitOpError( 925 "the type must be a pointer to the type of the referenced function"); 926 927 return success(); 928 } 929 930 //===----------------------------------------------------------------------===// 931 // Builder, printer and verifier for LLVM::GlobalOp. 932 //===----------------------------------------------------------------------===// 933 934 /// Returns the name used for the linkage attribute. This *must* correspond to 935 /// the name of the attribute in ODS. 936 static StringRef getLinkageAttrName() { return "linkage"; } 937 938 void GlobalOp::build(OpBuilder &builder, OperationState &result, LLVMType type, 939 bool isConstant, Linkage linkage, StringRef name, 940 Attribute value, unsigned addrSpace, 941 ArrayRef<NamedAttribute> attrs) { 942 result.addAttribute(SymbolTable::getSymbolAttrName(), 943 builder.getStringAttr(name)); 944 result.addAttribute("type", TypeAttr::get(type)); 945 if (isConstant) 946 result.addAttribute("constant", builder.getUnitAttr()); 947 if (value) 948 result.addAttribute("value", value); 949 result.addAttribute(getLinkageAttrName(), 950 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 951 if (addrSpace != 0) 952 result.addAttribute("addr_space", builder.getI32IntegerAttr(addrSpace)); 953 result.attributes.append(attrs.begin(), attrs.end()); 954 result.addRegion(); 955 } 956 957 static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) { 958 p << op.getOperationName() << ' ' << stringifyLinkage(op.linkage()) << ' '; 959 if (op.constant()) 960 p << "constant "; 961 p.printSymbolName(op.sym_name()); 962 p << '('; 963 if (auto value = op.getValueOrNull()) 964 p.printAttribute(value); 965 p << ')'; 966 p.printOptionalAttrDict(op.getAttrs(), 967 {SymbolTable::getSymbolAttrName(), "type", "constant", 968 "value", getLinkageAttrName()}); 969 970 // Print the trailing type unless it's a string global. 971 if (op.getValueOrNull().dyn_cast_or_null<StringAttr>()) 972 return; 973 p << " : " << op.type(); 974 975 Region &initializer = op.getInitializerRegion(); 976 if (!initializer.empty()) 977 p.printRegion(initializer, /*printEntryBlockArgs=*/false); 978 } 979 980 //===----------------------------------------------------------------------===// 981 // Verifier for LLVM::DialectCastOp. 982 //===----------------------------------------------------------------------===// 983 984 static LogicalResult verify(DialectCastOp op) { 985 auto verifyMLIRCastType = [&op](Type type) -> LogicalResult { 986 if (auto llvmType = type.dyn_cast<LLVM::LLVMType>()) { 987 if (llvmType.isVectorTy()) 988 llvmType = llvmType.getVectorElementType(); 989 if (llvmType.isIntegerTy() || llvmType.isBFloatTy() || 990 llvmType.isHalfTy() || llvmType.isFloatTy() || 991 llvmType.isDoubleTy()) { 992 return success(); 993 } 994 return op.emitOpError("type must be non-index integer types, float " 995 "types, or vector of mentioned types."); 996 } 997 if (auto vectorType = type.dyn_cast<VectorType>()) { 998 if (vectorType.getShape().size() > 1) 999 return op.emitOpError("only 1-d vector is allowed"); 1000 type = vectorType.getElementType(); 1001 } 1002 if (type.isSignlessIntOrFloat()) 1003 return success(); 1004 // Note that memrefs are not supported. We currently don't have a use case 1005 // for it, but even if we do, there are challenges: 1006 // * if we allow memrefs to cast from/to memref descriptors, then the 1007 // semantics of the cast op depends on the implementation detail of the 1008 // descriptor. 1009 // * if we allow memrefs to cast from/to bare pointers, some users might 1010 // alternatively want metadata that only present in the descriptor. 1011 // 1012 // TODO: re-evaluate the memref cast design when it's needed. 1013 return op.emitOpError("type must be non-index integer types, float types, " 1014 "or vector of mentioned types."); 1015 }; 1016 return failure(failed(verifyMLIRCastType(op.in().getType())) || 1017 failed(verifyMLIRCastType(op.getType()))); 1018 } 1019 1020 // Parses one of the keywords provided in the list `keywords` and returns the 1021 // position of the parsed keyword in the list. If none of the keywords from the 1022 // list is parsed, returns -1. 1023 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 1024 ArrayRef<StringRef> keywords) { 1025 for (auto en : llvm::enumerate(keywords)) { 1026 if (succeeded(parser.parseOptionalKeyword(en.value()))) 1027 return en.index(); 1028 } 1029 return -1; 1030 } 1031 1032 namespace { 1033 template <typename Ty> struct EnumTraits {}; 1034 1035 #define REGISTER_ENUM_TYPE(Ty) \ 1036 template <> struct EnumTraits<Ty> { \ 1037 static StringRef stringify(Ty value) { return stringify##Ty(value); } \ 1038 static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ 1039 } 1040 1041 REGISTER_ENUM_TYPE(Linkage); 1042 } // end namespace 1043 1044 template <typename EnumTy> 1045 static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser, 1046 OperationState &result, 1047 StringRef name) { 1048 SmallVector<StringRef, 10> names; 1049 for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i) 1050 names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); 1051 1052 int index = parseOptionalKeywordAlternative(parser, names); 1053 if (index == -1) 1054 return failure(); 1055 result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index)); 1056 return success(); 1057 } 1058 1059 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier 1060 // `(` attribute? `)` attribute-list? (`:` type)? region? 1061 // 1062 // The type can be omitted for string attributes, in which case it will be 1063 // inferred from the value of the string as [strlen(value) x i8]. 1064 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) { 1065 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1066 getLinkageAttrName()))) 1067 result.addAttribute(getLinkageAttrName(), 1068 parser.getBuilder().getI64IntegerAttr( 1069 static_cast<int64_t>(LLVM::Linkage::External))); 1070 1071 if (succeeded(parser.parseOptionalKeyword("constant"))) 1072 result.addAttribute("constant", parser.getBuilder().getUnitAttr()); 1073 1074 StringAttr name; 1075 if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), 1076 result.attributes) || 1077 parser.parseLParen()) 1078 return failure(); 1079 1080 Attribute value; 1081 if (parser.parseOptionalRParen()) { 1082 if (parser.parseAttribute(value, "value", result.attributes) || 1083 parser.parseRParen()) 1084 return failure(); 1085 } 1086 1087 SmallVector<Type, 1> types; 1088 if (parser.parseOptionalAttrDict(result.attributes) || 1089 parser.parseOptionalColonTypeList(types)) 1090 return failure(); 1091 1092 if (types.size() > 1) 1093 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1094 1095 Region &initRegion = *result.addRegion(); 1096 if (types.empty()) { 1097 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1098 MLIRContext *context = parser.getBuilder().getContext(); 1099 auto arrayType = LLVM::LLVMType::getArrayTy( 1100 LLVM::LLVMType::getInt8Ty(context), strAttr.getValue().size()); 1101 types.push_back(arrayType); 1102 } else { 1103 return parser.emitError(parser.getNameLoc(), 1104 "type can only be omitted for string globals"); 1105 } 1106 } else if (parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1107 /*argTypes=*/{})) { 1108 return failure(); 1109 } 1110 1111 result.addAttribute("type", TypeAttr::get(types[0])); 1112 return success(); 1113 } 1114 1115 static LogicalResult verify(GlobalOp op) { 1116 if (!LLVMType::isValidPointerElementType(op.getType())) 1117 return op.emitOpError( 1118 "expects type to be a valid element type for an LLVM pointer"); 1119 if (op.getParentOp() && !satisfiesLLVMModule(op.getParentOp())) 1120 return op.emitOpError("must appear at the module level"); 1121 1122 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1123 auto type = op.getType(); 1124 if (!type.isArrayTy() || !type.getArrayElementType().isIntegerTy(8) || 1125 type.getArrayNumElements() != strAttr.getValue().size()) 1126 return op.emitOpError( 1127 "requires an i8 array type of the length equal to that of the string " 1128 "attribute"); 1129 } 1130 1131 if (Block *b = op.getInitializerBlock()) { 1132 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1133 if (ret.operand_type_begin() == ret.operand_type_end()) 1134 return op.emitOpError("initializer region cannot return void"); 1135 if (*ret.operand_type_begin() != op.getType()) 1136 return op.emitOpError("initializer region type ") 1137 << *ret.operand_type_begin() << " does not match global type " 1138 << op.getType(); 1139 1140 if (op.getValueOrNull()) 1141 return op.emitOpError("cannot have both initializer value and region"); 1142 } 1143 return success(); 1144 } 1145 1146 //===----------------------------------------------------------------------===// 1147 // Printing/parsing for LLVM::ShuffleVectorOp. 1148 //===----------------------------------------------------------------------===// 1149 // Expects vector to be of wrapped LLVM vector type and position to be of 1150 // wrapped LLVM i32 type. 1151 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 1152 Value v1, Value v2, ArrayAttr mask, 1153 ArrayRef<NamedAttribute> attrs) { 1154 auto wrappedContainerType1 = v1.getType().cast<LLVM::LLVMType>(); 1155 auto vType = LLVMType::getVectorTy( 1156 wrappedContainerType1.getVectorElementType(), mask.size()); 1157 build(b, result, vType, v1, v2, mask); 1158 result.addAttributes(attrs); 1159 } 1160 1161 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1162 p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " " 1163 << op.mask(); 1164 p.printOptionalAttrDict(op.getAttrs(), {"mask"}); 1165 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1166 } 1167 1168 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1169 // `[` integer-literal (`,` integer-literal)* `]` 1170 // attribute-dict? `:` type 1171 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1172 OperationState &result) { 1173 llvm::SMLoc loc; 1174 OpAsmParser::OperandType v1, v2; 1175 ArrayAttr maskAttr; 1176 Type typeV1, typeV2; 1177 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1178 parser.parseComma() || parser.parseOperand(v2) || 1179 parser.parseAttribute(maskAttr, "mask", result.attributes) || 1180 parser.parseOptionalAttrDict(result.attributes) || 1181 parser.parseColonType(typeV1) || parser.parseComma() || 1182 parser.parseType(typeV2) || 1183 parser.resolveOperand(v1, typeV1, result.operands) || 1184 parser.resolveOperand(v2, typeV2, result.operands)) 1185 return failure(); 1186 auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>(); 1187 if (!wrappedContainerType1 || !wrappedContainerType1.isVectorTy()) 1188 return parser.emitError( 1189 loc, "expected LLVM IR dialect vector type for operand #1"); 1190 auto vType = LLVMType::getVectorTy( 1191 wrappedContainerType1.getVectorElementType(), maskAttr.size()); 1192 result.addTypes(vType); 1193 return success(); 1194 } 1195 1196 //===----------------------------------------------------------------------===// 1197 // Implementations for LLVM::LLVMFuncOp. 1198 //===----------------------------------------------------------------------===// 1199 1200 // Add the entry block to the function. 1201 Block *LLVMFuncOp::addEntryBlock() { 1202 assert(empty() && "function already has an entry block"); 1203 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1204 1205 auto *entry = new Block; 1206 push_back(entry); 1207 1208 LLVMType type = getType(); 1209 for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i) 1210 entry->addArgument(type.getFunctionParamType(i)); 1211 return entry; 1212 } 1213 1214 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 1215 StringRef name, LLVMType type, LLVM::Linkage linkage, 1216 ArrayRef<NamedAttribute> attrs, 1217 ArrayRef<MutableDictionaryAttr> argAttrs) { 1218 result.addRegion(); 1219 result.addAttribute(SymbolTable::getSymbolAttrName(), 1220 builder.getStringAttr(name)); 1221 result.addAttribute("type", TypeAttr::get(type)); 1222 result.addAttribute(getLinkageAttrName(), 1223 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1224 result.attributes.append(attrs.begin(), attrs.end()); 1225 if (argAttrs.empty()) 1226 return; 1227 1228 unsigned numInputs = type.getFunctionNumParams(); 1229 assert(numInputs == argAttrs.size() && 1230 "expected as many argument attribute lists as arguments"); 1231 SmallString<8> argAttrName; 1232 for (unsigned i = 0; i < numInputs; ++i) 1233 if (auto argDict = argAttrs[i].getDictionary(builder.getContext())) 1234 result.addAttribute(getArgAttrName(i, argAttrName), argDict); 1235 } 1236 1237 // Builds an LLVM function type from the given lists of input and output types. 1238 // Returns a null type if any of the types provided are non-LLVM types, or if 1239 // there is more than one output type. 1240 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1241 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1242 impl::VariadicFlag variadicFlag) { 1243 Builder &b = parser.getBuilder(); 1244 if (outputs.size() > 1) { 1245 parser.emitError(loc, "failed to construct function type: expected zero or " 1246 "one function result"); 1247 return {}; 1248 } 1249 1250 // Convert inputs to LLVM types, exit early on error. 1251 SmallVector<LLVMType, 4> llvmInputs; 1252 for (auto t : inputs) { 1253 auto llvmTy = t.dyn_cast<LLVMType>(); 1254 if (!llvmTy) { 1255 parser.emitError(loc, "failed to construct function type: expected LLVM " 1256 "type for function arguments"); 1257 return {}; 1258 } 1259 llvmInputs.push_back(llvmTy); 1260 } 1261 1262 // No output is denoted as "void" in LLVM type system. 1263 LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(b.getContext()) 1264 : outputs.front().dyn_cast<LLVMType>(); 1265 if (!llvmOutput) { 1266 parser.emitError(loc, "failed to construct function type: expected LLVM " 1267 "type for function results"); 1268 return {}; 1269 } 1270 return LLVMType::getFunctionTy(llvmOutput, llvmInputs, 1271 variadicFlag.isVariadic()); 1272 } 1273 1274 // Parses an LLVM function. 1275 // 1276 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1277 // function-body 1278 // 1279 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1280 OperationState &result) { 1281 // Default to external linkage if no keyword is provided. 1282 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1283 getLinkageAttrName()))) 1284 result.addAttribute(getLinkageAttrName(), 1285 parser.getBuilder().getI64IntegerAttr( 1286 static_cast<int64_t>(LLVM::Linkage::External))); 1287 1288 StringAttr nameAttr; 1289 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1290 SmallVector<NamedAttrList, 1> argAttrs; 1291 SmallVector<NamedAttrList, 1> resultAttrs; 1292 SmallVector<Type, 8> argTypes; 1293 SmallVector<Type, 4> resultTypes; 1294 bool isVariadic; 1295 1296 auto signatureLocation = parser.getCurrentLocation(); 1297 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1298 result.attributes) || 1299 impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs, 1300 argTypes, argAttrs, isVariadic, resultTypes, 1301 resultAttrs)) 1302 return failure(); 1303 1304 auto type = 1305 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1306 impl::VariadicFlag(isVariadic)); 1307 if (!type) 1308 return failure(); 1309 result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type)); 1310 1311 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1312 return failure(); 1313 impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs, 1314 resultAttrs); 1315 1316 auto *body = result.addRegion(); 1317 return parser.parseOptionalRegion( 1318 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1319 } 1320 1321 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1322 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1323 // the external linkage since it is the default value. 1324 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1325 p << op.getOperationName() << ' '; 1326 if (op.linkage() != LLVM::Linkage::External) 1327 p << stringifyLinkage(op.linkage()) << ' '; 1328 p.printSymbolName(op.getName()); 1329 1330 LLVMType fnType = op.getType(); 1331 SmallVector<Type, 8> argTypes; 1332 SmallVector<Type, 1> resTypes; 1333 argTypes.reserve(fnType.getFunctionNumParams()); 1334 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i) 1335 argTypes.push_back(fnType.getFunctionParamType(i)); 1336 1337 LLVMType returnType = fnType.getFunctionResultType(); 1338 if (!returnType.isVoidTy()) 1339 resTypes.push_back(returnType); 1340 1341 impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes); 1342 impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(), 1343 {getLinkageAttrName()}); 1344 1345 // Print the body if this is not an external function. 1346 Region &body = op.body(); 1347 if (!body.empty()) 1348 p.printRegion(body, /*printEntryBlockArgs=*/false, 1349 /*printBlockTerminators=*/true); 1350 } 1351 1352 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1353 // attribute is present. This can check for preconditions of the 1354 // getNumArguments hook not failing. 1355 LogicalResult LLVMFuncOp::verifyType() { 1356 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>(); 1357 if (!llvmType || !llvmType.isFunctionTy()) 1358 return emitOpError("requires '" + getTypeAttrName() + 1359 "' attribute of wrapped LLVM function type"); 1360 1361 return success(); 1362 } 1363 1364 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1365 // Depends on the type attribute being correct as checked by verifyType 1366 unsigned LLVMFuncOp::getNumFuncArguments() { 1367 return getType().getFunctionNumParams(); 1368 } 1369 1370 // Hook for OpTrait::FunctionLike, returns the number of function results. 1371 // Depends on the type attribute being correct as checked by verifyType 1372 unsigned LLVMFuncOp::getNumFuncResults() { 1373 // We model LLVM functions that return void as having zero results, 1374 // and all others as having one result. 1375 // If we modeled a void return as one result, then it would be possible to 1376 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1377 // would assign to that. 1378 if (getType().getFunctionResultType().isVoidTy()) 1379 return 0; 1380 return 1; 1381 } 1382 1383 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1384 // - functions don't have 'common' linkage 1385 // - external functions have 'external' or 'extern_weak' linkage; 1386 // - vararg is (currently) only supported for external functions; 1387 // - entry block arguments are of LLVM types and match the function signature. 1388 static LogicalResult verify(LLVMFuncOp op) { 1389 if (op.linkage() == LLVM::Linkage::Common) 1390 return op.emitOpError() 1391 << "functions cannot have '" 1392 << stringifyLinkage(LLVM::Linkage::Common) << "' linkage"; 1393 1394 if (op.isExternal()) { 1395 if (op.linkage() != LLVM::Linkage::External && 1396 op.linkage() != LLVM::Linkage::ExternWeak) 1397 return op.emitOpError() 1398 << "external functions must have '" 1399 << stringifyLinkage(LLVM::Linkage::External) << "' or '" 1400 << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage"; 1401 return success(); 1402 } 1403 1404 if (op.isVarArg()) 1405 return op.emitOpError("only external functions can be variadic"); 1406 1407 unsigned numArguments = op.getType().getFunctionNumParams(); 1408 Block &entryBlock = op.front(); 1409 for (unsigned i = 0; i < numArguments; ++i) { 1410 Type argType = entryBlock.getArgument(i).getType(); 1411 auto argLLVMType = argType.dyn_cast<LLVMType>(); 1412 if (!argLLVMType) 1413 return op.emitOpError("entry block argument #") 1414 << i << " is not of LLVM type"; 1415 if (op.getType().getFunctionParamType(i) != argLLVMType) 1416 return op.emitOpError("the type of entry block argument #") 1417 << i << " does not match the function signature"; 1418 } 1419 1420 return success(); 1421 } 1422 1423 //===----------------------------------------------------------------------===// 1424 // Verification for LLVM::NullOp. 1425 //===----------------------------------------------------------------------===// 1426 1427 // Only LLVM pointer types are supported. 1428 static LogicalResult verify(LLVM::NullOp op) { 1429 auto llvmType = op.getType().dyn_cast<LLVM::LLVMType>(); 1430 if (!llvmType || !llvmType.isPointerTy()) 1431 return op.emitOpError("expected LLVM IR pointer type"); 1432 return success(); 1433 } 1434 1435 //===----------------------------------------------------------------------===// 1436 // Verification for LLVM::ConstantOp. 1437 //===----------------------------------------------------------------------===// 1438 1439 static LogicalResult verify(LLVM::ConstantOp op) { 1440 if (!(op.value().isa<IntegerAttr>() || op.value().isa<FloatAttr>() || 1441 op.value().isa<ElementsAttr>() || op.value().isa<StringAttr>())) 1442 return op.emitOpError() 1443 << "only supports integer, float, string or elements attributes"; 1444 return success(); 1445 } 1446 1447 //===----------------------------------------------------------------------===// 1448 // Utility functions for parsing atomic ops 1449 //===----------------------------------------------------------------------===// 1450 1451 // Helper function to parse a keyword into the specified attribute named by 1452 // `attrName`. The keyword must match one of the string values defined by the 1453 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 1454 // state. 1455 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 1456 StringRef attrName) { 1457 llvm::SMLoc loc; 1458 StringRef keyword; 1459 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 1460 return failure(); 1461 1462 // Replace the keyword `keyword` with an integer attribute. 1463 auto kind = symbolizeAtomicBinOp(keyword); 1464 if (!kind) { 1465 return parser.emitError(loc) 1466 << "'" << keyword << "' is an incorrect value of the '" << attrName 1467 << "' attribute"; 1468 } 1469 1470 auto value = static_cast<int64_t>(kind.getValue()); 1471 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1472 result.addAttribute(attrName, attr); 1473 1474 return success(); 1475 } 1476 1477 // Helper function to parse a keyword into the specified attribute named by 1478 // `attrName`. The keyword must match one of the string values defined by the 1479 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 1480 // state. 1481 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 1482 OperationState &result, 1483 StringRef attrName) { 1484 llvm::SMLoc loc; 1485 StringRef ordering; 1486 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 1487 return failure(); 1488 1489 // Replace the keyword `ordering` with an integer attribute. 1490 auto kind = symbolizeAtomicOrdering(ordering); 1491 if (!kind) { 1492 return parser.emitError(loc) 1493 << "'" << ordering << "' is an incorrect value of the '" << attrName 1494 << "' attribute"; 1495 } 1496 1497 auto value = static_cast<int64_t>(kind.getValue()); 1498 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1499 result.addAttribute(attrName, attr); 1500 1501 return success(); 1502 } 1503 1504 //===----------------------------------------------------------------------===// 1505 // Printer, parser and verifier for LLVM::AtomicRMWOp. 1506 //===----------------------------------------------------------------------===// 1507 1508 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) { 1509 p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' 1510 << op.ptr() << ", " << op.val() << ' ' 1511 << stringifyAtomicOrdering(op.ordering()) << ' '; 1512 p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"}); 1513 p << " : " << op.res().getType(); 1514 } 1515 1516 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 1517 // attribute-dict? `:` type 1518 static ParseResult parseAtomicRMWOp(OpAsmParser &parser, 1519 OperationState &result) { 1520 LLVMType type; 1521 OpAsmParser::OperandType ptr, val; 1522 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 1523 parser.parseComma() || parser.parseOperand(val) || 1524 parseAtomicOrdering(parser, result, "ordering") || 1525 parser.parseOptionalAttrDict(result.attributes) || 1526 parser.parseColonType(type) || 1527 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1528 parser.resolveOperand(val, type, result.operands)) 1529 return failure(); 1530 1531 result.addTypes(type); 1532 return success(); 1533 } 1534 1535 static LogicalResult verify(AtomicRMWOp op) { 1536 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1537 if (!ptrType.isPointerTy()) 1538 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1539 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1540 if (valType != ptrType.getPointerElementTy()) 1541 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1542 "match type for operand #1"); 1543 auto resType = op.res().getType().cast<LLVM::LLVMType>(); 1544 if (resType != valType) 1545 return op.emitOpError( 1546 "expected LLVM IR result type to match type for operand #1"); 1547 if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) { 1548 if (!valType.isFloatingPointTy()) 1549 return op.emitOpError("expected LLVM IR floating point type"); 1550 } else if (op.bin_op() == AtomicBinOp::xchg) { 1551 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1552 !valType.isIntegerTy(32) && !valType.isIntegerTy(64) && 1553 !valType.isBFloatTy() && !valType.isHalfTy() && !valType.isFloatTy() && 1554 !valType.isDoubleTy()) 1555 return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 1556 } else { 1557 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1558 !valType.isIntegerTy(32) && !valType.isIntegerTy(64)) 1559 return op.emitOpError("expected LLVM IR integer type"); 1560 } 1561 return success(); 1562 } 1563 1564 //===----------------------------------------------------------------------===// 1565 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 1566 //===----------------------------------------------------------------------===// 1567 1568 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) { 1569 p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", " 1570 << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' ' 1571 << stringifyAtomicOrdering(op.failure_ordering()); 1572 p.printOptionalAttrDict(op.getAttrs(), 1573 {"success_ordering", "failure_ordering"}); 1574 p << " : " << op.val().getType(); 1575 } 1576 1577 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 1578 // keyword keyword attribute-dict? `:` type 1579 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser, 1580 OperationState &result) { 1581 auto &builder = parser.getBuilder(); 1582 LLVMType type; 1583 OpAsmParser::OperandType ptr, cmp, val; 1584 if (parser.parseOperand(ptr) || parser.parseComma() || 1585 parser.parseOperand(cmp) || parser.parseComma() || 1586 parser.parseOperand(val) || 1587 parseAtomicOrdering(parser, result, "success_ordering") || 1588 parseAtomicOrdering(parser, result, "failure_ordering") || 1589 parser.parseOptionalAttrDict(result.attributes) || 1590 parser.parseColonType(type) || 1591 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1592 parser.resolveOperand(cmp, type, result.operands) || 1593 parser.resolveOperand(val, type, result.operands)) 1594 return failure(); 1595 1596 auto boolType = LLVMType::getInt1Ty(builder.getContext()); 1597 auto resultType = LLVMType::getStructTy(type, boolType); 1598 result.addTypes(resultType); 1599 1600 return success(); 1601 } 1602 1603 static LogicalResult verify(AtomicCmpXchgOp op) { 1604 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1605 if (!ptrType.isPointerTy()) 1606 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1607 auto cmpType = op.cmp().getType().cast<LLVM::LLVMType>(); 1608 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1609 if (cmpType != ptrType.getPointerElementTy() || cmpType != valType) 1610 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1611 "match type for all other operands"); 1612 if (!valType.isPointerTy() && !valType.isIntegerTy(8) && 1613 !valType.isIntegerTy(16) && !valType.isIntegerTy(32) && 1614 !valType.isIntegerTy(64) && !valType.isBFloatTy() && 1615 !valType.isHalfTy() && !valType.isFloatTy() && !valType.isDoubleTy()) 1616 return op.emitOpError("unexpected LLVM IR type"); 1617 if (op.success_ordering() < AtomicOrdering::monotonic || 1618 op.failure_ordering() < AtomicOrdering::monotonic) 1619 return op.emitOpError("ordering must be at least 'monotonic'"); 1620 if (op.failure_ordering() == AtomicOrdering::release || 1621 op.failure_ordering() == AtomicOrdering::acq_rel) 1622 return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 1623 return success(); 1624 } 1625 1626 //===----------------------------------------------------------------------===// 1627 // Printer, parser and verifier for LLVM::FenceOp. 1628 //===----------------------------------------------------------------------===// 1629 1630 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 1631 // attribute-dict? 1632 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) { 1633 StringAttr sScope; 1634 StringRef syncscopeKeyword = "syncscope"; 1635 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 1636 if (parser.parseLParen() || 1637 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 1638 parser.parseRParen()) 1639 return failure(); 1640 } else { 1641 result.addAttribute(syncscopeKeyword, 1642 parser.getBuilder().getStringAttr("")); 1643 } 1644 if (parseAtomicOrdering(parser, result, "ordering") || 1645 parser.parseOptionalAttrDict(result.attributes)) 1646 return failure(); 1647 return success(); 1648 } 1649 1650 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) { 1651 StringRef syncscopeKeyword = "syncscope"; 1652 p << op.getOperationName() << ' '; 1653 if (!op.getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 1654 p << "syncscope(" << op.getAttr(syncscopeKeyword) << ") "; 1655 p << stringifyAtomicOrdering(op.ordering()); 1656 } 1657 1658 static LogicalResult verify(FenceOp &op) { 1659 if (op.ordering() == AtomicOrdering::not_atomic || 1660 op.ordering() == AtomicOrdering::unordered || 1661 op.ordering() == AtomicOrdering::monotonic) 1662 return op.emitOpError("can be given only acquire, release, acq_rel, " 1663 "and seq_cst orderings"); 1664 return success(); 1665 } 1666 1667 //===----------------------------------------------------------------------===// 1668 // LLVMDialect initialization, type parsing, and registration. 1669 //===----------------------------------------------------------------------===// 1670 1671 namespace mlir { 1672 namespace LLVM { 1673 namespace detail { 1674 struct LLVMDialectImpl { 1675 LLVMDialectImpl() : layout("") {} 1676 1677 /// Default data layout to use. 1678 // TODO: this should be moved to some Op equivalent to LLVM module and 1679 // eventually replaced with a proper MLIR data layout. 1680 llvm::DataLayout layout; 1681 }; 1682 } // end namespace detail 1683 } // end namespace LLVM 1684 } // end namespace mlir 1685 1686 void LLVMDialect::initialize() { 1687 impl = new detail::LLVMDialectImpl(); 1688 // clang-format off 1689 addTypes<LLVMVoidType, 1690 LLVMHalfType, 1691 LLVMBFloatType, 1692 LLVMFloatType, 1693 LLVMDoubleType, 1694 LLVMFP128Type, 1695 LLVMX86FP80Type, 1696 LLVMPPCFP128Type, 1697 LLVMX86MMXType, 1698 LLVMTokenType, 1699 LLVMLabelType, 1700 LLVMMetadataType, 1701 LLVMFunctionType, 1702 LLVMIntegerType, 1703 LLVMPointerType, 1704 LLVMFixedVectorType, 1705 LLVMScalableVectorType, 1706 LLVMArrayType, 1707 LLVMStructType>(); 1708 // clang-format on 1709 addOperations< 1710 #define GET_OP_LIST 1711 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1712 >(); 1713 1714 // Support unknown operations because not all LLVM operations are registered. 1715 allowUnknownOperations(); 1716 } 1717 1718 LLVMDialect::~LLVMDialect() { delete impl; } 1719 1720 #define GET_OP_CLASSES 1721 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1722 1723 const llvm::DataLayout &LLVMDialect::getDataLayout() { return impl->layout; } 1724 1725 /// Parse a type registered to this dialect. 1726 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 1727 return detail::parseType(parser); 1728 } 1729 1730 /// Print a type registered to this dialect. 1731 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 1732 return detail::printType(type.cast<LLVMType>(), os); 1733 } 1734 1735 /// Verify LLVMIR function argument attributes. 1736 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 1737 unsigned regionIdx, 1738 unsigned argIdx, 1739 NamedAttribute argAttr) { 1740 // Check that llvm.noalias is a boolean attribute. 1741 if (argAttr.first == "llvm.noalias" && !argAttr.second.isa<BoolAttr>()) 1742 return op->emitError() 1743 << "llvm.noalias argument attribute of non boolean type"; 1744 // Check that llvm.align is an integer attribute. 1745 if (argAttr.first == "llvm.align" && !argAttr.second.isa<IntegerAttr>()) 1746 return op->emitError() 1747 << "llvm.align argument attribute of non integer type"; 1748 return success(); 1749 } 1750 1751 //===----------------------------------------------------------------------===// 1752 // Utility functions. 1753 //===----------------------------------------------------------------------===// 1754 1755 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 1756 StringRef name, StringRef value, 1757 LLVM::Linkage linkage) { 1758 assert(builder.getInsertionBlock() && 1759 builder.getInsertionBlock()->getParentOp() && 1760 "expected builder to point to a block constrained in an op"); 1761 auto module = 1762 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 1763 assert(module && "builder points to an op outside of a module"); 1764 1765 // Create the global at the entry of the module. 1766 OpBuilder moduleBuilder(module.getBodyRegion()); 1767 MLIRContext *ctx = builder.getContext(); 1768 auto type = 1769 LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(ctx), value.size()); 1770 auto global = moduleBuilder.create<LLVM::GlobalOp>( 1771 loc, type, /*isConstant=*/true, linkage, name, 1772 builder.getStringAttr(value)); 1773 1774 // Get the pointer to the first character in the global string. 1775 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 1776 Value cst0 = builder.create<LLVM::ConstantOp>( 1777 loc, LLVM::LLVMType::getInt64Ty(ctx), 1778 builder.getIntegerAttr(builder.getIndexType(), 0)); 1779 return builder.create<LLVM::GEPOp>(loc, LLVM::LLVMType::getInt8PtrTy(ctx), 1780 globalPtr, ArrayRef<Value>({cst0, cst0})); 1781 } 1782 1783 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 1784 return op->hasTrait<OpTrait::SymbolTable>() && 1785 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 1786 } 1787