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