1 //===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===// 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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "flang/Optimizer/CodeGen/CodeGen.h" 14 #include "PassDetail.h" 15 #include "flang/Optimizer/Dialect/FIROps.h" 16 #include "flang/Optimizer/Dialect/FIRType.h" 17 #include "flang/Optimizer/Support/FIRContext.h" 18 #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h" 19 #include "mlir/Conversion/LLVMCommon/Pattern.h" 20 #include "mlir/Conversion/LLVMCommon/TypeConverter.h" 21 #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" 22 #include "mlir/IR/BuiltinTypes.h" 23 #include "mlir/IR/Matchers.h" 24 #include "mlir/Pass/Pass.h" 25 #include "llvm/ADT/ArrayRef.h" 26 27 #define DEBUG_TYPE "flang-codegen" 28 29 // fir::LLVMTypeConverter for converting to LLVM IR dialect types. 30 #include "TypeConverter.h" 31 32 namespace { 33 /// FIR conversion pattern template 34 template <typename FromOp> 35 class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> { 36 public: 37 explicit FIROpConversion(fir::LLVMTypeConverter &lowering) 38 : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {} 39 40 protected: 41 mlir::Type convertType(mlir::Type ty) const { 42 return lowerTy().convertType(ty); 43 } 44 45 mlir::LLVM::ConstantOp 46 genConstantOffset(mlir::Location loc, 47 mlir::ConversionPatternRewriter &rewriter, 48 int offset) const { 49 auto ity = lowerTy().offsetType(); 50 auto cattr = rewriter.getI32IntegerAttr(offset); 51 return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 52 } 53 54 /// Construct code sequence to get the rank from a box. 55 mlir::Value getRankFromBox(mlir::Location loc, mlir::Value box, 56 mlir::Type resultTy, 57 mlir::ConversionPatternRewriter &rewriter) const { 58 mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 59 mlir::LLVM::ConstantOp cRank = 60 genConstantOffset(loc, rewriter, kRankPosInBox); 61 auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); 62 auto p = rewriter.create<mlir::LLVM::GEPOp>( 63 loc, pty, mlir::ValueRange{box, c0, cRank}); 64 return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p); 65 } 66 67 /// Method to construct code sequence to get the triple for dimension `dim` 68 /// from a box. 69 SmallVector<mlir::Value, 3> 70 getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys, 71 mlir::Value box, mlir::Value dim, 72 mlir::ConversionPatternRewriter &rewriter) const { 73 mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 74 mlir::LLVM::ConstantOp cDims = 75 genConstantOffset(loc, rewriter, kDimsPosInBox); 76 mlir::LLVM::LoadOp l0 = 77 loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter); 78 mlir::LLVM::LoadOp l1 = 79 loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter); 80 mlir::LLVM::LoadOp l2 = 81 loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter); 82 return {l0.getResult(), l1.getResult(), l2.getResult()}; 83 } 84 85 mlir::LLVM::LoadOp 86 loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0, 87 mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off, 88 mlir::Type ty, 89 mlir::ConversionPatternRewriter &rewriter) const { 90 auto pty = mlir::LLVM::LLVMPointerType::get(ty); 91 mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off); 92 mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c); 93 return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 94 } 95 96 /// Read base address from a fir.box. Returned address has type ty. 97 mlir::Value 98 loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 99 mlir::ConversionPatternRewriter &rewriter) const { 100 mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 101 mlir::LLVM::ConstantOp cAddr = 102 genConstantOffset(loc, rewriter, kAddrPosInBox); 103 auto pty = mlir::LLVM::LLVMPointerType::get(ty); 104 mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr); 105 return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 106 } 107 108 mlir::Value 109 loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 110 mlir::ConversionPatternRewriter &rewriter) const { 111 mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 112 mlir::LLVM::ConstantOp cElemLen = 113 genConstantOffset(loc, rewriter, kElemLenPosInBox); 114 auto pty = mlir::LLVM::LLVMPointerType::get(ty); 115 mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen); 116 return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 117 } 118 119 template <typename... ARGS> 120 mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, 121 mlir::ConversionPatternRewriter &rewriter, 122 mlir::Value base, ARGS... args) const { 123 SmallVector<mlir::Value> cv{args...}; 124 return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv); 125 } 126 127 fir::LLVMTypeConverter &lowerTy() const { 128 return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter()); 129 } 130 }; 131 132 /// FIR conversion pattern template 133 template <typename FromOp> 134 class FIROpAndTypeConversion : public FIROpConversion<FromOp> { 135 public: 136 using FIROpConversion<FromOp>::FIROpConversion; 137 using OpAdaptor = typename FromOp::Adaptor; 138 139 mlir::LogicalResult 140 matchAndRewrite(FromOp op, OpAdaptor adaptor, 141 mlir::ConversionPatternRewriter &rewriter) const final { 142 mlir::Type ty = this->convertType(op.getType()); 143 return doRewrite(op, ty, adaptor, rewriter); 144 } 145 146 virtual mlir::LogicalResult 147 doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor, 148 mlir::ConversionPatternRewriter &rewriter) const = 0; 149 }; 150 151 // Lower `fir.address_of` operation to `llvm.address_of` operation. 152 struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> { 153 using FIROpConversion::FIROpConversion; 154 155 mlir::LogicalResult 156 matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor, 157 mlir::ConversionPatternRewriter &rewriter) const override { 158 auto ty = convertType(addr.getType()); 159 rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>( 160 addr, ty, addr.symbol().getRootReference().getValue()); 161 return success(); 162 } 163 }; 164 165 /// Lower `fir.box_addr` to the sequence of operations to extract the first 166 /// element of the box. 167 struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> { 168 using FIROpConversion::FIROpConversion; 169 170 mlir::LogicalResult 171 matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor, 172 mlir::ConversionPatternRewriter &rewriter) const override { 173 mlir::Value a = adaptor.getOperands()[0]; 174 auto loc = boxaddr.getLoc(); 175 mlir::Type ty = convertType(boxaddr.getType()); 176 if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) { 177 rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter)); 178 } else { 179 auto c0attr = rewriter.getI32IntegerAttr(0); 180 auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr); 181 rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a, 182 c0); 183 } 184 return success(); 185 } 186 }; 187 188 /// Lower `fir.box_dims` to a sequence of operations to extract the requested 189 /// dimension infomartion from the boxed value. 190 /// Result in a triple set of GEPs and loads. 191 struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> { 192 using FIROpConversion::FIROpConversion; 193 194 mlir::LogicalResult 195 matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor, 196 mlir::ConversionPatternRewriter &rewriter) const override { 197 SmallVector<mlir::Type, 3> resultTypes = { 198 convertType(boxdims.getResult(0).getType()), 199 convertType(boxdims.getResult(1).getType()), 200 convertType(boxdims.getResult(2).getType()), 201 }; 202 auto results = 203 getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0], 204 adaptor.getOperands()[1], rewriter); 205 rewriter.replaceOp(boxdims, results); 206 return success(); 207 } 208 }; 209 210 /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of 211 /// an element in the boxed value. 212 struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> { 213 using FIROpConversion::FIROpConversion; 214 215 mlir::LogicalResult 216 matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor, 217 mlir::ConversionPatternRewriter &rewriter) const override { 218 mlir::Value a = adaptor.getOperands()[0]; 219 auto loc = boxelesz.getLoc(); 220 auto ty = convertType(boxelesz.getType()); 221 rewriter.replaceOp(boxelesz, loadElementSizeFromBox(loc, ty, a, rewriter)); 222 return success(); 223 } 224 }; 225 226 /// Lower `fir.box_rank` to the sequence of operation to extract the rank from 227 /// the box. 228 struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> { 229 using FIROpConversion::FIROpConversion; 230 231 mlir::LogicalResult 232 matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor, 233 mlir::ConversionPatternRewriter &rewriter) const override { 234 mlir::Value a = adaptor.getOperands()[0]; 235 auto loc = boxrank.getLoc(); 236 mlir::Type ty = convertType(boxrank.getType()); 237 auto result = getRankFromBox(loc, a, ty, rewriter); 238 rewriter.replaceOp(boxrank, result); 239 return success(); 240 } 241 }; 242 243 // `fir.call` -> `llvm.call` 244 struct CallOpConversion : public FIROpConversion<fir::CallOp> { 245 using FIROpConversion::FIROpConversion; 246 247 mlir::LogicalResult 248 matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 249 mlir::ConversionPatternRewriter &rewriter) const override { 250 SmallVector<mlir::Type> resultTys; 251 for (auto r : call.getResults()) 252 resultTys.push_back(convertType(r.getType())); 253 rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 254 call, resultTys, adaptor.getOperands(), call->getAttrs()); 255 return success(); 256 } 257 }; 258 259 static mlir::Type getComplexEleTy(mlir::Type complex) { 260 if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 261 return cc.getElementType(); 262 return complex.cast<fir::ComplexType>().getElementType(); 263 } 264 265 /// convert value of from-type to value of to-type 266 struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 267 using FIROpConversion::FIROpConversion; 268 269 static bool isFloatingPointTy(mlir::Type ty) { 270 return ty.isa<mlir::FloatType>(); 271 } 272 273 mlir::LogicalResult 274 matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 275 mlir::ConversionPatternRewriter &rewriter) const override { 276 auto fromTy = convertType(convert.value().getType()); 277 auto toTy = convertType(convert.res().getType()); 278 mlir::Value op0 = adaptor.getOperands()[0]; 279 if (fromTy == toTy) { 280 rewriter.replaceOp(convert, op0); 281 return success(); 282 } 283 auto loc = convert.getLoc(); 284 auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 285 unsigned toBits, mlir::Type toTy) -> mlir::Value { 286 if (fromBits == toBits) { 287 // TODO: Converting between two floating-point representations with the 288 // same bitwidth is not allowed for now. 289 mlir::emitError(loc, 290 "cannot implicitly convert between two floating-point " 291 "representations of the same bitwidth"); 292 return {}; 293 } 294 if (fromBits > toBits) 295 return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 296 return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 297 }; 298 // Complex to complex conversion. 299 if (fir::isa_complex(convert.value().getType()) && 300 fir::isa_complex(convert.res().getType())) { 301 // Special case: handle the conversion of a complex such that both the 302 // real and imaginary parts are converted together. 303 auto zero = mlir::ArrayAttr::get(convert.getContext(), 304 rewriter.getI32IntegerAttr(0)); 305 auto one = mlir::ArrayAttr::get(convert.getContext(), 306 rewriter.getI32IntegerAttr(1)); 307 auto ty = convertType(getComplexEleTy(convert.value().getType())); 308 auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 309 auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 310 auto nt = convertType(getComplexEleTy(convert.res().getType())); 311 auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 312 auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 313 auto rc = convertFpToFp(rp, fromBits, toBits, nt); 314 auto ic = convertFpToFp(ip, fromBits, toBits, nt); 315 auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 316 auto i1 = 317 rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 318 rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 319 ic, one); 320 return mlir::success(); 321 } 322 // Floating point to floating point conversion. 323 if (isFloatingPointTy(fromTy)) { 324 if (isFloatingPointTy(toTy)) { 325 auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 326 auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 327 auto v = convertFpToFp(op0, fromBits, toBits, toTy); 328 rewriter.replaceOp(convert, v); 329 return mlir::success(); 330 } 331 if (toTy.isa<mlir::IntegerType>()) { 332 rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 333 return mlir::success(); 334 } 335 } else if (fromTy.isa<mlir::IntegerType>()) { 336 // Integer to integer conversion. 337 if (toTy.isa<mlir::IntegerType>()) { 338 auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 339 auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 340 assert(fromBits != toBits); 341 if (fromBits > toBits) { 342 rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 343 return mlir::success(); 344 } 345 rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 346 return mlir::success(); 347 } 348 // Integer to floating point conversion. 349 if (isFloatingPointTy(toTy)) { 350 rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 351 return mlir::success(); 352 } 353 // Integer to pointer conversion. 354 if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 355 rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 356 return mlir::success(); 357 } 358 } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 359 // Pointer to integer conversion. 360 if (toTy.isa<mlir::IntegerType>()) { 361 rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 362 return mlir::success(); 363 } 364 // Pointer to pointer conversion. 365 if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 366 rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 367 return mlir::success(); 368 } 369 } 370 return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 371 } 372 }; 373 374 /// Lower `fir.has_value` operation to `llvm.return` operation. 375 struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 376 using FIROpConversion::FIROpConversion; 377 378 mlir::LogicalResult 379 matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 380 mlir::ConversionPatternRewriter &rewriter) const override { 381 rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 382 return success(); 383 } 384 }; 385 386 /// Lower `fir.global` operation to `llvm.global` operation. 387 /// `fir.insert_on_range` operations are replaced with constant dense attribute 388 /// if they are applied on the full range. 389 struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 390 using FIROpConversion::FIROpConversion; 391 392 mlir::LogicalResult 393 matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 394 mlir::ConversionPatternRewriter &rewriter) const override { 395 auto tyAttr = convertType(global.getType()); 396 if (global.getType().isa<fir::BoxType>()) 397 tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 398 auto loc = global.getLoc(); 399 mlir::Attribute initAttr{}; 400 if (global.initVal()) 401 initAttr = global.initVal().getValue(); 402 auto linkage = convertLinkage(global.linkName()); 403 auto isConst = global.constant().hasValue(); 404 auto g = rewriter.create<mlir::LLVM::GlobalOp>( 405 loc, tyAttr, isConst, linkage, global.sym_name(), initAttr); 406 auto &gr = g.getInitializerRegion(); 407 rewriter.inlineRegionBefore(global.region(), gr, gr.end()); 408 if (!gr.empty()) { 409 // Replace insert_on_range with a constant dense attribute if the 410 // initialization is on the full range. 411 auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 412 for (auto insertOp : insertOnRangeOps) { 413 if (isFullRange(insertOp.coor(), insertOp.getType())) { 414 auto seqTyAttr = convertType(insertOp.getType()); 415 auto *op = insertOp.val().getDefiningOp(); 416 auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 417 if (!constant) { 418 auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 419 if (!convertOp) 420 continue; 421 constant = cast<mlir::arith::ConstantOp>( 422 convertOp.value().getDefiningOp()); 423 } 424 mlir::Type vecType = mlir::VectorType::get( 425 insertOp.getType().getShape(), constant.getType()); 426 auto denseAttr = mlir::DenseElementsAttr::get( 427 vecType.cast<ShapedType>(), constant.value()); 428 rewriter.setInsertionPointAfter(insertOp); 429 rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 430 insertOp, seqTyAttr, denseAttr); 431 } 432 } 433 } 434 rewriter.eraseOp(global); 435 return success(); 436 } 437 438 bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const { 439 auto extents = seqTy.getShape(); 440 if (indexes.size() / 2 != extents.size()) 441 return false; 442 for (unsigned i = 0; i < indexes.size(); i += 2) { 443 if (indexes[i].cast<IntegerAttr>().getInt() != 0) 444 return false; 445 if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1) 446 return false; 447 } 448 return true; 449 } 450 451 // TODO: String comparaison should be avoided. Replace linkName with an 452 // enumeration. 453 mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 454 if (optLinkage.hasValue()) { 455 auto name = optLinkage.getValue(); 456 if (name == "internal") 457 return mlir::LLVM::Linkage::Internal; 458 if (name == "linkonce") 459 return mlir::LLVM::Linkage::Linkonce; 460 if (name == "common") 461 return mlir::LLVM::Linkage::Common; 462 if (name == "weak") 463 return mlir::LLVM::Linkage::Weak; 464 } 465 return mlir::LLVM::Linkage::External; 466 } 467 }; 468 469 template <typename OP> 470 void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 471 typename OP::Adaptor adaptor, 472 mlir::ConversionPatternRewriter &rewriter) { 473 unsigned conds = select.getNumConditions(); 474 auto cases = select.getCases().getValue(); 475 mlir::Value selector = adaptor.selector(); 476 auto loc = select.getLoc(); 477 assert(conds > 0 && "select must have cases"); 478 479 llvm::SmallVector<mlir::Block *> destinations; 480 llvm::SmallVector<mlir::ValueRange> destinationsOperands; 481 mlir::Block *defaultDestination; 482 mlir::ValueRange defaultOperands; 483 llvm::SmallVector<int32_t> caseValues; 484 485 for (unsigned t = 0; t != conds; ++t) { 486 mlir::Block *dest = select.getSuccessor(t); 487 auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 488 const mlir::Attribute &attr = cases[t]; 489 if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 490 destinations.push_back(dest); 491 destinationsOperands.push_back(destOps.hasValue() ? *destOps 492 : ValueRange()); 493 caseValues.push_back(intAttr.getInt()); 494 continue; 495 } 496 assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 497 assert((t + 1 == conds) && "unit must be last"); 498 defaultDestination = dest; 499 defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 500 } 501 502 // LLVM::SwitchOp takes a i32 type for the selector. 503 if (select.getSelector().getType() != rewriter.getI32Type()) 504 selector = 505 rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 506 507 rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 508 select, selector, 509 /*defaultDestination=*/defaultDestination, 510 /*defaultOperands=*/defaultOperands, 511 /*caseValues=*/caseValues, 512 /*caseDestinations=*/destinations, 513 /*caseOperands=*/destinationsOperands, 514 /*branchWeights=*/ArrayRef<int32_t>()); 515 } 516 517 /// conversion of fir::SelectOp to an if-then-else ladder 518 struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 519 using FIROpConversion::FIROpConversion; 520 521 mlir::LogicalResult 522 matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 523 mlir::ConversionPatternRewriter &rewriter) const override { 524 selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 525 return success(); 526 } 527 }; 528 529 /// `fir.load` --> `llvm.load` 530 struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 531 using FIROpConversion::FIROpConversion; 532 533 mlir::LogicalResult 534 matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 535 mlir::ConversionPatternRewriter &rewriter) const override { 536 // fir.box is a special case because it is considered as an ssa values in 537 // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 538 // and fir.box end up being the same llvm types and loading a 539 // fir.ref<fir.box> is actually a no op in LLVM. 540 if (load.getType().isa<fir::BoxType>()) { 541 rewriter.replaceOp(load, adaptor.getOperands()[0]); 542 } else { 543 mlir::Type ty = convertType(load.getType()); 544 ArrayRef<NamedAttribute> at = load->getAttrs(); 545 rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 546 load, ty, adaptor.getOperands(), at); 547 } 548 return success(); 549 } 550 }; 551 552 /// conversion of fir::SelectRankOp to an if-then-else ladder 553 struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 554 using FIROpConversion::FIROpConversion; 555 556 mlir::LogicalResult 557 matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 558 mlir::ConversionPatternRewriter &rewriter) const override { 559 selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 560 return success(); 561 } 562 }; 563 564 /// `fir.store` --> `llvm.store` 565 struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 566 using FIROpConversion::FIROpConversion; 567 568 mlir::LogicalResult 569 matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 570 mlir::ConversionPatternRewriter &rewriter) const override { 571 if (store.value().getType().isa<fir::BoxType>()) { 572 // fir.box value is actually in memory, load it first before storing it. 573 mlir::Location loc = store.getLoc(); 574 mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 575 auto val = rewriter.create<mlir::LLVM::LoadOp>( 576 loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 577 adaptor.getOperands()[0]); 578 rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 579 store, val, adaptor.getOperands()[1]); 580 } else { 581 rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 582 store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 583 } 584 return success(); 585 } 586 }; 587 588 /// convert to LLVM IR dialect `undef` 589 struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 590 using FIROpConversion::FIROpConversion; 591 592 mlir::LogicalResult 593 matchAndRewrite(fir::UndefOp undef, OpAdaptor, 594 mlir::ConversionPatternRewriter &rewriter) const override { 595 rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 596 undef, convertType(undef.getType())); 597 return success(); 598 } 599 }; 600 601 /// `fir.unreachable` --> `llvm.unreachable` 602 struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 603 using FIROpConversion::FIROpConversion; 604 605 mlir::LogicalResult 606 matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 607 mlir::ConversionPatternRewriter &rewriter) const override { 608 rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 609 return success(); 610 } 611 }; 612 613 struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 614 using FIROpConversion::FIROpConversion; 615 616 mlir::LogicalResult 617 matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 618 mlir::ConversionPatternRewriter &rewriter) const override { 619 auto ty = convertType(zero.getType()); 620 if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 621 rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 622 } else if (ty.isa<mlir::IntegerType>()) { 623 rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 624 zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 625 } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 626 rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 627 zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 628 } else { 629 // TODO: create ConstantAggregateZero for FIR aggregate/array types. 630 return rewriter.notifyMatchFailure( 631 zero, 632 "conversion of fir.zero with aggregate type not implemented yet"); 633 } 634 return success(); 635 } 636 }; 637 638 // Code shared between insert_value and extract_value Ops. 639 struct ValueOpCommon { 640 // Translate the arguments pertaining to any multidimensional array to 641 // row-major order for LLVM-IR. 642 static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 643 mlir::Type ty) { 644 assert(ty && "type is null"); 645 const auto end = attrs.size(); 646 for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 647 if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 648 const auto dim = getDimension(seq); 649 if (dim > 1) { 650 auto ub = std::min(i + dim, end); 651 std::reverse(attrs.begin() + i, attrs.begin() + ub); 652 i += dim - 1; 653 } 654 ty = getArrayElementType(seq); 655 } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 656 ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 657 } else { 658 llvm_unreachable("index into invalid type"); 659 } 660 } 661 } 662 663 static llvm::SmallVector<mlir::Attribute> 664 collectIndices(mlir::ConversionPatternRewriter &rewriter, 665 mlir::ArrayAttr arrAttr) { 666 llvm::SmallVector<mlir::Attribute> attrs; 667 for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 668 if (i->isa<mlir::IntegerAttr>()) { 669 attrs.push_back(*i); 670 } else { 671 auto fieldName = i->cast<mlir::StringAttr>().getValue(); 672 ++i; 673 auto ty = i->cast<mlir::TypeAttr>().getValue(); 674 auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 675 attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 676 } 677 } 678 return attrs; 679 } 680 681 private: 682 static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 683 unsigned result = 1; 684 for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 685 eleTy; 686 eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 687 ++result; 688 return result; 689 } 690 691 static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 692 auto eleTy = ty.getElementType(); 693 while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 694 eleTy = arrTy.getElementType(); 695 return eleTy; 696 } 697 }; 698 699 /// Extract a subobject value from an ssa-value of aggregate type 700 struct ExtractValueOpConversion 701 : public FIROpAndTypeConversion<fir::ExtractValueOp>, 702 public ValueOpCommon { 703 using FIROpAndTypeConversion::FIROpAndTypeConversion; 704 705 mlir::LogicalResult 706 doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 707 mlir::ConversionPatternRewriter &rewriter) const override { 708 auto attrs = collectIndices(rewriter, extractVal.coor()); 709 toRowMajor(attrs, adaptor.getOperands()[0].getType()); 710 auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 711 rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 712 extractVal, ty, adaptor.getOperands()[0], position); 713 return success(); 714 } 715 }; 716 717 /// InsertValue is the generalized instruction for the composition of new 718 /// aggregate type values. 719 struct InsertValueOpConversion 720 : public FIROpAndTypeConversion<fir::InsertValueOp>, 721 public ValueOpCommon { 722 using FIROpAndTypeConversion::FIROpAndTypeConversion; 723 724 mlir::LogicalResult 725 doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 726 mlir::ConversionPatternRewriter &rewriter) const override { 727 auto attrs = collectIndices(rewriter, insertVal.coor()); 728 toRowMajor(attrs, adaptor.getOperands()[0].getType()); 729 auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 730 rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 731 insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 732 position); 733 return success(); 734 } 735 }; 736 737 /// InsertOnRange inserts a value into a sequence over a range of offsets. 738 struct InsertOnRangeOpConversion 739 : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 740 using FIROpAndTypeConversion::FIROpAndTypeConversion; 741 742 // Increments an array of subscripts in a row major fasion. 743 void incrementSubscripts(const SmallVector<uint64_t> &dims, 744 SmallVector<uint64_t> &subscripts) const { 745 for (size_t i = dims.size(); i > 0; --i) { 746 if (++subscripts[i - 1] < dims[i - 1]) { 747 return; 748 } 749 subscripts[i - 1] = 0; 750 } 751 } 752 753 mlir::LogicalResult 754 doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 755 mlir::ConversionPatternRewriter &rewriter) const override { 756 757 llvm::SmallVector<uint64_t> dims; 758 auto type = adaptor.getOperands()[0].getType(); 759 760 // Iteratively extract the array dimensions from the type. 761 while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 762 dims.push_back(t.getNumElements()); 763 type = t.getElementType(); 764 } 765 766 SmallVector<uint64_t> lBounds; 767 SmallVector<uint64_t> uBounds; 768 769 // Extract integer value from the attribute 770 SmallVector<int64_t> coordinates = llvm::to_vector<4>( 771 llvm::map_range(range.coor(), [](Attribute a) -> int64_t { 772 return a.cast<IntegerAttr>().getInt(); 773 })); 774 775 // Unzip the upper and lower bound and convert to a row major format. 776 for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) { 777 uBounds.push_back(*i++); 778 lBounds.push_back(*i); 779 } 780 781 auto &subscripts = lBounds; 782 auto loc = range.getLoc(); 783 mlir::Value lastOp = adaptor.getOperands()[0]; 784 mlir::Value insertVal = adaptor.getOperands()[1]; 785 786 auto i64Ty = rewriter.getI64Type(); 787 while (subscripts != uBounds) { 788 // Convert uint64_t's to Attribute's. 789 SmallVector<mlir::Attribute> subscriptAttrs; 790 for (const auto &subscript : subscripts) 791 subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 792 lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 793 loc, ty, lastOp, insertVal, 794 ArrayAttr::get(range.getContext(), subscriptAttrs)); 795 796 incrementSubscripts(dims, subscripts); 797 } 798 799 // Convert uint64_t's to Attribute's. 800 SmallVector<mlir::Attribute> subscriptAttrs; 801 for (const auto &subscript : subscripts) 802 subscriptAttrs.push_back( 803 IntegerAttr::get(rewriter.getI64Type(), subscript)); 804 mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 805 806 rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 807 range, ty, lastOp, insertVal, 808 ArrayAttr::get(range.getContext(), arrayRef)); 809 810 return success(); 811 } 812 }; 813 814 // 815 // Primitive operations on Complex types 816 // 817 818 /// Generate inline code for complex addition/subtraction 819 template <typename LLVMOP, typename OPTY> 820 mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds, 821 mlir::ConversionPatternRewriter &rewriter, 822 fir::LLVMTypeConverter &lowering) { 823 mlir::Value a = opnds[0]; 824 mlir::Value b = opnds[1]; 825 auto loc = sumop.getLoc(); 826 auto ctx = sumop.getContext(); 827 auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 828 auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 829 mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 830 mlir::Type ty = lowering.convertType(sumop.getType()); 831 auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 832 auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 833 auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 834 auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 835 auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 836 auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 837 auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 838 auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 839 return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 840 } 841 842 struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 843 using FIROpConversion::FIROpConversion; 844 845 mlir::LogicalResult 846 matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 847 mlir::ConversionPatternRewriter &rewriter) const override { 848 // given: (x + iy) + (x' + iy') 849 // result: (x + x') + i(y + y') 850 auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 851 rewriter, lowerTy()); 852 rewriter.replaceOp(addc, r.getResult()); 853 return success(); 854 } 855 }; 856 857 struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 858 using FIROpConversion::FIROpConversion; 859 860 mlir::LogicalResult 861 matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 862 mlir::ConversionPatternRewriter &rewriter) const override { 863 // given: (x + iy) - (x' + iy') 864 // result: (x - x') + i(y - y') 865 auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 866 rewriter, lowerTy()); 867 rewriter.replaceOp(subc, r.getResult()); 868 return success(); 869 } 870 }; 871 872 /// Inlined complex multiply 873 struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 874 using FIROpConversion::FIROpConversion; 875 876 mlir::LogicalResult 877 matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 878 mlir::ConversionPatternRewriter &rewriter) const override { 879 // TODO: Can we use a call to __muldc3 ? 880 // given: (x + iy) * (x' + iy') 881 // result: (xx'-yy')+i(xy'+yx') 882 mlir::Value a = adaptor.getOperands()[0]; 883 mlir::Value b = adaptor.getOperands()[1]; 884 auto loc = mulc.getLoc(); 885 auto *ctx = mulc.getContext(); 886 auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 887 auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 888 mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 889 mlir::Type ty = convertType(mulc.getType()); 890 auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 891 auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 892 auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 893 auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 894 auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 895 auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 896 auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 897 auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 898 auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 899 auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 900 auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 901 auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 902 auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 903 rewriter.replaceOp(mulc, r0.getResult()); 904 return success(); 905 } 906 }; 907 908 /// Inlined complex division 909 struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 910 using FIROpConversion::FIROpConversion; 911 912 mlir::LogicalResult 913 matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 914 mlir::ConversionPatternRewriter &rewriter) const override { 915 // TODO: Can we use a call to __divdc3 instead? 916 // Just generate inline code for now. 917 // given: (x + iy) / (x' + iy') 918 // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 919 mlir::Value a = adaptor.getOperands()[0]; 920 mlir::Value b = adaptor.getOperands()[1]; 921 auto loc = divc.getLoc(); 922 auto *ctx = divc.getContext(); 923 auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 924 auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 925 mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 926 mlir::Type ty = convertType(divc.getType()); 927 auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 928 auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 929 auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 930 auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 931 auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 932 auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 933 auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 934 auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 935 auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 936 auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 937 auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 938 auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 939 auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 940 auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 941 auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 942 auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 943 auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 944 auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 945 rewriter.replaceOp(divc, r0.getResult()); 946 return success(); 947 } 948 }; 949 950 /// Inlined complex negation 951 struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 952 using FIROpConversion::FIROpConversion; 953 954 mlir::LogicalResult 955 matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 956 mlir::ConversionPatternRewriter &rewriter) const override { 957 // given: -(x + iy) 958 // result: -x - iy 959 auto *ctxt = neg.getContext(); 960 auto eleTy = convertType(getComplexEleTy(neg.getType())); 961 auto ty = convertType(neg.getType()); 962 auto loc = neg.getLoc(); 963 mlir::Value o0 = adaptor.getOperands()[0]; 964 auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 965 auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 966 auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 967 auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 968 auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 969 auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 970 auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 971 rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 972 return success(); 973 } 974 }; 975 976 } // namespace 977 978 namespace { 979 /// Convert FIR dialect to LLVM dialect 980 /// 981 /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 982 /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 983 /// 984 /// This pass is not complete yet. We are upstreaming it in small patches. 985 class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 986 public: 987 mlir::ModuleOp getModule() { return getOperation(); } 988 989 void runOnOperation() override final { 990 auto mod = getModule(); 991 if (!forcedTargetTriple.empty()) { 992 fir::setTargetTriple(mod, forcedTargetTriple); 993 } 994 995 auto *context = getModule().getContext(); 996 fir::LLVMTypeConverter typeConverter{getModule()}; 997 mlir::OwningRewritePatternList pattern(context); 998 pattern.insert< 999 AddcOpConversion, AddrOfOpConversion, BoxAddrOpConversion, 1000 BoxDimsOpConversion, BoxEleSizeOpConversion, BoxRankOpConversion, 1001 CallOpConversion, ConvertOpConversion, DivcOpConversion, 1002 ExtractValueOpConversion, HasValueOpConversion, GlobalOpConversion, 1003 InsertOnRangeOpConversion, InsertValueOpConversion, LoadOpConversion, 1004 NegcOpConversion, MulcOpConversion, SelectOpConversion, 1005 SelectRankOpConversion, StoreOpConversion, SubcOpConversion, 1006 UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>( 1007 typeConverter); 1008 mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); 1009 mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 1010 pattern); 1011 mlir::ConversionTarget target{*context}; 1012 target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 1013 1014 // required NOPs for applying a full conversion 1015 target.addLegalOp<mlir::ModuleOp>(); 1016 1017 // apply the patterns 1018 if (mlir::failed(mlir::applyFullConversion(getModule(), target, 1019 std::move(pattern)))) { 1020 signalPassFailure(); 1021 } 1022 } 1023 }; 1024 } // namespace 1025 1026 std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 1027 return std::make_unique<FIRToLLVMLowering>(); 1028 } 1029