This reverts commit 511dd4f438 along with
a couple fixes.
Original message:
Now the context is the first, rather than the last input.
This better matches the rest of the infrastructure and makes
it easier to move these types to being declaratively specified.
Phabricator: https://reviews.llvm.org/D96111
187 lines
7.3 KiB
C++
187 lines
7.3 KiB
C++
//===-- 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<mlir::FuncOp>(name);
|
|
}
|
|
|
|
fir::GlobalOp
|
|
Fortran::lower::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp,
|
|
llvm::StringRef name) {
|
|
return modOp.lookupSymbol<fir::GlobalOp>(name);
|
|
}
|
|
|
|
mlir::Type Fortran::lower::FirOpBuilder::getRefType(mlir::Type eleTy) {
|
|
assert(!eleTy.isa<fir::ReferenceType>());
|
|
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<mlir::ConstantOp>(loc, ty, getIntegerAttr(ty, cst));
|
|
}
|
|
|
|
mlir::Value Fortran::lower::FirOpBuilder::createRealConstant(
|
|
mlir::Location loc, mlir::Type realType, const llvm::APFloat &val) {
|
|
return create<mlir::ConstantOp>(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<fir::RealType>()) {
|
|
attr = getFloatAttr(
|
|
realType,
|
|
llvm::APFloat(kindMap.getFloatSemantics(firType.getFKind()), 0));
|
|
} else { // mlir::FloatType.
|
|
attr = getZeroAttr(realType);
|
|
}
|
|
return create<mlir::ConstantOp>(loc, realType, attr);
|
|
}
|
|
|
|
mlir::Value Fortran::lower::FirOpBuilder::allocateLocal(
|
|
mlir::Location loc, mlir::Type ty, llvm::StringRef nm,
|
|
llvm::ArrayRef<mlir::Value> shape, bool asTarget) {
|
|
llvm::SmallVector<mlir::Value, 8> indices;
|
|
auto idxTy = getIndexType();
|
|
llvm::for_each(shape, [&](mlir::Value sh) {
|
|
indices.push_back(createConvert(loc, idxTy, sh));
|
|
});
|
|
llvm::SmallVector<mlir::NamedAttribute, 2> attrs;
|
|
if (asTarget)
|
|
attrs.emplace_back(mlir::Identifier::get("target", getContext()),
|
|
getUnitAttr());
|
|
return create<fir::AllocaOp>(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<mlir::Value> shape) {
|
|
auto insPt = saveInsertionPoint();
|
|
if (shape.empty())
|
|
setInsertionPointToStart(getEntryBlock());
|
|
else
|
|
setInsertionPointAfter(shape.back().getDefiningOp());
|
|
assert(!type.isa<fir::ReferenceType>() && "cannot be a reference");
|
|
auto ae = create<fir::AllocaOp>(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<fir::GlobalOp>(name))
|
|
return glob;
|
|
setInsertionPoint(module.getBody()->getTerminator());
|
|
auto glob = create<fir::GlobalOp>(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<void(FirOpBuilder &)> bodyBuilder, mlir::StringAttr linkage) {
|
|
auto module = getModule();
|
|
auto insertPt = saveInsertionPoint();
|
|
if (auto glob = module.lookupSymbol<fir::GlobalOp>(name))
|
|
return glob;
|
|
setInsertionPoint(module.getBody()->getTerminator());
|
|
auto glob = create<fir::GlobalOp>(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<fir::ComplexType>().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<fir::ConvertOp>(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(getContext(), data);
|
|
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<mlir::NamedAttribute, 2> attrs{dataAttr, sizeAttr};
|
|
auto arrTy =
|
|
fir::SequenceType::get(fir::SequenceType::Shape(1, data.size()), eleTy);
|
|
return create<fir::StringLitOp>(loc, llvm::ArrayRef<mlir::Type>{arrTy},
|
|
llvm::None, attrs);
|
|
}
|