diff --git a/flang/include/flang/Lower/Bridge.h b/flang/include/flang/Lower/Bridge.h index fd2945a68e00e..52110b861b680 100644 --- a/flang/include/flang/Lower/Bridge.h +++ b/flang/include/flang/Lower/Bridge.h @@ -24,7 +24,7 @@ #include namespace llvm { -class DataLayout; +class TargetMachine; } // namespace llvm namespace Fortran { @@ -65,11 +65,11 @@ class LoweringBridge { const Fortran::lower::LoweringOptions &loweringOptions, const std::vector &envDefaults, const Fortran::common::LanguageFeatureControl &languageFeatures, - const llvm::DataLayout *dataLayout = nullptr) { + const llvm::TargetMachine &targetMachine) { return LoweringBridge(ctx, semanticsContext, defaultKinds, intrinsics, targetCharacteristics, allCooked, triple, kindMap, loweringOptions, envDefaults, languageFeatures, - dataLayout); + targetMachine); } //===--------------------------------------------------------------------===// @@ -148,7 +148,7 @@ class LoweringBridge { const Fortran::lower::LoweringOptions &loweringOptions, const std::vector &envDefaults, const Fortran::common::LanguageFeatureControl &languageFeatures, - const llvm::DataLayout *dataLayout); + const llvm::TargetMachine &targetMachine); LoweringBridge() = delete; LoweringBridge(const LoweringBridge &) = delete; diff --git a/flang/include/flang/Optimizer/CodeGen/CGPasses.td b/flang/include/flang/Optimizer/CodeGen/CGPasses.td index 9798019bfd6a9..f524fb4237344 100644 --- a/flang/include/flang/Optimizer/CodeGen/CGPasses.td +++ b/flang/include/flang/Optimizer/CodeGen/CGPasses.td @@ -29,6 +29,10 @@ def FIRToLLVMLowering : Pass<"fir-to-llvm-ir", "mlir::ModuleOp"> { "Override module's target triple.">, Option<"forcedDataLayout", "datalayout", "std::string", /*default=*/"", "Override module's data layout.">, + Option<"forcedTargetCPU", "target-cpu", "std::string", /*default=*/"", + "Override module's target CPU.">, + Option<"forcedTargetFeatures", "target-features", "std::string", + /*default=*/"", "Override module's target features.">, Option<"applyTBAA", "apply-tbaa", "bool", /*default=*/"false", "Attach TBAA tags to memory accessing operations."> ]; @@ -60,6 +64,10 @@ def TargetRewritePass : Pass<"target-rewrite", "mlir::ModuleOp"> { let options = [ Option<"forcedTargetTriple", "target", "std::string", /*default=*/"", "Override module's target triple.">, + Option<"forcedTargetCPU", "target-cpu", "std::string", /*default=*/"", + "Override module's target CPU.">, + Option<"forcedTargetFeatures", "target-features", "std::string", + /*default=*/"", "Override module's target features.">, Option<"noCharacterConversion", "no-character-conversion", "bool", /*default=*/"false", "Disable target-specific conversion of CHARACTER.">, diff --git a/flang/include/flang/Optimizer/CodeGen/Target.h b/flang/include/flang/Optimizer/CodeGen/Target.h index c3ef521ced120..3cf6a74a9adb7 100644 --- a/flang/include/flang/Optimizer/CodeGen/Target.h +++ b/flang/include/flang/Optimizer/CodeGen/Target.h @@ -15,6 +15,7 @@ #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Dialect/Support/KindMapping.h" +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/IR/BuiltinTypes.h" #include "llvm/TargetParser/Triple.h" #include @@ -70,17 +71,19 @@ class CodeGenSpecifics { using TypeAndAttr = std::tuple; using Marshalling = std::vector; - static std::unique_ptr get(mlir::MLIRContext *ctx, - llvm::Triple &&trp, - KindMapping &&kindMap, - const mlir::DataLayout &dl); + static std::unique_ptr + get(mlir::MLIRContext *ctx, llvm::Triple &&trp, KindMapping &&kindMap, + llvm::StringRef targetCPU, mlir::LLVM::TargetFeaturesAttr targetFeatures, + const mlir::DataLayout &dl); static TypeAndAttr getTypeAndAttr(mlir::Type t) { return TypeAndAttr{t, {}}; } CodeGenSpecifics(mlir::MLIRContext *ctx, llvm::Triple &&trp, - KindMapping &&kindMap, const mlir::DataLayout &dl) + KindMapping &&kindMap, llvm::StringRef targetCPU, + mlir::LLVM::TargetFeaturesAttr targetFeatures, + const mlir::DataLayout &dl) : context{*ctx}, triple{std::move(trp)}, kindMap{std::move(kindMap)}, - dataLayout{&dl} {} + targetCPU{targetCPU}, targetFeatures{targetFeatures}, dataLayout{&dl} {} CodeGenSpecifics() = delete; virtual ~CodeGenSpecifics() {} @@ -161,6 +164,12 @@ class CodeGenSpecifics { // Returns width in bits of C/C++ 'int' type size. virtual unsigned char getCIntTypeWidth() const = 0; + llvm::StringRef getTargetCPU() const { return targetCPU; } + + mlir::LLVM::TargetFeaturesAttr getTargetFeatures() const { + return targetFeatures; + } + const mlir::DataLayout &getDataLayout() const { assert(dataLayout && "dataLayout must be set"); return *dataLayout; @@ -170,6 +179,8 @@ class CodeGenSpecifics { mlir::MLIRContext &context; llvm::Triple triple; KindMapping kindMap; + llvm::StringRef targetCPU; + mlir::LLVM::TargetFeaturesAttr targetFeatures; const mlir::DataLayout *dataLayout = nullptr; }; diff --git a/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h b/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h index ad91da6a4432d..059a10ce2fe51 100644 --- a/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h +++ b/flang/include/flang/Optimizer/Dialect/Support/FIRContext.h @@ -17,6 +17,7 @@ #ifndef FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H #define FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "llvm/ADT/StringRef.h" #include "llvm/TargetParser/Triple.h" @@ -50,6 +51,19 @@ KindMapping getKindMapping(mlir::ModuleOp mod); /// If a ModuleOp cannot be reached, the function returns default KindMapping. KindMapping getKindMapping(mlir::Operation *op); +/// Set the target CPU for the module. `cpu` must not be deallocated while +/// module `mod` is still live. +void setTargetCPU(mlir::ModuleOp mod, llvm::StringRef cpu); + +/// Get the target CPU string from the Module or return a null reference. +llvm::StringRef getTargetCPU(mlir::ModuleOp mod); + +/// Set the target features for the module. +void setTargetFeatures(mlir::ModuleOp mod, llvm::StringRef features); + +/// Get the target features from the Module. +mlir::LLVM::TargetFeaturesAttr getTargetFeatures(mlir::ModuleOp mod); + /// Helper for determining the target from the host, etc. Tools may use this /// function to provide a consistent interpretation of the `--target=` /// command-line option. diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 65c4df7388f97..4738f7ba57042 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -285,8 +285,6 @@ bool CodeGenAction::beginSourceFileAction() { ci.getSemanticsContext().defaultKinds(); fir::KindMapping kindMap(mlirCtx.get(), llvm::ArrayRef{ fir::fromDefaultKinds(defKinds)}); - const llvm::DataLayout &dl = targetMachine.createDataLayout(); - lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create( *mlirCtx, ci.getSemanticsContext(), defKinds, ci.getSemanticsContext().intrinsics(), @@ -294,7 +292,7 @@ bool CodeGenAction::beginSourceFileAction() { ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple, kindMap, ci.getInvocation().getLoweringOpts(), ci.getInvocation().getFrontendOpts().envDefaults, - ci.getInvocation().getFrontendOpts().features, &dl); + ci.getInvocation().getFrontendOpts().features, targetMachine); // Fetch module from lb, so we can set mlirModule = std::make_unique(lb.getModule()); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index c3a14125bba85..d657075d53efb 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -64,6 +64,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Target/TargetMachine.h" #include #define DEBUG_TYPE "flang-lower-bridge" @@ -5092,7 +5093,7 @@ Fortran::lower::LoweringBridge::LoweringBridge( const Fortran::lower::LoweringOptions &loweringOptions, const std::vector &envDefaults, const Fortran::common::LanguageFeatureControl &languageFeatures, - const llvm::DataLayout *dataLayout) + const llvm::TargetMachine &targetMachine) : semanticsContext{semanticsContext}, defaultKinds{defaultKinds}, intrinsics{intrinsics}, targetCharacteristics{targetCharacteristics}, cooked{&cooked}, context{context}, kindMap{kindMap}, @@ -5148,6 +5149,8 @@ Fortran::lower::LoweringBridge::LoweringBridge( assert(module.get() && "module was not created"); fir::setTargetTriple(*module.get(), triple); fir::setKindMapping(*module.get(), kindMap); - if (dataLayout) - fir::support::setMLIRDataLayout(*module.get(), *dataLayout); + fir::setTargetCPU(*module.get(), targetMachine.getTargetCPU()); + fir::setTargetFeatures(*module.get(), targetMachine.getTargetFeatureString()); + fir::support::setMLIRDataLayout(*module.get(), + targetMachine.createDataLayout()); } diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index ba5946415b6f9..8b0d47ec08ec3 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -3879,6 +3879,12 @@ class FIRToLLVMLowering fir::support::setMLIRDataLayout(mod, dl); } + if (!forcedTargetCPU.empty()) + fir::setTargetCPU(mod, forcedTargetCPU); + + if (!forcedTargetFeatures.empty()) + fir::setTargetFeatures(mod, forcedTargetFeatures); + // Run dynamic pass pipeline for converting Math dialect // operations into other dialects (llvm, func, etc.). // Some conversions of Math operations cannot be done diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp index f2c47ffa88941..19730f7a64337 100644 --- a/flang/lib/Optimizer/CodeGen/Target.cpp +++ b/flang/lib/Optimizer/CodeGen/Target.cpp @@ -1057,51 +1057,57 @@ struct TargetLoongArch64 : public GenericTarget { // TODO: Add other targets to this file as needed. std::unique_ptr fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp, - KindMapping &&kindMap, const mlir::DataLayout &dl) { + KindMapping &&kindMap, llvm::StringRef targetCPU, + mlir::LLVM::TargetFeaturesAttr targetFeatures, + const mlir::DataLayout &dl) { switch (trp.getArch()) { default: break; case llvm::Triple::ArchType::x86: if (trp.isOSWindows()) return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + std::move(kindMap), targetCPU, + targetFeatures, dl); else return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + std::move(kindMap), targetCPU, + targetFeatures, dl); case llvm::Triple::ArchType::x86_64: if (trp.isOSWindows()) return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + std::move(kindMap), targetCPU, + targetFeatures, dl); else return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + std::move(kindMap), targetCPU, + targetFeatures, dl); case llvm::Triple::ArchType::aarch64: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); case llvm::Triple::ArchType::ppc64: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); case llvm::Triple::ArchType::ppc64le: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); case llvm::Triple::ArchType::sparc: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); case llvm::Triple::ArchType::sparcv9: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); case llvm::Triple::ArchType::riscv64: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); case llvm::Triple::ArchType::amdgcn: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); case llvm::Triple::ArchType::nvptx64: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); case llvm::Triple::ArchType::loongarch64: - return std::make_unique(ctx, std::move(trp), - std::move(kindMap), dl); + return std::make_unique( + ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); } TODO(mlir::UnknownLoc::get(ctx), "target not implemented"); } diff --git a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp index f324e18c65465..7bf31ec386959 100644 --- a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp +++ b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp @@ -90,6 +90,12 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase { if (!forcedTargetTriple.empty()) fir::setTargetTriple(mod, forcedTargetTriple); + if (!forcedTargetCPU.empty()) + fir::setTargetCPU(mod, forcedTargetCPU); + + if (!forcedTargetFeatures.empty()) + fir::setTargetFeatures(mod, forcedTargetFeatures); + // TargetRewrite will require querying the type storage sizes, if it was // not set already, create a DataLayoutSpec for the ModuleOp now. std::optional dl = @@ -102,9 +108,9 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase { return; } - auto specifics = - fir::CodeGenSpecifics::get(mod.getContext(), fir::getTargetTriple(mod), - fir::getKindMapping(mod), *dl); + auto specifics = fir::CodeGenSpecifics::get( + mod.getContext(), fir::getTargetTriple(mod), fir::getKindMapping(mod), + fir::getTargetCPU(mod), fir::getTargetFeatures(mod), *dl); setMembers(specifics.get(), &rewriter, &*dl); @@ -666,8 +672,21 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase { /// As the type signature is being changed, this must also update the /// function itself to use any new arguments, etc. mlir::LogicalResult convertTypes(mlir::ModuleOp mod) { - for (auto fn : mod.getOps()) + mlir::MLIRContext *ctx = mod->getContext(); + auto targetCPU = specifics->getTargetCPU(); + mlir::StringAttr targetCPUAttr = + targetCPU.empty() ? nullptr : mlir::StringAttr::get(ctx, targetCPU); + auto targetFeaturesAttr = specifics->getTargetFeatures(); + + for (auto fn : mod.getOps()) { + if (targetCPUAttr) + fn->setAttr("target_cpu", targetCPUAttr); + + if (targetFeaturesAttr) + fn->setAttr("target_features", targetFeaturesAttr); + convertSignature(fn); + } return mlir::success(); } diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp index 62a8e4750dc8c..8fa423f35806e 100644 --- a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp @@ -32,9 +32,9 @@ LLVMTypeConverter::LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA, const mlir::DataLayout &dl) : mlir::LLVMTypeConverter(module.getContext()), kindMapping(getKindMapping(module)), - specifics(CodeGenSpecifics::get(module.getContext(), - getTargetTriple(module), - getKindMapping(module), dl)), + specifics(CodeGenSpecifics::get( + module.getContext(), getTargetTriple(module), getKindMapping(module), + getTargetCPU(module), getTargetFeatures(module), dl)), tbaaBuilder(std::make_unique(module->getContext(), applyTBAA, forceUnifiedTBAATree)) { LLVM_DEBUG(llvm::dbgs() << "FIR type converter\n"); diff --git a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp index 1b2d1c88c86b5..c4d00875c45e4 100644 --- a/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp +++ b/flang/lib/Optimizer/Dialect/Support/FIRContext.cpp @@ -60,6 +60,42 @@ fir::KindMapping fir::getKindMapping(mlir::Operation *op) { return getKindMapping(moduleOp); } +static constexpr const char *targetCpuName = "fir.target_cpu"; + +void fir::setTargetCPU(mlir::ModuleOp mod, llvm::StringRef cpu) { + if (cpu.empty()) + return; + + auto *ctx = mod.getContext(); + mod->setAttr(targetCpuName, mlir::StringAttr::get(ctx, cpu)); +} + +llvm::StringRef fir::getTargetCPU(mlir::ModuleOp mod) { + if (auto attr = mod->getAttrOfType(targetCpuName)) + return attr.getValue(); + + return {}; +} + +static constexpr const char *targetFeaturesName = "fir.target_features"; + +void fir::setTargetFeatures(mlir::ModuleOp mod, llvm::StringRef features) { + if (features.empty()) + return; + + auto *ctx = mod.getContext(); + mod->setAttr(targetFeaturesName, + mlir::LLVM::TargetFeaturesAttr::get(ctx, features)); +} + +mlir::LLVM::TargetFeaturesAttr fir::getTargetFeatures(mlir::ModuleOp mod) { + if (auto attr = mod->getAttrOfType( + targetFeaturesName)) + return attr; + + return {}; +} + std::string fir::determineTargetTriple(llvm::StringRef triple) { // Treat "" or "default" as stand-ins for the default machine. if (triple.empty() || triple == "default") diff --git a/flang/test/Driver/save-mlir-temps.f90 b/flang/test/Driver/save-mlir-temps.f90 index 1c8935fbd7aac..e9478a6c521b2 100644 --- a/flang/test/Driver/save-mlir-temps.f90 +++ b/flang/test/Driver/save-mlir-temps.f90 @@ -51,9 +51,9 @@ ! Content to check from the MLIR outputs !-------------------------- ! MLIR-FIR-NOT: llvm.func -! MLIR-FIR: func.func @{{.*}}main(){{.*}}{ +! MLIR-FIR: func.func @{{.*}}main(){{.*}} -! MLIR-FIR-NOT: func.func -! MLIR-LLVMIR: llvm.func @{{.*}}main(){{.*}}{ +! MLIR-LLVMIR-NOT: func.func +! MLIR-LLVMIR: llvm.func @{{.*}}main(){{.*}} end program diff --git a/flang/test/Fir/target-rewrite-target-cpu.fir b/flang/test/Fir/target-rewrite-target-cpu.fir new file mode 100644 index 0000000000000..8450aaf7d1575 --- /dev/null +++ b/flang/test/Fir/target-rewrite-target-cpu.fir @@ -0,0 +1,35 @@ +// RUN: fir-opt --target-rewrite %s | FileCheck %s --check-prefixes=ALL_MLIR,UNCHANGED_MLIR +// RUN: fir-opt --target-rewrite="target-cpu=gfx90a" %s | FileCheck %s --check-prefixes=ALL_MLIR,CHANGED_MLIR + +// RUN: tco %s | FileCheck %s --check-prefixes=ALL_LLVM,UNCHANGED_LLVM +// RUN: tco -target-cpu=gfx90a %s | FileCheck %s --check-prefixes=ALL_LLVM,CHANGED_LLVM + + +// Check MLIR output from the 'fir-opt' tool + +// ALL_MLIR: module attributes { +// ALL_MLIR-SAME: fir.target_cpu = + +// UNCHANGED_MLIR-SAME: "x86_64" +// CHANGED_MLIR-SAME: "gfx90a" + +// ALL_MLIR: func.func @dummyfunc() attributes { +// ALL_MLIR-SAME: target_cpu = + +// UNCHANGED_MLIR-SAME: "x86_64" +// CHANGED_MLIR-SAME: "gfx90a" + + +// Check LLVM output from the 'tco' tool + +// ALL_LLVM: define void @dummyfunc() #[[ATTRS:.*]] { +// ALL_LLVM: attributes #[[ATTRS]] = { + +// UNCHANGED_LLVM-SAME: "target-cpu"="x86_64" +// CHANGED_LLVM-SAME: "target-cpu"="gfx90a" + +module attributes {fir.target_cpu = "x86_64"} { + func.func @dummyfunc() -> () { + return + } +} diff --git a/flang/test/Fir/target-rewrite-target-features.fir b/flang/test/Fir/target-rewrite-target-features.fir new file mode 100644 index 0000000000000..6e6efa2678f2d --- /dev/null +++ b/flang/test/Fir/target-rewrite-target-features.fir @@ -0,0 +1,39 @@ +// RUN: fir-opt --target-rewrite %s | FileCheck %s --check-prefixes=ALL_MLIR,UNCHANGED_MLIR +// RUN: fir-opt --target-rewrite="target-features=+gfx9-insts,+wavefrontsize64" %s | FileCheck %s --check-prefixes=ALL_MLIR,CHANGED_MLIR + +// RUN: tco %s | FileCheck %s --check-prefixes=ALL_LLVM,UNCHANGED_LLVM +// RUN: tco -target-features=+gfx9-insts,+wavefrontsize64 %s | FileCheck %s --check-prefixes=ALL_LLVM,CHANGED_LLVM + + +// Check MLIR output from the 'fir-opt' tool + +// ALL_MLIR: module attributes { +// ALL_MLIR-SAME: fir.target_features = #llvm.target_features<[ + +// UNCHANGED_MLIR-SAME: "+sse" +// CHANGED_MLIR-SAME: "+gfx9-insts", "+wavefrontsize64" + +// ALL_MLIR-SAME: ]> + +// ALL_MLIR: func.func @dummyfunc() attributes { +// ALL_MLIR-SAME: target_features = #llvm.target_features<[ + +// UNCHANGED_MLIR-SAME: "+sse" +// CHANGED_MLIR-SAME: "+gfx9-insts", "+wavefrontsize64" + +// ALL_MLIR-SAME: ]> + + +// Check LLVM output from the 'tco' tool + +// ALL_LLVM: define void @dummyfunc() #[[ATTRS:.*]] { +// ALL_LLVM: attributes #[[ATTRS]] = { + +// UNCHANGED_LLVM-SAME: "target-features"="+sse" +// CHANGED_LLVM-SAME: "target-features"="+gfx9-insts,+wavefrontsize64" + +module attributes {fir.target_features = #llvm.target_features<["+sse"]>} { + func.func @dummyfunc() -> () { + return + } +} diff --git a/flang/test/Lower/target-features-amdgcn.f90 b/flang/test/Lower/target-features-amdgcn.f90 new file mode 100644 index 0000000000000..1f0439bba80a6 --- /dev/null +++ b/flang/test/Lower/target-features-amdgcn.f90 @@ -0,0 +1,21 @@ +! REQUIRES: amdgpu-registered-target +! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s --check-prefixes=ALL,NONE +! RUN: %flang_fc1 -emit-fir -triple amdgcn-amd-amdhsa %s -o - | FileCheck %s --check-prefixes=ALL,TRIPLE +! RUN: %flang_fc1 -emit-fir -target-cpu gfx90a %s -o - | FileCheck %s --check-prefixes=ALL,CPU +! RUN: %flang_fc1 -emit-fir -triple amdgcn-amd-amdhsa -target-cpu gfx90a %s -o - | FileCheck %s --check-prefixes=ALL,BOTH + +! ALL: module attributes { + +! NONE-NOT: fir.target_cpu +! NONE-NOT: fir.target_features + +! TRIPLE-SAME: fir.target_cpu = "generic-hsa" +! TRIPLE-NOT: fir.target_features + +! CPU-SAME: fir.target_cpu = "gfx90a" +! CPU-NOT: fir.target_features + +! BOTH-SAME: fir.target_cpu = "gfx90a" +! BOTH-SAME: fir.target_features = #llvm.target_features<[ +! BOTH-SAME: "+gfx90a-insts" +! BOTH-SAME: ]> diff --git a/flang/test/Lower/target-features-x86_64.f90 b/flang/test/Lower/target-features-x86_64.f90 new file mode 100644 index 0000000000000..1b628b6b5b9c8 --- /dev/null +++ b/flang/test/Lower/target-features-x86_64.f90 @@ -0,0 +1,19 @@ +! REQUIRES: x86-registered-target +! RUN: %flang_fc1 -emit-fir -triple x86_64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefixes=ALL,NONE +! RUN: %flang_fc1 -emit-fir -triple x86_64-unknown-linux-gnu -target-cpu x86-64 %s -o - | FileCheck %s --check-prefixes=ALL,CPU +! RUN: %flang_fc1 -emit-fir -triple x86_64-unknown-linux-gnu -target-feature +sse %s -o - | FileCheck %s --check-prefixes=ALL,FEATURE +! RUN: %flang_fc1 -emit-fir -triple x86_64-unknown-linux-gnu -target-cpu x86-64 -target-feature +sse %s -o - | FileCheck %s --check-prefixes=ALL,BOTH + +! ALL: module attributes { + +! NONE-NOT: fir.target_cpu +! NONE-NOT: fir.target_features + +! CPU-SAME: fir.target_cpu = "x86-64" +! CPU-NOT: fir.target_features + +! FEATURE-NOT: fir.target_cpu +! FEATURE-SAME: fir.target_features = #llvm.target_features<["+sse"]> + +! BOTH-SAME: fir.target_cpu = "x86-64" +! BOTH-SAME: fir.target_features = #llvm.target_features<["+sse"]> diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index b4ba837a3263f..98d9258e023e5 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -331,7 +331,6 @@ static mlir::LogicalResult convertFortranSourceToMLIR( auto &defKinds = semanticsContext.defaultKinds(); fir::KindMapping kindMap( &ctx, llvm::ArrayRef{fir::fromDefaultKinds(defKinds)}); - const llvm::DataLayout &dataLayout = targetMachine.createDataLayout(); std::string targetTriple = targetMachine.getTargetTriple().normalize(); // Use default lowering options for bbc. Fortran::lower::LoweringOptions loweringOptions{}; @@ -342,7 +341,7 @@ static mlir::LogicalResult convertFortranSourceToMLIR( ctx, semanticsContext, defKinds, semanticsContext.intrinsics(), semanticsContext.targetCharacteristics(), parsing.allCooked(), targetTriple, kindMap, loweringOptions, {}, - semanticsContext.languageFeatures(), &dataLayout); + semanticsContext.languageFeatures(), targetMachine); burnside.lower(parseTree, semanticsContext); mlir::ModuleOp mlirModule = burnside.getModule(); if (enableOpenMP) { diff --git a/flang/tools/tco/tco.cpp b/flang/tools/tco/tco.cpp index d5f5cd0002ede..2153e0e3e6249 100644 --- a/flang/tools/tco/tco.cpp +++ b/flang/tools/tco/tco.cpp @@ -55,6 +55,13 @@ static cl::opt targetTriple("target", cl::desc("specify a target triple"), cl::init("native")); +static cl::opt + targetCPU("target-cpu", cl::desc("specify a target CPU"), cl::init("")); + +static cl::opt + targetFeatures("target-features", cl::desc("specify the target features"), + cl::init("")); + static cl::opt codeGenLLVM( "code-gen-llvm", cl::desc("Run only CodeGen passes and translate FIR to LLVM IR"), @@ -104,6 +111,8 @@ compileFIR(const mlir::PassPipelineCLParser &passPipeline) { fir::KindMapping kindMap{&context}; fir::setTargetTriple(*owningRef, targetTriple); fir::setKindMapping(*owningRef, kindMap); + fir::setTargetCPU(*owningRef, targetCPU); + fir::setTargetFeatures(*owningRef, targetFeatures); // tco is a testing tool, so it will happily use the target independent // data layout if none is on the module. fir::support::setMLIRDataLayoutFromAttributes(*owningRef, diff --git a/flang/unittests/Optimizer/FIRContextTest.cpp b/flang/unittests/Optimizer/FIRContextTest.cpp index 88bb4363b2b45..49e1ebf23d8aa 100644 --- a/flang/unittests/Optimizer/FIRContextTest.cpp +++ b/flang/unittests/Optimizer/FIRContextTest.cpp @@ -8,6 +8,8 @@ #include "flang/Optimizer/Dialect/Support/FIRContext.h" #include "gtest/gtest.h" +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/BuiltinOps.h" #include "flang/Optimizer/Dialect/Support/KindMapping.h" @@ -19,6 +21,7 @@ using namespace fir; struct StringAttributesTests : public testing::Test { public: void SetUp() { + context.loadDialect(); kindMap = new KindMapping(&context, kindMapInit, "r42a10c14d28i40l41"); mod = mlir::ModuleOp::create(mlir::UnknownLoc::get(&context)); } @@ -30,12 +33,16 @@ struct StringAttributesTests : public testing::Test { std::string kindMapInit = "i10:80,l3:24,a1:8,r54:Double,r62:X86_FP80,r11:PPC_FP128"; std::string target = "powerpc64le-unknown-linux-gnu"; + std::string targetCPU = "gfx90a"; + std::string targetFeatures = "+gfx9-insts,+wavefrontsize64"; mlir::ModuleOp mod; }; TEST_F(StringAttributesTests, moduleStringAttrTest) { setTargetTriple(mod, target); setKindMapping(mod, *kindMap); + setTargetCPU(mod, targetCPU); + setTargetFeatures(mod, targetFeatures); auto triple = getTargetTriple(mod); EXPECT_EQ(triple.getArch(), llvm::Triple::ArchType::ppc64le); @@ -52,6 +59,15 @@ TEST_F(StringAttributesTests, moduleStringAttrTest) { EXPECT_TRUE(mapStr.find("r11:PPC_FP128") != std::string::npos); EXPECT_TRUE(mapStr.find("r54:Double") != std::string::npos); EXPECT_TRUE(mapStr.find("r62:X86_FP80") != std::string::npos); + + EXPECT_EQ(getTargetCPU(mod), targetCPU); + + auto features = getTargetFeatures(mod); + auto featuresList = features.getFeatures(); + EXPECT_EQ(features.getFeaturesString(), targetFeatures); + EXPECT_EQ(featuresList.size(), 2u); + EXPECT_EQ(featuresList[0].str(), "+gfx9-insts"); + EXPECT_EQ(featuresList[1].str(), "+wavefrontsize64"); } // main() from gtest_main