//===-- 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 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(name); } fir::GlobalOp fir::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp, llvm::StringRef name) { return modOp.lookupSymbol(name); } mlir::Type fir::FirOpBuilder::getRefType(mlir::Type eleTy) { assert(!eleTy.isa() && "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"); } } mlir::Value fir::FirOpBuilder::createNullConstant(mlir::Location loc, mlir::Type ptrType) { auto ty = ptrType ? ptrType : getRefType(getNoneType()); return create(loc, ty); } mlir::Value fir::FirOpBuilder::createIntegerConstant(mlir::Location loc, mlir::Type ty, std::int64_t cst) { return create(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()) 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()) { auto attr = getFloatAttr(fltTy, value); return create(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(name)) return glob; setInsertionPoint(module.getBody(), module.getBody()->end()); auto glob = create(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 bodyBuilder, mlir::StringAttr linkage) { auto module = getModule(); auto insertPt = saveInsertionPoint(); if (auto glob = module.lookupSymbol(name)) return glob; setInsertionPoint(module.getBody(), module.getBody()->end()); 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 fir::FirOpBuilder::createConvert(mlir::Location loc, mlir::Type toTy, mlir::Value val) { if (val.getType() != toTy) { assert(!fir::isa_derived(toTy)); return create(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 attrs{dataAttr, sizeAttr}; return create(loc, llvm::ArrayRef{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(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()) { // 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()) 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(loc, stringLitOp); }, builder.createLinkOnceLinkage()); auto addr = builder.create(loc, global.resultType(), global.getSymbol()); auto len = builder.createIntegerConstant( loc, builder.getCharacterLengthType(), str.size()); return fir::CharBoxValue{addr, len}; }