blob: ab060af1147710451b9fa24fb1a95251b0b23d8a [file] [log] [blame]
//===-- 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/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/BoxValue.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Support/FatalError.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MD5.h"
static llvm::cl::opt<std::size_t>
nameLengthHashSize("length-to-hash-string-literal",
llvm::cl::desc("string literals that exceed this length"
" will use a hash value as their symbol "
"name"),
llvm::cl::init(32));
mlir::FuncOp fir::FirOpBuilder::createFunction(mlir::Location loc,
mlir::ModuleOp module,
llvm::StringRef name,
mlir::FunctionType ty) {
return fir::createFuncOp(loc, module, name, ty);
}
mlir::FuncOp fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp,
llvm::StringRef name) {
return modOp.lookupSymbol<mlir::FuncOp>(name);
}
fir::GlobalOp fir::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp,
llvm::StringRef name) {
return modOp.lookupSymbol<fir::GlobalOp>(name);
}
mlir::Type fir::FirOpBuilder::getRefType(mlir::Type eleTy) {
assert(!eleTy.isa<fir::ReferenceType>() && "cannot be a reference type");
return fir::ReferenceType::get(eleTy);
}
mlir::Type fir::FirOpBuilder::getVarLenSeqTy(mlir::Type eleTy, unsigned rank) {
fir::SequenceType::Shape shape(rank, fir::SequenceType::getUnknownExtent());
return fir::SequenceType::get(shape, eleTy);
}
mlir::Type fir::FirOpBuilder::getRealType(int kind) {
switch (kindMap.getRealTypeID(kind)) {
case llvm::Type::TypeID::HalfTyID:
return mlir::FloatType::getF16(getContext());
case llvm::Type::TypeID::FloatTyID:
return mlir::FloatType::getF32(getContext());
case llvm::Type::TypeID::DoubleTyID:
return mlir::FloatType::getF64(getContext());
case llvm::Type::TypeID::X86_FP80TyID:
return mlir::FloatType::getF80(getContext());
case llvm::Type::TypeID::FP128TyID:
return mlir::FloatType::getF128(getContext());
default:
fir::emitFatalError(UnknownLoc::get(getContext()),
"unsupported type !fir.real<kind>");
}
}
mlir::Value fir::FirOpBuilder::createNullConstant(mlir::Location loc,
mlir::Type ptrType) {
auto ty = ptrType ? ptrType : getRefType(getNoneType());
return create<fir::ZeroOp>(loc, ty);
}
mlir::Value fir::FirOpBuilder::createIntegerConstant(mlir::Location loc,
mlir::Type ty,
std::int64_t cst) {
return create<mlir::ConstantOp>(loc, ty, getIntegerAttr(ty, cst));
}
mlir::Value
fir::FirOpBuilder::createRealConstant(mlir::Location loc, mlir::Type fltTy,
llvm::APFloat::integerPart val) {
auto apf = [&]() -> llvm::APFloat {
if (auto ty = fltTy.dyn_cast<fir::RealType>())
return llvm::APFloat(kindMap.getFloatSemantics(ty.getFKind()), val);
if (fltTy.isF16())
return llvm::APFloat(llvm::APFloat::IEEEhalf(), val);
if (fltTy.isBF16())
return llvm::APFloat(llvm::APFloat::BFloat(), val);
if (fltTy.isF32())
return llvm::APFloat(llvm::APFloat::IEEEsingle(), val);
if (fltTy.isF64())
return llvm::APFloat(llvm::APFloat::IEEEdouble(), val);
if (fltTy.isF80())
return llvm::APFloat(llvm::APFloat::x87DoubleExtended(), val);
if (fltTy.isF128())
return llvm::APFloat(llvm::APFloat::IEEEquad(), val);
llvm_unreachable("unhandled MLIR floating-point type");
};
return createRealConstant(loc, fltTy, apf());
}
mlir::Value fir::FirOpBuilder::createRealConstant(mlir::Location loc,
mlir::Type fltTy,
const llvm::APFloat &value) {
if (fltTy.isa<mlir::FloatType>()) {
auto attr = getFloatAttr(fltTy, value);
return create<mlir::arith::ConstantOp>(loc, fltTy, attr);
}
llvm_unreachable("should use builtin floating-point type");
}
/// 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
fir::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(), module.getBody()->end());
auto glob = create<fir::GlobalOp>(loc, name, isConst, type, value, linkage);
restoreInsertionPoint(insertPt);
return glob;
}
fir::GlobalOp fir::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(), module.getBody()->end());
auto glob = create<fir::GlobalOp>(loc, name, isConst, type, mlir::Attribute{},
linkage);
auto &region = glob.getRegion();
region.push_back(new mlir::Block);
auto &block = glob.getRegion().back();
setInsertionPointToStart(&block);
bodyBuilder(*this);
restoreInsertionPoint(insertPt);
return glob;
}
mlir::Value fir::FirOpBuilder::createConvert(mlir::Location loc,
mlir::Type toTy, mlir::Value val) {
if (val.getType() != toTy) {
assert(!fir::isa_derived(toTy));
return create<fir::ConvertOp>(loc, toTy, val);
}
return val;
}
fir::StringLitOp fir::FirOpBuilder::createStringLitOp(mlir::Location loc,
llvm::StringRef data) {
auto type = fir::CharacterType::get(getContext(), 1, data.size());
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> attrs{dataAttr, sizeAttr};
return create<fir::StringLitOp>(loc, llvm::ArrayRef<mlir::Type>{type},
llvm::None, attrs);
}
static mlir::Value genNullPointerComparison(fir::FirOpBuilder &builder,
mlir::Location loc,
mlir::Value addr,
arith::CmpIPredicate condition) {
auto intPtrTy = builder.getIntPtrType();
auto ptrToInt = builder.createConvert(loc, intPtrTy, addr);
auto c0 = builder.createIntegerConstant(loc, intPtrTy, 0);
return builder.create<arith::CmpIOp>(loc, condition, ptrToInt, c0);
}
mlir::Value fir::FirOpBuilder::genIsNotNull(mlir::Location loc,
mlir::Value addr) {
return genNullPointerComparison(*this, loc, addr, arith::CmpIPredicate::ne);
}
mlir::Value fir::FirOpBuilder::genIsNull(mlir::Location loc, mlir::Value addr) {
return genNullPointerComparison(*this, loc, addr, arith::CmpIPredicate::eq);
}
std::string fir::factory::uniqueCGIdent(llvm::StringRef prefix,
llvm::StringRef name) {
// For "long" identifiers use a hash value
if (name.size() > nameLengthHashSize) {
llvm::MD5 hash;
hash.update(name);
llvm::MD5::MD5Result result;
hash.final(result);
llvm::SmallString<32> str;
llvm::MD5::stringifyResult(result, str);
std::string hashName = prefix.str();
hashName.append(".").append(str.c_str());
return fir::NameUniquer::doGenerated(hashName);
}
// "Short" identifiers use a reversible hex string
std::string nm = prefix.str();
return fir::NameUniquer::doGenerated(
nm.append(".").append(llvm::toHex(name)));
}
mlir::Value fir::factory::locationToFilename(fir::FirOpBuilder &builder,
mlir::Location loc) {
if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>()) {
// must be encoded as asciiz, C string
auto fn = flc.getFilename().str() + '\0';
return fir::getBase(createStringLiteral(builder, loc, fn));
}
return builder.createNullConstant(loc);
}
mlir::Value fir::factory::locationToLineNo(fir::FirOpBuilder &builder,
mlir::Location loc,
mlir::Type type) {
if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>())
return builder.createIntegerConstant(loc, type, flc.getLine());
return builder.createIntegerConstant(loc, type, 0);
}
fir::ExtendedValue fir::factory::createStringLiteral(fir::FirOpBuilder &builder,
mlir::Location loc,
llvm::StringRef str) {
std::string globalName = fir::factory::uniqueCGIdent("cl", str);
auto type = fir::CharacterType::get(builder.getContext(), 1, str.size());
auto global = builder.getNamedGlobal(globalName);
if (!global)
global = builder.createGlobalConstant(
loc, type, globalName,
[&](fir::FirOpBuilder &builder) {
auto stringLitOp = builder.createStringLitOp(loc, str);
builder.create<fir::HasValueOp>(loc, stringLitOp);
},
builder.createLinkOnceLinkage());
auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(),
global.getSymbol());
auto len = builder.createIntegerConstant(
loc, builder.getCharacterLengthType(), str.size());
return fir::CharBoxValue{addr, len};
}