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.isHalfTy() || 943 llvmType.isFloatTy() || llvmType.isDoubleTy()) { 944 return success(); 945 } 946 return op.emitOpError("type must be non-index integer types, float " 947 "types, or vector of mentioned types."); 948 } 949 if (auto vectorType = type.dyn_cast<VectorType>()) { 950 if (vectorType.getShape().size() > 1) 951 return op.emitOpError("only 1-d vector is allowed"); 952 type = vectorType.getElementType(); 953 } 954 if (type.isSignlessIntOrFloat()) 955 return success(); 956 // Note that memrefs are not supported. We currently don't have a use case 957 // for it, but even if we do, there are challenges: 958 // * if we allow memrefs to cast from/to memref descriptors, then the 959 // semantics of the cast op depends on the implementation detail of the 960 // descriptor. 961 // * if we allow memrefs to cast from/to bare pointers, some users might 962 // alternatively want metadata that only present in the descriptor. 963 // 964 // TODO(timshen): re-evaluate the memref cast design when it's needed. 965 return op.emitOpError("type must be non-index integer types, float types, " 966 "or vector of mentioned types."); 967 }; 968 return failure(failed(verifyMLIRCastType(op.in().getType())) || 969 failed(verifyMLIRCastType(op.getType()))); 970 } 971 972 // Parses one of the keywords provided in the list `keywords` and returns the 973 // position of the parsed keyword in the list. If none of the keywords from the 974 // list is parsed, returns -1. 975 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 976 ArrayRef<StringRef> keywords) { 977 for (auto en : llvm::enumerate(keywords)) { 978 if (succeeded(parser.parseOptionalKeyword(en.value()))) 979 return en.index(); 980 } 981 return -1; 982 } 983 984 namespace { 985 template <typename Ty> struct EnumTraits {}; 986 987 #define REGISTER_ENUM_TYPE(Ty) \ 988 template <> struct EnumTraits<Ty> { \ 989 static StringRef stringify(Ty value) { return stringify##Ty(value); } \ 990 static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ 991 } 992 993 REGISTER_ENUM_TYPE(Linkage); 994 } // end namespace 995 996 template <typename EnumTy> 997 static ParseResult parseOptionalLLVMKeyword(OpAsmParser &parser, 998 OperationState &result, 999 StringRef name) { 1000 SmallVector<StringRef, 10> names; 1001 for (unsigned i = 0, e = getMaxEnumValForLinkage(); i <= e; ++i) 1002 names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i))); 1003 1004 int index = parseOptionalKeywordAlternative(parser, names); 1005 if (index == -1) 1006 return failure(); 1007 result.addAttribute(name, parser.getBuilder().getI64IntegerAttr(index)); 1008 return success(); 1009 } 1010 1011 // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier 1012 // `(` attribute? `)` attribute-list? (`:` type)? region? 1013 // 1014 // The type can be omitted for string attributes, in which case it will be 1015 // inferred from the value of the string as [strlen(value) x i8]. 1016 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) { 1017 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1018 getLinkageAttrName()))) 1019 result.addAttribute(getLinkageAttrName(), 1020 parser.getBuilder().getI64IntegerAttr( 1021 static_cast<int64_t>(LLVM::Linkage::External))); 1022 1023 if (succeeded(parser.parseOptionalKeyword("constant"))) 1024 result.addAttribute("constant", parser.getBuilder().getUnitAttr()); 1025 1026 StringAttr name; 1027 if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), 1028 result.attributes) || 1029 parser.parseLParen()) 1030 return failure(); 1031 1032 Attribute value; 1033 if (parser.parseOptionalRParen()) { 1034 if (parser.parseAttribute(value, "value", result.attributes) || 1035 parser.parseRParen()) 1036 return failure(); 1037 } 1038 1039 SmallVector<Type, 1> types; 1040 if (parser.parseOptionalAttrDict(result.attributes) || 1041 parser.parseOptionalColonTypeList(types)) 1042 return failure(); 1043 1044 if (types.size() > 1) 1045 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1046 1047 Region &initRegion = *result.addRegion(); 1048 if (types.empty()) { 1049 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1050 MLIRContext *context = parser.getBuilder().getContext(); 1051 auto *dialect = context->getRegisteredDialect<LLVMDialect>(); 1052 auto arrayType = LLVM::LLVMType::getArrayTy( 1053 LLVM::LLVMType::getInt8Ty(dialect), strAttr.getValue().size()); 1054 types.push_back(arrayType); 1055 } else { 1056 return parser.emitError(parser.getNameLoc(), 1057 "type can only be omitted for string globals"); 1058 } 1059 } else if (parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1060 /*argTypes=*/{})) { 1061 return failure(); 1062 } 1063 1064 result.addAttribute("type", TypeAttr::get(types[0])); 1065 return success(); 1066 } 1067 1068 static LogicalResult verify(GlobalOp op) { 1069 if (!llvm::PointerType::isValidElementType(op.getType().getUnderlyingType())) 1070 return op.emitOpError( 1071 "expects type to be a valid element type for an LLVM pointer"); 1072 if (op.getParentOp() && !satisfiesLLVMModule(op.getParentOp())) 1073 return op.emitOpError("must appear at the module level"); 1074 1075 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1076 auto type = op.getType(); 1077 if (!type.getUnderlyingType()->isArrayTy() || 1078 !type.getArrayElementType().getUnderlyingType()->isIntegerTy(8) || 1079 type.getArrayNumElements() != strAttr.getValue().size()) 1080 return op.emitOpError( 1081 "requires an i8 array type of the length equal to that of the string " 1082 "attribute"); 1083 } 1084 1085 if (Block *b = op.getInitializerBlock()) { 1086 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1087 if (ret.operand_type_begin() == ret.operand_type_end()) 1088 return op.emitOpError("initializer region cannot return void"); 1089 if (*ret.operand_type_begin() != op.getType()) 1090 return op.emitOpError("initializer region type ") 1091 << *ret.operand_type_begin() << " does not match global type " 1092 << op.getType(); 1093 1094 if (op.getValueOrNull()) 1095 return op.emitOpError("cannot have both initializer value and region"); 1096 } 1097 return success(); 1098 } 1099 1100 //===----------------------------------------------------------------------===// 1101 // Printing/parsing for LLVM::ShuffleVectorOp. 1102 //===----------------------------------------------------------------------===// 1103 // Expects vector to be of wrapped LLVM vector type and position to be of 1104 // wrapped LLVM i32 type. 1105 void LLVM::ShuffleVectorOp::build(OpBuilder &b, OperationState &result, 1106 Value v1, Value v2, ArrayAttr mask, 1107 ArrayRef<NamedAttribute> attrs) { 1108 auto wrappedContainerType1 = v1.getType().cast<LLVM::LLVMType>(); 1109 auto vType = LLVMType::getVectorTy( 1110 wrappedContainerType1.getVectorElementType(), mask.size()); 1111 build(b, result, vType, v1, v2, mask); 1112 result.addAttributes(attrs); 1113 } 1114 1115 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1116 p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " " 1117 << op.mask(); 1118 p.printOptionalAttrDict(op.getAttrs(), {"mask"}); 1119 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1120 } 1121 1122 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1123 // `[` integer-literal (`,` integer-literal)* `]` 1124 // attribute-dict? `:` type 1125 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1126 OperationState &result) { 1127 llvm::SMLoc loc; 1128 OpAsmParser::OperandType v1, v2; 1129 ArrayAttr maskAttr; 1130 Type typeV1, typeV2; 1131 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1132 parser.parseComma() || parser.parseOperand(v2) || 1133 parser.parseAttribute(maskAttr, "mask", result.attributes) || 1134 parser.parseOptionalAttrDict(result.attributes) || 1135 parser.parseColonType(typeV1) || parser.parseComma() || 1136 parser.parseType(typeV2) || 1137 parser.resolveOperand(v1, typeV1, result.operands) || 1138 parser.resolveOperand(v2, typeV2, result.operands)) 1139 return failure(); 1140 auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>(); 1141 if (!wrappedContainerType1 || 1142 !wrappedContainerType1.getUnderlyingType()->isVectorTy()) 1143 return parser.emitError( 1144 loc, "expected LLVM IR dialect vector type for operand #1"); 1145 auto vType = LLVMType::getVectorTy( 1146 wrappedContainerType1.getVectorElementType(), maskAttr.size()); 1147 result.addTypes(vType); 1148 return success(); 1149 } 1150 1151 //===----------------------------------------------------------------------===// 1152 // Implementations for LLVM::LLVMFuncOp. 1153 //===----------------------------------------------------------------------===// 1154 1155 // Add the entry block to the function. 1156 Block *LLVMFuncOp::addEntryBlock() { 1157 assert(empty() && "function already has an entry block"); 1158 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1159 1160 auto *entry = new Block; 1161 push_back(entry); 1162 1163 LLVMType type = getType(); 1164 for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i) 1165 entry->addArgument(type.getFunctionParamType(i)); 1166 return entry; 1167 } 1168 1169 void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, 1170 StringRef name, LLVMType type, LLVM::Linkage linkage, 1171 ArrayRef<NamedAttribute> attrs, 1172 ArrayRef<MutableDictionaryAttr> argAttrs) { 1173 result.addRegion(); 1174 result.addAttribute(SymbolTable::getSymbolAttrName(), 1175 builder.getStringAttr(name)); 1176 result.addAttribute("type", TypeAttr::get(type)); 1177 result.addAttribute(getLinkageAttrName(), 1178 builder.getI64IntegerAttr(static_cast<int64_t>(linkage))); 1179 result.attributes.append(attrs.begin(), attrs.end()); 1180 if (argAttrs.empty()) 1181 return; 1182 1183 unsigned numInputs = type.getUnderlyingType()->getFunctionNumParams(); 1184 assert(numInputs == argAttrs.size() && 1185 "expected as many argument attribute lists as arguments"); 1186 SmallString<8> argAttrName; 1187 for (unsigned i = 0; i < numInputs; ++i) 1188 if (auto argDict = argAttrs[i].getDictionary(builder.getContext())) 1189 result.addAttribute(getArgAttrName(i, argAttrName), argDict); 1190 } 1191 1192 // Builds an LLVM function type from the given lists of input and output types. 1193 // Returns a null type if any of the types provided are non-LLVM types, or if 1194 // there is more than one output type. 1195 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1196 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1197 impl::VariadicFlag variadicFlag) { 1198 Builder &b = parser.getBuilder(); 1199 if (outputs.size() > 1) { 1200 parser.emitError(loc, "failed to construct function type: expected zero or " 1201 "one function result"); 1202 return {}; 1203 } 1204 1205 // Convert inputs to LLVM types, exit early on error. 1206 SmallVector<LLVMType, 4> llvmInputs; 1207 for (auto t : inputs) { 1208 auto llvmTy = t.dyn_cast<LLVMType>(); 1209 if (!llvmTy) { 1210 parser.emitError(loc, "failed to construct function type: expected LLVM " 1211 "type for function arguments"); 1212 return {}; 1213 } 1214 llvmInputs.push_back(llvmTy); 1215 } 1216 1217 // Get the dialect from the input type, if any exist. Look it up in the 1218 // context otherwise. 1219 LLVMDialect *dialect = 1220 llvmInputs.empty() ? b.getContext()->getRegisteredDialect<LLVMDialect>() 1221 : &llvmInputs.front().getDialect(); 1222 1223 // No output is denoted as "void" in LLVM type system. 1224 LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(dialect) 1225 : outputs.front().dyn_cast<LLVMType>(); 1226 if (!llvmOutput) { 1227 parser.emitError(loc, "failed to construct function type: expected LLVM " 1228 "type for function results"); 1229 return {}; 1230 } 1231 return LLVMType::getFunctionTy(llvmOutput, llvmInputs, 1232 variadicFlag.isVariadic()); 1233 } 1234 1235 // Parses an LLVM function. 1236 // 1237 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1238 // function-body 1239 // 1240 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1241 OperationState &result) { 1242 // Default to external linkage if no keyword is provided. 1243 if (failed(parseOptionalLLVMKeyword<Linkage>(parser, result, 1244 getLinkageAttrName()))) 1245 result.addAttribute(getLinkageAttrName(), 1246 parser.getBuilder().getI64IntegerAttr( 1247 static_cast<int64_t>(LLVM::Linkage::External))); 1248 1249 StringAttr nameAttr; 1250 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1251 SmallVector<NamedAttrList, 1> argAttrs; 1252 SmallVector<NamedAttrList, 1> resultAttrs; 1253 SmallVector<Type, 8> argTypes; 1254 SmallVector<Type, 4> resultTypes; 1255 bool isVariadic; 1256 1257 auto signatureLocation = parser.getCurrentLocation(); 1258 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1259 result.attributes) || 1260 impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs, 1261 argTypes, argAttrs, isVariadic, resultTypes, 1262 resultAttrs)) 1263 return failure(); 1264 1265 auto type = 1266 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1267 impl::VariadicFlag(isVariadic)); 1268 if (!type) 1269 return failure(); 1270 result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type)); 1271 1272 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1273 return failure(); 1274 impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs, 1275 resultAttrs); 1276 1277 auto *body = result.addRegion(); 1278 return parser.parseOptionalRegion( 1279 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1280 } 1281 1282 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1283 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1284 // the external linkage since it is the default value. 1285 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1286 p << op.getOperationName() << ' '; 1287 if (op.linkage() != LLVM::Linkage::External) 1288 p << stringifyLinkage(op.linkage()) << ' '; 1289 p.printSymbolName(op.getName()); 1290 1291 LLVMType fnType = op.getType(); 1292 SmallVector<Type, 8> argTypes; 1293 SmallVector<Type, 1> resTypes; 1294 argTypes.reserve(fnType.getFunctionNumParams()); 1295 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i) 1296 argTypes.push_back(fnType.getFunctionParamType(i)); 1297 1298 LLVMType returnType = fnType.getFunctionResultType(); 1299 if (!returnType.isVoidTy()) 1300 resTypes.push_back(returnType); 1301 1302 impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes); 1303 impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(), 1304 {getLinkageAttrName()}); 1305 1306 // Print the body if this is not an external function. 1307 Region &body = op.body(); 1308 if (!body.empty()) 1309 p.printRegion(body, /*printEntryBlockArgs=*/false, 1310 /*printBlockTerminators=*/true); 1311 } 1312 1313 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1314 // attribute is present. This can check for preconditions of the 1315 // getNumArguments hook not failing. 1316 LogicalResult LLVMFuncOp::verifyType() { 1317 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>(); 1318 if (!llvmType || !llvmType.getUnderlyingType()->isFunctionTy()) 1319 return emitOpError("requires '" + getTypeAttrName() + 1320 "' attribute of wrapped LLVM function type"); 1321 1322 return success(); 1323 } 1324 1325 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1326 // Depends on the type attribute being correct as checked by verifyType 1327 unsigned LLVMFuncOp::getNumFuncArguments() { 1328 return getType().getUnderlyingType()->getFunctionNumParams(); 1329 } 1330 1331 // Hook for OpTrait::FunctionLike, returns the number of function results. 1332 // Depends on the type attribute being correct as checked by verifyType 1333 unsigned LLVMFuncOp::getNumFuncResults() { 1334 // We model LLVM functions that return void as having zero results, 1335 // and all others as having one result. 1336 // If we modeled a void return as one result, then it would be possible to 1337 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1338 // would assign to that. 1339 if (getType().getFunctionResultType().isVoidTy()) 1340 return 0; 1341 return 1; 1342 } 1343 1344 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1345 // - functions don't have 'common' linkage 1346 // - external functions have 'external' or 'extern_weak' linkage; 1347 // - vararg is (currently) only supported for external functions; 1348 // - entry block arguments are of LLVM types and match the function signature. 1349 static LogicalResult verify(LLVMFuncOp op) { 1350 if (op.linkage() == LLVM::Linkage::Common) 1351 return op.emitOpError() 1352 << "functions cannot have '" 1353 << stringifyLinkage(LLVM::Linkage::Common) << "' linkage"; 1354 1355 if (op.isExternal()) { 1356 if (op.linkage() != LLVM::Linkage::External && 1357 op.linkage() != LLVM::Linkage::ExternWeak) 1358 return op.emitOpError() 1359 << "external functions must have '" 1360 << stringifyLinkage(LLVM::Linkage::External) << "' or '" 1361 << stringifyLinkage(LLVM::Linkage::ExternWeak) << "' linkage"; 1362 return success(); 1363 } 1364 1365 if (op.isVarArg()) 1366 return op.emitOpError("only external functions can be variadic"); 1367 1368 auto *funcType = cast<llvm::FunctionType>(op.getType().getUnderlyingType()); 1369 unsigned numArguments = funcType->getNumParams(); 1370 Block &entryBlock = op.front(); 1371 for (unsigned i = 0; i < numArguments; ++i) { 1372 Type argType = entryBlock.getArgument(i).getType(); 1373 auto argLLVMType = argType.dyn_cast<LLVMType>(); 1374 if (!argLLVMType) 1375 return op.emitOpError("entry block argument #") 1376 << i << " is not of LLVM type"; 1377 if (funcType->getParamType(i) != argLLVMType.getUnderlyingType()) 1378 return op.emitOpError("the type of entry block argument #") 1379 << i << " does not match the function signature"; 1380 } 1381 1382 return success(); 1383 } 1384 1385 //===----------------------------------------------------------------------===// 1386 // Verification for LLVM::NullOp. 1387 //===----------------------------------------------------------------------===// 1388 1389 // Only LLVM pointer types are supported. 1390 static LogicalResult verify(LLVM::NullOp op) { 1391 auto llvmType = op.getType().dyn_cast<LLVM::LLVMType>(); 1392 if (!llvmType || !llvmType.isPointerTy()) 1393 return op.emitOpError("expected LLVM IR pointer type"); 1394 return success(); 1395 } 1396 1397 //===----------------------------------------------------------------------===// 1398 // Utility functions for parsing atomic ops 1399 //===----------------------------------------------------------------------===// 1400 1401 // Helper function to parse a keyword into the specified attribute named by 1402 // `attrName`. The keyword must match one of the string values defined by the 1403 // AtomicBinOp enum. The resulting I64 attribute is added to the `result` 1404 // state. 1405 static ParseResult parseAtomicBinOp(OpAsmParser &parser, OperationState &result, 1406 StringRef attrName) { 1407 llvm::SMLoc loc; 1408 StringRef keyword; 1409 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&keyword)) 1410 return failure(); 1411 1412 // Replace the keyword `keyword` with an integer attribute. 1413 auto kind = symbolizeAtomicBinOp(keyword); 1414 if (!kind) { 1415 return parser.emitError(loc) 1416 << "'" << keyword << "' is an incorrect value of the '" << attrName 1417 << "' attribute"; 1418 } 1419 1420 auto value = static_cast<int64_t>(kind.getValue()); 1421 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1422 result.addAttribute(attrName, attr); 1423 1424 return success(); 1425 } 1426 1427 // Helper function to parse a keyword into the specified attribute named by 1428 // `attrName`. The keyword must match one of the string values defined by the 1429 // AtomicOrdering enum. The resulting I64 attribute is added to the `result` 1430 // state. 1431 static ParseResult parseAtomicOrdering(OpAsmParser &parser, 1432 OperationState &result, 1433 StringRef attrName) { 1434 llvm::SMLoc loc; 1435 StringRef ordering; 1436 if (parser.getCurrentLocation(&loc) || parser.parseKeyword(&ordering)) 1437 return failure(); 1438 1439 // Replace the keyword `ordering` with an integer attribute. 1440 auto kind = symbolizeAtomicOrdering(ordering); 1441 if (!kind) { 1442 return parser.emitError(loc) 1443 << "'" << ordering << "' is an incorrect value of the '" << attrName 1444 << "' attribute"; 1445 } 1446 1447 auto value = static_cast<int64_t>(kind.getValue()); 1448 auto attr = parser.getBuilder().getI64IntegerAttr(value); 1449 result.addAttribute(attrName, attr); 1450 1451 return success(); 1452 } 1453 1454 //===----------------------------------------------------------------------===// 1455 // Printer, parser and verifier for LLVM::AtomicRMWOp. 1456 //===----------------------------------------------------------------------===// 1457 1458 static void printAtomicRMWOp(OpAsmPrinter &p, AtomicRMWOp &op) { 1459 p << op.getOperationName() << ' ' << stringifyAtomicBinOp(op.bin_op()) << ' ' 1460 << op.ptr() << ", " << op.val() << ' ' 1461 << stringifyAtomicOrdering(op.ordering()) << ' '; 1462 p.printOptionalAttrDict(op.getAttrs(), {"bin_op", "ordering"}); 1463 p << " : " << op.res().getType(); 1464 } 1465 1466 // <operation> ::= `llvm.atomicrmw` keyword ssa-use `,` ssa-use keyword 1467 // attribute-dict? `:` type 1468 static ParseResult parseAtomicRMWOp(OpAsmParser &parser, 1469 OperationState &result) { 1470 LLVMType type; 1471 OpAsmParser::OperandType ptr, val; 1472 if (parseAtomicBinOp(parser, result, "bin_op") || parser.parseOperand(ptr) || 1473 parser.parseComma() || parser.parseOperand(val) || 1474 parseAtomicOrdering(parser, result, "ordering") || 1475 parser.parseOptionalAttrDict(result.attributes) || 1476 parser.parseColonType(type) || 1477 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1478 parser.resolveOperand(val, type, result.operands)) 1479 return failure(); 1480 1481 result.addTypes(type); 1482 return success(); 1483 } 1484 1485 static LogicalResult verify(AtomicRMWOp op) { 1486 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1487 if (!ptrType.isPointerTy()) 1488 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1489 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1490 if (valType != ptrType.getPointerElementTy()) 1491 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1492 "match type for operand #1"); 1493 auto resType = op.res().getType().cast<LLVM::LLVMType>(); 1494 if (resType != valType) 1495 return op.emitOpError( 1496 "expected LLVM IR result type to match type for operand #1"); 1497 if (op.bin_op() == AtomicBinOp::fadd || op.bin_op() == AtomicBinOp::fsub) { 1498 if (!valType.getUnderlyingType()->isFloatingPointTy()) 1499 return op.emitOpError("expected LLVM IR floating point type"); 1500 } else if (op.bin_op() == AtomicBinOp::xchg) { 1501 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1502 !valType.isIntegerTy(32) && !valType.isIntegerTy(64) && 1503 !valType.isHalfTy() && !valType.isFloatTy() && !valType.isDoubleTy()) 1504 return op.emitOpError("unexpected LLVM IR type for 'xchg' bin_op"); 1505 } else { 1506 if (!valType.isIntegerTy(8) && !valType.isIntegerTy(16) && 1507 !valType.isIntegerTy(32) && !valType.isIntegerTy(64)) 1508 return op.emitOpError("expected LLVM IR integer type"); 1509 } 1510 return success(); 1511 } 1512 1513 //===----------------------------------------------------------------------===// 1514 // Printer, parser and verifier for LLVM::AtomicCmpXchgOp. 1515 //===----------------------------------------------------------------------===// 1516 1517 static void printAtomicCmpXchgOp(OpAsmPrinter &p, AtomicCmpXchgOp &op) { 1518 p << op.getOperationName() << ' ' << op.ptr() << ", " << op.cmp() << ", " 1519 << op.val() << ' ' << stringifyAtomicOrdering(op.success_ordering()) << ' ' 1520 << stringifyAtomicOrdering(op.failure_ordering()); 1521 p.printOptionalAttrDict(op.getAttrs(), 1522 {"success_ordering", "failure_ordering"}); 1523 p << " : " << op.val().getType(); 1524 } 1525 1526 // <operation> ::= `llvm.cmpxchg` ssa-use `,` ssa-use `,` ssa-use 1527 // keyword keyword attribute-dict? `:` type 1528 static ParseResult parseAtomicCmpXchgOp(OpAsmParser &parser, 1529 OperationState &result) { 1530 auto &builder = parser.getBuilder(); 1531 LLVMType type; 1532 OpAsmParser::OperandType ptr, cmp, val; 1533 if (parser.parseOperand(ptr) || parser.parseComma() || 1534 parser.parseOperand(cmp) || parser.parseComma() || 1535 parser.parseOperand(val) || 1536 parseAtomicOrdering(parser, result, "success_ordering") || 1537 parseAtomicOrdering(parser, result, "failure_ordering") || 1538 parser.parseOptionalAttrDict(result.attributes) || 1539 parser.parseColonType(type) || 1540 parser.resolveOperand(ptr, type.getPointerTo(), result.operands) || 1541 parser.resolveOperand(cmp, type, result.operands) || 1542 parser.resolveOperand(val, type, result.operands)) 1543 return failure(); 1544 1545 auto *dialect = builder.getContext()->getRegisteredDialect<LLVMDialect>(); 1546 auto boolType = LLVMType::getInt1Ty(dialect); 1547 auto resultType = LLVMType::getStructTy(type, boolType); 1548 result.addTypes(resultType); 1549 1550 return success(); 1551 } 1552 1553 static LogicalResult verify(AtomicCmpXchgOp op) { 1554 auto ptrType = op.ptr().getType().cast<LLVM::LLVMType>(); 1555 if (!ptrType.isPointerTy()) 1556 return op.emitOpError("expected LLVM IR pointer type for operand #0"); 1557 auto cmpType = op.cmp().getType().cast<LLVM::LLVMType>(); 1558 auto valType = op.val().getType().cast<LLVM::LLVMType>(); 1559 if (cmpType != ptrType.getPointerElementTy() || cmpType != valType) 1560 return op.emitOpError("expected LLVM IR element type for operand #0 to " 1561 "match type for all other operands"); 1562 if (!valType.isPointerTy() && !valType.isIntegerTy(8) && 1563 !valType.isIntegerTy(16) && !valType.isIntegerTy(32) && 1564 !valType.isIntegerTy(64) && !valType.isHalfTy() && !valType.isFloatTy() && 1565 !valType.isDoubleTy()) 1566 return op.emitOpError("unexpected LLVM IR type"); 1567 if (op.success_ordering() < AtomicOrdering::monotonic || 1568 op.failure_ordering() < AtomicOrdering::monotonic) 1569 return op.emitOpError("ordering must be at least 'monotonic'"); 1570 if (op.failure_ordering() == AtomicOrdering::release || 1571 op.failure_ordering() == AtomicOrdering::acq_rel) 1572 return op.emitOpError("failure ordering cannot be 'release' or 'acq_rel'"); 1573 return success(); 1574 } 1575 1576 //===----------------------------------------------------------------------===// 1577 // Printer, parser and verifier for LLVM::FenceOp. 1578 //===----------------------------------------------------------------------===// 1579 1580 // <operation> ::= `llvm.fence` (`syncscope(`strAttr`)`)? keyword 1581 // attribute-dict? 1582 static ParseResult parseFenceOp(OpAsmParser &parser, OperationState &result) { 1583 StringAttr sScope; 1584 StringRef syncscopeKeyword = "syncscope"; 1585 if (!failed(parser.parseOptionalKeyword(syncscopeKeyword))) { 1586 if (parser.parseLParen() || 1587 parser.parseAttribute(sScope, syncscopeKeyword, result.attributes) || 1588 parser.parseRParen()) 1589 return failure(); 1590 } else { 1591 result.addAttribute(syncscopeKeyword, 1592 parser.getBuilder().getStringAttr("")); 1593 } 1594 if (parseAtomicOrdering(parser, result, "ordering") || 1595 parser.parseOptionalAttrDict(result.attributes)) 1596 return failure(); 1597 return success(); 1598 } 1599 1600 static void printFenceOp(OpAsmPrinter &p, FenceOp &op) { 1601 StringRef syncscopeKeyword = "syncscope"; 1602 p << op.getOperationName() << ' '; 1603 if (!op.getAttr(syncscopeKeyword).cast<StringAttr>().getValue().empty()) 1604 p << "syncscope(" << op.getAttr(syncscopeKeyword) << ") "; 1605 p << stringifyAtomicOrdering(op.ordering()); 1606 } 1607 1608 static LogicalResult verify(FenceOp &op) { 1609 if (op.ordering() == AtomicOrdering::not_atomic || 1610 op.ordering() == AtomicOrdering::unordered || 1611 op.ordering() == AtomicOrdering::monotonic) 1612 return op.emitOpError("can be given only acquire, release, acq_rel, " 1613 "and seq_cst orderings"); 1614 return success(); 1615 } 1616 1617 //===----------------------------------------------------------------------===// 1618 // LLVMDialect initialization, type parsing, and registration. 1619 //===----------------------------------------------------------------------===// 1620 1621 namespace mlir { 1622 namespace LLVM { 1623 namespace detail { 1624 struct LLVMDialectImpl { 1625 LLVMDialectImpl() : module("LLVMDialectModule", llvmContext) {} 1626 1627 llvm::LLVMContext llvmContext; 1628 llvm::Module module; 1629 1630 /// A set of LLVMTypes that are cached on construction to avoid any lookups or 1631 /// locking. 1632 LLVMType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty; 1633 LLVMType doubleTy, floatTy, halfTy, fp128Ty, x86_fp80Ty; 1634 LLVMType voidTy; 1635 1636 /// A smart mutex to lock access to the llvm context. Unlike MLIR, LLVM is not 1637 /// multi-threaded and requires locked access to prevent race conditions. 1638 llvm::sys::SmartMutex<true> mutex; 1639 }; 1640 } // end namespace detail 1641 } // end namespace LLVM 1642 } // end namespace mlir 1643 1644 LLVMDialect::LLVMDialect(MLIRContext *context) 1645 : Dialect(getDialectNamespace(), context), 1646 impl(new detail::LLVMDialectImpl()) { 1647 addTypes<LLVMType>(); 1648 addOperations< 1649 #define GET_OP_LIST 1650 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1651 >(); 1652 1653 // Support unknown operations because not all LLVM operations are registered. 1654 allowUnknownOperations(); 1655 1656 // Cache some of the common LLVM types to avoid the need for lookups/locking. 1657 auto &llvmContext = impl->llvmContext; 1658 /// Integer Types. 1659 impl->int1Ty = LLVMType::get(context, llvm::Type::getInt1Ty(llvmContext)); 1660 impl->int8Ty = LLVMType::get(context, llvm::Type::getInt8Ty(llvmContext)); 1661 impl->int16Ty = LLVMType::get(context, llvm::Type::getInt16Ty(llvmContext)); 1662 impl->int32Ty = LLVMType::get(context, llvm::Type::getInt32Ty(llvmContext)); 1663 impl->int64Ty = LLVMType::get(context, llvm::Type::getInt64Ty(llvmContext)); 1664 impl->int128Ty = LLVMType::get(context, llvm::Type::getInt128Ty(llvmContext)); 1665 /// Float Types. 1666 impl->doubleTy = LLVMType::get(context, llvm::Type::getDoubleTy(llvmContext)); 1667 impl->floatTy = LLVMType::get(context, llvm::Type::getFloatTy(llvmContext)); 1668 impl->halfTy = LLVMType::get(context, llvm::Type::getHalfTy(llvmContext)); 1669 impl->fp128Ty = LLVMType::get(context, llvm::Type::getFP128Ty(llvmContext)); 1670 impl->x86_fp80Ty = 1671 LLVMType::get(context, llvm::Type::getX86_FP80Ty(llvmContext)); 1672 /// Other Types. 1673 impl->voidTy = LLVMType::get(context, llvm::Type::getVoidTy(llvmContext)); 1674 } 1675 1676 LLVMDialect::~LLVMDialect() {} 1677 1678 #define GET_OP_CLASSES 1679 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1680 1681 llvm::LLVMContext &LLVMDialect::getLLVMContext() { return impl->llvmContext; } 1682 llvm::Module &LLVMDialect::getLLVMModule() { return impl->module; } 1683 llvm::sys::SmartMutex<true> &LLVMDialect::getLLVMContextMutex() { 1684 return impl->mutex; 1685 } 1686 1687 /// Parse a type registered to this dialect. 1688 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 1689 StringRef tyData = parser.getFullSymbolSpec(); 1690 1691 // LLVM is not thread-safe, so lock access to it. 1692 llvm::sys::SmartScopedLock<true> lock(impl->mutex); 1693 1694 llvm::SMDiagnostic errorMessage; 1695 llvm::Type *type = llvm::parseType(tyData, errorMessage, impl->module); 1696 if (!type) 1697 return (parser.emitError(parser.getNameLoc(), errorMessage.getMessage()), 1698 nullptr); 1699 return LLVMType::get(getContext(), type); 1700 } 1701 1702 /// Print a type registered to this dialect. 1703 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 1704 auto llvmType = type.dyn_cast<LLVMType>(); 1705 assert(llvmType && "printing wrong type"); 1706 assert(llvmType.getUnderlyingType() && "no underlying LLVM type"); 1707 llvmType.getUnderlyingType()->print(os.getStream()); 1708 } 1709 1710 /// Verify LLVMIR function argument attributes. 1711 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 1712 unsigned regionIdx, 1713 unsigned argIdx, 1714 NamedAttribute argAttr) { 1715 // Check that llvm.noalias is a boolean attribute. 1716 if (argAttr.first == "llvm.noalias" && !argAttr.second.isa<BoolAttr>()) 1717 return op->emitError() 1718 << "llvm.noalias argument attribute of non boolean type"; 1719 return success(); 1720 } 1721 1722 //===----------------------------------------------------------------------===// 1723 // LLVMType. 1724 //===----------------------------------------------------------------------===// 1725 1726 namespace mlir { 1727 namespace LLVM { 1728 namespace detail { 1729 struct LLVMTypeStorage : public ::mlir::TypeStorage { 1730 LLVMTypeStorage(llvm::Type *ty) : underlyingType(ty) {} 1731 1732 // LLVM types are pointer-unique. 1733 using KeyTy = llvm::Type *; 1734 bool operator==(const KeyTy &key) const { return key == underlyingType; } 1735 1736 static LLVMTypeStorage *construct(TypeStorageAllocator &allocator, 1737 llvm::Type *ty) { 1738 return new (allocator.allocate<LLVMTypeStorage>()) LLVMTypeStorage(ty); 1739 } 1740 1741 llvm::Type *underlyingType; 1742 }; 1743 } // end namespace detail 1744 } // end namespace LLVM 1745 } // end namespace mlir 1746 1747 LLVMType LLVMType::get(MLIRContext *context, llvm::Type *llvmType) { 1748 return Base::get(context, FIRST_LLVM_TYPE, llvmType); 1749 } 1750 1751 /// Get an LLVMType with an llvm type that may cause changes to the underlying 1752 /// llvm context when constructed. 1753 LLVMType LLVMType::getLocked(LLVMDialect *dialect, 1754 function_ref<llvm::Type *()> typeBuilder) { 1755 // Lock access to the llvm context and build the type. 1756 llvm::sys::SmartScopedLock<true> lock(dialect->impl->mutex); 1757 return get(dialect->getContext(), typeBuilder()); 1758 } 1759 1760 LLVMDialect &LLVMType::getDialect() { 1761 return static_cast<LLVMDialect &>(Type::getDialect()); 1762 } 1763 1764 llvm::Type *LLVMType::getUnderlyingType() const { 1765 return getImpl()->underlyingType; 1766 } 1767 1768 /// Array type utilities. 1769 LLVMType LLVMType::getArrayElementType() { 1770 return get(getContext(), getUnderlyingType()->getArrayElementType()); 1771 } 1772 unsigned LLVMType::getArrayNumElements() { 1773 return getUnderlyingType()->getArrayNumElements(); 1774 } 1775 bool LLVMType::isArrayTy() { return getUnderlyingType()->isArrayTy(); } 1776 1777 /// Vector type utilities. 1778 LLVMType LLVMType::getVectorElementType() { 1779 return get( 1780 getContext(), 1781 llvm::cast<llvm::VectorType>(getUnderlyingType())->getElementType()); 1782 } 1783 unsigned LLVMType::getVectorNumElements() { 1784 return llvm::cast<llvm::VectorType>(getUnderlyingType())->getNumElements(); 1785 } 1786 bool LLVMType::isVectorTy() { return getUnderlyingType()->isVectorTy(); } 1787 1788 /// Function type utilities. 1789 LLVMType LLVMType::getFunctionParamType(unsigned argIdx) { 1790 return get(getContext(), getUnderlyingType()->getFunctionParamType(argIdx)); 1791 } 1792 unsigned LLVMType::getFunctionNumParams() { 1793 return getUnderlyingType()->getFunctionNumParams(); 1794 } 1795 LLVMType LLVMType::getFunctionResultType() { 1796 return get( 1797 getContext(), 1798 llvm::cast<llvm::FunctionType>(getUnderlyingType())->getReturnType()); 1799 } 1800 bool LLVMType::isFunctionTy() { return getUnderlyingType()->isFunctionTy(); } 1801 1802 /// Pointer type utilities. 1803 LLVMType LLVMType::getPointerTo(unsigned addrSpace) { 1804 // Lock access to the dialect as this may modify the LLVM context. 1805 return getLocked(&getDialect(), [=] { 1806 return getUnderlyingType()->getPointerTo(addrSpace); 1807 }); 1808 } 1809 LLVMType LLVMType::getPointerElementTy() { 1810 return get(getContext(), getUnderlyingType()->getPointerElementType()); 1811 } 1812 bool LLVMType::isPointerTy() { return getUnderlyingType()->isPointerTy(); } 1813 1814 /// Struct type utilities. 1815 LLVMType LLVMType::getStructElementType(unsigned i) { 1816 return get(getContext(), getUnderlyingType()->getStructElementType(i)); 1817 } 1818 unsigned LLVMType::getStructNumElements() { 1819 return getUnderlyingType()->getStructNumElements(); 1820 } 1821 bool LLVMType::isStructTy() { return getUnderlyingType()->isStructTy(); } 1822 1823 /// Utilities used to generate floating point types. 1824 LLVMType LLVMType::getDoubleTy(LLVMDialect *dialect) { 1825 return dialect->impl->doubleTy; 1826 } 1827 LLVMType LLVMType::getFloatTy(LLVMDialect *dialect) { 1828 return dialect->impl->floatTy; 1829 } 1830 LLVMType LLVMType::getHalfTy(LLVMDialect *dialect) { 1831 return dialect->impl->halfTy; 1832 } 1833 LLVMType LLVMType::getFP128Ty(LLVMDialect *dialect) { 1834 return dialect->impl->fp128Ty; 1835 } 1836 LLVMType LLVMType::getX86_FP80Ty(LLVMDialect *dialect) { 1837 return dialect->impl->x86_fp80Ty; 1838 } 1839 1840 /// Utilities used to generate integer types. 1841 LLVMType LLVMType::getIntNTy(LLVMDialect *dialect, unsigned numBits) { 1842 switch (numBits) { 1843 case 1: 1844 return dialect->impl->int1Ty; 1845 case 8: 1846 return dialect->impl->int8Ty; 1847 case 16: 1848 return dialect->impl->int16Ty; 1849 case 32: 1850 return dialect->impl->int32Ty; 1851 case 64: 1852 return dialect->impl->int64Ty; 1853 case 128: 1854 return dialect->impl->int128Ty; 1855 default: 1856 break; 1857 } 1858 1859 // Lock access to the dialect as this may modify the LLVM context. 1860 return getLocked(dialect, [=] { 1861 return llvm::Type::getIntNTy(dialect->getLLVMContext(), numBits); 1862 }); 1863 } 1864 1865 /// Utilities used to generate other miscellaneous types. 1866 LLVMType LLVMType::getArrayTy(LLVMType elementType, uint64_t numElements) { 1867 // Lock access to the dialect as this may modify the LLVM context. 1868 return getLocked(&elementType.getDialect(), [=] { 1869 return llvm::ArrayType::get(elementType.getUnderlyingType(), numElements); 1870 }); 1871 } 1872 LLVMType LLVMType::getFunctionTy(LLVMType result, ArrayRef<LLVMType> params, 1873 bool isVarArg) { 1874 SmallVector<llvm::Type *, 8> llvmParams; 1875 for (auto param : params) 1876 llvmParams.push_back(param.getUnderlyingType()); 1877 1878 // Lock access to the dialect as this may modify the LLVM context. 1879 return getLocked(&result.getDialect(), [=] { 1880 return llvm::FunctionType::get(result.getUnderlyingType(), llvmParams, 1881 isVarArg); 1882 }); 1883 } 1884 LLVMType LLVMType::getStructTy(LLVMDialect *dialect, 1885 ArrayRef<LLVMType> elements, bool isPacked) { 1886 SmallVector<llvm::Type *, 8> llvmElements; 1887 for (auto elt : elements) 1888 llvmElements.push_back(elt.getUnderlyingType()); 1889 1890 // Lock access to the dialect as this may modify the LLVM context. 1891 return getLocked(dialect, [=] { 1892 return llvm::StructType::get(dialect->getLLVMContext(), llvmElements, 1893 isPacked); 1894 }); 1895 } 1896 inline static SmallVector<llvm::Type *, 8> 1897 toUnderlyingTypes(ArrayRef<LLVMType> elements) { 1898 SmallVector<llvm::Type *, 8> llvmElements; 1899 for (auto elt : elements) 1900 llvmElements.push_back(elt.getUnderlyingType()); 1901 return llvmElements; 1902 } 1903 LLVMType LLVMType::createStructTy(LLVMDialect *dialect, 1904 ArrayRef<LLVMType> elements, 1905 Optional<StringRef> name, bool isPacked) { 1906 StringRef sr = name.hasValue() ? *name : ""; 1907 SmallVector<llvm::Type *, 8> llvmElements(toUnderlyingTypes(elements)); 1908 return getLocked(dialect, [=] { 1909 auto *rv = llvm::StructType::create(dialect->getLLVMContext(), sr); 1910 if (!llvmElements.empty()) 1911 rv->setBody(llvmElements, isPacked); 1912 return rv; 1913 }); 1914 } 1915 LLVMType LLVMType::setStructTyBody(LLVMType structType, 1916 ArrayRef<LLVMType> elements, bool isPacked) { 1917 llvm::StructType *st = 1918 llvm::cast<llvm::StructType>(structType.getUnderlyingType()); 1919 SmallVector<llvm::Type *, 8> llvmElements(toUnderlyingTypes(elements)); 1920 return getLocked(&structType.getDialect(), [=] { 1921 st->setBody(llvmElements, isPacked); 1922 return st; 1923 }); 1924 } 1925 LLVMType LLVMType::getVectorTy(LLVMType elementType, unsigned numElements) { 1926 // Lock access to the dialect as this may modify the LLVM context. 1927 return getLocked(&elementType.getDialect(), [=] { 1928 return llvm::VectorType::get(elementType.getUnderlyingType(), numElements); 1929 }); 1930 } 1931 1932 LLVMType LLVMType::getVoidTy(LLVMDialect *dialect) { 1933 return dialect->impl->voidTy; 1934 } 1935 1936 bool LLVMType::isVoidTy() { return getUnderlyingType()->isVoidTy(); } 1937 1938 //===----------------------------------------------------------------------===// 1939 // Utility functions. 1940 //===----------------------------------------------------------------------===// 1941 1942 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 1943 StringRef name, StringRef value, 1944 LLVM::Linkage linkage, 1945 LLVM::LLVMDialect *llvmDialect) { 1946 assert(builder.getInsertionBlock() && 1947 builder.getInsertionBlock()->getParentOp() && 1948 "expected builder to point to a block constrained in an op"); 1949 auto module = 1950 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 1951 assert(module && "builder points to an op outside of a module"); 1952 1953 // Create the global at the entry of the module. 1954 OpBuilder moduleBuilder(module.getBodyRegion()); 1955 auto type = LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(llvmDialect), 1956 value.size()); 1957 auto global = moduleBuilder.create<LLVM::GlobalOp>( 1958 loc, type, /*isConstant=*/true, linkage, name, 1959 builder.getStringAttr(value)); 1960 1961 // Get the pointer to the first character in the global string. 1962 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 1963 Value cst0 = builder.create<LLVM::ConstantOp>( 1964 loc, LLVM::LLVMType::getInt64Ty(llvmDialect), 1965 builder.getIntegerAttr(builder.getIndexType(), 0)); 1966 return builder.create<LLVM::GEPOp>(loc, 1967 LLVM::LLVMType::getInt8PtrTy(llvmDialect), 1968 globalPtr, ArrayRef<Value>({cst0, cst0})); 1969 } 1970 1971 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 1972 return op->hasTrait<OpTrait::SymbolTable>() && 1973 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 1974 } 1975 1976 std::unique_ptr<llvm::Module> 1977 mlir::LLVM::cloneModuleIntoNewContext(llvm::LLVMContext *context, 1978 llvm::Module *module) { 1979 SmallVector<char, 1> buffer; 1980 { 1981 llvm::raw_svector_ostream os(buffer); 1982 WriteBitcodeToFile(*module, os); 1983 } 1984 llvm::MemoryBufferRef bufferRef(StringRef(buffer.data(), buffer.size()), 1985 "cloned module buffer"); 1986 return cantFail(parseBitcodeFile(bufferRef, *context)); 1987 } 1988