Skip to content

[flang] Updating drivers to create data layout before semantics #73301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions flang/include/flang/Frontend/CompilerInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "flang/Semantics/runtime-type-info.h"
#include "flang/Semantics/semantics.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"

namespace Fortran::frontend {

Expand Down Expand Up @@ -57,6 +58,8 @@ class CompilerInstance {

std::unique_ptr<Fortran::semantics::SemanticsContext> semaContext;

std::unique_ptr<llvm::TargetMachine> targetMachine;

/// The stream for diagnostics from Semantics
llvm::raw_ostream *semaOutputStream = &llvm::errs();

Expand Down Expand Up @@ -231,6 +234,26 @@ class CompilerInstance {
createDefaultOutputFile(bool binary = true, llvm::StringRef baseInput = "",
llvm::StringRef extension = "");

/// {
/// @name Target Machine
/// {

/// Get the target machine.
const llvm::TargetMachine &getTargetMachine() const {
assert(targetMachine && "target machine was not set");
return *targetMachine;
}
llvm::TargetMachine &getTargetMachine() {
assert(targetMachine && "target machine was not set");
return *targetMachine;
}

/// Sets up LLVM's TargetMachine.
bool setUpTargetMachine();

/// Produces the string which represents target feature
std::string getTargetFeatures();

private:
/// Create a new output file
///
Expand Down
7 changes: 6 additions & 1 deletion flang/include/flang/Frontend/CompilerInvocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include "llvm/Option/ArgList.h"
#include <memory>

namespace llvm {
class TargetMachine;
}

namespace Fortran::frontend {

/// Fill out Opts based on the options given in Args.
Expand Down Expand Up @@ -158,7 +162,8 @@ class CompilerInvocation : public CompilerInvocationBase {

/// Creates and configures semantics context based on the compilation flags.
std::unique_ptr<Fortran::semantics::SemanticsContext>
getSemanticsCtx(Fortran::parser::AllCookedSources &allCookedSources);
getSemanticsCtx(Fortran::parser::AllCookedSources &allCookedSources,
const llvm::TargetMachine &);

std::string &getModuleDir() { return moduleDir; }
const std::string &getModuleDir() const { return moduleDir; }
Expand Down
4 changes: 0 additions & 4 deletions flang/include/flang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "mlir/IR/BuiltinOps.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Module.h"
#include "llvm/Target/TargetMachine.h"
#include <memory>

namespace Fortran::frontend {
Expand Down Expand Up @@ -204,8 +203,6 @@ class CodeGenAction : public FrontendAction {
void executeAction() override;
/// Runs prescan, parsing, sema and lowers to MLIR.
bool beginSourceFileAction() override;
/// Sets up LLVM's TargetMachine.
bool setUpTargetMachine();
/// Runs the optimization (aka middle-end) pipeline on the LLVM module
/// associated with this action.
void runOptimizationPipeline(llvm::raw_pwrite_stream &os);
Expand Down Expand Up @@ -234,7 +231,6 @@ class CodeGenAction : public FrontendAction {

BackendActionTy action;

std::unique_ptr<llvm::TargetMachine> tm;
/// }
public:
~CodeGenAction() override;
Expand Down
13 changes: 10 additions & 3 deletions flang/include/flang/Lower/Bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "mlir/IR/BuiltinOps.h"

namespace llvm {
class DataLayout;
} // namespace llvm

namespace Fortran {
namespace common {
class IntrinsicTypeDefaultKinds;
Expand Down Expand Up @@ -59,10 +63,12 @@ class LoweringBridge {
llvm::StringRef triple, fir::KindMapping &kindMap,
const Fortran::lower::LoweringOptions &loweringOptions,
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
const Fortran::common::LanguageFeatureControl &languageFeatures) {
const Fortran::common::LanguageFeatureControl &languageFeatures,
const llvm::DataLayout *dataLayout = nullptr) {
return LoweringBridge(ctx, semanticsContext, defaultKinds, intrinsics,
targetCharacteristics, allCooked, triple, kindMap,
loweringOptions, envDefaults, languageFeatures);
loweringOptions, envDefaults, languageFeatures,
dataLayout);
}

//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -140,7 +146,8 @@ class LoweringBridge {
fir::KindMapping &kindMap,
const Fortran::lower::LoweringOptions &loweringOptions,
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
const Fortran::common::LanguageFeatureControl &languageFeatures);
const Fortran::common::LanguageFeatureControl &languageFeatures,
const llvm::DataLayout *dataLayout);
LoweringBridge() = delete;
LoweringBridge(const LoweringBridge &) = delete;

Expand Down
39 changes: 39 additions & 0 deletions flang/include/flang/Optimizer/Support/DataLayout.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//===-- Optimizer/Support/DataLayout.h --------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H
#define FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H

namespace mlir {
class ModuleOp;
}
namespace llvm {
class DataLayout;
}

namespace fir::support {
/// Create an mlir::DataLayoutSpecInterface attribute from an llvm::DataLayout
/// and set it on the provided mlir::ModuleOp.
/// Also set the llvm.data_layout attribute with the string representation of
/// the llvm::DataLayout on the module.
/// These attributes are replaced if they were already set.
void setMLIRDataLayout(mlir::ModuleOp mlirModule, const llvm::DataLayout &dl);

/// Create an mlir::DataLayoutSpecInterface from the llvm.data_layout attribute
/// if one is provided. If such attribute is not available, create a default
/// target independent layout when allowDefaultLayout is true. Otherwise do
/// nothing.
void setMLIRDataLayoutFromAttributes(mlir::ModuleOp mlirModule,
bool allowDefaultLayout);
} // namespace fir::support

#endif // FORTRAN_OPTIMIZER_SUPPORT_DATALAYOUT_H
40 changes: 40 additions & 0 deletions flang/include/flang/Tools/TargetSetup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===-- Tools/TargetSetup.h ------------------------------------- *-C++-*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_TOOLS_TARGET_SETUP_H
#define FORTRAN_TOOLS_TARGET_SETUP_H

#include "flang/Evaluate/target.h"
#include "llvm/Target/TargetMachine.h"

namespace Fortran::tools {

[[maybe_unused]] inline static void setUpTargetCharacteristics(
Fortran::evaluate::TargetCharacteristics &targetCharacteristics,
const llvm::TargetMachine &targetMachine,
const std::string &compilerVersion, const std::string &compilerOptions) {

const llvm::Triple &targetTriple{targetMachine.getTargetTriple()};
// FIXME: Handle real(3) ?
if (targetTriple.getArch() != llvm::Triple::ArchType::x86_64)
targetCharacteristics.DisableType(
Fortran::common::TypeCategory::Real, /*kind=*/10);

targetCharacteristics.set_compilerOptionsString(compilerOptions)
.set_compilerVersionString(compilerVersion);

if (targetTriple.isPPC())
targetCharacteristics.set_isPPC(true);

// TODO: use target machine data layout to set-up the target characteristics
// type size and alignment info.
}

} // namespace Fortran::tools

#endif // FORTRAN_TOOLS_TARGET_SETUP_H
134 changes: 133 additions & 1 deletion flang/lib/Frontend/CompilerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@
#include "flang/Parser/parsing.h"
#include "flang/Parser/provenance.h"
#include "flang/Semantics/semantics.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/TargetParser.h"
#include "llvm/TargetParser/Triple.h"

using namespace Fortran::frontend;
Expand Down Expand Up @@ -156,8 +160,10 @@ bool CompilerInstance::executeAction(FrontendAction &act) {
invoc.setFortranOpts();
// Set the encoding to read all input files in based on user input.
allSources->set_encoding(invoc.getFortranOpts().encoding);
if (!setUpTargetMachine())
return false;
// Create the semantics context
semaContext = invoc.getSemanticsCtx(*allCookedSources);
semaContext = invoc.getSemanticsCtx(*allCookedSources, getTargetMachine());
// Set options controlling lowering to FIR.
invoc.setLoweringOptions();

Expand Down Expand Up @@ -197,3 +203,129 @@ CompilerInstance::createDiagnostics(clang::DiagnosticOptions *opts,
}
return diags;
}

// Get feature string which represents combined explicit target features
// for AMD GPU and the target features specified by the user
static std::string
getExplicitAndImplicitAMDGPUTargetFeatures(clang::DiagnosticsEngine &diags,
const TargetOptions &targetOpts,
const llvm::Triple triple) {
llvm::StringRef cpu = targetOpts.cpu;
llvm::StringMap<bool> implicitFeaturesMap;
std::string errorMsg;
// Get the set of implicit target features
llvm::AMDGPU::fillAMDGPUFeatureMap(cpu, triple, implicitFeaturesMap);

// Add target features specified by the user
for (auto &userFeature : targetOpts.featuresAsWritten) {
std::string userKeyString = userFeature.substr(1);
implicitFeaturesMap[userKeyString] = (userFeature[0] == '+');
}

if (!llvm::AMDGPU::insertWaveSizeFeature(cpu, triple, implicitFeaturesMap,
errorMsg)) {
unsigned diagID = diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
"Unsupported feature ID: %0");
diags.Report(diagID) << errorMsg.data();
return std::string();
}

llvm::SmallVector<std::string> featuresVec;
for (auto &implicitFeatureItem : implicitFeaturesMap) {
featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
implicitFeatureItem.first().str())
.str());
}
llvm::sort(featuresVec);
return llvm::join(featuresVec, ",");
}

// Get feature string which represents combined explicit target features
// for NVPTX and the target features specified by the user/
// TODO: Have a more robust target conf like `clang/lib/Basic/Targets/NVPTX.cpp`
static std::string
getExplicitAndImplicitNVPTXTargetFeatures(clang::DiagnosticsEngine &diags,
const TargetOptions &targetOpts,
const llvm::Triple triple) {
llvm::StringRef cpu = targetOpts.cpu;
llvm::StringMap<bool> implicitFeaturesMap;
std::string errorMsg;
bool ptxVer = false;

// Add target features specified by the user
for (auto &userFeature : targetOpts.featuresAsWritten) {
llvm::StringRef userKeyString(llvm::StringRef(userFeature).drop_front(1));
implicitFeaturesMap[userKeyString.str()] = (userFeature[0] == '+');
// Check if the user provided a PTX version
if (userKeyString.startswith("ptx"))
ptxVer = true;
}

// Set the default PTX version to `ptx61` if none was provided.
// TODO: set the default PTX version based on the chip.
if (!ptxVer)
implicitFeaturesMap["ptx61"] = true;

// Set the compute capability.
implicitFeaturesMap[cpu.str()] = true;

llvm::SmallVector<std::string> featuresVec;
for (auto &implicitFeatureItem : implicitFeaturesMap) {
featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
implicitFeatureItem.first().str())
.str());
}
llvm::sort(featuresVec);
return llvm::join(featuresVec, ",");
}

std::string CompilerInstance::getTargetFeatures() {
const TargetOptions &targetOpts = getInvocation().getTargetOpts();
const llvm::Triple triple(targetOpts.triple);

// Clang does not append all target features to the clang -cc1 invocation.
// Some target features are parsed implicitly by clang::TargetInfo child
// class. Clang::TargetInfo classes are the basic clang classes and
// they cannot be reused by Flang.
// That's why we need to extract implicit target features and add
// them to the target features specified by the user
if (triple.isAMDGPU()) {
return getExplicitAndImplicitAMDGPUTargetFeatures(getDiagnostics(),
targetOpts, triple);
} else if (triple.isNVPTX()) {
return getExplicitAndImplicitNVPTXTargetFeatures(getDiagnostics(),
targetOpts, triple);
}
return llvm::join(targetOpts.featuresAsWritten.begin(),
targetOpts.featuresAsWritten.end(), ",");
}

bool CompilerInstance::setUpTargetMachine() {
const TargetOptions &targetOpts = getInvocation().getTargetOpts();
const std::string &theTriple = targetOpts.triple;

// Create `Target`
std::string error;
const llvm::Target *theTarget =
llvm::TargetRegistry::lookupTarget(theTriple, error);
if (!theTarget) {
getDiagnostics().Report(clang::diag::err_fe_unable_to_create_target)
<< error;
return false;
}

// Create `TargetMachine`
const auto &CGOpts = getInvocation().getCodeGenOpts();
std::optional<llvm::CodeGenOptLevel> OptLevelOrNone =
llvm::CodeGenOpt::getLevel(CGOpts.OptimizationLevel);
assert(OptLevelOrNone && "Invalid optimization level!");
llvm::CodeGenOptLevel OptLevel = *OptLevelOrNone;
std::string featuresStr = getTargetFeatures();
targetMachine.reset(theTarget->createTargetMachine(
theTriple, /*CPU=*/targetOpts.cpu,
/*Features=*/featuresStr, llvm::TargetOptions(),
/*Reloc::Model=*/CGOpts.getRelocationModel(),
/*CodeModel::Model=*/std::nullopt, OptLevel));
assert(targetMachine && "Failed to create TargetMachine");
return true;
}
Loading