Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions llvm/include/llvm/TargetParser/RISCVTargetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"

Expand Down Expand Up @@ -47,13 +48,32 @@ struct CPUInfo {
bool is64Bit() const { return DefaultMarch.starts_with("rv64"); }
};

/// Fatal errors encountered during parsing.
struct ParserError : public ErrorInfo<ParserError, StringError> {
using ErrorInfo<ParserError, StringError>::ErrorInfo;
explicit ParserError(const Twine &S)
: ErrorInfo(S, inconvertibleErrorCode()) {}
static char ID;
};

/// Warnings encountered during parsing.
struct ParserWarning : public ErrorInfo<ParserWarning, StringError> {
using ErrorInfo<ParserWarning, StringError>::ErrorInfo;
explicit ParserWarning(const Twine &S)
: ErrorInfo(S, inconvertibleErrorCode()) {}
static char ID;
};

// We use 64 bits as the known part in the scalable vector types.
static constexpr unsigned RVVBitsPerBlock = 64;
static constexpr unsigned RVVBytesPerBlock = RVVBitsPerBlock / 8;

LLVM_ABI void getFeaturesForCPU(StringRef CPU,
SmallVectorImpl<std::string> &EnabledFeatures,
bool NeedPlus = false);
LLVM_ABI void getAllTuneFeatures(SmallVectorImpl<StringRef> &TuneFeatures);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to hook this up to a clang option, eventually. Right now, clang --target=riscv32 -mtune=help just prints a list of known CPUs. This can be a follow-up.

We might also want something akin to clang's clang --target=riscv64 --print-enabled-extensions, which is focussed on architecture extensions rather than tuning parameters.

LLVM_ABI Error parseTuneFeatureString(
StringRef TFString, SmallVectorImpl<std::string> &TuneFeatures);
LLVM_ABI bool parseCPU(StringRef CPU, bool IsRV64);
LLVM_ABI bool parseTuneCPU(StringRef CPU, bool IsRV64);
LLVM_ABI StringRef getMArchFromMcpu(StringRef CPU);
Expand Down
48 changes: 26 additions & 22 deletions llvm/lib/Target/RISCV/RISCVFeatures.td
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,10 @@ def HasVendorXSMTVDot
// LLVM specific features and extensions
//===----------------------------------------------------------------------===//

class RISCVTuneFeature<string name, string field_name, string value,
string description, list<SubtargetFeature> implied = []>
: SubtargetFeature<name, field_name, value, description, implied>;

// Feature32Bit exists to mark CPUs that support RV32 to distinguish them from
// tuning CPU names.
def Feature32Bit
Expand Down Expand Up @@ -1788,46 +1792,46 @@ def FeatureUnalignedVectorMem
"loads and stores">;

def TuneNLogNVRGather
: SubtargetFeature<"log-vrgather", "RISCVVRGatherCostModel", "NLog2N",
: RISCVTuneFeature<"log-vrgather", "RISCVVRGatherCostModel", "NLog2N",
"Has vrgather.vv with LMUL*log2(LMUL) latency">;

def TunePostRAScheduler : SubtargetFeature<"use-postra-scheduler",
def TunePostRAScheduler : RISCVTuneFeature<"use-postra-scheduler",
"UsePostRAScheduler", "true", "Schedule again after register allocation">;

def TuneDisableMISchedLoadClustering : SubtargetFeature<"disable-misched-load-clustering",
def TuneDisableMISchedLoadClustering : RISCVTuneFeature<"disable-misched-load-clustering",
"EnableMISchedLoadClustering", "false", "Disable load clustering in the machine scheduler">;

def TuneDisableMISchedStoreClustering : SubtargetFeature<"disable-misched-store-clustering",
def TuneDisableMISchedStoreClustering : RISCVTuneFeature<"disable-misched-store-clustering",
"EnableMISchedStoreClustering", "false", "Disable store clustering in the machine scheduler">;

def TuneDisablePostMISchedLoadClustering : SubtargetFeature<"disable-postmisched-load-clustering",
def TuneDisablePostMISchedLoadClustering : RISCVTuneFeature<"disable-postmisched-load-clustering",
"EnablePostMISchedLoadClustering", "false", "Disable PostRA load clustering in the machine scheduler">;

def TuneDisablePostMISchedStoreClustering : SubtargetFeature<"disable-postmisched-store-clustering",
def TuneDisablePostMISchedStoreClustering : RISCVTuneFeature<"disable-postmisched-store-clustering",
"EnablePostMISchedStoreClustering", "false", "Disable PostRA store clustering in the machine scheduler">;

def TuneDisableLatencySchedHeuristic
: SubtargetFeature<"disable-latency-sched-heuristic", "DisableLatencySchedHeuristic", "true",
: RISCVTuneFeature<"disable-latency-sched-heuristic", "DisableLatencySchedHeuristic", "true",
"Disable latency scheduling heuristic">;

def TunePredictableSelectIsExpensive
: SubtargetFeature<"predictable-select-expensive", "PredictableSelectIsExpensive", "true",
: RISCVTuneFeature<"predictable-select-expensive", "PredictableSelectIsExpensive", "true",
"Prefer likely predicted branches over selects">;

def TuneOptimizedZeroStrideLoad
: SubtargetFeature<"optimized-zero-stride-load", "HasOptimizedZeroStrideLoad",
: RISCVTuneFeature<"optimized-zero-stride-load", "HasOptimizedZeroStrideLoad",
"true", "Optimized (perform fewer memory operations)"
"zero-stride vector load">;

foreach nf = {2-8} in
def TuneOptimizedNF#nf#SegmentLoadStore :
SubtargetFeature<"optimized-nf"#nf#"-segment-load-store",
RISCVTuneFeature<"optimized-nf"#nf#"-segment-load-store",
"HasOptimizedNF"#nf#"SegmentLoadStore",
"true", "vlseg"#nf#"eN.v and vsseg"#nf#"eN.v are "
"implemented as a wide memory op and shuffle">;

def TuneVLDependentLatency
: SubtargetFeature<"vl-dependent-latency", "HasVLDependentLatency", "true",
: RISCVTuneFeature<"vl-dependent-latency", "HasVLDependentLatency", "true",
"Latency of vector instructions is dependent on the "
"dynamic value of vl">;

Expand All @@ -1839,50 +1843,50 @@ def Experimental
// and instead split over multiple cycles. DLEN refers to the datapath width
// that can be done in parallel.
def TuneDLenFactor2
: SubtargetFeature<"dlen-factor-2", "DLenFactor2", "true",
: RISCVTuneFeature<"dlen-factor-2", "DLenFactor2", "true",
"Vector unit DLEN(data path width) is half of VLEN">;

def TuneNoDefaultUnroll
: SubtargetFeature<"no-default-unroll", "EnableDefaultUnroll", "false",
: RISCVTuneFeature<"no-default-unroll", "EnableDefaultUnroll", "false",
"Disable default unroll preference.">;

// SiFive 7 is able to fuse integer ALU operations with a preceding branch
// instruction.
def TuneShortForwardBranchOpt
: SubtargetFeature<"short-forward-branch-opt", "HasShortForwardBranchOpt",
: RISCVTuneFeature<"short-forward-branch-opt", "HasShortForwardBranchOpt",
"true", "Enable short forward branch optimization">;
def HasShortForwardBranchOpt : Predicate<"Subtarget->hasShortForwardBranchOpt()">;
def NoShortForwardBranchOpt : Predicate<"!Subtarget->hasShortForwardBranchOpt()">;

def TuneShortForwardBranchIMinMax
: SubtargetFeature<"short-forward-branch-i-minmax", "HasShortForwardBranchIMinMax",
: RISCVTuneFeature<"short-forward-branch-i-minmax", "HasShortForwardBranchIMinMax",
"true", "Enable short forward branch optimization for min,max instructions in Zbb",
[TuneShortForwardBranchOpt]>;

def TuneShortForwardBranchIMul
: SubtargetFeature<"short-forward-branch-i-mul", "HasShortForwardBranchIMul",
: RISCVTuneFeature<"short-forward-branch-i-mul", "HasShortForwardBranchIMul",
"true", "Enable short forward branch optimization for mul instruction",
[TuneShortForwardBranchOpt]>;

// Some subtargets require a S2V transfer buffer to move scalars into vectors.
// FIXME: Forming .vx/.vf/.wx/.wf can reduce register pressure.
def TuneNoSinkSplatOperands
: SubtargetFeature<"no-sink-splat-operands", "SinkSplatOperands",
: RISCVTuneFeature<"no-sink-splat-operands", "SinkSplatOperands",
"false", "Disable sink splat operands to enable .vx, .vf,"
".wx, and .wf instructions">;

def TunePreferWInst
: SubtargetFeature<"prefer-w-inst", "PreferWInst", "true",
: RISCVTuneFeature<"prefer-w-inst", "PreferWInst", "true",
"Prefer instructions with W suffix">;

def TuneConditionalCompressedMoveFusion
: SubtargetFeature<"conditional-cmv-fusion", "HasConditionalCompressedMoveFusion",
: RISCVTuneFeature<"conditional-cmv-fusion", "HasConditionalCompressedMoveFusion",
"true", "Enable branch+c.mv fusion">;
def HasConditionalMoveFusion : Predicate<"Subtarget->hasConditionalMoveFusion()">;
def NoConditionalMoveFusion : Predicate<"!Subtarget->hasConditionalMoveFusion()">;

def TuneHasSingleElementVecFP64
: SubtargetFeature<"single-element-vec-fp64", "HasSingleElementVectorFP64", "true",
: RISCVTuneFeature<"single-element-vec-fp64", "HasSingleElementVectorFP64", "true",
"Certain vector FP64 operations produce a single result "
"element per cycle">;

Expand All @@ -1899,11 +1903,11 @@ def TuneVentanaVeyron : SubtargetFeature<"ventana-veyron", "RISCVProcFamily", "V
def TuneAndes45 : SubtargetFeature<"andes45", "RISCVProcFamily", "Andes45",
"Andes 45-Series processors">;

def TuneVXRMPipelineFlush : SubtargetFeature<"vxrm-pipeline-flush", "HasVXRMPipelineFlush",
def TuneVXRMPipelineFlush : RISCVTuneFeature<"vxrm-pipeline-flush", "HasVXRMPipelineFlush",
"true", "VXRM writes causes pipeline flush">;

def TunePreferVsetvliOverReadVLENB
: SubtargetFeature<"prefer-vsetvli-over-read-vlenb",
: RISCVTuneFeature<"prefer-vsetvli-over-read-vlenb",
"PreferVsetvliOverReadVLENB",
"true",
"Prefer vsetvli over read vlenb CSR to calculate VLEN">;
Expand Down
99 changes: 99 additions & 0 deletions llvm/lib/TargetParser/RISCVTargetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,20 @@
//===----------------------------------------------------------------------===//

#include "llvm/TargetParser/RISCVTargetParser.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/TargetParser/RISCVISAInfo.h"

namespace llvm {
namespace RISCV {

char ParserError::ID = 0;
char ParserWarning::ID = 0;

enum CPUKind : unsigned {
#define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN, \
FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID) \
Expand Down Expand Up @@ -145,6 +152,98 @@ void getFeaturesForCPU(StringRef CPU,
EnabledFeatures.push_back(F.substr(1));
}

using RISCVImpliedTuneFeature = std::pair<const char *, const char *>;

#define GET_TUNE_FEATURES
#define GET_IMPLIED_TUNE_FEATURES
#include "llvm/TargetParser/RISCVTargetParserDef.inc"

void getAllTuneFeatures(SmallVectorImpl<StringRef> &Features) {
Features.assign(std::begin(TuneFeatures), std::end(TuneFeatures));
}

Error parseTuneFeatureString(StringRef TFString,
SmallVectorImpl<std::string> &ResFeatures) {
const StringSet<> AllTuneFeatureSet(llvm::from_range, TuneFeatures);
using SmallStringSet = SmallSet<StringRef, 4>;

TFString = TFString.trim();
// Note: StringSet is not really ergnomic to use in this case here.
SmallStringSet PositiveFeatures;
SmallStringSet NegativeFeatures;
// Phase 1: Collect explicit features.
StringRef FeatureStr;
do {
std::tie(FeatureStr, TFString) = TFString.split(",");
if (AllTuneFeatureSet.count(FeatureStr)) {
if (!PositiveFeatures.insert(FeatureStr).second)
return make_error<ParserError>(
"cannot specify more than one instance of '" + Twine(FeatureStr) +
"'");
} else if (FeatureStr.starts_with("no-")) {
// Check if this is a negative feature, like `no-foo` for `foo`.
StringRef ActualFeature = FeatureStr.drop_front(3);
if (AllTuneFeatureSet.count(ActualFeature)) {
if (!NegativeFeatures.insert(ActualFeature).second)
return make_error<ParserError>(
"cannot specify more than one instance of '" + Twine(FeatureStr) +
"'");
}
} else {
// Raise it as a warning for better compatibilities.
return make_error<ParserWarning>("unrecognized tune feature directive '" +
Twine(FeatureStr) + "'");
}
} while (!TFString.empty());

auto Intersection =
llvm::set_intersection(PositiveFeatures, NegativeFeatures);
if (!Intersection.empty()) {
std::string IntersectedStr = join(Intersection, "', '");
return make_error<ParserError>("Feature(s) '" + Twine(IntersectedStr) +
"' cannot appear in both "
"positive and negative directives");
}

// Phase 2: Derive implied features.
StringMap<SmallVector<StringRef, 2>> ImpliedFeatureMap;
StringMap<SmallVector<StringRef, 2>> InverseImpliedFeatureMap;
for (auto [Feature, ImpliedFeature] : ImpliedTuneFeatures) {
ImpliedFeatureMap[Feature].push_back(ImpliedFeature);
InverseImpliedFeatureMap[ImpliedFeature].push_back(Feature);
}

for (StringRef PF : PositiveFeatures) {
auto ItFeatures = ImpliedFeatureMap.find(PF);
if (ItFeatures != ImpliedFeatureMap.end())
PositiveFeatures.insert(ItFeatures->second.begin(),
ItFeatures->second.end());
}
for (StringRef NF : NegativeFeatures) {
auto ItFeatures = InverseImpliedFeatureMap.find(NF);
if (ItFeatures != InverseImpliedFeatureMap.end())
NegativeFeatures.insert(ItFeatures->second.begin(),
ItFeatures->second.end());
}

Intersection = llvm::set_intersection(PositiveFeatures, NegativeFeatures);
if (!Intersection.empty()) {
std::string IntersectedStr = join(Intersection, "', '");
return make_error<ParserError>("Feature(s) '" + Twine(IntersectedStr) +
"' were implied by both "
"positive and negative directives");
}

// Export the result.
const std::string PosPrefix("+");
const std::string NegPrefix("-");
for (StringRef PF : PositiveFeatures)
ResFeatures.emplace_back(PosPrefix + PF.str());
for (StringRef NF : NegativeFeatures)
ResFeatures.emplace_back(NegPrefix + NF.str());

return Error::success();
}
} // namespace RISCV

namespace RISCVVType {
Expand Down
Loading