//===-- FIRBuilder.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "flang/Lower/FIRBuilder.h" #include "SymbolMap.h" #include "flang/Lower/Bridge.h" #include "flang/Lower/ComplexExpr.h" #include "flang/Lower/ConvertType.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Semantics/symbol.h" #include "llvm/Support/ErrorHandling.h" mlir::FuncOp Fortran::lower::FirOpBuilder::createFunction( mlir::Location loc, mlir::ModuleOp module, llvm::StringRef name, mlir::FunctionType ty) { return fir::createFuncOp(loc, module, name, ty); } mlir::FuncOp Fortran::lower::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp, llvm::StringRef name) { return modOp.lookupSymbol(name); } fir::GlobalOp Fortran::lower::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp, llvm::StringRef name) { return modOp.lookupSymbol(name); } mlir::Type Fortran::lower::FirOpBuilder::getRefType(mlir::Type eleTy) { assert(!eleTy.isa()); return fir::ReferenceType::get(eleTy); } mlir::Value Fortran::lower::FirOpBuilder::createNullConstant(mlir::Location loc) { auto indexType = getIndexType(); auto zero = createIntegerConstant(loc, indexType, 0); auto noneRefType = getRefType(getNoneType()); return createConvert(loc, noneRefType, zero); } mlir::Value Fortran::lower::FirOpBuilder::createIntegerConstant( mlir::Location loc, mlir::Type ty, std::int64_t cst) { return create(loc, ty, getIntegerAttr(ty, cst)); } mlir::Value Fortran::lower::FirOpBuilder::createRealConstant( mlir::Location loc, mlir::Type realType, const llvm::APFloat &val) { return create(loc, realType, getFloatAttr(realType, val)); } mlir::Value Fortran::lower::FirOpBuilder::createRealZeroConstant(mlir::Location loc, mlir::Type realType) { mlir::Attribute attr; if (auto firType = realType.dyn_cast()) { attr = getFloatAttr( realType, llvm::APFloat(kindMap.getFloatSemantics(firType.getFKind()), 0)); } else { // mlir::FloatType. attr = getZeroAttr(realType); } return create(loc, realType, attr); } mlir::Value Fortran::lower::FirOpBuilder::allocateLocal( mlir::Location loc, mlir::Type ty, llvm::StringRef nm, llvm::ArrayRef shape, bool asTarget) { llvm::SmallVector indices; auto idxTy = getIndexType(); llvm::for_each(shape, [&](mlir::Value sh) { indices.push_back(createConvert(loc, idxTy, sh)); }); llvm::SmallVector attrs; if (asTarget) attrs.emplace_back(mlir::Identifier::get("target", getContext()), getUnitAttr()); return create(loc, ty, nm, llvm::None, indices, attrs); } /// Create a temporary variable on the stack. Anonymous temporaries have no /// `name` value. mlir::Value Fortran::lower::FirOpBuilder::createTemporary( mlir::Location loc, mlir::Type type, llvm::StringRef name, llvm::ArrayRef shape) { auto insPt = saveInsertionPoint(); if (shape.empty()) setInsertionPointToStart(getEntryBlock()); else setInsertionPointAfter(shape.back().getDefiningOp()); assert(!type.isa() && "cannot be a reference"); auto ae = create(loc, type, name, llvm::None, shape); restoreInsertionPoint(insPt); return ae; } /// Create a global variable in the (read-only) data section. A global variable /// must have a unique name to identify and reference it. fir::GlobalOp Fortran::lower::FirOpBuilder::createGlobal( mlir::Location loc, mlir::Type type, llvm::StringRef name, mlir::StringAttr linkage, mlir::Attribute value, bool isConst) { auto module = getModule(); auto insertPt = saveInsertionPoint(); if (auto glob = module.lookupSymbol(name)) return glob; setInsertionPoint(module.getBody()->getTerminator()); auto glob = create(loc, name, isConst, type, value, linkage); restoreInsertionPoint(insertPt); return glob; } fir::GlobalOp Fortran::lower::FirOpBuilder::createGlobal( mlir::Location loc, mlir::Type type, llvm::StringRef name, bool isConst, std::function bodyBuilder, mlir::StringAttr linkage) { auto module = getModule(); auto insertPt = saveInsertionPoint(); if (auto glob = module.lookupSymbol(name)) return glob; setInsertionPoint(module.getBody()->getTerminator()); auto glob = create(loc, name, isConst, type, mlir::Attribute{}, linkage); auto ®ion = glob.getRegion(); region.push_back(new mlir::Block); auto &block = glob.getRegion().back(); setInsertionPointToStart(&block); bodyBuilder(*this); restoreInsertionPoint(insertPt); return glob; } mlir::Value Fortran::lower::FirOpBuilder::convertWithSemantics( mlir::Location loc, mlir::Type toTy, mlir::Value val) { assert(toTy && "store location must be typed"); auto fromTy = val.getType(); if (fromTy == toTy) return val; // FIXME: add a fir::is_integer() test ComplexExprHelper helper{*this, loc}; if ((fir::isa_real(fromTy) || fromTy.isSignlessInteger()) && fir::isa_complex(toTy)) { // imaginary part is zero auto eleTy = helper.getComplexPartType(toTy); auto cast = createConvert(loc, eleTy, val); llvm::APFloat zero{ kindMap.getFloatSemantics(toTy.cast().getFKind()), 0}; auto imag = createRealConstant(loc, eleTy, zero); return helper.createComplex(toTy, cast, imag); } // FIXME: add a fir::is_integer() test if (fir::isa_complex(fromTy) && (toTy.isSignlessInteger() || fir::isa_real(toTy))) { // drop the imaginary part auto rp = helper.extractComplexPart(val, /*isImagPart=*/false); return createConvert(loc, toTy, rp); } return createConvert(loc, toTy, val); } mlir::Value Fortran::lower::FirOpBuilder::createConvert(mlir::Location loc, mlir::Type toTy, mlir::Value val) { if (val.getType() != toTy) return create(loc, toTy, val); return val; } fir::StringLitOp Fortran::lower::FirOpBuilder::createStringLit( mlir::Location loc, mlir::Type eleTy, llvm::StringRef data) { auto strAttr = mlir::StringAttr::get(data, getContext()); auto valTag = mlir::Identifier::get(fir::StringLitOp::value(), getContext()); mlir::NamedAttribute dataAttr(valTag, strAttr); auto sizeTag = mlir::Identifier::get(fir::StringLitOp::size(), getContext()); mlir::NamedAttribute sizeAttr(sizeTag, getI64IntegerAttr(data.size())); llvm::SmallVector attrs{dataAttr, sizeAttr}; auto arrTy = fir::SequenceType::get(fir::SequenceType::Shape(1, data.size()), eleTy); return create(loc, llvm::ArrayRef{arrTy}, llvm::None, attrs); }