1 //===- LLVMDialect.cpp - LLVM IR Ops and Dialect registration -------------===// 2 // 3 // Part of the MLIR 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/AsmParser/Parser.h" 22 #include "llvm/IR/Attributes.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/IR/Type.h" 25 #include "llvm/Support/Mutex.h" 26 #include "llvm/Support/SourceMgr.h" 27 28 using namespace mlir; 29 using namespace mlir::LLVM; 30 31 #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc" 32 33 //===----------------------------------------------------------------------===// 34 // Printing/parsing for LLVM::CmpOp. 35 //===----------------------------------------------------------------------===// 36 static void printICmpOp(OpAsmPrinter &p, ICmpOp &op) { 37 p << op.getOperationName() << " \"" << stringifyICmpPredicate(op.predicate()) 38 << "\" " << op.getOperand(0) << ", " << op.getOperand(1); 39 p.printOptionalAttrDict(op.getAttrs(), {"predicate"}); 40 p << " : " << op.lhs().getType(); 41 } 42 43 static void printFCmpOp(OpAsmPrinter &p, FCmpOp &op) { 44 p << op.getOperationName() << " \"" << stringifyFCmpPredicate(op.predicate()) 45 << "\" " << op.getOperand(0) << ", " << op.getOperand(1); 46 p.printOptionalAttrDict(op.getAttrs(), {"predicate"}); 47 p << " : " << op.lhs().getType(); 48 } 49 50 // <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use 51 // attribute-dict? `:` type 52 // <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use 53 // attribute-dict? `:` type 54 template <typename CmpPredicateType> 55 static ParseResult parseCmpOp(OpAsmParser &parser, OperationState &result) { 56 Builder &builder = parser.getBuilder(); 57 58 Attribute predicate; 59 SmallVector<NamedAttribute, 4> attrs; 60 OpAsmParser::OperandType lhs, rhs; 61 Type type; 62 llvm::SMLoc predicateLoc, trailingTypeLoc; 63 if (parser.getCurrentLocation(&predicateLoc) || 64 parser.parseAttribute(predicate, "predicate", attrs) || 65 parser.parseOperand(lhs) || parser.parseComma() || 66 parser.parseOperand(rhs) || parser.parseOptionalAttrDict(attrs) || 67 parser.parseColon() || parser.getCurrentLocation(&trailingTypeLoc) || 68 parser.parseType(type) || 69 parser.resolveOperand(lhs, type, result.operands) || 70 parser.resolveOperand(rhs, type, result.operands)) 71 return failure(); 72 73 // Replace the string attribute `predicate` with an integer attribute. 74 auto predicateStr = predicate.dyn_cast<StringAttr>(); 75 if (!predicateStr) 76 return parser.emitError(predicateLoc, 77 "expected 'predicate' attribute of string type"); 78 79 int64_t predicateValue = 0; 80 if (std::is_same<CmpPredicateType, ICmpPredicate>()) { 81 Optional<ICmpPredicate> predicate = 82 symbolizeICmpPredicate(predicateStr.getValue()); 83 if (!predicate) 84 return parser.emitError(predicateLoc) 85 << "'" << predicateStr.getValue() 86 << "' is an incorrect value of the 'predicate' attribute"; 87 predicateValue = static_cast<int64_t>(predicate.getValue()); 88 } else { 89 Optional<FCmpPredicate> predicate = 90 symbolizeFCmpPredicate(predicateStr.getValue()); 91 if (!predicate) 92 return parser.emitError(predicateLoc) 93 << "'" << predicateStr.getValue() 94 << "' is an incorrect value of the 'predicate' attribute"; 95 predicateValue = static_cast<int64_t>(predicate.getValue()); 96 } 97 98 attrs[0].second = parser.getBuilder().getI64IntegerAttr(predicateValue); 99 100 // The result type is either i1 or a vector type <? x i1> if the inputs are 101 // vectors. 102 auto *dialect = builder.getContext()->getRegisteredDialect<LLVMDialect>(); 103 auto resultType = LLVMType::getInt1Ty(dialect); 104 auto argType = type.dyn_cast<LLVM::LLVMType>(); 105 if (!argType) 106 return parser.emitError(trailingTypeLoc, "expected LLVM IR dialect type"); 107 if (argType.getUnderlyingType()->isVectorTy()) 108 resultType = LLVMType::getVectorTy( 109 resultType, argType.getUnderlyingType()->getVectorNumElements()); 110 111 result.attributes = attrs; 112 result.addTypes({resultType}); 113 return success(); 114 } 115 116 //===----------------------------------------------------------------------===// 117 // Printing/parsing for LLVM::AllocaOp. 118 //===----------------------------------------------------------------------===// 119 120 static void printAllocaOp(OpAsmPrinter &p, AllocaOp &op) { 121 auto elemTy = op.getType().cast<LLVM::LLVMType>().getPointerElementTy(); 122 123 auto funcTy = FunctionType::get({op.arraySize().getType()}, {op.getType()}, 124 op.getContext()); 125 126 p << op.getOperationName() << ' ' << op.arraySize() << " x " << elemTy; 127 if (op.alignment().hasValue() && op.alignment()->getSExtValue() != 0) 128 p.printOptionalAttrDict(op.getAttrs()); 129 else 130 p.printOptionalAttrDict(op.getAttrs(), {"alignment"}); 131 p << " : " << funcTy; 132 } 133 134 // <operation> ::= `llvm.alloca` ssa-use `x` type attribute-dict? 135 // `:` type `,` type 136 static ParseResult parseAllocaOp(OpAsmParser &parser, OperationState &result) { 137 SmallVector<NamedAttribute, 4> attrs; 138 OpAsmParser::OperandType arraySize; 139 Type type, elemType; 140 llvm::SMLoc trailingTypeLoc; 141 if (parser.parseOperand(arraySize) || parser.parseKeyword("x") || 142 parser.parseType(elemType) || parser.parseOptionalAttrDict(attrs) || 143 parser.parseColon() || parser.getCurrentLocation(&trailingTypeLoc) || 144 parser.parseType(type)) 145 return failure(); 146 147 // Extract the result type from the trailing function type. 148 auto funcType = type.dyn_cast<FunctionType>(); 149 if (!funcType || funcType.getNumInputs() != 1 || 150 funcType.getNumResults() != 1) 151 return parser.emitError( 152 trailingTypeLoc, 153 "expected trailing function type with one argument and one result"); 154 155 if (parser.resolveOperand(arraySize, funcType.getInput(0), result.operands)) 156 return failure(); 157 158 result.attributes = attrs; 159 result.addTypes({funcType.getResult(0)}); 160 return success(); 161 } 162 163 //===----------------------------------------------------------------------===// 164 // Printing/parsing for LLVM::GEPOp. 165 //===----------------------------------------------------------------------===// 166 167 static void printGEPOp(OpAsmPrinter &p, GEPOp &op) { 168 SmallVector<Type, 8> types(op.getOperandTypes()); 169 auto funcTy = FunctionType::get(types, op.getType(), op.getContext()); 170 171 p << op.getOperationName() << ' ' << op.base() << '[' 172 << op.getOperands().drop_front() << ']'; 173 p.printOptionalAttrDict(op.getAttrs()); 174 p << " : " << funcTy; 175 } 176 177 // <operation> ::= `llvm.getelementptr` ssa-use `[` ssa-use-list `]` 178 // attribute-dict? `:` type 179 static ParseResult parseGEPOp(OpAsmParser &parser, OperationState &result) { 180 SmallVector<NamedAttribute, 4> attrs; 181 OpAsmParser::OperandType base; 182 SmallVector<OpAsmParser::OperandType, 8> indices; 183 Type type; 184 llvm::SMLoc trailingTypeLoc; 185 if (parser.parseOperand(base) || 186 parser.parseOperandList(indices, OpAsmParser::Delimiter::Square) || 187 parser.parseOptionalAttrDict(attrs) || parser.parseColon() || 188 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 189 return failure(); 190 191 // Deconstruct the trailing function type to extract the types of the base 192 // pointer and result (same type) and the types of the indices. 193 auto funcType = type.dyn_cast<FunctionType>(); 194 if (!funcType || funcType.getNumResults() != 1 || 195 funcType.getNumInputs() == 0) 196 return parser.emitError(trailingTypeLoc, 197 "expected trailing function type with at least " 198 "one argument and one result"); 199 200 if (parser.resolveOperand(base, funcType.getInput(0), result.operands) || 201 parser.resolveOperands(indices, funcType.getInputs().drop_front(), 202 parser.getNameLoc(), result.operands)) 203 return failure(); 204 205 result.attributes = attrs; 206 result.addTypes(funcType.getResults()); 207 return success(); 208 } 209 210 //===----------------------------------------------------------------------===// 211 // Printing/parsing for LLVM::LoadOp. 212 //===----------------------------------------------------------------------===// 213 214 static void printLoadOp(OpAsmPrinter &p, LoadOp &op) { 215 p << op.getOperationName() << ' ' << op.addr(); 216 p.printOptionalAttrDict(op.getAttrs()); 217 p << " : " << op.addr().getType(); 218 } 219 220 // Extract the pointee type from the LLVM pointer type wrapped in MLIR. Return 221 // the resulting type wrapped in MLIR, or nullptr on error. 222 static Type getLoadStoreElementType(OpAsmParser &parser, Type type, 223 llvm::SMLoc trailingTypeLoc) { 224 auto llvmTy = type.dyn_cast<LLVM::LLVMType>(); 225 if (!llvmTy) 226 return parser.emitError(trailingTypeLoc, "expected LLVM IR dialect type"), 227 nullptr; 228 if (!llvmTy.getUnderlyingType()->isPointerTy()) 229 return parser.emitError(trailingTypeLoc, "expected LLVM pointer type"), 230 nullptr; 231 return llvmTy.getPointerElementTy(); 232 } 233 234 // <operation> ::= `llvm.load` ssa-use attribute-dict? `:` type 235 static ParseResult parseLoadOp(OpAsmParser &parser, OperationState &result) { 236 SmallVector<NamedAttribute, 4> attrs; 237 OpAsmParser::OperandType addr; 238 Type type; 239 llvm::SMLoc trailingTypeLoc; 240 241 if (parser.parseOperand(addr) || parser.parseOptionalAttrDict(attrs) || 242 parser.parseColon() || parser.getCurrentLocation(&trailingTypeLoc) || 243 parser.parseType(type) || 244 parser.resolveOperand(addr, type, result.operands)) 245 return failure(); 246 247 Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc); 248 249 result.attributes = attrs; 250 result.addTypes(elemTy); 251 return success(); 252 } 253 254 //===----------------------------------------------------------------------===// 255 // Printing/parsing for LLVM::StoreOp. 256 //===----------------------------------------------------------------------===// 257 258 static void printStoreOp(OpAsmPrinter &p, StoreOp &op) { 259 p << op.getOperationName() << ' ' << op.value() << ", " << op.addr(); 260 p.printOptionalAttrDict(op.getAttrs()); 261 p << " : " << op.addr().getType(); 262 } 263 264 // <operation> ::= `llvm.store` ssa-use `,` ssa-use attribute-dict? `:` type 265 static ParseResult parseStoreOp(OpAsmParser &parser, OperationState &result) { 266 SmallVector<NamedAttribute, 4> attrs; 267 OpAsmParser::OperandType addr, value; 268 Type type; 269 llvm::SMLoc trailingTypeLoc; 270 271 if (parser.parseOperand(value) || parser.parseComma() || 272 parser.parseOperand(addr) || parser.parseOptionalAttrDict(attrs) || 273 parser.parseColon() || parser.getCurrentLocation(&trailingTypeLoc) || 274 parser.parseType(type)) 275 return failure(); 276 277 Type elemTy = getLoadStoreElementType(parser, type, trailingTypeLoc); 278 if (!elemTy) 279 return failure(); 280 281 if (parser.resolveOperand(value, elemTy, result.operands) || 282 parser.resolveOperand(addr, type, result.operands)) 283 return failure(); 284 285 result.attributes = attrs; 286 return success(); 287 } 288 289 //===----------------------------------------------------------------------===// 290 // Printing/parsing for LLVM::CallOp. 291 //===----------------------------------------------------------------------===// 292 293 static void printCallOp(OpAsmPrinter &p, CallOp &op) { 294 auto callee = op.callee(); 295 bool isDirect = callee.hasValue(); 296 297 // Print the direct callee if present as a function attribute, or an indirect 298 // callee (first operand) otherwise. 299 p << op.getOperationName() << ' '; 300 if (isDirect) 301 p.printSymbolName(callee.getValue()); 302 else 303 p << op.getOperand(0); 304 305 p << '(' << op.getOperands().drop_front(isDirect ? 0 : 1) << ')'; 306 p.printOptionalAttrDict(op.getAttrs(), {"callee"}); 307 308 // Reconstruct the function MLIR function type from operand and result types. 309 SmallVector<Type, 1> resultTypes(op.getResultTypes()); 310 SmallVector<Type, 8> argTypes( 311 llvm::drop_begin(op.getOperandTypes(), isDirect ? 0 : 1)); 312 313 p << " : " << FunctionType::get(argTypes, resultTypes, op.getContext()); 314 } 315 316 // <operation> ::= `llvm.call` (function-id | ssa-use) `(` ssa-use-list `)` 317 // attribute-dict? `:` function-type 318 static ParseResult parseCallOp(OpAsmParser &parser, OperationState &result) { 319 SmallVector<NamedAttribute, 4> attrs; 320 SmallVector<OpAsmParser::OperandType, 8> operands; 321 Type type; 322 SymbolRefAttr funcAttr; 323 llvm::SMLoc trailingTypeLoc; 324 325 // Parse an operand list that will, in practice, contain 0 or 1 operand. In 326 // case of an indirect call, there will be 1 operand before `(`. In case of a 327 // direct call, there will be no operands and the parser will stop at the 328 // function identifier without complaining. 329 if (parser.parseOperandList(operands)) 330 return failure(); 331 bool isDirect = operands.empty(); 332 333 // Optionally parse a function identifier. 334 if (isDirect) 335 if (parser.parseAttribute(funcAttr, "callee", attrs)) 336 return failure(); 337 338 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren) || 339 parser.parseOptionalAttrDict(attrs) || parser.parseColon() || 340 parser.getCurrentLocation(&trailingTypeLoc) || parser.parseType(type)) 341 return failure(); 342 343 auto funcType = type.dyn_cast<FunctionType>(); 344 if (!funcType) 345 return parser.emitError(trailingTypeLoc, "expected function type"); 346 if (isDirect) { 347 // Make sure types match. 348 if (parser.resolveOperands(operands, funcType.getInputs(), 349 parser.getNameLoc(), result.operands)) 350 return failure(); 351 result.addTypes(funcType.getResults()); 352 } else { 353 // Construct the LLVM IR Dialect function type that the first operand 354 // should match. 355 if (funcType.getNumResults() > 1) 356 return parser.emitError(trailingTypeLoc, 357 "expected function with 0 or 1 result"); 358 359 Builder &builder = parser.getBuilder(); 360 auto *llvmDialect = 361 builder.getContext()->getRegisteredDialect<LLVM::LLVMDialect>(); 362 LLVM::LLVMType llvmResultType; 363 if (funcType.getNumResults() == 0) { 364 llvmResultType = LLVM::LLVMType::getVoidTy(llvmDialect); 365 } else { 366 llvmResultType = funcType.getResult(0).dyn_cast<LLVM::LLVMType>(); 367 if (!llvmResultType) 368 return parser.emitError(trailingTypeLoc, 369 "expected result to have LLVM type"); 370 } 371 372 SmallVector<LLVM::LLVMType, 8> argTypes; 373 argTypes.reserve(funcType.getNumInputs()); 374 for (int i = 0, e = funcType.getNumInputs(); i < e; ++i) { 375 auto argType = funcType.getInput(i).dyn_cast<LLVM::LLVMType>(); 376 if (!argType) 377 return parser.emitError(trailingTypeLoc, 378 "expected LLVM types as inputs"); 379 argTypes.push_back(argType); 380 } 381 auto llvmFuncType = LLVM::LLVMType::getFunctionTy(llvmResultType, argTypes, 382 /*isVarArg=*/false); 383 auto wrappedFuncType = llvmFuncType.getPointerTo(); 384 385 auto funcArguments = 386 ArrayRef<OpAsmParser::OperandType>(operands).drop_front(); 387 388 // Make sure that the first operand (indirect callee) matches the wrapped 389 // LLVM IR function type, and that the types of the other call operands 390 // match the types of the function arguments. 391 if (parser.resolveOperand(operands[0], wrappedFuncType, result.operands) || 392 parser.resolveOperands(funcArguments, funcType.getInputs(), 393 parser.getNameLoc(), result.operands)) 394 return failure(); 395 396 result.addTypes(llvmResultType); 397 } 398 399 result.attributes = attrs; 400 return success(); 401 } 402 403 //===----------------------------------------------------------------------===// 404 // Printing/parsing for LLVM::ExtractElementOp. 405 //===----------------------------------------------------------------------===// 406 // Expects vector to be of wrapped LLVM vector type and position to be of 407 // wrapped LLVM i32 type. 408 void LLVM::ExtractElementOp::build(Builder *b, OperationState &result, 409 Value vector, Value position, 410 ArrayRef<NamedAttribute> attrs) { 411 auto wrappedVectorType = vector.getType().cast<LLVM::LLVMType>(); 412 auto llvmType = wrappedVectorType.getVectorElementType(); 413 build(b, result, llvmType, vector, position); 414 result.addAttributes(attrs); 415 } 416 417 static void printExtractElementOp(OpAsmPrinter &p, ExtractElementOp &op) { 418 p << op.getOperationName() << ' ' << op.vector() << "[" << op.position() 419 << " : " << op.position().getType() << "]"; 420 p.printOptionalAttrDict(op.getAttrs()); 421 p << " : " << op.vector().getType(); 422 } 423 424 // <operation> ::= `llvm.extractelement` ssa-use `, ` ssa-use 425 // attribute-dict? `:` type 426 static ParseResult parseExtractElementOp(OpAsmParser &parser, 427 OperationState &result) { 428 llvm::SMLoc loc; 429 OpAsmParser::OperandType vector, position; 430 Type type, positionType; 431 if (parser.getCurrentLocation(&loc) || parser.parseOperand(vector) || 432 parser.parseLSquare() || parser.parseOperand(position) || 433 parser.parseColonType(positionType) || parser.parseRSquare() || 434 parser.parseOptionalAttrDict(result.attributes) || 435 parser.parseColonType(type) || 436 parser.resolveOperand(vector, type, result.operands) || 437 parser.resolveOperand(position, positionType, result.operands)) 438 return failure(); 439 auto wrappedVectorType = type.dyn_cast<LLVM::LLVMType>(); 440 if (!wrappedVectorType || 441 !wrappedVectorType.getUnderlyingType()->isVectorTy()) 442 return parser.emitError( 443 loc, "expected LLVM IR dialect vector type for operand #1"); 444 result.addTypes(wrappedVectorType.getVectorElementType()); 445 return success(); 446 } 447 448 //===----------------------------------------------------------------------===// 449 // Printing/parsing for LLVM::ExtractValueOp. 450 //===----------------------------------------------------------------------===// 451 452 static void printExtractValueOp(OpAsmPrinter &p, ExtractValueOp &op) { 453 p << op.getOperationName() << ' ' << op.container() << op.position(); 454 p.printOptionalAttrDict(op.getAttrs(), {"position"}); 455 p << " : " << op.container().getType(); 456 } 457 458 // Extract the type at `position` in the wrapped LLVM IR aggregate type 459 // `containerType`. Position is an integer array attribute where each value 460 // is a zero-based position of the element in the aggregate type. Return the 461 // resulting type wrapped in MLIR, or nullptr on error. 462 static LLVM::LLVMType getInsertExtractValueElementType(OpAsmParser &parser, 463 Type containerType, 464 Attribute positionAttr, 465 llvm::SMLoc attributeLoc, 466 llvm::SMLoc typeLoc) { 467 auto wrappedContainerType = containerType.dyn_cast<LLVM::LLVMType>(); 468 if (!wrappedContainerType) 469 return parser.emitError(typeLoc, "expected LLVM IR Dialect type"), nullptr; 470 471 auto positionArrayAttr = positionAttr.dyn_cast<ArrayAttr>(); 472 if (!positionArrayAttr) 473 return parser.emitError(attributeLoc, "expected an array attribute"), 474 nullptr; 475 476 // Infer the element type from the structure type: iteratively step inside the 477 // type by taking the element type, indexed by the position attribute for 478 // structures. Check the position index before accessing, it is supposed to 479 // be in bounds. 480 for (Attribute subAttr : positionArrayAttr) { 481 auto positionElementAttr = subAttr.dyn_cast<IntegerAttr>(); 482 if (!positionElementAttr) 483 return parser.emitError(attributeLoc, 484 "expected an array of integer literals"), 485 nullptr; 486 int position = positionElementAttr.getInt(); 487 auto *llvmContainerType = wrappedContainerType.getUnderlyingType(); 488 if (llvmContainerType->isArrayTy()) { 489 if (position < 0 || static_cast<unsigned>(position) >= 490 llvmContainerType->getArrayNumElements()) 491 return parser.emitError(attributeLoc, "position out of bounds"), 492 nullptr; 493 wrappedContainerType = wrappedContainerType.getArrayElementType(); 494 } else if (llvmContainerType->isStructTy()) { 495 if (position < 0 || static_cast<unsigned>(position) >= 496 llvmContainerType->getStructNumElements()) 497 return parser.emitError(attributeLoc, "position out of bounds"), 498 nullptr; 499 wrappedContainerType = 500 wrappedContainerType.getStructElementType(position); 501 } else { 502 return parser.emitError(typeLoc, 503 "expected wrapped LLVM IR structure/array type"), 504 nullptr; 505 } 506 } 507 return wrappedContainerType; 508 } 509 510 // <operation> ::= `llvm.extractvalue` ssa-use 511 // `[` integer-literal (`,` integer-literal)* `]` 512 // attribute-dict? `:` type 513 static ParseResult parseExtractValueOp(OpAsmParser &parser, 514 OperationState &result) { 515 SmallVector<NamedAttribute, 4> attrs; 516 OpAsmParser::OperandType container; 517 Type containerType; 518 Attribute positionAttr; 519 llvm::SMLoc attributeLoc, trailingTypeLoc; 520 521 if (parser.parseOperand(container) || 522 parser.getCurrentLocation(&attributeLoc) || 523 parser.parseAttribute(positionAttr, "position", attrs) || 524 parser.parseOptionalAttrDict(attrs) || parser.parseColon() || 525 parser.getCurrentLocation(&trailingTypeLoc) || 526 parser.parseType(containerType) || 527 parser.resolveOperand(container, containerType, result.operands)) 528 return failure(); 529 530 auto elementType = getInsertExtractValueElementType( 531 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 532 if (!elementType) 533 return failure(); 534 535 result.attributes = attrs; 536 result.addTypes(elementType); 537 return success(); 538 } 539 540 //===----------------------------------------------------------------------===// 541 // Printing/parsing for LLVM::InsertElementOp. 542 //===----------------------------------------------------------------------===// 543 544 static void printInsertElementOp(OpAsmPrinter &p, InsertElementOp &op) { 545 p << op.getOperationName() << ' ' << op.value() << ", " << op.vector() << "[" 546 << op.position() << " : " << op.position().getType() << "]"; 547 p.printOptionalAttrDict(op.getAttrs()); 548 p << " : " << op.vector().getType(); 549 } 550 551 // <operation> ::= `llvm.insertelement` ssa-use `,` ssa-use `,` ssa-use 552 // attribute-dict? `:` type 553 static ParseResult parseInsertElementOp(OpAsmParser &parser, 554 OperationState &result) { 555 llvm::SMLoc loc; 556 OpAsmParser::OperandType vector, value, position; 557 Type vectorType, positionType; 558 if (parser.getCurrentLocation(&loc) || parser.parseOperand(value) || 559 parser.parseComma() || parser.parseOperand(vector) || 560 parser.parseLSquare() || parser.parseOperand(position) || 561 parser.parseColonType(positionType) || parser.parseRSquare() || 562 parser.parseOptionalAttrDict(result.attributes) || 563 parser.parseColonType(vectorType)) 564 return failure(); 565 566 auto wrappedVectorType = vectorType.dyn_cast<LLVM::LLVMType>(); 567 if (!wrappedVectorType || 568 !wrappedVectorType.getUnderlyingType()->isVectorTy()) 569 return parser.emitError( 570 loc, "expected LLVM IR dialect vector type for operand #1"); 571 auto valueType = wrappedVectorType.getVectorElementType(); 572 if (!valueType) 573 return failure(); 574 575 if (parser.resolveOperand(vector, vectorType, result.operands) || 576 parser.resolveOperand(value, valueType, result.operands) || 577 parser.resolveOperand(position, positionType, result.operands)) 578 return failure(); 579 580 result.addTypes(vectorType); 581 return success(); 582 } 583 584 //===----------------------------------------------------------------------===// 585 // Printing/parsing for LLVM::InsertValueOp. 586 //===----------------------------------------------------------------------===// 587 588 static void printInsertValueOp(OpAsmPrinter &p, InsertValueOp &op) { 589 p << op.getOperationName() << ' ' << op.value() << ", " << op.container() 590 << op.position(); 591 p.printOptionalAttrDict(op.getAttrs(), {"position"}); 592 p << " : " << op.container().getType(); 593 } 594 595 // <operation> ::= `llvm.insertvaluevalue` ssa-use `,` ssa-use 596 // `[` integer-literal (`,` integer-literal)* `]` 597 // attribute-dict? `:` type 598 static ParseResult parseInsertValueOp(OpAsmParser &parser, 599 OperationState &result) { 600 OpAsmParser::OperandType container, value; 601 Type containerType; 602 Attribute positionAttr; 603 llvm::SMLoc attributeLoc, trailingTypeLoc; 604 605 if (parser.parseOperand(value) || parser.parseComma() || 606 parser.parseOperand(container) || 607 parser.getCurrentLocation(&attributeLoc) || 608 parser.parseAttribute(positionAttr, "position", result.attributes) || 609 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || 610 parser.getCurrentLocation(&trailingTypeLoc) || 611 parser.parseType(containerType)) 612 return failure(); 613 614 auto valueType = getInsertExtractValueElementType( 615 parser, containerType, positionAttr, attributeLoc, trailingTypeLoc); 616 if (!valueType) 617 return failure(); 618 619 if (parser.resolveOperand(container, containerType, result.operands) || 620 parser.resolveOperand(value, valueType, result.operands)) 621 return failure(); 622 623 result.addTypes(containerType); 624 return success(); 625 } 626 627 //===----------------------------------------------------------------------===// 628 // Printing/parsing for LLVM::SelectOp. 629 //===----------------------------------------------------------------------===// 630 631 static void printSelectOp(OpAsmPrinter &p, SelectOp &op) { 632 p << op.getOperationName() << ' ' << op.condition() << ", " << op.trueValue() 633 << ", " << op.falseValue(); 634 p.printOptionalAttrDict(op.getAttrs()); 635 p << " : " << op.condition().getType() << ", " << op.trueValue().getType(); 636 } 637 638 // <operation> ::= `llvm.select` ssa-use `,` ssa-use `,` ssa-use 639 // attribute-dict? `:` type, type 640 static ParseResult parseSelectOp(OpAsmParser &parser, OperationState &result) { 641 OpAsmParser::OperandType condition, trueValue, falseValue; 642 Type conditionType, argType; 643 644 if (parser.parseOperand(condition) || parser.parseComma() || 645 parser.parseOperand(trueValue) || parser.parseComma() || 646 parser.parseOperand(falseValue) || 647 parser.parseOptionalAttrDict(result.attributes) || 648 parser.parseColonType(conditionType) || parser.parseComma() || 649 parser.parseType(argType)) 650 return failure(); 651 652 if (parser.resolveOperand(condition, conditionType, result.operands) || 653 parser.resolveOperand(trueValue, argType, result.operands) || 654 parser.resolveOperand(falseValue, argType, result.operands)) 655 return failure(); 656 657 result.addTypes(argType); 658 return success(); 659 } 660 661 //===----------------------------------------------------------------------===// 662 // Printing/parsing for LLVM::BrOp. 663 //===----------------------------------------------------------------------===// 664 665 static void printBrOp(OpAsmPrinter &p, BrOp &op) { 666 p << op.getOperationName() << ' '; 667 p.printSuccessorAndUseList(op.getOperation(), 0); 668 p.printOptionalAttrDict(op.getAttrs()); 669 } 670 671 // <operation> ::= `llvm.br` bb-id (`[` ssa-use-and-type-list `]`)? 672 // attribute-dict? 673 static ParseResult parseBrOp(OpAsmParser &parser, OperationState &result) { 674 Block *dest; 675 SmallVector<Value, 4> operands; 676 if (parser.parseSuccessorAndUseList(dest, operands) || 677 parser.parseOptionalAttrDict(result.attributes)) 678 return failure(); 679 680 result.addSuccessor(dest, operands); 681 return success(); 682 } 683 684 //===----------------------------------------------------------------------===// 685 // Printing/parsing for LLVM::CondBrOp. 686 //===----------------------------------------------------------------------===// 687 688 static void printCondBrOp(OpAsmPrinter &p, CondBrOp &op) { 689 p << op.getOperationName() << ' ' << op.getOperand(0) << ", "; 690 p.printSuccessorAndUseList(op.getOperation(), 0); 691 p << ", "; 692 p.printSuccessorAndUseList(op.getOperation(), 1); 693 p.printOptionalAttrDict(op.getAttrs()); 694 } 695 696 // <operation> ::= `llvm.cond_br` ssa-use `,` 697 // bb-id (`[` ssa-use-and-type-list `]`)? `,` 698 // bb-id (`[` ssa-use-and-type-list `]`)? attribute-dict? 699 static ParseResult parseCondBrOp(OpAsmParser &parser, OperationState &result) { 700 Block *trueDest; 701 Block *falseDest; 702 SmallVector<Value, 4> trueOperands; 703 SmallVector<Value, 4> falseOperands; 704 OpAsmParser::OperandType condition; 705 706 Builder &builder = parser.getBuilder(); 707 auto *llvmDialect = 708 builder.getContext()->getRegisteredDialect<LLVM::LLVMDialect>(); 709 auto i1Type = LLVM::LLVMType::getInt1Ty(llvmDialect); 710 711 if (parser.parseOperand(condition) || parser.parseComma() || 712 parser.parseSuccessorAndUseList(trueDest, trueOperands) || 713 parser.parseComma() || 714 parser.parseSuccessorAndUseList(falseDest, falseOperands) || 715 parser.parseOptionalAttrDict(result.attributes) || 716 parser.resolveOperand(condition, i1Type, result.operands)) 717 return failure(); 718 719 result.addSuccessor(trueDest, trueOperands); 720 result.addSuccessor(falseDest, falseOperands); 721 return success(); 722 } 723 724 //===----------------------------------------------------------------------===// 725 // Printing/parsing for LLVM::ReturnOp. 726 //===----------------------------------------------------------------------===// 727 728 static void printReturnOp(OpAsmPrinter &p, ReturnOp &op) { 729 p << op.getOperationName(); 730 p.printOptionalAttrDict(op.getAttrs()); 731 assert(op.getNumOperands() <= 1); 732 733 if (op.getNumOperands() == 0) 734 return; 735 736 p << ' ' << op.getOperand(0) << " : " << op.getOperand(0).getType(); 737 } 738 739 // <operation> ::= `llvm.return` ssa-use-list attribute-dict? `:` 740 // type-list-no-parens 741 static ParseResult parseReturnOp(OpAsmParser &parser, OperationState &result) { 742 SmallVector<OpAsmParser::OperandType, 1> operands; 743 Type type; 744 745 if (parser.parseOperandList(operands) || 746 parser.parseOptionalAttrDict(result.attributes)) 747 return failure(); 748 if (operands.empty()) 749 return success(); 750 751 if (parser.parseColonType(type) || 752 parser.resolveOperand(operands[0], type, result.operands)) 753 return failure(); 754 return success(); 755 } 756 757 //===----------------------------------------------------------------------===// 758 // Printing/parsing for LLVM::UndefOp. 759 //===----------------------------------------------------------------------===// 760 761 static void printUndefOp(OpAsmPrinter &p, UndefOp &op) { 762 p << op.getOperationName(); 763 p.printOptionalAttrDict(op.getAttrs()); 764 p << " : " << op.res().getType(); 765 } 766 767 // <operation> ::= `llvm.mlir.undef` attribute-dict? : type 768 static ParseResult parseUndefOp(OpAsmParser &parser, OperationState &result) { 769 Type type; 770 771 if (parser.parseOptionalAttrDict(result.attributes) || 772 parser.parseColonType(type)) 773 return failure(); 774 775 result.addTypes(type); 776 return success(); 777 } 778 779 //===----------------------------------------------------------------------===// 780 // Printer, parser and verifier for LLVM::AddressOfOp. 781 //===----------------------------------------------------------------------===// 782 783 GlobalOp AddressOfOp::getGlobal() { 784 Operation *module = getParentOp(); 785 while (module && !satisfiesLLVMModule(module)) 786 module = module->getParentOp(); 787 assert(module && "unexpected operation outside of a module"); 788 return dyn_cast_or_null<LLVM::GlobalOp>( 789 mlir::SymbolTable::lookupSymbolIn(module, global_name())); 790 } 791 792 static void printAddressOfOp(OpAsmPrinter &p, AddressOfOp op) { 793 p << op.getOperationName() << " @" << op.global_name(); 794 p.printOptionalAttrDict(op.getAttrs(), {"global_name"}); 795 p << " : " << op.getResult().getType(); 796 } 797 798 static ParseResult parseAddressOfOp(OpAsmParser &parser, 799 OperationState &result) { 800 Attribute symRef; 801 Type type; 802 if (parser.parseAttribute(symRef, "global_name", result.attributes) || 803 parser.parseOptionalAttrDict(result.attributes) || 804 parser.parseColonType(type) || parser.addTypeToList(type, result.types)) 805 return failure(); 806 807 if (!symRef.isa<SymbolRefAttr>()) 808 return parser.emitError(parser.getNameLoc(), "expected symbol reference"); 809 return success(); 810 } 811 812 static LogicalResult verify(AddressOfOp op) { 813 auto global = op.getGlobal(); 814 if (!global) 815 return op.emitOpError( 816 "must reference a global defined by 'llvm.mlir.global'"); 817 818 if (global.getType().getPointerTo(global.addr_space().getZExtValue()) != 819 op.getResult().getType()) 820 return op.emitOpError( 821 "the type must be a pointer to the type of the referred global"); 822 823 return success(); 824 } 825 826 //===----------------------------------------------------------------------===// 827 // Printing/parsing for LLVM::ConstantOp. 828 //===----------------------------------------------------------------------===// 829 830 static void printConstantOp(OpAsmPrinter &p, ConstantOp &op) { 831 p << op.getOperationName() << '(' << op.value() << ')'; 832 p.printOptionalAttrDict(op.getAttrs(), {"value"}); 833 p << " : " << op.res().getType(); 834 } 835 836 // <operation> ::= `llvm.mlir.constant` `(` attribute `)` attribute-list? : type 837 static ParseResult parseConstantOp(OpAsmParser &parser, 838 OperationState &result) { 839 Attribute valueAttr; 840 Type type; 841 842 if (parser.parseLParen() || 843 parser.parseAttribute(valueAttr, "value", result.attributes) || 844 parser.parseRParen() || parser.parseOptionalAttrDict(result.attributes) || 845 parser.parseColonType(type)) 846 return failure(); 847 848 result.addTypes(type); 849 return success(); 850 } 851 852 //===----------------------------------------------------------------------===// 853 // Builder, printer and verifier for LLVM::GlobalOp. 854 //===----------------------------------------------------------------------===// 855 856 /// Returns the name used for the linkge attribute. This *must* correspond to 857 /// the name of the attribute in ODS. 858 static StringRef getLinkageAttrName() { return "linkage"; } 859 860 void GlobalOp::build(Builder *builder, OperationState &result, LLVMType type, 861 bool isConstant, Linkage linkage, StringRef name, 862 Attribute value, unsigned addrSpace, 863 ArrayRef<NamedAttribute> attrs) { 864 result.addAttribute(SymbolTable::getSymbolAttrName(), 865 builder->getStringAttr(name)); 866 result.addAttribute("type", TypeAttr::get(type)); 867 if (isConstant) 868 result.addAttribute("constant", builder->getUnitAttr()); 869 if (value) 870 result.addAttribute("value", value); 871 result.addAttribute(getLinkageAttrName(), builder->getI64IntegerAttr( 872 static_cast<int64_t>(linkage))); 873 if (addrSpace != 0) 874 result.addAttribute("addr_space", builder->getI32IntegerAttr(addrSpace)); 875 result.attributes.append(attrs.begin(), attrs.end()); 876 result.addRegion(); 877 } 878 879 // Returns the textual representation of the given linkage. 880 static StringRef linkageToStr(LLVM::Linkage linkage) { 881 switch (linkage) { 882 case LLVM::Linkage::Private: 883 return "private"; 884 case LLVM::Linkage::Internal: 885 return "internal"; 886 case LLVM::Linkage::AvailableExternally: 887 return "available_externally"; 888 case LLVM::Linkage::Linkonce: 889 return "linkonce"; 890 case LLVM::Linkage::Weak: 891 return "weak"; 892 case LLVM::Linkage::Common: 893 return "common"; 894 case LLVM::Linkage::Appending: 895 return "appending"; 896 case LLVM::Linkage::ExternWeak: 897 return "extern_weak"; 898 case LLVM::Linkage::LinkonceODR: 899 return "linkonce_odr"; 900 case LLVM::Linkage::WeakODR: 901 return "weak_odr"; 902 case LLVM::Linkage::External: 903 return "external"; 904 } 905 llvm_unreachable("unknown linkage type"); 906 } 907 908 // Prints the keyword for the linkage type using the printer. 909 static void printLinkage(OpAsmPrinter &p, LLVM::Linkage linkage) { 910 p << linkageToStr(linkage); 911 } 912 913 static void printGlobalOp(OpAsmPrinter &p, GlobalOp op) { 914 p << op.getOperationName() << ' '; 915 printLinkage(p, op.linkage()); 916 p << ' '; 917 if (op.constant()) 918 p << "constant "; 919 p.printSymbolName(op.sym_name()); 920 p << '('; 921 if (auto value = op.getValueOrNull()) 922 p.printAttribute(value); 923 p << ')'; 924 p.printOptionalAttrDict(op.getAttrs(), 925 {SymbolTable::getSymbolAttrName(), "type", "constant", 926 "value", getLinkageAttrName()}); 927 928 // Print the trailing type unless it's a string global. 929 if (op.getValueOrNull().dyn_cast_or_null<StringAttr>()) 930 return; 931 p << " : " << op.type(); 932 933 Region &initializer = op.getInitializerRegion(); 934 if (!initializer.empty()) 935 p.printRegion(initializer, /*printEntryBlockArgs=*/false); 936 } 937 938 // Parses one of the keywords provided in the list `keywords` and returns the 939 // position of the parsed keyword in the list. If none of the keywords from the 940 // list is parsed, returns -1. 941 static int parseOptionalKeywordAlternative(OpAsmParser &parser, 942 ArrayRef<StringRef> keywords) { 943 for (auto en : llvm::enumerate(keywords)) { 944 if (succeeded(parser.parseOptionalKeyword(en.value()))) 945 return en.index(); 946 } 947 return -1; 948 } 949 950 // Parses one of the linkage keywords and, if succeeded, appends the "linkage" 951 // integer attribute with the corresponding value to `result`. 952 // 953 // linkage ::= `private` | `internal` | `available_externally` | `linkonce` 954 // | `weak` | `common` | `appending` | `extern_weak` 955 // | `linkonce_odr` | `weak_odr` | `external 956 static ParseResult parseOptionalLinkageKeyword(OpAsmParser &parser, 957 OperationState &result) { 958 int index = parseOptionalKeywordAlternative( 959 parser, {"private", "internal", "available_externally", "linkonce", 960 "weak", "common", "appending", "extern_weak", "linkonce_odr", 961 "weak_odr", "external"}); 962 if (index == -1) 963 return failure(); 964 result.addAttribute(getLinkageAttrName(), 965 parser.getBuilder().getI64IntegerAttr(index)); 966 return success(); 967 } 968 969 // operation ::= `llvm.mlir.global` linkage `constant`? `@` identifier 970 // `(` attribute? `)` attribute-list? (`:` type)? region? 971 // 972 // The type can be omitted for string attributes, in which case it will be 973 // inferred from the value of the string as [strlen(value) x i8]. 974 static ParseResult parseGlobalOp(OpAsmParser &parser, OperationState &result) { 975 if (failed(parseOptionalLinkageKeyword(parser, result))) 976 return parser.emitError(parser.getCurrentLocation(), "expected linkage"); 977 978 if (succeeded(parser.parseOptionalKeyword("constant"))) 979 result.addAttribute("constant", parser.getBuilder().getUnitAttr()); 980 981 StringAttr name; 982 if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), 983 result.attributes) || 984 parser.parseLParen()) 985 return failure(); 986 987 Attribute value; 988 if (parser.parseOptionalRParen()) { 989 if (parser.parseAttribute(value, "value", result.attributes) || 990 parser.parseRParen()) 991 return failure(); 992 } 993 994 SmallVector<Type, 1> types; 995 if (parser.parseOptionalAttrDict(result.attributes) || 996 parser.parseOptionalColonTypeList(types)) 997 return failure(); 998 999 if (types.size() > 1) 1000 return parser.emitError(parser.getNameLoc(), "expected zero or one type"); 1001 1002 Region &initRegion = *result.addRegion(); 1003 if (types.empty()) { 1004 if (auto strAttr = value.dyn_cast_or_null<StringAttr>()) { 1005 MLIRContext *context = parser.getBuilder().getContext(); 1006 auto *dialect = context->getRegisteredDialect<LLVMDialect>(); 1007 auto arrayType = LLVM::LLVMType::getArrayTy( 1008 LLVM::LLVMType::getInt8Ty(dialect), strAttr.getValue().size()); 1009 types.push_back(arrayType); 1010 } else { 1011 return parser.emitError(parser.getNameLoc(), 1012 "type can only be omitted for string globals"); 1013 } 1014 } else if (parser.parseOptionalRegion(initRegion, /*arguments=*/{}, 1015 /*argTypes=*/{})) { 1016 return failure(); 1017 } 1018 1019 result.addAttribute("type", TypeAttr::get(types[0])); 1020 return success(); 1021 } 1022 1023 static LogicalResult verify(GlobalOp op) { 1024 if (!llvm::PointerType::isValidElementType(op.getType().getUnderlyingType())) 1025 return op.emitOpError( 1026 "expects type to be a valid element type for an LLVM pointer"); 1027 if (op.getParentOp() && !satisfiesLLVMModule(op.getParentOp())) 1028 return op.emitOpError("must appear at the module level"); 1029 1030 if (auto strAttr = op.getValueOrNull().dyn_cast_or_null<StringAttr>()) { 1031 auto type = op.getType(); 1032 if (!type.getUnderlyingType()->isArrayTy() || 1033 !type.getArrayElementType().getUnderlyingType()->isIntegerTy(8) || 1034 type.getArrayNumElements() != strAttr.getValue().size()) 1035 return op.emitOpError( 1036 "requires an i8 array type of the length equal to that of the string " 1037 "attribute"); 1038 } 1039 1040 if (Block *b = op.getInitializerBlock()) { 1041 ReturnOp ret = cast<ReturnOp>(b->getTerminator()); 1042 if (ret.operand_type_begin() == ret.operand_type_end()) 1043 return op.emitOpError("initializer region cannot return void"); 1044 if (*ret.operand_type_begin() != op.getType()) 1045 return op.emitOpError("initializer region type ") 1046 << *ret.operand_type_begin() << " does not match global type " 1047 << op.getType(); 1048 1049 if (op.getValueOrNull()) 1050 return op.emitOpError("cannot have both initializer value and region"); 1051 } 1052 return success(); 1053 } 1054 1055 //===----------------------------------------------------------------------===// 1056 // Printing/parsing for LLVM::ShuffleVectorOp. 1057 //===----------------------------------------------------------------------===// 1058 // Expects vector to be of wrapped LLVM vector type and position to be of 1059 // wrapped LLVM i32 type. 1060 void LLVM::ShuffleVectorOp::build(Builder *b, OperationState &result, Value v1, 1061 Value v2, ArrayAttr mask, 1062 ArrayRef<NamedAttribute> attrs) { 1063 auto wrappedContainerType1 = v1.getType().cast<LLVM::LLVMType>(); 1064 auto vType = LLVMType::getVectorTy( 1065 wrappedContainerType1.getVectorElementType(), mask.size()); 1066 build(b, result, vType, v1, v2, mask); 1067 result.addAttributes(attrs); 1068 } 1069 1070 static void printShuffleVectorOp(OpAsmPrinter &p, ShuffleVectorOp &op) { 1071 p << op.getOperationName() << ' ' << op.v1() << ", " << op.v2() << " " 1072 << op.mask(); 1073 p.printOptionalAttrDict(op.getAttrs(), {"mask"}); 1074 p << " : " << op.v1().getType() << ", " << op.v2().getType(); 1075 } 1076 1077 // <operation> ::= `llvm.shufflevector` ssa-use `, ` ssa-use 1078 // `[` integer-literal (`,` integer-literal)* `]` 1079 // attribute-dict? `:` type 1080 static ParseResult parseShuffleVectorOp(OpAsmParser &parser, 1081 OperationState &result) { 1082 llvm::SMLoc loc; 1083 SmallVector<NamedAttribute, 4> attrs; 1084 OpAsmParser::OperandType v1, v2; 1085 Attribute maskAttr; 1086 Type typeV1, typeV2; 1087 if (parser.getCurrentLocation(&loc) || parser.parseOperand(v1) || 1088 parser.parseComma() || parser.parseOperand(v2) || 1089 parser.parseAttribute(maskAttr, "mask", attrs) || 1090 parser.parseOptionalAttrDict(attrs) || parser.parseColonType(typeV1) || 1091 parser.parseComma() || parser.parseType(typeV2) || 1092 parser.resolveOperand(v1, typeV1, result.operands) || 1093 parser.resolveOperand(v2, typeV2, result.operands)) 1094 return failure(); 1095 auto wrappedContainerType1 = typeV1.dyn_cast<LLVM::LLVMType>(); 1096 if (!wrappedContainerType1 || 1097 !wrappedContainerType1.getUnderlyingType()->isVectorTy()) 1098 return parser.emitError( 1099 loc, "expected LLVM IR dialect vector type for operand #1"); 1100 auto vType = 1101 LLVMType::getVectorTy(wrappedContainerType1.getVectorElementType(), 1102 maskAttr.cast<ArrayAttr>().size()); 1103 result.attributes = attrs; 1104 result.addTypes(vType); 1105 return success(); 1106 } 1107 1108 //===----------------------------------------------------------------------===// 1109 // Implementations for LLVM::LLVMFuncOp. 1110 //===----------------------------------------------------------------------===// 1111 1112 // Add the entry block to the function. 1113 Block *LLVMFuncOp::addEntryBlock() { 1114 assert(empty() && "function already has an entry block"); 1115 assert(!isVarArg() && "unimplemented: non-external variadic functions"); 1116 1117 auto *entry = new Block; 1118 push_back(entry); 1119 1120 LLVMType type = getType(); 1121 for (unsigned i = 0, e = type.getFunctionNumParams(); i < e; ++i) 1122 entry->addArgument(type.getFunctionParamType(i)); 1123 return entry; 1124 } 1125 1126 void LLVMFuncOp::build(Builder *builder, OperationState &result, StringRef name, 1127 LLVMType type, LLVM::Linkage linkage, 1128 ArrayRef<NamedAttribute> attrs, 1129 ArrayRef<NamedAttributeList> argAttrs) { 1130 result.addRegion(); 1131 result.addAttribute(SymbolTable::getSymbolAttrName(), 1132 builder->getStringAttr(name)); 1133 result.addAttribute("type", TypeAttr::get(type)); 1134 result.addAttribute(getLinkageAttrName(), builder->getI64IntegerAttr( 1135 static_cast<int64_t>(linkage))); 1136 result.attributes.append(attrs.begin(), attrs.end()); 1137 if (argAttrs.empty()) 1138 return; 1139 1140 unsigned numInputs = type.getUnderlyingType()->getFunctionNumParams(); 1141 assert(numInputs == argAttrs.size() && 1142 "expected as many argument attribute lists as arguments"); 1143 SmallString<8> argAttrName; 1144 for (unsigned i = 0; i < numInputs; ++i) 1145 if (auto argDict = argAttrs[i].getDictionary()) 1146 result.addAttribute(getArgAttrName(i, argAttrName), argDict); 1147 } 1148 1149 // Builds an LLVM function type from the given lists of input and output types. 1150 // Returns a null type if any of the types provided are non-LLVM types, or if 1151 // there is more than one output type. 1152 static Type buildLLVMFunctionType(OpAsmParser &parser, llvm::SMLoc loc, 1153 ArrayRef<Type> inputs, ArrayRef<Type> outputs, 1154 impl::VariadicFlag variadicFlag) { 1155 Builder &b = parser.getBuilder(); 1156 if (outputs.size() > 1) { 1157 parser.emitError(loc, "failed to construct function type: expected zero or " 1158 "one function result"); 1159 return {}; 1160 } 1161 1162 // Convert inputs to LLVM types, exit early on error. 1163 SmallVector<LLVMType, 4> llvmInputs; 1164 for (auto t : inputs) { 1165 auto llvmTy = t.dyn_cast<LLVMType>(); 1166 if (!llvmTy) { 1167 parser.emitError(loc, "failed to construct function type: expected LLVM " 1168 "type for function arguments"); 1169 return {}; 1170 } 1171 llvmInputs.push_back(llvmTy); 1172 } 1173 1174 // Get the dialect from the input type, if any exist. Look it up in the 1175 // context otherwise. 1176 LLVMDialect *dialect = 1177 llvmInputs.empty() ? b.getContext()->getRegisteredDialect<LLVMDialect>() 1178 : &llvmInputs.front().getDialect(); 1179 1180 // No output is denoted as "void" in LLVM type system. 1181 LLVMType llvmOutput = outputs.empty() ? LLVMType::getVoidTy(dialect) 1182 : outputs.front().dyn_cast<LLVMType>(); 1183 if (!llvmOutput) { 1184 parser.emitError(loc, "failed to construct function type: expected LLVM " 1185 "type for function results"); 1186 return {}; 1187 } 1188 return LLVMType::getFunctionTy(llvmOutput, llvmInputs, 1189 variadicFlag.isVariadic()); 1190 } 1191 1192 // Parses an LLVM function. 1193 // 1194 // operation ::= `llvm.func` linkage? function-signature function-attributes? 1195 // function-body 1196 // 1197 static ParseResult parseLLVMFuncOp(OpAsmParser &parser, 1198 OperationState &result) { 1199 // Default to external linkage if no keyword is provided. 1200 if (failed(parseOptionalLinkageKeyword(parser, result))) 1201 result.addAttribute(getLinkageAttrName(), 1202 parser.getBuilder().getI64IntegerAttr( 1203 static_cast<int64_t>(LLVM::Linkage::External))); 1204 1205 StringAttr nameAttr; 1206 SmallVector<OpAsmParser::OperandType, 8> entryArgs; 1207 SmallVector<SmallVector<NamedAttribute, 2>, 1> argAttrs; 1208 SmallVector<SmallVector<NamedAttribute, 2>, 1> resultAttrs; 1209 SmallVector<Type, 8> argTypes; 1210 SmallVector<Type, 4> resultTypes; 1211 bool isVariadic; 1212 1213 auto signatureLocation = parser.getCurrentLocation(); 1214 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(), 1215 result.attributes) || 1216 impl::parseFunctionSignature(parser, /*allowVariadic=*/true, entryArgs, 1217 argTypes, argAttrs, isVariadic, resultTypes, 1218 resultAttrs)) 1219 return failure(); 1220 1221 auto type = 1222 buildLLVMFunctionType(parser, signatureLocation, argTypes, resultTypes, 1223 impl::VariadicFlag(isVariadic)); 1224 if (!type) 1225 return failure(); 1226 result.addAttribute(impl::getTypeAttrName(), TypeAttr::get(type)); 1227 1228 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes))) 1229 return failure(); 1230 impl::addArgAndResultAttrs(parser.getBuilder(), result, argAttrs, 1231 resultAttrs); 1232 1233 auto *body = result.addRegion(); 1234 return parser.parseOptionalRegion( 1235 *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes); 1236 } 1237 1238 // Print the LLVMFuncOp. Collects argument and result types and passes them to 1239 // helper functions. Drops "void" result since it cannot be parsed back. Skips 1240 // the external linkage since it is the default value. 1241 static void printLLVMFuncOp(OpAsmPrinter &p, LLVMFuncOp op) { 1242 p << op.getOperationName() << ' '; 1243 if (op.linkage() != LLVM::Linkage::External) { 1244 printLinkage(p, op.linkage()); 1245 p << ' '; 1246 } 1247 p.printSymbolName(op.getName()); 1248 1249 LLVMType fnType = op.getType(); 1250 SmallVector<Type, 8> argTypes; 1251 SmallVector<Type, 1> resTypes; 1252 argTypes.reserve(fnType.getFunctionNumParams()); 1253 for (unsigned i = 0, e = fnType.getFunctionNumParams(); i < e; ++i) 1254 argTypes.push_back(fnType.getFunctionParamType(i)); 1255 1256 LLVMType returnType = fnType.getFunctionResultType(); 1257 if (!returnType.getUnderlyingType()->isVoidTy()) 1258 resTypes.push_back(returnType); 1259 1260 impl::printFunctionSignature(p, op, argTypes, op.isVarArg(), resTypes); 1261 impl::printFunctionAttributes(p, op, argTypes.size(), resTypes.size(), 1262 {getLinkageAttrName()}); 1263 1264 // Print the body if this is not an external function. 1265 Region &body = op.body(); 1266 if (!body.empty()) 1267 p.printRegion(body, /*printEntryBlockArgs=*/false, 1268 /*printBlockTerminators=*/true); 1269 } 1270 1271 // Hook for OpTrait::FunctionLike, called after verifying that the 'type' 1272 // attribute is present. This can check for preconditions of the 1273 // getNumArguments hook not failing. 1274 LogicalResult LLVMFuncOp::verifyType() { 1275 auto llvmType = getTypeAttr().getValue().dyn_cast_or_null<LLVMType>(); 1276 if (!llvmType || !llvmType.getUnderlyingType()->isFunctionTy()) 1277 return emitOpError("requires '" + getTypeAttrName() + 1278 "' attribute of wrapped LLVM function type"); 1279 1280 return success(); 1281 } 1282 1283 // Hook for OpTrait::FunctionLike, returns the number of function arguments. 1284 // Depends on the type attribute being correct as checked by verifyType 1285 unsigned LLVMFuncOp::getNumFuncArguments() { 1286 return getType().getUnderlyingType()->getFunctionNumParams(); 1287 } 1288 1289 // Hook for OpTrait::FunctionLike, returns the number of function results. 1290 // Depends on the type attribute being correct as checked by verifyType 1291 unsigned LLVMFuncOp::getNumFuncResults() { 1292 llvm::FunctionType *funcType = 1293 cast<llvm::FunctionType>(getType().getUnderlyingType()); 1294 // We model LLVM functions that return void as having zero results, 1295 // and all others as having one result. 1296 // If we modeled a void return as one result, then it would be possible to 1297 // attach an MLIR result attribute to it, and it isn't clear what semantics we 1298 // would assign to that. 1299 if (funcType->getReturnType()->isVoidTy()) 1300 return 0; 1301 return 1; 1302 } 1303 1304 // Verifies LLVM- and implementation-specific properties of the LLVM func Op: 1305 // - functions don't have 'common' linkage 1306 // - external functions have 'external' or 'extern_weak' linkage; 1307 // - vararg is (currently) only supported for external functions; 1308 // - entry block arguments are of LLVM types and match the function signature. 1309 static LogicalResult verify(LLVMFuncOp op) { 1310 if (op.linkage() == LLVM::Linkage::Common) 1311 return op.emitOpError() 1312 << "functions cannot have '" << linkageToStr(LLVM::Linkage::Common) 1313 << "' linkage"; 1314 1315 if (op.isExternal()) { 1316 if (op.linkage() != LLVM::Linkage::External && 1317 op.linkage() != LLVM::Linkage::ExternWeak) 1318 return op.emitOpError() 1319 << "external functions must have '" 1320 << linkageToStr(LLVM::Linkage::External) << "' or '" 1321 << linkageToStr(LLVM::Linkage::ExternWeak) << "' linkage"; 1322 return success(); 1323 } 1324 1325 if (op.isVarArg()) 1326 return op.emitOpError("only external functions can be variadic"); 1327 1328 auto *funcType = cast<llvm::FunctionType>(op.getType().getUnderlyingType()); 1329 unsigned numArguments = funcType->getNumParams(); 1330 Block &entryBlock = op.front(); 1331 for (unsigned i = 0; i < numArguments; ++i) { 1332 Type argType = entryBlock.getArgument(i).getType(); 1333 auto argLLVMType = argType.dyn_cast<LLVMType>(); 1334 if (!argLLVMType) 1335 return op.emitOpError("entry block argument #") 1336 << i << " is not of LLVM type"; 1337 if (funcType->getParamType(i) != argLLVMType.getUnderlyingType()) 1338 return op.emitOpError("the type of entry block argument #") 1339 << i << " does not match the function signature"; 1340 } 1341 1342 return success(); 1343 } 1344 1345 //===----------------------------------------------------------------------===// 1346 // Printing, parsing and verification for LLVM::NullOp. 1347 //===----------------------------------------------------------------------===// 1348 1349 static void printNullOp(OpAsmPrinter &p, LLVM::NullOp op) { 1350 p << NullOp::getOperationName(); 1351 p.printOptionalAttrDict(op.getAttrs()); 1352 p << " : " << op.getType(); 1353 } 1354 1355 // <operation> = `llvm.mlir.null` : type 1356 static ParseResult parseNullOp(OpAsmParser &parser, OperationState &result) { 1357 Type type; 1358 return failure(parser.parseOptionalAttrDict(result.attributes) || 1359 parser.parseColonType(type) || 1360 parser.addTypeToList(type, result.types)); 1361 } 1362 1363 // Only LLVM pointer types are supported. 1364 static LogicalResult verify(LLVM::NullOp op) { 1365 auto llvmType = op.getType().dyn_cast<LLVM::LLVMType>(); 1366 if (!llvmType || !llvmType.isPointerTy()) 1367 return op.emitOpError("expected LLVM IR pointer type"); 1368 return success(); 1369 } 1370 1371 //===----------------------------------------------------------------------===// 1372 // LLVMDialect initialization, type parsing, and registration. 1373 //===----------------------------------------------------------------------===// 1374 1375 namespace mlir { 1376 namespace LLVM { 1377 namespace detail { 1378 struct LLVMDialectImpl { 1379 LLVMDialectImpl() : module("LLVMDialectModule", llvmContext) {} 1380 1381 llvm::LLVMContext llvmContext; 1382 llvm::Module module; 1383 1384 /// A set of LLVMTypes that are cached on construction to avoid any lookups or 1385 /// locking. 1386 LLVMType int1Ty, int8Ty, int16Ty, int32Ty, int64Ty, int128Ty; 1387 LLVMType doubleTy, floatTy, halfTy, fp128Ty, x86_fp80Ty; 1388 LLVMType voidTy; 1389 1390 /// A smart mutex to lock access to the llvm context. Unlike MLIR, LLVM is not 1391 /// multi-threaded and requires locked access to prevent race conditions. 1392 llvm::sys::SmartMutex<true> mutex; 1393 }; 1394 } // end namespace detail 1395 } // end namespace LLVM 1396 } // end namespace mlir 1397 1398 LLVMDialect::LLVMDialect(MLIRContext *context) 1399 : Dialect(getDialectNamespace(), context), 1400 impl(new detail::LLVMDialectImpl()) { 1401 addTypes<LLVMType>(); 1402 addOperations< 1403 #define GET_OP_LIST 1404 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1405 >(); 1406 1407 // Support unknown operations because not all LLVM operations are registered. 1408 allowUnknownOperations(); 1409 1410 // Cache some of the common LLVM types to avoid the need for lookups/locking. 1411 auto &llvmContext = impl->llvmContext; 1412 /// Integer Types. 1413 impl->int1Ty = LLVMType::get(context, llvm::Type::getInt1Ty(llvmContext)); 1414 impl->int8Ty = LLVMType::get(context, llvm::Type::getInt8Ty(llvmContext)); 1415 impl->int16Ty = LLVMType::get(context, llvm::Type::getInt16Ty(llvmContext)); 1416 impl->int32Ty = LLVMType::get(context, llvm::Type::getInt32Ty(llvmContext)); 1417 impl->int64Ty = LLVMType::get(context, llvm::Type::getInt64Ty(llvmContext)); 1418 impl->int128Ty = LLVMType::get(context, llvm::Type::getInt128Ty(llvmContext)); 1419 /// Float Types. 1420 impl->doubleTy = LLVMType::get(context, llvm::Type::getDoubleTy(llvmContext)); 1421 impl->floatTy = LLVMType::get(context, llvm::Type::getFloatTy(llvmContext)); 1422 impl->halfTy = LLVMType::get(context, llvm::Type::getHalfTy(llvmContext)); 1423 impl->fp128Ty = LLVMType::get(context, llvm::Type::getFP128Ty(llvmContext)); 1424 impl->x86_fp80Ty = 1425 LLVMType::get(context, llvm::Type::getX86_FP80Ty(llvmContext)); 1426 /// Other Types. 1427 impl->voidTy = LLVMType::get(context, llvm::Type::getVoidTy(llvmContext)); 1428 } 1429 1430 LLVMDialect::~LLVMDialect() {} 1431 1432 #define GET_OP_CLASSES 1433 #include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc" 1434 1435 llvm::LLVMContext &LLVMDialect::getLLVMContext() { return impl->llvmContext; } 1436 llvm::Module &LLVMDialect::getLLVMModule() { return impl->module; } 1437 1438 /// Parse a type registered to this dialect. 1439 Type LLVMDialect::parseType(DialectAsmParser &parser) const { 1440 StringRef tyData = parser.getFullSymbolSpec(); 1441 1442 // LLVM is not thread-safe, so lock access to it. 1443 llvm::sys::SmartScopedLock<true> lock(impl->mutex); 1444 1445 llvm::SMDiagnostic errorMessage; 1446 llvm::Type *type = llvm::parseType(tyData, errorMessage, impl->module); 1447 if (!type) 1448 return (parser.emitError(parser.getNameLoc(), errorMessage.getMessage()), 1449 nullptr); 1450 return LLVMType::get(getContext(), type); 1451 } 1452 1453 /// Print a type registered to this dialect. 1454 void LLVMDialect::printType(Type type, DialectAsmPrinter &os) const { 1455 auto llvmType = type.dyn_cast<LLVMType>(); 1456 assert(llvmType && "printing wrong type"); 1457 assert(llvmType.getUnderlyingType() && "no underlying LLVM type"); 1458 llvmType.getUnderlyingType()->print(os.getStream()); 1459 } 1460 1461 /// Verify LLVMIR function argument attributes. 1462 LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op, 1463 unsigned regionIdx, 1464 unsigned argIdx, 1465 NamedAttribute argAttr) { 1466 // Check that llvm.noalias is a boolean attribute. 1467 if (argAttr.first == "llvm.noalias" && !argAttr.second.isa<BoolAttr>()) 1468 return op->emitError() 1469 << "llvm.noalias argument attribute of non boolean type"; 1470 return success(); 1471 } 1472 1473 static DialectRegistration<LLVMDialect> llvmDialect; 1474 1475 //===----------------------------------------------------------------------===// 1476 // LLVMType. 1477 //===----------------------------------------------------------------------===// 1478 1479 namespace mlir { 1480 namespace LLVM { 1481 namespace detail { 1482 struct LLVMTypeStorage : public ::mlir::TypeStorage { 1483 LLVMTypeStorage(llvm::Type *ty) : underlyingType(ty) {} 1484 1485 // LLVM types are pointer-unique. 1486 using KeyTy = llvm::Type *; 1487 bool operator==(const KeyTy &key) const { return key == underlyingType; } 1488 1489 static LLVMTypeStorage *construct(TypeStorageAllocator &allocator, 1490 llvm::Type *ty) { 1491 return new (allocator.allocate<LLVMTypeStorage>()) LLVMTypeStorage(ty); 1492 } 1493 1494 llvm::Type *underlyingType; 1495 }; 1496 } // end namespace detail 1497 } // end namespace LLVM 1498 } // end namespace mlir 1499 1500 LLVMType LLVMType::get(MLIRContext *context, llvm::Type *llvmType) { 1501 return Base::get(context, FIRST_LLVM_TYPE, llvmType); 1502 } 1503 1504 /// Get an LLVMType with an llvm type that may cause changes to the underlying 1505 /// llvm context when constructed. 1506 LLVMType LLVMType::getLocked(LLVMDialect *dialect, 1507 function_ref<llvm::Type *()> typeBuilder) { 1508 // Lock access to the llvm context and build the type. 1509 llvm::sys::SmartScopedLock<true> lock(dialect->impl->mutex); 1510 return get(dialect->getContext(), typeBuilder()); 1511 } 1512 1513 LLVMDialect &LLVMType::getDialect() { 1514 return static_cast<LLVMDialect &>(Type::getDialect()); 1515 } 1516 1517 llvm::Type *LLVMType::getUnderlyingType() const { 1518 return getImpl()->underlyingType; 1519 } 1520 1521 /// Array type utilities. 1522 LLVMType LLVMType::getArrayElementType() { 1523 return get(getContext(), getUnderlyingType()->getArrayElementType()); 1524 } 1525 unsigned LLVMType::getArrayNumElements() { 1526 return getUnderlyingType()->getArrayNumElements(); 1527 } 1528 bool LLVMType::isArrayTy() { return getUnderlyingType()->isArrayTy(); } 1529 1530 /// Vector type utilities. 1531 LLVMType LLVMType::getVectorElementType() { 1532 return get(getContext(), getUnderlyingType()->getVectorElementType()); 1533 } 1534 bool LLVMType::isVectorTy() { return getUnderlyingType()->isVectorTy(); } 1535 1536 /// Function type utilities. 1537 LLVMType LLVMType::getFunctionParamType(unsigned argIdx) { 1538 return get(getContext(), getUnderlyingType()->getFunctionParamType(argIdx)); 1539 } 1540 unsigned LLVMType::getFunctionNumParams() { 1541 return getUnderlyingType()->getFunctionNumParams(); 1542 } 1543 LLVMType LLVMType::getFunctionResultType() { 1544 return get( 1545 getContext(), 1546 llvm::cast<llvm::FunctionType>(getUnderlyingType())->getReturnType()); 1547 } 1548 bool LLVMType::isFunctionTy() { return getUnderlyingType()->isFunctionTy(); } 1549 1550 /// Pointer type utilities. 1551 LLVMType LLVMType::getPointerTo(unsigned addrSpace) { 1552 // Lock access to the dialect as this may modify the LLVM context. 1553 return getLocked(&getDialect(), [=] { 1554 return getUnderlyingType()->getPointerTo(addrSpace); 1555 }); 1556 } 1557 LLVMType LLVMType::getPointerElementTy() { 1558 return get(getContext(), getUnderlyingType()->getPointerElementType()); 1559 } 1560 bool LLVMType::isPointerTy() { return getUnderlyingType()->isPointerTy(); } 1561 1562 /// Struct type utilities. 1563 LLVMType LLVMType::getStructElementType(unsigned i) { 1564 return get(getContext(), getUnderlyingType()->getStructElementType(i)); 1565 } 1566 unsigned LLVMType::getStructNumElements() { 1567 return getUnderlyingType()->getStructNumElements(); 1568 } 1569 bool LLVMType::isStructTy() { return getUnderlyingType()->isStructTy(); } 1570 1571 /// Utilities used to generate floating point types. 1572 LLVMType LLVMType::getDoubleTy(LLVMDialect *dialect) { 1573 return dialect->impl->doubleTy; 1574 } 1575 LLVMType LLVMType::getFloatTy(LLVMDialect *dialect) { 1576 return dialect->impl->floatTy; 1577 } 1578 LLVMType LLVMType::getHalfTy(LLVMDialect *dialect) { 1579 return dialect->impl->halfTy; 1580 } 1581 LLVMType LLVMType::getFP128Ty(LLVMDialect *dialect) { 1582 return dialect->impl->fp128Ty; 1583 } 1584 LLVMType LLVMType::getX86_FP80Ty(LLVMDialect *dialect) { 1585 return dialect->impl->x86_fp80Ty; 1586 } 1587 1588 /// Utilities used to generate integer types. 1589 LLVMType LLVMType::getIntNTy(LLVMDialect *dialect, unsigned numBits) { 1590 switch (numBits) { 1591 case 1: 1592 return dialect->impl->int1Ty; 1593 case 8: 1594 return dialect->impl->int8Ty; 1595 case 16: 1596 return dialect->impl->int16Ty; 1597 case 32: 1598 return dialect->impl->int32Ty; 1599 case 64: 1600 return dialect->impl->int64Ty; 1601 case 128: 1602 return dialect->impl->int128Ty; 1603 default: 1604 break; 1605 } 1606 1607 // Lock access to the dialect as this may modify the LLVM context. 1608 return getLocked(dialect, [=] { 1609 return llvm::Type::getIntNTy(dialect->getLLVMContext(), numBits); 1610 }); 1611 } 1612 1613 /// Utilities used to generate other miscellaneous types. 1614 LLVMType LLVMType::getArrayTy(LLVMType elementType, uint64_t numElements) { 1615 // Lock access to the dialect as this may modify the LLVM context. 1616 return getLocked(&elementType.getDialect(), [=] { 1617 return llvm::ArrayType::get(elementType.getUnderlyingType(), numElements); 1618 }); 1619 } 1620 LLVMType LLVMType::getFunctionTy(LLVMType result, ArrayRef<LLVMType> params, 1621 bool isVarArg) { 1622 SmallVector<llvm::Type *, 8> llvmParams; 1623 for (auto param : params) 1624 llvmParams.push_back(param.getUnderlyingType()); 1625 1626 // Lock access to the dialect as this may modify the LLVM context. 1627 return getLocked(&result.getDialect(), [=] { 1628 return llvm::FunctionType::get(result.getUnderlyingType(), llvmParams, 1629 isVarArg); 1630 }); 1631 } 1632 LLVMType LLVMType::getStructTy(LLVMDialect *dialect, 1633 ArrayRef<LLVMType> elements, bool isPacked) { 1634 SmallVector<llvm::Type *, 8> llvmElements; 1635 for (auto elt : elements) 1636 llvmElements.push_back(elt.getUnderlyingType()); 1637 1638 // Lock access to the dialect as this may modify the LLVM context. 1639 return getLocked(dialect, [=] { 1640 return llvm::StructType::get(dialect->getLLVMContext(), llvmElements, 1641 isPacked); 1642 }); 1643 } 1644 LLVMType LLVMType::getVectorTy(LLVMType elementType, unsigned numElements) { 1645 // Lock access to the dialect as this may modify the LLVM context. 1646 return getLocked(&elementType.getDialect(), [=] { 1647 return llvm::VectorType::get(elementType.getUnderlyingType(), numElements); 1648 }); 1649 } 1650 LLVMType LLVMType::getVoidTy(LLVMDialect *dialect) { 1651 return dialect->impl->voidTy; 1652 } 1653 1654 //===----------------------------------------------------------------------===// 1655 // Utility functions. 1656 //===----------------------------------------------------------------------===// 1657 1658 Value mlir::LLVM::createGlobalString(Location loc, OpBuilder &builder, 1659 StringRef name, StringRef value, 1660 LLVM::Linkage linkage, 1661 LLVM::LLVMDialect *llvmDialect) { 1662 assert(builder.getInsertionBlock() && 1663 builder.getInsertionBlock()->getParentOp() && 1664 "expected builder to point to a block constrained in an op"); 1665 auto module = 1666 builder.getInsertionBlock()->getParentOp()->getParentOfType<ModuleOp>(); 1667 assert(module && "builder points to an op outside of a module"); 1668 1669 // Create the global at the entry of the module. 1670 OpBuilder moduleBuilder(module.getBodyRegion()); 1671 auto type = LLVM::LLVMType::getArrayTy(LLVM::LLVMType::getInt8Ty(llvmDialect), 1672 value.size()); 1673 auto global = moduleBuilder.create<LLVM::GlobalOp>( 1674 loc, type, /*isConstant=*/true, linkage, name, 1675 builder.getStringAttr(value)); 1676 1677 // Get the pointer to the first character in the global string. 1678 Value globalPtr = builder.create<LLVM::AddressOfOp>(loc, global); 1679 Value cst0 = builder.create<LLVM::ConstantOp>( 1680 loc, LLVM::LLVMType::getInt64Ty(llvmDialect), 1681 builder.getIntegerAttr(builder.getIndexType(), 0)); 1682 return builder.create<LLVM::GEPOp>(loc, 1683 LLVM::LLVMType::getInt8PtrTy(llvmDialect), 1684 globalPtr, ArrayRef<Value>({cst0, cst0})); 1685 } 1686 1687 bool mlir::LLVM::satisfiesLLVMModule(Operation *op) { 1688 return op->hasTrait<OpTrait::SymbolTable>() && 1689 op->hasTrait<OpTrait::IsIsolatedFromAbove>(); 1690 } 1691