[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:
@@ -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)
|
||||
|
||||
@@ -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"{{.*}} }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
178
llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp
Normal file
178
llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp
Normal 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");
|
||||
49
llvm/utils/TableGen/Basic/TargetFeaturesEmitter.h
Normal file
49
llvm/utils/TableGen/Basic/TargetFeaturesEmitter.h
Normal 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
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user