[Reland] [PowerPC] frontend get target feature from backend with cpu name (#144594)

1. The PR proceeds with a backend target hook to allow front-ends to
determine what target features are available in a compilation based on
the CPU name.
2. Fix a backend target feature bug that supports HTM for
Power8/9/10/11. However, HTM is only supported on Power8/9 according to
the ISA.
3. All target features that are hardcoded in PPC.cpp can be retrieved
from the backend target feature. I have double-checked that the
hardcoded logic for inferring target features from the CPU in the
frontend(PPC.cpp) is the same as in PPC.td.

The reland patch addressed the comment
https://github.com/llvm/llvm-project/pull/137670#discussion_r2143541120
This commit is contained in:
zhijian lin
2025-06-19 09:22:16 -04:00
committed by GitHub
parent 5645d67109
commit bf79d4819e
16 changed files with 383 additions and 263 deletions

View File

@@ -15,6 +15,7 @@
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/TargetParser/PPCTargetParser.h"
#include <optional>
using namespace clang;
using namespace clang::targets;
@@ -516,129 +517,14 @@ static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags,
bool PPCTargetInfo::initFeatureMap(
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
const std::vector<std::string> &FeaturesVec) const {
Features["altivec"] = llvm::StringSwitch<bool>(CPU)
.Case("7400", true)
.Case("g4", true)
.Case("7450", true)
.Case("g4+", true)
.Case("970", true)
.Case("g5", true)
.Case("pwr6", true)
.Case("pwr7", true)
.Case("pwr8", true)
.Case("pwr9", true)
.Case("ppc64", true)
.Case("ppc64le", true)
.Default(false);
Features["power9-vector"] = (CPU == "pwr9");
Features["crypto"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Default(false);
Features["power8-vector"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Default(false);
Features["bpermd"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Case("pwr7", true)
.Default(false);
Features["extdiv"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Case("pwr7", true)
.Default(false);
Features["direct-move"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Default(false);
Features["crbits"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Default(false);
Features["vsx"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Case("pwr7", true)
.Default(false);
Features["htm"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Default(false);
const llvm::Triple &TheTriple = getTriple();
// ROP Protect is off by default.
Features["rop-protect"] = false;
// Privileged instructions are off by default.
Features["privileged"] = false;
if (getTriple().isOSAIX()) {
// The code generated by the -maix-small-local-[exec|dynamic]-tls option is
// turned off by default.
Features["aix-small-local-exec-tls"] = false;
Features["aix-small-local-dynamic-tls"] = false;
// Turn off TLS model opt by default.
Features["aix-shared-lib-tls-model-opt"] = false;
}
Features["spe"] = llvm::StringSwitch<bool>(CPU)
.Case("8548", true)
.Case("e500", true)
.Default(false);
Features["isa-v206-instructions"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Case("pwr7", true)
.Case("a2", true)
.Default(false);
Features["isa-v207-instructions"] = llvm::StringSwitch<bool>(CPU)
.Case("ppc64le", true)
.Case("pwr9", true)
.Case("pwr8", true)
.Default(false);
Features["isa-v30-instructions"] =
llvm::StringSwitch<bool>(CPU).Case("pwr9", true).Default(false);
Features["quadword-atomics"] =
getTriple().isArch64Bit() && llvm::StringSwitch<bool>(CPU)
.Case("pwr9", true)
.Case("pwr8", true)
.Default(false);
// Power10 includes all the same features as Power9 plus any features specific
// to the Power10 core.
if (CPU == "pwr10" || CPU == "power10") {
initFeatureMap(Features, Diags, "pwr9", FeaturesVec);
addP10SpecificFeatures(Features);
}
// Power11 includes all the same features as Power10 plus any features
// specific to the Power11 core.
if (CPU == "pwr11" || CPU == "power11") {
initFeatureMap(Features, Diags, "pwr10", FeaturesVec);
addP11SpecificFeatures(Features);
}
// Future CPU should include all of the features of Power 11 as well as any
// additional features (yet to be determined) specific to it.
if (CPU == "future") {
initFeatureMap(Features, Diags, "pwr11", FeaturesVec);
addFutureSpecificFeatures(Features);
}
std::optional<llvm::StringMap<bool>> FeaturesOpt =
llvm::PPC::getPPCDefaultTargetFeatures(TheTriple,
llvm::PPC::normalizeCPUName(CPU));
if (FeaturesOpt)
Features = FeaturesOpt.value();
if (!ppcUserFeaturesCheck(Diags, FeaturesVec))
return false;
@@ -700,26 +586,6 @@ bool PPCTargetInfo::initFeatureMap(
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
}
// Add any Power10 specific features.
void PPCTargetInfo::addP10SpecificFeatures(
llvm::StringMap<bool> &Features) const {
Features["htm"] = false; // HTM was removed for P10.
Features["paired-vector-memops"] = true;
Features["mma"] = true;
Features["power10-vector"] = true;
Features["pcrelative-memops"] = true;
Features["prefix-instrs"] = true;
Features["isa-v31-instructions"] = true;
}
// Add any Power11 specific features.
void PPCTargetInfo::addP11SpecificFeatures(
llvm::StringMap<bool> &Features) const {}
// Add features specific to the "Future" CPU.
void PPCTargetInfo::addFutureSpecificFeatures(
llvm::StringMap<bool> &Features) const {}
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Case("powerpc", true)

View File

@@ -35,5 +35,5 @@ int &g() { return r; }
// DARWIN-LABEL: define internal cxx_fast_tlscc void @__tls_init()
// CHECK: call void @[[R_INIT]]()
// LINUX_AIX: attributes [[ATTR0]] = { {{.*}}"target-features"{{.*}} }
// LINUX_AIX: attributes [[ATTR0]] = { {{.*}} }
// DARWIN: attributes [[ATTR1]] = { {{.*}}nounwind{{.*}}"target-features"{{.*}} }

View File

@@ -1,5 +1,5 @@
// RUN: %clang -target powerpc64-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK-AIX,CHECK-AIX-OFF %s
// RUN: %clang -target powerpc-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK-AIX,CHECK-AIX-OFF %s
// RUN: %clang -target powerpc64-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-AIX %s
// RUN: %clang -target powerpc-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-AIX %s
// RUN: %clang -target powerpc64le-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-LINUX %s
// RUN: %clang -target powerpc64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-LINUX %s
@@ -19,9 +19,8 @@ int test(void) {
// CHECK-AIX: test() #0 {
// CHECK-AIX: attributes #0 = {
// CHECK-AIX-OFF-SAME: -aix-shared-lib-tls-model-opt
// CHECK-AIX-ON-SAME: +aix-shared-lib-tls-model-opt
// CHECK-LINUX-NOT: {{[-+]aix-shared-lib-tls-model-opt}}
// CHECK-LINUX-NOT: {{[+]aix-shared-lib-tls-model-opt}}
// CHECK-UNSUPPORTED-TARGET: option '-maix-shared-lib-tls-model-opt' cannot be specified on this target

View File

@@ -1,37 +1,37 @@
// RUN: %clang -target powerpc64-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-AIX-DEFAULT %s
// RUN: %clang -target powerpc-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-AIX-DEFAULT %s
// RUN: %clang -target powerpc64le-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-LINUX %s
// RUN: %clang -target powerpc64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-LINUX %s
// RUN: %clang --target=powerpc64-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-DEFAULT %s
// RUN: %clang --target=powerpc-unknown-aix -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-DEFAULT %s
// RUN: %clang --target=powerpc64le-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-DEFAULT %s
// RUN: %clang --target=powerpc64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-DEFAULT %s
// RUN: %clang -target powerpc64-unknown-aix -maix-small-local-exec-tls -S -emit-llvm \
// RUN: %clang --target=powerpc64-unknown-aix -maix-small-local-exec-tls -S -emit-llvm \
// RUN: %s -o - | FileCheck %s --check-prefix=CHECK-AIX_SMALL_LOCALEXEC_TLS
// RUN: %clang -target powerpc64-unknown-aix -maix-small-local-dynamic-tls -S -emit-llvm \
// RUN: %clang --target=powerpc64-unknown-aix -maix-small-local-dynamic-tls -S -emit-llvm \
// RUN: %s -o - | FileCheck %s --check-prefix=CHECK-AIX_SMALL_LOCALDYNAMIC_TLS
// RUN: not %clang -target powerpc-unknown-aix -maix-small-local-exec-tls \
// RUN: not %clang --target=powerpc-unknown-aix -maix-small-local-exec-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-AIX32 %s
// RUN: not %clang -target powerpc64le-unknown-linux-gnu -maix-small-local-exec-tls \
// RUN: not %clang --target=powerpc64le-unknown-linux-gnu -maix-small-local-exec-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s
// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-exec-tls \
// RUN: not %clang --target=powerpc64-unknown-linux-gnu -maix-small-local-exec-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s
// RUN: not %clang -target powerpc64-unknown-aix -maix-small-local-exec-tls \
// RUN: not %clang --target=powerpc64-unknown-aix -maix-small-local-exec-tls \
// RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s
// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-exec-tls \
// RUN: not %clang --target=powerpc64-unknown-linux-gnu -maix-small-local-exec-tls \
// RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s
// RUN: not %clang -target powerpc-unknown-aix -maix-small-local-dynamic-tls \
// RUN: not %clang --target=powerpc-unknown-aix -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-AIX32 %s
// RUN: not %clang -target powerpc64le-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: not %clang --target=powerpc64le-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s
// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: not %clang --target=powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-UNSUPPORTED-LINUX %s
// RUN: not %clang -target powerpc64-unknown-aix -maix-small-local-dynamic-tls \
// RUN: not %clang --target=powerpc64-unknown-aix -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s
// RUN: not %clang -target powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: not %clang --target=powerpc64-unknown-linux-gnu -maix-small-local-dynamic-tls \
// RUN: -fsyntax-only -fno-data-sections %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED-NO-DATASEC %s
@@ -39,10 +39,9 @@ int test(void) {
return 0;
}
// CHECK-AIX-DEFAULT: test() #0 {
// CHECK-AIX-DEFAULT: attributes #0 = {
// CHECK-AIX-DEFAULT-SAME: {{-aix-small-local-exec-tls,.*-aix-small-local-dynamic-tls|-aix-small-local-dynamic-tls,.*-aix-small-local-exec-tls}}
// CHECK-LINUX-NOT: {{[-+]aix-small-local-exec-tls,.*[-+]aix-small-local-dynamic-tls|[-+]aix-small-local-dynamic-tls,.*[-+]aix-small-local-exec-tls}}
// CHECK-DEFAULT: test() #0 {
// CHECK-DEFAULT: attributes #0 = {
// CHECK-DEFAULT-NOT: {{[-+]aix-small-local-exec-tls,.*[-+]aix-small-local-dynamic-tls|[-+]aix-small-local-dynamic-tls,.*[-+]aix-small-local-exec-tls}}
// CHECK-UNSUPPORTED-AIX32: option '-maix-small-local-[exec|dynamic]-tls' cannot be specified on this target
// CHECK-UNSUPPORTED-LINUX: option '-maix-small-local-[exec|dynamic]-tls' cannot be specified on this target

View File

@@ -64,8 +64,6 @@
// RUN: %clang -target powerpc64le-unknown-linux-gnu -mcpu=pwr8 -mno-crbits \
// RUN: -emit-llvm -S %s -o - | FileCheck %s --check-prefix=HAS-NOCRBITS
// RUN: %clang -target powerpc64le-unknown-linux-gnu -mcpu=pwr7 -emit-llvm \
// RUN: -S %s -o - | FileCheck %s --check-prefix=HAS-NOCRBITS
// RUN: %clang -target powerpc64le-unknown-linux-gnu -mcpu=pwr7 -mcrbits \
// RUN: -emit-llvm -S %s -o - | FileCheck %s --check-prefix=HAS-CRBITS
// RUN: %clang -target powerpc64le-unknown-linux-gnu -mcpu=pwr7 -mno-crbits \
@@ -92,8 +90,6 @@
// RUN: %clang -target powerpc-ibm-aix -mcpu=pwr8 -mno-crbits \
// RUN: -emit-llvm -S %s -o - | FileCheck %s --check-prefix=HAS-NOCRBITS
// RUN: %clang -target powerpc-ibm-aix -mcpu=pwr7 -emit-llvm \
// RUN: -S %s -o - | FileCheck %s --check-prefix=HAS-NOCRBITS
// RUN: %clang -target powerpc-ibm-aix -mcpu=pwr7 -mcrbits \
// RUN: -emit-llvm -S %s -o - | FileCheck %s --check-prefix=HAS-CRBITS
// RUN: %clang -target powerpc-ibm-aix -mcpu=pwr7 -mno-crbits \

View File

@@ -5,20 +5,20 @@
// RUN: %clang -target powerpc64-unknown-aix -mcpu=pwr9 -S -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-PWR9
// RUN: %clang -target powerpc-unknown-aix -mcpu=pwr10 -S -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-PWR10
// CHECK-PWR6: -isa-v206-instructions
// CHECK-PWR6: -isa-v207-instructions
// CHECK-PWR6: -isa-v30-instructions
// CHECK-PWR6-NOT: isa-v206-instructions
// CHECK-PWR6-NOT: isa-v207-instructions
// CHECK-PWR6-NOT: isa-v30-instructions
// CHECK-A2: +isa-v206-instructions
// CHECK-A2: -isa-v207-instructions
// CHECK-A2: -isa-v30-instructions
// CHECK-A2: +isa-v206-instructions
// CHECK-A2-NOT: isa-v207-instructions
// CHECK-A2-NOT: isa-v30-instructions
// CHECK-PWR7: +isa-v206-instructions
// CHECK-PWR7: -isa-v207-instructions
// CHECK-PWR7: -isa-v30-instructions
// CHECK-PWR7: +isa-v206-instructions
// CHECK-PWR7-NOT: isa-v207-instructions
// CHECK-PWR7-NOT: isa-v30-instructions
// CHECK-PWR8: +isa-v207-instructions
// CHECK-PWR8: -isa-v30-instructions
// CHECK-PWR8: +isa-v207-instructions
// CHECK-PWR8-NOT: isa-v30-instructions
// CHECK-PWR9: +isa-v207-instructions
// CHECK-PWR9: +isa-v30-instructions

View File

@@ -7,5 +7,8 @@ tablegen(LLVM AArch64TargetParserDef.inc -gen-arm-target-def -I ${PROJECT_SOURCE
set(LLVM_TARGET_DEFINITIONS ${PROJECT_SOURCE_DIR}/lib/Target/RISCV/RISCV.td)
tablegen(LLVM RISCVTargetParserDef.inc -gen-riscv-target-def -I ${PROJECT_SOURCE_DIR}/lib/Target/RISCV/)
set(LLVM_TARGET_DEFINITIONS ${PROJECT_SOURCE_DIR}/lib/Target/PowerPC/PPC.td)
tablegen(LLVM PPCGenTargetFeatures.inc -gen-target-features -I${PROJECT_SOURCE_DIR}/lib/Target/PowerPC)
# This covers all of the tablegen calls above.
add_public_tablegen_target(target_parser_gen)

View File

@@ -14,6 +14,8 @@
#ifndef LLVM_TARGETPARSER_PPCTARGETPARSER_H
#define LLVM_TARGETPARSER_PPCTARGETPARSER_H
#include "TargetParser.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/TargetParser/Triple.h"
@@ -37,6 +39,10 @@ LLVM_ABI StringRef getNormalizedPPCTuneCPU(const Triple &T,
// For PPC, there are some cpu names for same CPU, like pwr10 and power10,
// normalize them.
LLVM_ABI StringRef normalizeCPUName(StringRef CPUName);
LLVM_ABI std::optional<llvm::StringMap<bool>>
getPPCDefaultTargetFeatures(const Triple &T, StringRef CPUName);
} // namespace PPC
} // namespace llvm

View File

@@ -14,6 +14,8 @@
#ifndef LLVM_TARGETPARSER_TARGETPARSER_H
#define LLVM_TARGETPARSER_TARGETPARSER_H
#include "SubtargetFeature.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
@@ -190,6 +192,31 @@ insertWaveSizeFeature(StringRef GPU, const Triple &T,
StringMap<bool> &Features);
} // namespace AMDGPU
struct BasicSubtargetFeatureKV {
const char *Key; ///< K-V key string
unsigned Value; ///< K-V integer value
FeatureBitArray Implies; ///< K-V bit mask
};
/// Used to provide key value pairs for feature and CPU bit flags.
struct BasicSubtargetSubTypeKV {
const char *Key; ///< K-V key string
FeatureBitArray Implies; ///< K-V bit mask
/// Compare routine for std::lower_bound
bool operator<(StringRef S) const { return StringRef(Key) < S; }
/// Compare routine for std::is_sorted.
bool operator<(const BasicSubtargetSubTypeKV &Other) const {
return StringRef(Key) < StringRef(Other.Key);
}
};
std::optional<llvm::StringMap<bool>>
getCPUDefaultTargetFeatures(StringRef CPU,
ArrayRef<BasicSubtargetSubTypeKV> ProcDesc,
ArrayRef<BasicSubtargetFeatureKV> ProcFeatures);
} // namespace llvm
#endif

View File

@@ -411,7 +411,6 @@ def ProcessorFeatures {
FeatureP8Altivec,
FeatureP8Vector,
FeatureP8Crypto,
FeatureHTM,
FeatureDirectMove,
FeatureICBT,
FeaturePartwordAtomic,
@@ -422,6 +421,7 @@ def ProcessorFeatures {
];
list<SubtargetFeature> P8SpecificFeatures = [FeatureAddiLoadFusion,
FeatureHTM,
FeatureAddisLoadFusion];
list<SubtargetFeature> P8InheritableFeatures =
!listconcat(P7InheritableFeatures, P8AdditionalFeatures);
@@ -443,7 +443,7 @@ def ProcessorFeatures {
// dispatch for vector operations than scalar ones. For the time being,
// this list also includes scheduling-related features since we do not have
// enough info to create custom scheduling strategies for future CPUs.
list<SubtargetFeature> P9SpecificFeatures = [FeatureVectorsUseTwoUnits];
list<SubtargetFeature> P9SpecificFeatures = [FeatureVectorsUseTwoUnits, FeatureHTM];
list<SubtargetFeature> P9InheritableFeatures =
!listconcat(P8InheritableFeatures, P9AdditionalFeatures);
list<SubtargetFeature> P9Features =

View File

@@ -15,6 +15,10 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/TargetParser/Host.h"
#define GET_SUBTARGETFEATURES_ENUM
#define GET_SUBTARGETFEATURES_KV
#include "llvm/TargetParser/PPCGenTargetFeatures.inc"
namespace llvm {
namespace PPC {
@@ -117,5 +121,26 @@ StringRef getNormalizedPPCTuneCPU(const Triple &T, StringRef CPUName) {
return getNormalizedPPCTargetCPU(T, CPUName);
}
std::optional<StringMap<bool>> getPPCDefaultTargetFeatures(const Triple &T,
StringRef CPU) {
std::optional<StringMap<bool>> FeaturesOpt =
getCPUDefaultTargetFeatures(CPU, BasicPPCSubTypeKV, BasicPPCFeatureKV);
if (!FeaturesOpt.has_value())
return std::nullopt;
StringMap<bool> Features = FeaturesOpt.value();
// FIXME: We need to check for the processor model 8548, since the backend
// does not support this processor. When this processor model is implemented
// within the backend, the following code can be removed.
if (CPU == "8548")
Features["spe"] = true;
// The target feature `quadword-atomics` is only supported for 64-bit
// POWER8 and above.
if (Features.find("quadword-atomics") != Features.end() && !T.isArch64Bit())
Features["quadword-atomics"] = false;
return Features;
}
} // namespace PPC
} // namespace llvm

View File

@@ -18,6 +18,53 @@
using namespace llvm;
using namespace AMDGPU;
/// Find KV in array using binary search.
static const BasicSubtargetSubTypeKV *
find(StringRef S, ArrayRef<BasicSubtargetSubTypeKV> A) {
// Binary search the array
auto F = llvm::lower_bound(A, S);
// If not found then return NULL
if (F == A.end() || StringRef(F->Key) != S)
return nullptr;
// Return the found array item
return F;
}
/// For each feature that is (transitively) implied by this feature, set it.
static void setImpliedBits(FeatureBitset &Bits, const FeatureBitset &Implies,
ArrayRef<BasicSubtargetFeatureKV> FeatureTable) {
// OR the Implies bits in outside the loop. This allows the Implies for CPUs
// which might imply features not in FeatureTable to use this.
Bits |= Implies;
for (const auto &FE : FeatureTable)
if (Implies.test(FE.Value))
setImpliedBits(Bits, FE.Implies.getAsBitset(), FeatureTable);
}
std::optional<llvm::StringMap<bool>> llvm::getCPUDefaultTargetFeatures(
StringRef CPU, ArrayRef<BasicSubtargetSubTypeKV> ProcDesc,
ArrayRef<BasicSubtargetFeatureKV> ProcFeatures) {
if (CPU.empty())
return std::nullopt;
const BasicSubtargetSubTypeKV *CPUEntry = ::find(CPU, ProcDesc);
if (!CPUEntry)
return std::nullopt;
// Set the features implied by this CPU feature if there is a match.
FeatureBitset Bits;
llvm::StringMap<bool> DefaultFeatures;
setImpliedBits(Bits, CPUEntry->Implies.getAsBitset(), ProcFeatures);
unsigned BitSize = Bits.size();
for (const BasicSubtargetFeatureKV &FE : ProcFeatures) {
assert(FE.Value < BitSize && "Target Feature is out of range");
if (Bits[FE.Value])
DefaultFeatures[FE.Key] = true;
}
return DefaultFeatures;
}
namespace {
struct GPUInfo {

View File

@@ -17,6 +17,7 @@ add_llvm_library(LLVMTableGenBasic OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_LINK_LLV
RISCVTargetDefEmitter.cpp
SDNodeProperties.cpp
TableGen.cpp
TargetFeaturesEmitter.cpp
VTEmitter.cpp
)

View File

@@ -0,0 +1,178 @@
//===- TargetFeaturesEmitter.cpp - Generate CPU Target feature ----===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend exports cpu target features
// and cpu sub-type.
//
//===----------------------------------------------------------------------===//
#include "TargetFeaturesEmitter.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/TargetParser/SubtargetFeature.h"
using namespace llvm;
using FeatureMapTy = DenseMap<const Record *, unsigned>;
using ConstRecVec = std::vector<const Record *>;
TargetFeaturesEmitter::TargetFeaturesEmitter(const RecordKeeper &R)
: Records(R) {
ArrayRef<const Record *> Targets = Records.getAllDerivedDefinitions("Target");
if (Targets.size() == 0)
PrintFatalError("No 'Target' subclasses defined!");
if (Targets.size() != 1)
PrintFatalError("Multiple subclasses of Target defined!");
Target = Targets[0]->getName();
}
FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) {
ArrayRef<const Record *> DefList =
Records.getAllDerivedDefinitions("SubtargetFeature");
unsigned N = DefList.size();
if (N == 0)
return FeatureMapTy();
if (N + 1 > MAX_SUBTARGET_FEATURES)
PrintFatalError(
"Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
OS << "namespace " << Target << " {\n";
OS << "enum {\n";
FeatureMapTy FeatureMap;
for (unsigned I = 0; I < N; ++I) {
const Record *Def = DefList[I];
// Print the Feature Name.
OS << " " << Def->getName() << " = " << I << ",\n";
FeatureMap[Def] = I;
}
OS << " " << "NumSubtargetFeatures = " << N << "\n";
// Close enumeration and namespace
OS << "};\n";
OS << "} // end namespace " << Target << "\n";
return FeatureMap;
}
void TargetFeaturesEmitter::printFeatureMask(
raw_ostream &OS, ArrayRef<const Record *> FeatureList,
const FeatureMapTy &FeatureMap) {
std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {};
for (const Record *Feature : FeatureList) {
unsigned Bit = FeatureMap.lookup(Feature);
Mask[Bit / 64] |= 1ULL << (Bit % 64);
}
OS << "{ { { ";
for (unsigned I = 0; I != Mask.size(); ++I) {
OS << "0x";
OS.write_hex(Mask[I]);
OS << "ULL, ";
}
OS << "} } }";
}
void TargetFeaturesEmitter::printFeatureKeyValues(
raw_ostream &OS, const FeatureMapTy &FeatureMap) {
std::vector<const Record *> FeatureList =
Records.getAllDerivedDefinitions("SubtargetFeature");
// Remove features with empty name.
llvm::erase_if(FeatureList, [](const Record *Rec) {
return Rec->getValueAsString("Name").empty();
});
if (FeatureList.empty())
return;
llvm::sort(FeatureList, LessRecordFieldName());
// Begin feature table.
OS << "// Sorted (by key) array of values for CPU features.\n"
<< "extern const llvm::BasicSubtargetFeatureKV " << "Basic" << Target
<< "FeatureKV[] = {\n";
for (const Record *Feature : FeatureList) {
StringRef Name = Feature->getName();
StringRef ValueName = Feature->getValueAsString("Name");
OS << " { " << "\"" << ValueName << "\", " << Target << "::" << Name
<< ", ";
ConstRecVec ImpliesList = Feature->getValueAsListOfDefs("Implies");
printFeatureMask(OS, ImpliesList, FeatureMap);
OS << " },\n";
}
// End feature table.
OS << "};\n";
return;
}
void TargetFeaturesEmitter::printCPUKeyValues(raw_ostream &OS,
const FeatureMapTy &FeatureMap) {
// Gather and sort processor information
std::vector<const Record *> ProcessorList =
Records.getAllDerivedDefinitions("Processor");
llvm::sort(ProcessorList, LessRecordFieldName());
// Begin processor table.
OS << "// Sorted (by key) array of values for CPU subtype.\n"
<< "extern const llvm::BasicSubtargetSubTypeKV " << "Basic" << Target
<< "SubTypeKV[] = {\n";
for (const Record *Processor : ProcessorList) {
StringRef Name = Processor->getValueAsString("Name");
ConstRecVec FeatureList = Processor->getValueAsListOfDefs("Features");
OS << " { " << "\"" << Name << "\", ";
printFeatureMask(OS, FeatureList, FeatureMap);
OS << " },\n";
}
// End processor table.
OS << "};\n";
return;
}
void TargetFeaturesEmitter::run(raw_ostream &OS) {
OS << "// Autogenerated by TargetFeatureEmitter.cpp\n\n";
OS << "\n#ifdef GET_SUBTARGETFEATURES_ENUM\n";
OS << "#undef GET_SUBTARGETFEATURES_ENUM\n\n";
OS << "namespace llvm {\n";
auto FeatureMap = enumeration(OS);
OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_SUBTARGETFEATURES_ENUM\n\n";
OS << "\n#ifdef GET_SUBTARGETFEATURES_KV\n";
OS << "#undef GET_SUBTARGETFEATURES_KV\n\n";
OS << "namespace llvm {\n";
printFeatureKeyValues(OS, FeatureMap);
OS << "\n";
printCPUKeyValues(OS, FeatureMap);
OS << "\n";
OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_SUBTARGETFEATURES_KV\n\n";
}
static TableGen::Emitter::OptClass<TargetFeaturesEmitter>
X("gen-target-features", "Generate subtarget enumerations");

View File

@@ -0,0 +1,49 @@
//===- TargetFeaturesEmitter.h- Generate CPU Target features ----===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Defines the TargetFeaturesEmitter class, which is used to export
// CPU target features and CPU subtypes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_UTILS_TABLEGEN_BASIC_EMITTARGETFEATURE_H
#define LLVM_UTILS_TABLEGEN_BASIC_EMITTARGETFEATURE_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/TableGen/Record.h"
namespace llvm {
/// Sorting predicate to sort record pointers by their
/// FieldName field.
struct LessRecordFieldFieldName {
bool operator()(const Record *Rec1, const Record *Rec2) const {
return Rec1->getValueAsString("FieldName") <
Rec2->getValueAsString("FieldName");
}
};
using FeatureMapTy = DenseMap<const Record *, unsigned>;
class TargetFeaturesEmitter {
protected:
const RecordKeeper &Records;
std::string Target;
public:
TargetFeaturesEmitter(const RecordKeeper &R);
static void printFeatureMask(raw_ostream &OS,
ArrayRef<const Record *> FeatureList,
const FeatureMapTy &FeatureMap);
FeatureMapTy enumeration(raw_ostream &OS);
void printFeatureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
void printCPUKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
virtual void run(raw_ostream &O);
virtual ~TargetFeaturesEmitter() {};
};
} // namespace llvm
#endif

View File

@@ -10,12 +10,12 @@
//
//===----------------------------------------------------------------------===//
#include "Basic/TargetFeaturesEmitter.h"
#include "Common/CodeGenHwModes.h"
#include "Common/CodeGenSchedule.h"
#include "Common/CodeGenTarget.h"
#include "Common/PredicateExpander.h"
#include "Common/Utils.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
@@ -27,9 +27,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/TargetParser/SubtargetFeature.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
@@ -43,18 +41,7 @@ using namespace llvm;
namespace {
using FeatureMapTy = DenseMap<const Record *, unsigned>;
/// Sorting predicate to sort record pointers by their
/// FieldName field.
struct LessRecordFieldFieldName {
bool operator()(const Record *Rec1, const Record *Rec2) const {
return Rec1->getValueAsString("FieldName") <
Rec2->getValueAsString("FieldName");
}
};
class SubtargetEmitter {
class SubtargetEmitter : TargetFeaturesEmitter {
// Each processor has a SchedClassDesc table with an entry for each
// SchedClass. The SchedClassDesc table indexes into a global write resource
// table, write latency table, and read advance table.
@@ -83,11 +70,8 @@ class SubtargetEmitter {
};
CodeGenTarget TGT;
const RecordKeeper &Records;
CodeGenSchedModels &SchedModels;
std::string Target;
FeatureMapTy enumeration(raw_ostream &OS);
void emitSubtargetInfoMacroCalls(raw_ostream &OS);
unsigned featureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
unsigned cpuKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
@@ -143,73 +127,13 @@ class SubtargetEmitter {
public:
SubtargetEmitter(const RecordKeeper &R)
: TGT(R), Records(R), SchedModels(TGT.getSchedModels()),
Target(TGT.getName()) {}
: TargetFeaturesEmitter(R), TGT(R), SchedModels(TGT.getSchedModels()) {}
void run(raw_ostream &O);
void run(raw_ostream &O) override;
};
} // end anonymous namespace
//
// Enumeration - Emit the specified class as an enumeration.
//
FeatureMapTy SubtargetEmitter::enumeration(raw_ostream &OS) {
ArrayRef<const Record *> DefList =
Records.getAllDerivedDefinitions("SubtargetFeature");
unsigned N = DefList.size();
if (N == 0)
return FeatureMapTy();
if (N + 1 > MAX_SUBTARGET_FEATURES)
PrintFatalError(
"Too many subtarget features! Bump MAX_SUBTARGET_FEATURES.");
OS << "namespace " << Target << " {\n";
// Open enumeration.
OS << "enum {\n";
FeatureMapTy FeatureMap;
// For each record
for (unsigned I = 0; I < N; ++I) {
// Next record
const Record *Def = DefList[I];
// Get and emit name
OS << " " << Def->getName() << " = " << I << ",\n";
// Save the index for this feature.
FeatureMap[Def] = I;
}
OS << " "
<< "NumSubtargetFeatures = " << N << "\n";
// Close enumeration and namespace
OS << "};\n";
OS << "} // end namespace " << Target << "\n";
return FeatureMap;
}
static void printFeatureMask(raw_ostream &OS,
ArrayRef<const Record *> FeatureList,
const FeatureMapTy &FeatureMap) {
std::array<uint64_t, MAX_SUBTARGET_WORDS> Mask = {};
for (const Record *Feature : FeatureList) {
unsigned Bit = FeatureMap.lookup(Feature);
Mask[Bit / 64] |= 1ULL << (Bit % 64);
}
OS << "{ { { ";
for (unsigned I = 0; I != Mask.size(); ++I) {
OS << "0x";
OS.write_hex(Mask[I]);
OS << "ULL, ";
}
OS << "} } }";
}
/// Emit some information about the SubtargetFeature as calls to a macro so
/// that they can be used from C++.
void SubtargetEmitter::emitSubtargetInfoMacroCalls(raw_ostream &OS) {