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