[llvm-branch-commits] [llvm] b61a41c - Merge branch 'main' into revert-205399-revert-149886-slashy
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Jun 27 08:58:21 PDT 2026
Author: Vitaly Buka
Date: 2026-06-27T08:58:06-07:00
New Revision: b61a41c554a9051703308f22e5f1ca19cb6275d4
URL: https://github.com/llvm/llvm-project/commit/b61a41c554a9051703308f22e5f1ca19cb6275d4
DIFF: https://github.com/llvm/llvm-project/commit/b61a41c554a9051703308f22e5f1ca19cb6275d4.diff
LOG: Merge branch 'main' into revert-205399-revert-149886-slashy
Added:
llvm/test/CodeGen/X86/vector-reduce-add-subvector.ll
Modified:
llvm/include/llvm/Support/GlobPattern.h
llvm/lib/Support/GlobPattern.cpp
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
llvm/lib/Target/RISCV/RISCVSubtarget.cpp
llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/and-fcmp.ll
llvm/test/Transforms/InstCombine/or-fcmp.ll
llvm/unittests/Support/GlobPatternTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h
index bb4084603f547..8c84c93834c6b 100644
--- a/llvm/include/llvm/Support/GlobPattern.h
+++ b/llvm/include/llvm/Support/GlobPattern.h
@@ -56,7 +56,8 @@ class GlobPattern {
/// created from expanding braces otherwise disable
/// brace expansion
LLVM_ABI static Expected<GlobPattern>
- create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {});
+ create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {},
+ bool SlashAgnostic = false);
/// \returns \p true if \p S matches this glob pattern
LLVM_ABI bool match(StringRef S) const;
@@ -87,12 +88,14 @@ class GlobPattern {
StringRef Pattern;
size_t PrefixSize = 0;
size_t SuffixSize = 0;
+ bool SlashAgnostic = false;
struct SubGlobPattern {
/// \param Pat the pattern to match against
- LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat);
+ LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat,
+ bool SlashAgnostic);
/// \returns \p true if \p S matches this glob pattern
- LLVM_ABI bool match(StringRef S) const;
+ LLVM_ABI bool match(StringRef S, bool SlashAgnostic) const;
StringRef getPat() const { return StringRef(Pat.data(), Pat.size()); }
// Brackets with their end position and matched bytes.
diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp
index 1aaddbb8408a3..ebaa08cba96aa 100644
--- a/llvm/lib/Support/GlobPattern.cpp
+++ b/llvm/lib/Support/GlobPattern.cpp
@@ -18,6 +18,8 @@ using namespace llvm;
static constexpr char PrefixMetacharacters[] = "?*[{\\";
static constexpr char SuffixMetacharacters[] = "?*[]{}\\";
+static constexpr char PrefixMetacharactersWithSlash[] = "?*[{\\/";
+static constexpr char SuffixMetacharactersWithSlash[] = "?*[]{}\\/";
// Expands character ranges and returns a bitmap.
// For example, "a-cf-hz" is expanded to "abcfghz".
@@ -135,10 +137,12 @@ parseBraceExpansions(StringRef S, std::optional<size_t> MaxSubPatterns) {
return std::move(SubPatterns);
}
-static StringRef maxPlainSubstring(StringRef S) {
+static StringRef maxPlainSubstring(StringRef S, bool SlashAgnostic) {
+ const char *Metas =
+ SlashAgnostic ? PrefixMetacharactersWithSlash : PrefixMetacharacters;
StringRef Best;
while (!S.empty()) {
- size_t PrefixSize = S.find_first_of(PrefixMetacharacters);
+ size_t PrefixSize = S.find_first_of(Metas);
if (PrefixSize == std::string::npos)
PrefixSize = S.size();
@@ -178,13 +182,20 @@ static StringRef maxPlainSubstring(StringRef S) {
return Best;
}
-Expected<GlobPattern>
-GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) {
+Expected<GlobPattern> GlobPattern::create(StringRef S,
+ std::optional<size_t> MaxSubPatterns,
+ bool SlashAgnostic) {
GlobPattern Pat;
+ Pat.SlashAgnostic = SlashAgnostic;
Pat.Pattern = S;
+ const char *PrefixMetas =
+ SlashAgnostic ? PrefixMetacharactersWithSlash : PrefixMetacharacters;
+ const char *SuffixMetas =
+ SlashAgnostic ? SuffixMetacharactersWithSlash : SuffixMetacharacters;
+
// Store the prefix that does not contain any metacharacter.
- Pat.PrefixSize = S.find_first_of(PrefixMetacharacters);
+ Pat.PrefixSize = S.find_first_of(PrefixMetas);
if (Pat.PrefixSize == std::string::npos) {
Pat.PrefixSize = S.size();
return Pat;
@@ -192,7 +203,7 @@ GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) {
S = S.substr(Pat.PrefixSize);
// Just in case we stop on unmatched opening brackets.
- size_t SuffixStart = S.find_last_of(SuffixMetacharacters);
+ size_t SuffixStart = S.find_last_of(SuffixMetas);
assert(SuffixStart != std::string::npos);
if (S[SuffixStart] == '\\')
++SuffixStart;
@@ -205,7 +216,7 @@ GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) {
if (auto Err = parseBraceExpansions(S, MaxSubPatterns).moveInto(SubPats))
return std::move(Err);
for (StringRef SubPat : SubPats) {
- auto SubGlobOrErr = SubGlobPattern::create(SubPat);
+ auto SubGlobOrErr = SubGlobPattern::create(SubPat, SlashAgnostic);
if (!SubGlobOrErr)
return SubGlobOrErr.takeError();
Pat.SubGlobs.push_back(*SubGlobOrErr);
@@ -215,7 +226,7 @@ GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) {
}
Expected<GlobPattern::SubGlobPattern>
-GlobPattern::SubGlobPattern::create(StringRef S) {
+GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) {
SubGlobPattern Pat;
// Parse brackets.
@@ -237,6 +248,10 @@ GlobPattern::SubGlobPattern::create(StringRef S) {
if (!BVOrErr)
return BVOrErr.takeError();
BitVector &BV = *BVOrErr;
+ if (SlashAgnostic && (BV['\\'] || BV['/'])) {
+ BV.set('\\');
+ BV.set('/');
+ }
if (Invert)
BV.flip();
Pat.Brackets.push_back(Bracket{J + 1, std::move(BV)});
@@ -251,8 +266,8 @@ GlobPattern::SubGlobPattern::create(StringRef S) {
}
StringRef GlobPattern::longest_substr() const {
- return maxPlainSubstring(
- Pattern.drop_front(PrefixSize).drop_back(SuffixSize));
+ return maxPlainSubstring(Pattern.drop_front(PrefixSize).drop_back(SuffixSize),
+ SlashAgnostic);
}
bool GlobPattern::match(StringRef S) const {
@@ -263,15 +278,23 @@ bool GlobPattern::match(StringRef S) const {
if (SubGlobs.empty() && S.empty())
return true;
for (auto &Glob : SubGlobs)
- if (Glob.match(S))
+ if (Glob.match(S, SlashAgnostic))
return true;
return false;
}
+static bool matchChar(char PatC, char QueryC, bool SlashAgnostic) {
+ if (PatC == QueryC)
+ return true;
+ return SlashAgnostic && (PatC == '\\' || PatC == '/') &&
+ (QueryC == '\\' || QueryC == '/');
+}
+
// Factor the pattern into segments split by '*'. The segment is matched
// sequentianlly by finding the first occurrence past the end of the previous
// match.
-bool GlobPattern::SubGlobPattern::match(StringRef Str) const {
+bool GlobPattern::SubGlobPattern::match(StringRef Str,
+ bool SlashAgnostic) const {
const char *P = Pat.data(), *SegmentBegin = nullptr, *S = Str.data(),
*SavedS = S;
const char *const PEnd = P + Pat.size(), *const End = S + Str.size();
@@ -293,12 +316,12 @@ bool GlobPattern::SubGlobPattern::match(StringRef Str) const {
continue;
}
} else if (*P == '\\') {
- if (*++P == *S) {
+ if (matchChar(*++P, *S, SlashAgnostic)) {
++P;
++S;
continue;
}
- } else if (*P == *S || *P == '?') {
+ } else if (matchChar(*P, *S, SlashAgnostic) || *P == '?') {
++P;
++S;
continue;
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 41e83210ed356..e68f783b9ffdc 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -54,10 +54,6 @@ STATISTIC(RISCVNumInstrsCompressed,
static cl::opt<bool> AddBuildAttributes("riscv-add-build-attributes",
cl::init(false));
-namespace llvm {
-extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
-} // namespace llvm
-
namespace {
struct RISCVOperand;
@@ -333,8 +329,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
// Use computeTargetABI to check if ABIName is valid. If invalid, output
// error message.
- RISCVABI::computeTargetABI(STI.getTargetTriple(), STI.getFeatureBits(),
- ABIName);
+ RISCVABI::computeTargetABI(STI, ABIName);
const MCObjectFileInfo *MOFI = Parser.getContext().getObjectFileInfo();
ParserOptions.IsPicEnabled = MOFI->isPositionIndependent();
@@ -2083,18 +2078,19 @@ ParseStatus RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) {
// Accept a named Sys Reg if the required features are present.
const auto &FeatureBits = getSTI().getFeatureBits();
+ const auto &AllFeatures = getSTI().getAllProcessorFeatures();
if (!SysReg->haveRequiredFeatures(FeatureBits)) {
const auto *Feature =
- llvm::find_if(RISCVFeatureKV, [&](const auto &Feature) {
+ llvm::find_if(AllFeatures, [&](const auto &Feature) {
return SysReg->FeaturesRequired[Feature.Value];
});
auto ErrorMsg = std::string("system register '") + SysReg->Name + "' ";
if (SysReg->IsRV32Only && FeatureBits[RISCV::Feature64Bit]) {
ErrorMsg += "is RV32 only";
- if (Feature != std::end(RISCVFeatureKV))
+ if (Feature != std::end(AllFeatures))
ErrorMsg += " and ";
}
- if (Feature != std::end(RISCVFeatureKV)) {
+ if (Feature != std::end(AllFeatures)) {
ErrorMsg +=
"requires '" + std::string(Feature->key()) + "' to be enabled";
}
@@ -3131,7 +3127,8 @@ ParseStatus RISCVAsmParser::parseDirective(AsmToken DirectiveID) {
bool RISCVAsmParser::resetToArch(StringRef Arch, SMLoc Loc, std::string &Result,
bool FromOptionDirective) {
- for (auto &Feature : RISCVFeatureKV)
+ const auto &AllFeatures = getSTI().getAllProcessorFeatures();
+ for (auto &Feature : AllFeatures)
if (llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature.key()))
clearFeatureBits(Feature.Value, Feature.key());
@@ -3150,7 +3147,7 @@ bool RISCVAsmParser::resetToArch(StringRef Arch, SMLoc Loc, std::string &Result,
}
auto &ISAInfo = *ParseResult;
- for (auto &Feature : RISCVFeatureKV)
+ for (auto &Feature : AllFeatures)
if (ISAInfo->hasExtension(Feature.key()))
setFeatureBits(Feature.Value, Feature.key());
@@ -3246,8 +3243,9 @@ bool RISCVAsmParser::parseDirectiveOption() {
if (!enableExperimentalExtension() &&
StringRef(Feature).starts_with("experimental-"))
return Error(Loc, "unexpected experimental extensions");
- auto Ext = llvm::lower_bound(RISCVFeatureKV, Feature);
- if (Ext == std::end(RISCVFeatureKV) || StringRef(Ext->key()) != Feature)
+ const auto &AllFeatures = getSTI().getAllProcessorFeatures();
+ auto Ext = llvm::lower_bound(AllFeatures, Feature);
+ if (Ext == std::end(AllFeatures) || StringRef(Ext->key()) != Feature)
return Error(Loc, "unknown extension feature");
Args.emplace_back(Type, Arch.str());
@@ -3256,7 +3254,7 @@ bool RISCVAsmParser::parseDirectiveOption() {
FeatureBitset OldFeatureBits = STI->getFeatureBits();
setFeatureBits(Ext->Value, Ext->key());
- auto ParseResult = RISCVFeatures::parseFeatureBits(isRV64(), STI->getFeatureBits());
+ auto ParseResult = RISCVFeatures::parseFeatureBits(*STI);
if (!ParseResult) {
copySTI().setFeatureBits(OldFeatureBits);
setAvailableFeatures(ComputeAvailableFeatures(OldFeatureBits));
@@ -3274,7 +3272,7 @@ bool RISCVAsmParser::parseDirectiveOption() {
// It is invalid to disable an extension that there are other enabled
// extensions depend on it.
// TODO: Make use of RISCVISAInfo to handle this
- for (auto &Feature : RISCVFeatureKV) {
+ for (auto &Feature : AllFeatures) {
if (getSTI().hasFeature(Feature.Value) &&
Feature.Implies.test(Ext->Value))
return Error(Loc, Twine("can't disable ") + Ext->key() +
@@ -3292,8 +3290,7 @@ bool RISCVAsmParser::parseDirectiveOption() {
getTargetStreamer().emitDirectiveOptionArch(Args);
- if (auto ParseResult =
- RISCVFeatures::parseFeatureBits(isRV64(), STI->getFeatureBits()))
+ if (auto ParseResult = RISCVFeatures::parseFeatureBits(*STI))
getTargetStreamer().setArchString((*ParseResult)->toString());
return false;
}
@@ -3324,8 +3321,7 @@ bool RISCVAsmParser::parseDirectiveOption() {
getTargetStreamer().emitDirectiveOptionRVC();
setFeatureBits(RISCV::FeatureStdExtC, "c");
- if (auto ParseResult =
- RISCVFeatures::parseFeatureBits(isRV64(), STI->getFeatureBits()))
+ if (auto ParseResult = RISCVFeatures::parseFeatureBits(*STI))
getTargetStreamer().setArchString((*ParseResult)->toString());
return false;
}
@@ -3337,8 +3333,7 @@ bool RISCVAsmParser::parseDirectiveOption() {
getTargetStreamer().emitDirectiveOptionNoRVC();
clearFeatureBits(RISCV::FeatureStdExtC, "c");
clearFeatureBits(RISCV::FeatureStdExtZca, "zca");
- if (auto ParseResult =
- RISCVFeatures::parseFeatureBits(isRV64(), STI->getFeatureBits()))
+ if (auto ParseResult = RISCVFeatures::parseFeatureBits(*STI))
getTargetStreamer().setArchString((*ParseResult)->toString());
return false;
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
index 526ee0f1efd27..7753a0d118eef 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
@@ -23,8 +23,6 @@
namespace llvm {
-extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
-
namespace RISCVSysReg {
#define GET_SysRegsList_IMPL
#include "RISCVGenSearchableTables.inc"
@@ -55,8 +53,9 @@ namespace RISCV {
} // namespace RISCV
namespace RISCVABI {
-ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits,
- StringRef ABIName) {
+ABI computeTargetABI(const MCSubtargetInfo &STI, StringRef ABIName) {
+ const Triple &TT = STI.getTargetTriple();
+ const FeatureBitset &FeatureBits = STI.getFeatureBits();
auto TargetABI = getTargetABI(ABIName);
bool IsRV64 = TT.isArch64Bit();
bool IsRVE = FeatureBits[RISCV::FeatureStdExtE];
@@ -102,7 +101,7 @@ ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits,
return TargetABI;
// If no explicit ABI is given, try to compute the default ABI.
- auto ISAInfo = RISCVFeatures::parseFeatureBits(IsRV64, FeatureBits);
+ auto ISAInfo = RISCVFeatures::parseFeatureBits(STI);
if (!ISAInfo)
reportFatalUsageError(ISAInfo.takeError());
return getTargetABI((*ISAInfo)->computeDefaultABI());
@@ -153,11 +152,12 @@ void validate(const Triple &TT, const FeatureBitset &FeatureBits) {
}
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
-parseFeatureBits(bool IsRV64, const FeatureBitset &FeatureBits) {
- unsigned XLen = IsRV64 ? 64 : 32;
+parseFeatureBits(const MCSubtargetInfo &STI) {
+ const FeatureBitset &FeatureBits = STI.getFeatureBits();
+ unsigned XLen = FeatureBits[RISCV::Feature64Bit] ? 64 : 32;
std::vector<std::string> FeatureVector;
// Convert FeatureBitset to FeatureVector.
- for (const auto &Feature : RISCVFeatureKV) {
+ for (const auto &Feature : STI.getAllProcessorFeatures()) {
if (FeatureBits[Feature.Value] &&
llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature.key()))
FeatureVector.push_back(std::string("+") + Feature.key());
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index 1b76f4c1c5311..2e50e4223f4a4 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -25,6 +25,8 @@
namespace llvm {
+class MCSubtargetInfo;
+
namespace RISCVOp {
enum OperandType : unsigned {
OPERAND_FIRST_RISCV_IMM = MCOI::OPERAND_FIRST_TARGET,
@@ -687,9 +689,8 @@ enum ABI {
};
// Returns the target ABI, or else a StringError if the requested ABIName is
-// not supported for the given TT and FeatureBits combination.
-ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits,
- StringRef ABIName);
+// not supported for the subtargets triple and FeatureBits combination.
+ABI computeTargetABI(const MCSubtargetInfo &STI, StringRef ABIName);
ABI getTargetABI(StringRef ABIName);
@@ -708,7 +709,7 @@ namespace RISCVFeatures {
void validate(const Triple &TT, const FeatureBitset &FeatureBits);
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
-parseFeatureBits(bool IsRV64, const FeatureBitset &FeatureBits);
+parseFeatureBits(const MCSubtargetInfo &STI);
} // namespace RISCVFeatures
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
index 22991be4eb091..032a6a014436a 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
@@ -29,10 +29,9 @@ RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S,
const MCSubtargetInfo &STI)
: RISCVTargetStreamer(S), CurrentVendor("riscv") {
MCAssembler &MCA = getStreamer().getAssembler();
- const FeatureBitset &Features = STI.getFeatureBits();
auto &MAB = static_cast<RISCVAsmBackend &>(MCA.getBackend());
- setTargetABI(RISCVABI::computeTargetABI(STI.getTargetTriple(), Features,
- MAB.getTargetOptions().getABIName()));
+ setTargetABI(
+ RISCVABI::computeTargetABI(STI, MAB.getTargetOptions().getABIName()));
setFlagsFromFeatures(STI);
// Compute the initial ISA string. This serves two purposes:
@@ -41,8 +40,7 @@ RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S,
// 2. Initial symbol: seed the streamer's active ISA so a "$x<ArchString>"
// mapping symbol is emitted before the first instruction, recording
// the full ISA in the object even when no .option directive is present.
- if (auto ParseResult = RISCVFeatures::parseFeatureBits(
- STI.hasFeature(RISCV::Feature64Bit), Features)) {
+ if (auto ParseResult = RISCVFeatures::parseFeatureBits(STI)) {
InitialArchString = (*ParseResult)->toString();
ArchString = InitialArchString;
getStreamer().setMappingSymbolArch(ArchString);
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
index 3c4e58d0a0f9c..049152848c085 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
@@ -84,8 +84,7 @@ void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI,
emitAttribute(RISCVAttrs::STACK_ALIGN, StackAlign);
}
- auto ParseResult = RISCVFeatures::parseFeatureBits(
- STI.hasFeature(RISCV::Feature64Bit), STI.getFeatureBits());
+ auto ParseResult = RISCVFeatures::parseFeatureBits(STI);
if (!ParseResult) {
report_fatal_error(ParseResult.takeError());
} else {
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index 8ad3297a44fbb..dbda25c34cee0 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -51,10 +51,6 @@ using namespace llvm;
STATISTIC(RISCVNumInstrsCompressed,
"Number of RISC-V Compressed instructions emitted");
-namespace llvm {
-extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
-} // namespace llvm
-
namespace {
class RISCVAsmPrinter : public AsmPrinter {
public:
@@ -531,7 +527,7 @@ bool RISCVAsmPrinter::emitDirectiveOptionArch() {
RISCVTargetStreamer &RTS = getTargetStreamer();
SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs;
const MCSubtargetInfo &MCSTI = TM.getMCSubtargetInfo();
- for (const auto &Feature : RISCVFeatureKV) {
+ for (const auto &Feature : MCSTI.getAllProcessorFeatures()) {
if (STI->hasFeature(Feature.Value) == MCSTI.hasFeature(Feature.Value))
continue;
@@ -642,7 +638,7 @@ void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
/*ExperimentalExtensionVersionCheck=*/true);
if (!errorToBool(ParseResult.takeError())) {
auto &ISAInfo = *ParseResult;
- for (const auto &Feature : RISCVFeatureKV) {
+ for (const auto &Feature : SubtargetInfo.getAllProcessorFeatures()) {
if (ISAInfo->hasExtension(Feature.key()) &&
!SubtargetInfo.hasFeature(Feature.Value))
SubtargetInfo.ToggleFeature(Feature.key());
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index 9f68c8d354d6b..08562457bb966 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -103,7 +103,7 @@ RISCVSubtarget::initializeSubtargetDependencies(const Triple &TT, StringRef CPU,
HasStdExtC = hasFeature(RISCV::FeatureStdExtC);
HasStdExtZce = hasFeature(RISCV::FeatureStdExtZce);
- TargetABI = RISCVABI::computeTargetABI(TT, getFeatureBits(), ABIName);
+ TargetABI = RISCVABI::computeTargetABI(*this, ABIName);
RISCVFeatures::validate(TT, getFeatureBits());
return *this;
}
diff --git a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
index b3a89f5e16258..59b00ea5e8018 100644
--- a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
+++ b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
@@ -86,40 +86,12 @@ static cl::opt<unsigned>
/// %cttz_wide = call iN @llvm.cttz.iN(iN %val, i1 false)
/// %result = trunc iN %cttz_wide to i(N/2)
/// Alive proof (for i64/i32): https://alive2.llvm.org/ce/z/-s14-s
-static bool foldSelectSplitCTTZ(Instruction &I) {
- Value *Cond, *TrueVal, *FalseVal;
- if (!match(&I, m_Select(m_Value(Cond), m_Value(TrueVal), m_Value(FalseVal))))
- return false;
-
- Type *HalfTy = I.getType();
- if (!HalfTy->isIntegerTy())
- return false;
+// TrueVal/FalseVal are pre-normalized by the caller to the EQ/NE cases.
+static bool foldSelectSplitCTTZ(Instruction &I, Value *LoTrunc, Value *HiResult,
+ Value *LoResult, Type *HalfTy) {
unsigned HalfWidth = HalfTy->getIntegerBitWidth();
-
- // Bail out on very small types (i1, i2): the full-width cttz can return
- // values not representable in the half type (e.g., cttz.i4 can return 4,
- // which doesn't fit in i2).
- if (HalfWidth <= 2)
- return false;
-
unsigned FullWidth = HalfWidth * 2;
- // select (icmp eq (trunc SrcVal to i(N/2)), 0), HiResult, LoResult
- // Or select (icmp ne ...), LoResult, HiResult
- Value *LoTrunc;
- Value *HiResult, *LoResult;
- if (match(Cond,
- m_SpecificICmp(CmpInst::ICMP_EQ, m_Value(LoTrunc), m_ZeroInt()))) {
- HiResult = TrueVal;
- LoResult = FalseVal;
- } else if (match(Cond, m_SpecificICmp(CmpInst::ICMP_NE, m_Value(LoTrunc),
- m_ZeroInt()))) {
- HiResult = FalseVal;
- LoResult = TrueVal;
- } else {
- return false;
- }
-
// LoTrunc: trunc iN SrcVal to i(N/2)
Value *SrcVal;
if (!match(LoTrunc, m_Trunc(m_Value(SrcVal))))
@@ -171,51 +143,20 @@ static bool foldSelectSplitCTTZ(Instruction &I) {
/// %result = trunc iN %ctlz_wide to i(N/2)
///
/// Alive proof (for i64/i32): https://alive2.llvm.org/ce/z/WfQepH
-static bool foldSelectSplitCTLZ(Instruction &I) {
- Value *Cond, *TrueVal, *FalseVal;
- if (!match(&I, m_Select(m_Value(Cond), m_Value(TrueVal), m_Value(FalseVal))))
- return false;
-
- Type *HalfTy = I.getType();
- if (!HalfTy->isIntegerTy())
- return false;
+// TrueVal/FalseVal are pre-normalized by the caller to the EQ/NE cases.
+static bool foldSelectSplitCTLZ(Instruction &I, Value *HiPart, Value *LoResult,
+ Value *HiResult, Type *HalfTy) {
unsigned HalfWidth = HalfTy->getIntegerBitWidth();
-
- // Bail out on very small types (i1, i2): the full-width ctlz can return
- // values not representable in the half type (e.g., ctlz.i4 can return 4,
- // which doesn't fit in i2).
- if (HalfWidth <= 2)
- return false;
-
unsigned FullWidth = HalfWidth * 2;
- // select (icmp eq HiPart, 0), LoResult, HiResult
- // HiPart could be (trunc (lshr SrcVal, N/2) to i(N/2)) or (lshr SrcVal, N/2)
- Value *HiPart;
- Value *LoResult, *HiResult;
- if (match(Cond,
- m_SpecificICmp(CmpInst::ICMP_EQ, m_Value(HiPart), m_ZeroInt()))) {
- LoResult = TrueVal; // upper is zero: count in lower + N/2
- HiResult = FalseVal; // upper non-zero: count in upper
- } else if (match(Cond, m_SpecificICmp(CmpInst::ICMP_NE, m_Value(HiPart),
- m_ZeroInt()))) {
- LoResult = FalseVal;
- HiResult = TrueVal;
- } else {
- return false;
- }
-
// Extract SrcVal from HiPart: either trunc(lshr(SrcVal, N/2)) or
// lshr(SrcVal, N/2)
Value *SrcVal;
- if (match(HiPart,
- m_Trunc(m_LShr(m_Value(SrcVal), m_SpecificInt(HalfWidth))))) {
- // HiPart is trunc(lshr(SrcVal, N/2))
- } else if (match(HiPart, m_LShr(m_Value(SrcVal), m_SpecificInt(HalfWidth)))) {
- // HiPart is lshr(SrcVal, N/2)
- } else {
+ if (match(HiPart, m_Trunc(m_Value(SrcVal))))
+ HiPart = SrcVal;
+
+ if (!match(HiPart, m_LShr(m_Value(SrcVal), m_SpecificInt(HalfWidth))))
return false;
- }
if (!SrcVal->getType()->isIntegerTy(FullWidth))
return false;
@@ -252,6 +193,38 @@ static bool foldSelectSplitCTLZ(Instruction &I) {
return true;
}
+/// Common entry point for folding select-based split cttz/ctlz patterns.
+/// Performs the initial select and type matching shared by both transforms,
+/// then delegates to foldSelectSplitCTTZ and foldSelectSplitCTLZ.
+static bool foldSelectSplitCTLZCTTZ(Instruction &I) {
+ Value *Cond, *TrueVal, *FalseVal;
+ if (!match(&I, m_Select(m_Value(Cond), m_Value(TrueVal), m_Value(FalseVal))))
+ return false;
+
+ Type *Ty = I.getType();
+ if (!Ty->isIntegerTy())
+ return false;
+
+ // Bail out on very small types (i1, i2): the full-width cttz/ctlz can return
+ // values not representable in the half type (e.g., cttz.i4 can return 4,
+ // which doesn't fit in i2).
+ if (Ty->getIntegerBitWidth() <= 2)
+ return false;
+
+ CmpPredicate Pred;
+ Value *CmpOp;
+ if (!match(Cond, m_ICmp(Pred, m_Value(CmpOp), m_ZeroInt())) ||
+ !ICmpInst::isEquality(Pred))
+ return false;
+
+ // Canonicalize select operands.
+ if (Pred == CmpInst::ICMP_NE)
+ std::swap(TrueVal, FalseVal);
+
+ return foldSelectSplitCTTZ(I, CmpOp, TrueVal, FalseVal, Ty) ||
+ foldSelectSplitCTLZ(I, CmpOp, TrueVal, FalseVal, Ty);
+}
+
/// Match a pattern for a bitwise funnel/rotate operation that partially guards
/// against undefined behavior by branching around the funnel-shift/rotation
/// when the shift amount is 0.
@@ -2449,8 +2422,7 @@ static bool foldUnusualPatterns(Function &F, DominatorTree &DT,
for (Instruction &I : make_early_inc_range(llvm::reverse(BB))) {
MadeChange |= foldAnyOrAllBitsSet(I);
MadeChange |= foldGuardedFunnelShift(I, DT);
- MadeChange |= foldSelectSplitCTTZ(I);
- MadeChange |= foldSelectSplitCTLZ(I);
+ MadeChange |= foldSelectSplitCTLZCTTZ(I);
MadeChange |= tryToRecognizePopCount(I);
MadeChange |= tryToRecognizePopCount1(I);
MadeChange |= tryToRecognizePopCount2n3(I);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 50496065b8dfa..b6f4a55c07e8a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1472,11 +1472,8 @@ Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS,
FMFSource::intersect(LHS, RHS));
}
- // This transform is not valid for a logical select.
- if (!IsLogicalSelect &&
- ((PredL == FCmpInst::FCMP_ORD && PredR == FCmpInst::FCMP_ORD && IsAnd) ||
- (PredL == FCmpInst::FCMP_UNO && PredR == FCmpInst::FCMP_UNO &&
- !IsAnd))) {
+ if ((PredL == FCmpInst::FCMP_ORD && PredR == FCmpInst::FCMP_ORD && IsAnd) ||
+ (PredL == FCmpInst::FCMP_UNO && PredR == FCmpInst::FCMP_UNO && !IsAnd)) {
if (LHS0->getType() != RHS0->getType())
return nullptr;
@@ -1486,8 +1483,14 @@ Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS,
// Ignore the constants because they are obviously not NANs:
// (fcmp ord x, 0.0) & (fcmp ord y, 0.0) -> (fcmp ord x, y)
// (fcmp uno x, 0.0) | (fcmp uno y, 0.0) -> (fcmp uno x, y)
- return Builder.CreateFCmpFMF(PredL, LHS0, RHS0,
- FMFSource::intersect(LHS, RHS));
+ Value *Y = RHS0;
+ FastMathFlags FMF = LHS->getFastMathFlags() & RHS->getFastMathFlags();
+ if (IsLogicalSelect) {
+ Y = Builder.CreateFreeze(Y, Y->getName() + ".fr");
+ FMF.setNoNaNs(false);
+ FMF.setNoInfs(false);
+ }
+ return Builder.CreateFCmpFMF(PredL, LHS0, Y, FMF);
}
}
diff --git a/llvm/test/CodeGen/X86/vector-reduce-add-subvector.ll b/llvm/test/CodeGen/X86/vector-reduce-add-subvector.ll
new file mode 100644
index 0000000000000..f62b2a5cad2ed
--- /dev/null
+++ b/llvm/test/CodeGen/X86/vector-reduce-add-subvector.ll
@@ -0,0 +1,1129 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=i686-- -mattr=+sse2 | FileCheck %s --check-prefixes=SSE,X86-SSE,SSE2,X86-SSE2
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+sse2 | FileCheck %s --check-prefixes=SSE,X64-SSE,SSE2,X64-SSE2
+; RUN: llc < %s -mtriple=i686-- -mattr=+sse4.1 | FileCheck %s --check-prefixes=SSE,X86-SSE,SSE4,X86-SSE4
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+sse4.1 | FileCheck %s --check-prefixes=SSE,X64-SSE,SSE4,X64-SSE4
+; RUN: llc < %s -mtriple=i686-- -mattr=+sse4.2 | FileCheck %s --check-prefixes=SSE,X86-SSE,SSE4,X86-SSE4
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+sse4.2 | FileCheck %s --check-prefixes=SSE,X64-SSE,SSE4,X64-SSE4
+; RUN: llc < %s -mtriple=i686-- -mattr=+avx | FileCheck %s --check-prefixes=AVX,X86-AVX,AVX1,AVX1-SLOW,X86-AVX1,X86-AVX1-SLOW
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx | FileCheck %s --check-prefixes=AVX,X64-AVX,AVX1,AVX1-SLOW,X64-AVX1,X64-AVX1-SLOW
+; RUN: llc < %s -mtriple=i686-- -mattr=+avx,+fast-hops | FileCheck %s --check-prefixes=AVX,X86-AVX,AVX1,AVX1-FAST,X86-AVX1,X86-AVX1-FAST
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx,+fast-hops | FileCheck %s --check-prefixes=AVX,X64-AVX,AVX1,AVX1-FAST,X64-AVX1,X64-AVX1-FAST
+; RUN: llc < %s -mtriple=i686-- -mattr=+avx2 | FileCheck %s --check-prefixes=AVX,X86-AVX,AVX2,X86-AVX2
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx2 | FileCheck %s --check-prefixes=AVX,X64-AVX,AVX2,X64-AVX2
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512f,+avx512bw | FileCheck %s --check-prefixes=AVX,X64-AVX,AVX512
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512f,+avx512bw,+avx512vl | FileCheck %s --check-prefixes=AVX,X64-AVX,AVX512
+
+;
+; vXi64
+;
+
+define i64 @test_v2i64_v1i64(<2 x i64> %a0) nounwind {
+; X86-SSE2-LABEL: test_v2i64_v1i64:
+; X86-SSE2: # %bb.0:
+; X86-SSE2-NEXT: movd %xmm0, %eax
+; X86-SSE2-NEXT: pshufd {{.*#+}} xmm0 = xmm0[1,1,1,1]
+; X86-SSE2-NEXT: movd %xmm0, %edx
+; X86-SSE2-NEXT: retl
+;
+; X64-SSE-LABEL: test_v2i64_v1i64:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: movq %xmm0, %rax
+; X64-SSE-NEXT: retq
+;
+; X86-SSE4-LABEL: test_v2i64_v1i64:
+; X86-SSE4: # %bb.0:
+; X86-SSE4-NEXT: movd %xmm0, %eax
+; X86-SSE4-NEXT: pextrd $1, %xmm0, %edx
+; X86-SSE4-NEXT: retl
+;
+; X86-AVX-LABEL: test_v2i64_v1i64:
+; X86-AVX: # %bb.0:
+; X86-AVX-NEXT: vmovd %xmm0, %eax
+; X86-AVX-NEXT: vpextrd $1, %xmm0, %edx
+; X86-AVX-NEXT: retl
+;
+; X64-AVX-LABEL: test_v2i64_v1i64:
+; X64-AVX: # %bb.0:
+; X64-AVX-NEXT: vmovq %xmm0, %rax
+; X64-AVX-NEXT: retq
+ %v = shufflevector <2 x i64> %a0, <2 x i64> poison, <1 x i32> <i32 0>
+ %r = call i64 @llvm.vector.reduce.add.v1i64(<1 x i64> %v)
+ ret i64 %r
+}
+
+define i64 @test_v4i64_v2i64(<4 x i64> %a0) nounwind {
+; X86-SSE2-LABEL: test_v4i64_v2i64:
+; X86-SSE2: # %bb.0:
+; X86-SSE2-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-SSE2-NEXT: paddq %xmm0, %xmm1
+; X86-SSE2-NEXT: movd %xmm1, %eax
+; X86-SSE2-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; X86-SSE2-NEXT: movd %xmm0, %edx
+; X86-SSE2-NEXT: retl
+;
+; X64-SSE-LABEL: test_v4i64_v2i64:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-SSE-NEXT: paddq %xmm0, %xmm1
+; X64-SSE-NEXT: movq %xmm1, %rax
+; X64-SSE-NEXT: retq
+;
+; X86-SSE4-LABEL: test_v4i64_v2i64:
+; X86-SSE4: # %bb.0:
+; X86-SSE4-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-SSE4-NEXT: paddq %xmm0, %xmm1
+; X86-SSE4-NEXT: movd %xmm1, %eax
+; X86-SSE4-NEXT: pextrd $1, %xmm1, %edx
+; X86-SSE4-NEXT: retl
+;
+; X86-AVX-LABEL: test_v4i64_v2i64:
+; X86-AVX: # %bb.0:
+; X86-AVX-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-AVX-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X86-AVX-NEXT: vmovd %xmm0, %eax
+; X86-AVX-NEXT: vpextrd $1, %xmm0, %edx
+; X86-AVX-NEXT: vzeroupper
+; X86-AVX-NEXT: retl
+;
+; X64-AVX-LABEL: test_v4i64_v2i64:
+; X64-AVX: # %bb.0:
+; X64-AVX-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-AVX-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X64-AVX-NEXT: vmovq %xmm0, %rax
+; X64-AVX-NEXT: vzeroupper
+; X64-AVX-NEXT: retq
+ %v = shufflevector <4 x i64> %a0, <4 x i64> poison, <2 x i32> <i32 0, i32 1>
+ %r = call i64 @llvm.vector.reduce.add.v2i64(<2 x i64> %v)
+ ret i64 %r
+}
+
+define i64 @test_v8i64_v4i64(<8 x i64> %a0) nounwind {
+; X86-SSE2-LABEL: test_v8i64_v4i64:
+; X86-SSE2: # %bb.0:
+; X86-SSE2-NEXT: pushl %ebp
+; X86-SSE2-NEXT: movl %esp, %ebp
+; X86-SSE2-NEXT: andl $-16, %esp
+; X86-SSE2-NEXT: subl $16, %esp
+; X86-SSE2-NEXT: paddq %xmm1, %xmm0
+; X86-SSE2-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-SSE2-NEXT: paddq %xmm0, %xmm1
+; X86-SSE2-NEXT: movd %xmm1, %eax
+; X86-SSE2-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; X86-SSE2-NEXT: movd %xmm0, %edx
+; X86-SSE2-NEXT: movl %ebp, %esp
+; X86-SSE2-NEXT: popl %ebp
+; X86-SSE2-NEXT: retl
+;
+; X64-SSE-LABEL: test_v8i64_v4i64:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: paddq %xmm1, %xmm0
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-SSE-NEXT: paddq %xmm0, %xmm1
+; X64-SSE-NEXT: movq %xmm1, %rax
+; X64-SSE-NEXT: retq
+;
+; X86-SSE4-LABEL: test_v8i64_v4i64:
+; X86-SSE4: # %bb.0:
+; X86-SSE4-NEXT: pushl %ebp
+; X86-SSE4-NEXT: movl %esp, %ebp
+; X86-SSE4-NEXT: andl $-16, %esp
+; X86-SSE4-NEXT: subl $16, %esp
+; X86-SSE4-NEXT: paddq %xmm1, %xmm0
+; X86-SSE4-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-SSE4-NEXT: paddq %xmm0, %xmm1
+; X86-SSE4-NEXT: movd %xmm1, %eax
+; X86-SSE4-NEXT: pextrd $1, %xmm1, %edx
+; X86-SSE4-NEXT: movl %ebp, %esp
+; X86-SSE4-NEXT: popl %ebp
+; X86-SSE4-NEXT: retl
+;
+; X86-AVX1-LABEL: test_v8i64_v4i64:
+; X86-AVX1: # %bb.0:
+; X86-AVX1-NEXT: vextractf128 $1, %ymm0, %xmm1
+; X86-AVX1-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X86-AVX1-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-AVX1-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X86-AVX1-NEXT: vmovd %xmm0, %eax
+; X86-AVX1-NEXT: vpextrd $1, %xmm0, %edx
+; X86-AVX1-NEXT: vzeroupper
+; X86-AVX1-NEXT: retl
+;
+; X64-AVX1-LABEL: test_v8i64_v4i64:
+; X64-AVX1: # %bb.0:
+; X64-AVX1-NEXT: vextractf128 $1, %ymm0, %xmm1
+; X64-AVX1-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X64-AVX1-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-AVX1-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X64-AVX1-NEXT: vmovq %xmm0, %rax
+; X64-AVX1-NEXT: vzeroupper
+; X64-AVX1-NEXT: retq
+;
+; X86-AVX2-LABEL: test_v8i64_v4i64:
+; X86-AVX2: # %bb.0:
+; X86-AVX2-NEXT: vextracti128 $1, %ymm0, %xmm1
+; X86-AVX2-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X86-AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-AVX2-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X86-AVX2-NEXT: vmovd %xmm0, %eax
+; X86-AVX2-NEXT: vpextrd $1, %xmm0, %edx
+; X86-AVX2-NEXT: vzeroupper
+; X86-AVX2-NEXT: retl
+;
+; X64-AVX2-LABEL: test_v8i64_v4i64:
+; X64-AVX2: # %bb.0:
+; X64-AVX2-NEXT: vextracti128 $1, %ymm0, %xmm1
+; X64-AVX2-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X64-AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-AVX2-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X64-AVX2-NEXT: vmovq %xmm0, %rax
+; X64-AVX2-NEXT: vzeroupper
+; X64-AVX2-NEXT: retq
+;
+; AVX512-LABEL: test_v8i64_v4i64:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX512-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovq %xmm0, %rax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <8 x i64> %a0, <8 x i64> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %r = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v)
+ ret i64 %r
+}
+
+define i64 @test_v8i64_v4i64_hi(<16 x i64> %a0) nounwind {
+; X86-SSE2-LABEL: test_v8i64_v4i64_hi:
+; X86-SSE2: # %bb.0:
+; X86-SSE2-NEXT: pushl %ebp
+; X86-SSE2-NEXT: movl %esp, %ebp
+; X86-SSE2-NEXT: andl $-16, %esp
+; X86-SSE2-NEXT: subl $16, %esp
+; X86-SSE2-NEXT: paddq 8(%ebp), %xmm2
+; X86-SSE2-NEXT: pshufd {{.*#+}} xmm0 = xmm2[2,3,2,3]
+; X86-SSE2-NEXT: paddq %xmm2, %xmm0
+; X86-SSE2-NEXT: movd %xmm0, %eax
+; X86-SSE2-NEXT: pshufd {{.*#+}} xmm0 = xmm0[1,1,1,1]
+; X86-SSE2-NEXT: movd %xmm0, %edx
+; X86-SSE2-NEXT: movl %ebp, %esp
+; X86-SSE2-NEXT: popl %ebp
+; X86-SSE2-NEXT: retl
+;
+; X64-SSE-LABEL: test_v8i64_v4i64_hi:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: paddq %xmm3, %xmm2
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm2[2,3,2,3]
+; X64-SSE-NEXT: paddq %xmm2, %xmm0
+; X64-SSE-NEXT: movq %xmm0, %rax
+; X64-SSE-NEXT: retq
+;
+; X86-SSE4-LABEL: test_v8i64_v4i64_hi:
+; X86-SSE4: # %bb.0:
+; X86-SSE4-NEXT: pushl %ebp
+; X86-SSE4-NEXT: movl %esp, %ebp
+; X86-SSE4-NEXT: andl $-16, %esp
+; X86-SSE4-NEXT: subl $16, %esp
+; X86-SSE4-NEXT: paddq 8(%ebp), %xmm2
+; X86-SSE4-NEXT: pshufd {{.*#+}} xmm0 = xmm2[2,3,2,3]
+; X86-SSE4-NEXT: paddq %xmm2, %xmm0
+; X86-SSE4-NEXT: movd %xmm0, %eax
+; X86-SSE4-NEXT: pextrd $1, %xmm0, %edx
+; X86-SSE4-NEXT: movl %ebp, %esp
+; X86-SSE4-NEXT: popl %ebp
+; X86-SSE4-NEXT: retl
+;
+; X86-AVX1-LABEL: test_v8i64_v4i64_hi:
+; X86-AVX1: # %bb.0:
+; X86-AVX1-NEXT: pushl %ebp
+; X86-AVX1-NEXT: movl %esp, %ebp
+; X86-AVX1-NEXT: andl $-32, %esp
+; X86-AVX1-NEXT: subl $32, %esp
+; X86-AVX1-NEXT: vextractf128 $1, %ymm1, %xmm0
+; X86-AVX1-NEXT: vpaddq %xmm0, %xmm1, %xmm0
+; X86-AVX1-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-AVX1-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X86-AVX1-NEXT: vmovd %xmm0, %eax
+; X86-AVX1-NEXT: vpextrd $1, %xmm0, %edx
+; X86-AVX1-NEXT: movl %ebp, %esp
+; X86-AVX1-NEXT: popl %ebp
+; X86-AVX1-NEXT: vzeroupper
+; X86-AVX1-NEXT: retl
+;
+; X64-AVX1-LABEL: test_v8i64_v4i64_hi:
+; X64-AVX1: # %bb.0:
+; X64-AVX1-NEXT: vextractf128 $1, %ymm1, %xmm0
+; X64-AVX1-NEXT: vpaddq %xmm0, %xmm1, %xmm0
+; X64-AVX1-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-AVX1-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X64-AVX1-NEXT: vmovq %xmm0, %rax
+; X64-AVX1-NEXT: vzeroupper
+; X64-AVX1-NEXT: retq
+;
+; X86-AVX2-LABEL: test_v8i64_v4i64_hi:
+; X86-AVX2: # %bb.0:
+; X86-AVX2-NEXT: pushl %ebp
+; X86-AVX2-NEXT: movl %esp, %ebp
+; X86-AVX2-NEXT: andl $-32, %esp
+; X86-AVX2-NEXT: subl $32, %esp
+; X86-AVX2-NEXT: vextracti128 $1, %ymm1, %xmm0
+; X86-AVX2-NEXT: vpaddq %xmm0, %xmm1, %xmm0
+; X86-AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-AVX2-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X86-AVX2-NEXT: vmovd %xmm0, %eax
+; X86-AVX2-NEXT: vpextrd $1, %xmm0, %edx
+; X86-AVX2-NEXT: movl %ebp, %esp
+; X86-AVX2-NEXT: popl %ebp
+; X86-AVX2-NEXT: vzeroupper
+; X86-AVX2-NEXT: retl
+;
+; X64-AVX2-LABEL: test_v8i64_v4i64_hi:
+; X64-AVX2: # %bb.0:
+; X64-AVX2-NEXT: vextracti128 $1, %ymm1, %xmm0
+; X64-AVX2-NEXT: vpaddq %xmm0, %xmm1, %xmm0
+; X64-AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-AVX2-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; X64-AVX2-NEXT: vmovq %xmm0, %rax
+; X64-AVX2-NEXT: vzeroupper
+; X64-AVX2-NEXT: retq
+;
+; AVX512-LABEL: test_v8i64_v4i64_hi:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vextracti64x4 $1, %zmm0, %ymm0
+; AVX512-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX512-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddq %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovq %xmm0, %rax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <16 x i64> %a0, <16 x i64> poison, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ %r = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> %v)
+ ret i64 %r
+}
+
+;
+; vXi32
+;
+
+define i32 @test_v4i32_v2i32(<4 x i32> %a0) nounwind {
+; SSE-LABEL: test_v4i32_v2i32:
+; SSE: # %bb.0:
+; SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; SSE-NEXT: paddd %xmm0, %xmm1
+; SSE-NEXT: movd %xmm1, %eax
+; SSE-NEXT: ret{{[l|q]}}
+;
+; AVX1-SLOW-LABEL: test_v4i32_v2i32:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v4i32_v2i32:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v4i32_v2i32:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v4i32_v2i32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: retq
+ %v = shufflevector <4 x i32> %a0, <4 x i32> poison, <2 x i32> <i32 0, i32 1>
+ %r = call i32 @llvm.vector.reduce.add.v2i32(<2 x i32> %v)
+ ret i32 %r
+}
+
+define i32 @test_v4i32_v2i32_hi(<4 x i32> %a0) nounwind {
+; SSE-LABEL: test_v4i32_v2i32_hi:
+; SSE: # %bb.0:
+; SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; SSE-NEXT: paddd %xmm1, %xmm0
+; SSE-NEXT: movd %xmm0, %eax
+; SSE-NEXT: ret{{[l|q]}}
+;
+; AVX1-SLOW-LABEL: test_v4i32_v2i32_hi:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; AVX1-SLOW-NEXT: vpaddd %xmm0, %xmm1, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v4i32_v2i32_hi:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vpextrd $1, %xmm0, %eax
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v4i32_v2i32_hi:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; AVX2-NEXT: vpaddd %xmm0, %xmm1, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v4i32_v2i32_hi:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; AVX512-NEXT: vpaddd %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: retq
+ %v = shufflevector <4 x i32> %a0, <4 x i32> poison, <2 x i32> <i32 2, i32 3>
+ %r = call i32 @llvm.vector.reduce.add.v2i32(<2 x i32> %v)
+ ret i32 %r
+}
+
+define i32 @test_v8i32_v4i32(<8 x i32> %a0) nounwind {
+; SSE-LABEL: test_v8i32_v4i32:
+; SSE: # %bb.0:
+; SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; SSE-NEXT: paddd %xmm0, %xmm1
+; SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; SSE-NEXT: paddd %xmm1, %xmm0
+; SSE-NEXT: movd %xmm0, %eax
+; SSE-NEXT: ret{{[l|q]}}
+;
+; AVX1-SLOW-LABEL: test_v8i32_v4i32:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: vzeroupper
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v8i32_v4i32:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: vzeroupper
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v8i32_v4i32:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v8i32_v4i32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <8 x i32> %a0, <8 x i32> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %r = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %v)
+ ret i32 %r
+}
+
+define i32 @test_v8i32_v4i32_mid(<8 x i32> %a0) nounwind {
+; SSE-LABEL: test_v8i32_v4i32_mid:
+; SSE: # %bb.0:
+; SSE-NEXT: shufps {{.*#+}} xmm0 = xmm0[2,2],xmm1[0,1]
+; SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm1[0,1,0,1]
+; SSE-NEXT: paddd %xmm0, %xmm1
+; SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; SSE-NEXT: paddd %xmm1, %xmm0
+; SSE-NEXT: movd %xmm0, %eax
+; SSE-NEXT: ret{{[l|q]}}
+;
+; AVX1-SLOW-LABEL: test_v8i32_v4i32_mid:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX1-SLOW-NEXT: vshufps {{.*#+}} xmm0 = xmm0[2,2],xmm1[0,1]
+; AVX1-SLOW-NEXT: vshufps {{.*#+}} xmm1 = xmm1[0,1,0,1]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: vzeroupper
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v8i32_v4i32_mid:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX1-FAST-NEXT: vshufps {{.*#+}} xmm0 = xmm0[2,2],xmm1[0,1]
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: vzeroupper
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v8i32_v4i32_mid:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX2-NEXT: vshufps {{.*#+}} xmm0 = xmm0[2,2],xmm1[0,1]
+; AVX2-NEXT: vmovddup {{.*#+}} xmm1 = xmm1[0,0]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v8i32_v4i32_mid:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX512-NEXT: vshufps {{.*#+}} xmm0 = xmm0[2,2],xmm1[0,1]
+; AVX512-NEXT: vmovddup {{.*#+}} xmm1 = xmm1[0,0]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <8 x i32> %a0, <8 x i32> poison, <4 x i32> <i32 2, i32 2, i32 4, i32 5>
+ %r = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %v)
+ ret i32 %r
+}
+
+define i32 @test_v16i32_v4i32(<16 x i32> %a0) nounwind {
+; X86-SSE-LABEL: test_v16i32_v4i32:
+; X86-SSE: # %bb.0:
+; X86-SSE-NEXT: pushl %ebp
+; X86-SSE-NEXT: movl %esp, %ebp
+; X86-SSE-NEXT: andl $-16, %esp
+; X86-SSE-NEXT: subl $16, %esp
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-SSE-NEXT: paddd %xmm0, %xmm1
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; X86-SSE-NEXT: paddd %xmm1, %xmm0
+; X86-SSE-NEXT: movd %xmm0, %eax
+; X86-SSE-NEXT: movl %ebp, %esp
+; X86-SSE-NEXT: popl %ebp
+; X86-SSE-NEXT: retl
+;
+; X64-SSE-LABEL: test_v16i32_v4i32:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-SSE-NEXT: paddd %xmm0, %xmm1
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; X64-SSE-NEXT: paddd %xmm1, %xmm0
+; X64-SSE-NEXT: movd %xmm0, %eax
+; X64-SSE-NEXT: retq
+;
+; AVX1-SLOW-LABEL: test_v16i32_v4i32:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: vzeroupper
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v16i32_v4i32:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: vzeroupper
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v16i32_v4i32:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v16i32_v4i32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <16 x i32> %a0, <16 x i32> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %r = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %v)
+ ret i32 %r
+}
+
+define i32 @test_v16i32_v8i32(<16 x i32> %a0) nounwind {
+; X86-SSE-LABEL: test_v16i32_v8i32:
+; X86-SSE: # %bb.0:
+; X86-SSE-NEXT: pushl %ebp
+; X86-SSE-NEXT: movl %esp, %ebp
+; X86-SSE-NEXT: andl $-16, %esp
+; X86-SSE-NEXT: subl $16, %esp
+; X86-SSE-NEXT: paddd %xmm1, %xmm0
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-SSE-NEXT: paddd %xmm0, %xmm1
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; X86-SSE-NEXT: paddd %xmm1, %xmm0
+; X86-SSE-NEXT: movd %xmm0, %eax
+; X86-SSE-NEXT: movl %ebp, %esp
+; X86-SSE-NEXT: popl %ebp
+; X86-SSE-NEXT: retl
+;
+; X64-SSE-LABEL: test_v16i32_v8i32:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: paddd %xmm1, %xmm0
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-SSE-NEXT: paddd %xmm0, %xmm1
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; X64-SSE-NEXT: paddd %xmm1, %xmm0
+; X64-SSE-NEXT: movd %xmm0, %eax
+; X64-SSE-NEXT: retq
+;
+; AVX1-SLOW-LABEL: test_v16i32_v8i32:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: vzeroupper
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v16i32_v8i32:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm1, %xmm0
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: vzeroupper
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v16i32_v8i32:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v16i32_v8i32:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <16 x i32> %a0, <16 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %r = call i32 @llvm.vector.reduce.add.v8i32(<8 x i32> %v)
+ ret i32 %r
+}
+
+define i32 @test_v16i32_v8i32_mid(<16 x i32> %a0) nounwind {
+; X86-SSE-LABEL: test_v16i32_v8i32_mid:
+; X86-SSE: # %bb.0:
+; X86-SSE-NEXT: pushl %ebp
+; X86-SSE-NEXT: movl %esp, %ebp
+; X86-SSE-NEXT: andl $-16, %esp
+; X86-SSE-NEXT: subl $16, %esp
+; X86-SSE-NEXT: paddd %xmm2, %xmm1
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[2,3,2,3]
+; X86-SSE-NEXT: paddd %xmm1, %xmm0
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; X86-SSE-NEXT: paddd %xmm0, %xmm1
+; X86-SSE-NEXT: movd %xmm1, %eax
+; X86-SSE-NEXT: movl %ebp, %esp
+; X86-SSE-NEXT: popl %ebp
+; X86-SSE-NEXT: retl
+;
+; X64-SSE-LABEL: test_v16i32_v8i32_mid:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: paddd %xmm2, %xmm1
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[2,3,2,3]
+; X64-SSE-NEXT: paddd %xmm1, %xmm0
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; X64-SSE-NEXT: paddd %xmm0, %xmm1
+; X64-SSE-NEXT: movd %xmm1, %eax
+; X64-SSE-NEXT: retq
+;
+; AVX1-SLOW-LABEL: test_v16i32_v8i32_mid:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vextractf128 $1, %ymm0, %xmm0
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX1-SLOW-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: vzeroupper
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v16i32_v8i32_mid:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vextractf128 $1, %ymm0, %xmm0
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm1, %xmm0
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddd %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: vzeroupper
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v16i32_v8i32_mid:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vextracti128 $1, %ymm0, %xmm0
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v16i32_v8i32_mid:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX512-NEXT: vextracti32x4 $2, %zmm0, %xmm0
+; AVX512-NEXT: vpaddd %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX512-NEXT: vpaddd %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <16 x i32> %a0, <16 x i32> poison, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11>
+ %r = call i32 @llvm.vector.reduce.add.v8i32(<8 x i32> %v)
+ ret i32 %r
+}
+
+;
+; vXi16
+;
+
+define i16 @test_v8i16_v4i16_hi(<8 x i16> %a0) nounwind {
+; SSE-LABEL: test_v8i16_v4i16_hi:
+; SSE: # %bb.0:
+; SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; SSE-NEXT: paddw %xmm1, %xmm0
+; SSE-NEXT: movdqa %xmm0, %xmm1
+; SSE-NEXT: psrld $16, %xmm1
+; SSE-NEXT: paddw %xmm0, %xmm1
+; SSE-NEXT: movd %xmm1, %eax
+; SSE-NEXT: # kill: def $ax killed $ax killed $eax
+; SSE-NEXT: ret{{[l|q]}}
+;
+; AVX1-SLOW-LABEL: test_v8i16_v4i16_hi:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; AVX1-SLOW-NEXT: vpaddw %xmm0, %xmm1, %xmm0
+; AVX1-SLOW-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX1-SLOW-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v8i16_v4i16_hi:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-FAST-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; AVX1-FAST-NEXT: vpaddw %xmm0, %xmm1, %xmm0
+; AVX1-FAST-NEXT: vphaddw %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v8i16_v4i16_hi:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; AVX2-NEXT: vpaddw %xmm0, %xmm1, %xmm0
+; AVX2-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX2-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v8i16_v4i16_hi:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[3,3,3,3]
+; AVX512-NEXT: vpaddw %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX512-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX512-NEXT: retq
+ %v = shufflevector <8 x i16> %a0, <8 x i16> poison, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+ %r = call i16 @llvm.vector.reduce.add.v4i16(<4 x i16> %v)
+ ret i16 %r
+}
+
+define i16 @test_v16i16_v8i16_hi(<16 x i16> %a0) nounwind {
+; SSE-LABEL: test_v16i16_v8i16_hi:
+; SSE: # %bb.0:
+; SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[2,3,2,3]
+; SSE-NEXT: paddw %xmm1, %xmm0
+; SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; SSE-NEXT: paddw %xmm0, %xmm1
+; SSE-NEXT: movdqa %xmm1, %xmm0
+; SSE-NEXT: psrld $16, %xmm0
+; SSE-NEXT: paddw %xmm1, %xmm0
+; SSE-NEXT: movd %xmm0, %eax
+; SSE-NEXT: # kill: def $ax killed $ax killed $eax
+; SSE-NEXT: ret{{[l|q]}}
+;
+; AVX1-SLOW-LABEL: test_v16i16_v8i16_hi:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vextractf128 $1, %ymm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-SLOW-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX1-SLOW-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX1-SLOW-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX1-SLOW-NEXT: vzeroupper
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v16i16_v8i16_hi:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vextractf128 $1, %ymm0, %xmm0
+; AVX1-FAST-NEXT: vphaddw %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddw %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddw %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX1-FAST-NEXT: vzeroupper
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v16i16_v8i16_hi:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vextracti128 $1, %ymm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX2-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX2-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v16i16_v8i16_hi:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vextracti128 $1, %ymm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX512-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX512-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <16 x i16> %a0, <16 x i16> poison, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ %r = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> %v)
+ ret i16 %r
+}
+
+define i16 @test_v32i16_v16i16(<32 x i16> %a0) nounwind {
+; X86-SSE-LABEL: test_v32i16_v16i16:
+; X86-SSE: # %bb.0:
+; X86-SSE-NEXT: pushl %ebp
+; X86-SSE-NEXT: movl %esp, %ebp
+; X86-SSE-NEXT: andl $-16, %esp
+; X86-SSE-NEXT: subl $16, %esp
+; X86-SSE-NEXT: paddw %xmm1, %xmm0
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X86-SSE-NEXT: paddw %xmm0, %xmm1
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; X86-SSE-NEXT: paddw %xmm1, %xmm0
+; X86-SSE-NEXT: movdqa %xmm0, %xmm1
+; X86-SSE-NEXT: psrld $16, %xmm1
+; X86-SSE-NEXT: paddw %xmm0, %xmm1
+; X86-SSE-NEXT: movd %xmm1, %eax
+; X86-SSE-NEXT: # kill: def $ax killed $ax killed $eax
+; X86-SSE-NEXT: movl %ebp, %esp
+; X86-SSE-NEXT: popl %ebp
+; X86-SSE-NEXT: retl
+;
+; X64-SSE-LABEL: test_v32i16_v16i16:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: paddw %xmm1, %xmm0
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; X64-SSE-NEXT: paddw %xmm0, %xmm1
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm1[1,1,1,1]
+; X64-SSE-NEXT: paddw %xmm1, %xmm0
+; X64-SSE-NEXT: movdqa %xmm0, %xmm1
+; X64-SSE-NEXT: psrld $16, %xmm1
+; X64-SSE-NEXT: paddw %xmm0, %xmm1
+; X64-SSE-NEXT: movd %xmm1, %eax
+; X64-SSE-NEXT: # kill: def $ax killed $ax killed $eax
+; X64-SSE-NEXT: retq
+;
+; AVX1-SLOW-LABEL: test_v32i16_v16i16:
+; AVX1-SLOW: # %bb.0:
+; AVX1-SLOW-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX1-SLOW-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-SLOW-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX1-SLOW-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX1-SLOW-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX1-SLOW-NEXT: vmovd %xmm0, %eax
+; AVX1-SLOW-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX1-SLOW-NEXT: vzeroupper
+; AVX1-SLOW-NEXT: ret{{[l|q]}}
+;
+; AVX1-FAST-LABEL: test_v32i16_v16i16:
+; AVX1-FAST: # %bb.0:
+; AVX1-FAST-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX1-FAST-NEXT: vphaddw %xmm0, %xmm1, %xmm0
+; AVX1-FAST-NEXT: vphaddw %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddw %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vphaddw %xmm0, %xmm0, %xmm0
+; AVX1-FAST-NEXT: vmovd %xmm0, %eax
+; AVX1-FAST-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX1-FAST-NEXT: vzeroupper
+; AVX1-FAST-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v32i16_v16i16:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX2-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX2-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX2-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v32i16_v16i16:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX512-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[1,1,1,1]
+; AVX512-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpsrld $16, %xmm0, %xmm1
+; AVX512-NEXT: vpaddw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: # kill: def $ax killed $ax killed $eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <32 x i16> %a0, <32 x i16> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ %r = call i16 @llvm.vector.reduce.add.v16i16(<16 x i16> %v)
+ ret i16 %r
+}
+
+;
+; vXi8
+;
+
+define i8 @test_v16i8_v8i8_hi(<16 x i8> %a0) nounwind {
+; SSE-LABEL: test_v16i8_v8i8_hi:
+; SSE: # %bb.0:
+; SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; SSE-NEXT: pxor %xmm1, %xmm1
+; SSE-NEXT: psadbw %xmm0, %xmm1
+; SSE-NEXT: movd %xmm1, %eax
+; SSE-NEXT: # kill: def $al killed $al killed $eax
+; SSE-NEXT: ret{{[l|q]}}
+;
+; AVX-LABEL: test_v16i8_v8i8_hi:
+; AVX: # %bb.0:
+; AVX-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[2,3,2,3]
+; AVX-NEXT: vpxor %xmm1, %xmm1, %xmm1
+; AVX-NEXT: vpsadbw %xmm1, %xmm0, %xmm0
+; AVX-NEXT: vmovd %xmm0, %eax
+; AVX-NEXT: # kill: def $al killed $al killed $eax
+; AVX-NEXT: ret{{[l|q]}}
+ %v = shufflevector <16 x i8> %a0, <16 x i8> poison, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ %r = call i8 @llvm.vector.reduce.add.v8i8(<8 x i8> %v)
+ ret i8 %r
+}
+
+define i8 @test_v32i8_v16i8_mid(<32 x i8> %a0) nounwind {
+; SSE2-LABEL: test_v32i8_v16i8_mid:
+; SSE2: # %bb.0:
+; SSE2-NEXT: shufps {{.*#+}} xmm0 = xmm0[2,3],xmm1[0,1]
+; SSE2-NEXT: pshufd {{.*#+}} xmm1 = xmm1[0,1,0,1]
+; SSE2-NEXT: paddb %xmm0, %xmm1
+; SSE2-NEXT: pxor %xmm0, %xmm0
+; SSE2-NEXT: psadbw %xmm1, %xmm0
+; SSE2-NEXT: movd %xmm0, %eax
+; SSE2-NEXT: # kill: def $al killed $al killed $eax
+; SSE2-NEXT: ret{{[l|q]}}
+;
+; SSE4-LABEL: test_v32i8_v16i8_mid:
+; SSE4: # %bb.0:
+; SSE4-NEXT: pshufd {{.*#+}} xmm2 = xmm1[0,1,0,1]
+; SSE4-NEXT: palignr {{.*#+}} xmm1 = xmm0[8,9,10,11,12,13,14,15],xmm1[0,1,2,3,4,5,6,7]
+; SSE4-NEXT: paddb %xmm2, %xmm1
+; SSE4-NEXT: pxor %xmm0, %xmm0
+; SSE4-NEXT: psadbw %xmm1, %xmm0
+; SSE4-NEXT: movd %xmm0, %eax
+; SSE4-NEXT: # kill: def $al killed $al killed $eax
+; SSE4-NEXT: ret{{[l|q]}}
+;
+; AVX1-LABEL: test_v32i8_v16i8_mid:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vextractf128 $1, %ymm0, %xmm1
+; AVX1-NEXT: vpalignr {{.*#+}} xmm0 = xmm0[8,9,10,11,12,13,14,15],xmm1[0,1,2,3,4,5,6,7]
+; AVX1-NEXT: vpshufd {{.*#+}} xmm1 = xmm1[0,1,0,1]
+; AVX1-NEXT: vpaddb %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vpxor %xmm1, %xmm1, %xmm1
+; AVX1-NEXT: vpsadbw %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: vzeroupper
+; AVX1-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v32i8_v16i8_mid:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vpermq {{.*#+}} ymm1 = ymm0[1,2,2,3]
+; AVX2-NEXT: vextracti128 $1, %ymm0, %xmm0
+; AVX2-NEXT: vpbroadcastq %xmm0, %xmm0
+; AVX2-NEXT: vpaddb %xmm0, %xmm1, %xmm0
+; AVX2-NEXT: vpxor %xmm1, %xmm1, %xmm1
+; AVX2-NEXT: vpsadbw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: # kill: def $al killed $al killed $eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v32i8_v16i8_mid:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vpermq {{.*#+}} ymm1 = ymm0[1,2,2,3]
+; AVX512-NEXT: vextracti128 $1, %ymm0, %xmm0
+; AVX512-NEXT: vpbroadcastq %xmm0, %xmm0
+; AVX512-NEXT: vpaddb %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: vpxor %xmm1, %xmm1, %xmm1
+; AVX512-NEXT: vpsadbw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <32 x i8> %a0, <32 x i8> poison, <16 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
+ %r = call i8 @llvm.vector.reduce.add.v16i8(<16 x i8> %v)
+ ret i8 %r
+}
+
+define i8 @test_v64i8_v32i8_hi(<64 x i8> %a0) nounwind {
+; X86-SSE-LABEL: test_v64i8_v32i8_hi:
+; X86-SSE: # %bb.0:
+; X86-SSE-NEXT: pushl %ebp
+; X86-SSE-NEXT: movl %esp, %ebp
+; X86-SSE-NEXT: andl $-16, %esp
+; X86-SSE-NEXT: subl $16, %esp
+; X86-SSE-NEXT: paddb 8(%ebp), %xmm2
+; X86-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm2[2,3,2,3]
+; X86-SSE-NEXT: paddb %xmm2, %xmm0
+; X86-SSE-NEXT: pxor %xmm1, %xmm1
+; X86-SSE-NEXT: psadbw %xmm0, %xmm1
+; X86-SSE-NEXT: movd %xmm1, %eax
+; X86-SSE-NEXT: # kill: def $al killed $al killed $eax
+; X86-SSE-NEXT: movl %ebp, %esp
+; X86-SSE-NEXT: popl %ebp
+; X86-SSE-NEXT: retl
+;
+; X64-SSE-LABEL: test_v64i8_v32i8_hi:
+; X64-SSE: # %bb.0:
+; X64-SSE-NEXT: paddb %xmm3, %xmm2
+; X64-SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm2[2,3,2,3]
+; X64-SSE-NEXT: paddb %xmm2, %xmm0
+; X64-SSE-NEXT: pxor %xmm1, %xmm1
+; X64-SSE-NEXT: psadbw %xmm0, %xmm1
+; X64-SSE-NEXT: movd %xmm1, %eax
+; X64-SSE-NEXT: # kill: def $al killed $al killed $eax
+; X64-SSE-NEXT: retq
+;
+; AVX1-LABEL: test_v64i8_v32i8_hi:
+; AVX1: # %bb.0:
+; AVX1-NEXT: vextractf128 $1, %ymm1, %xmm0
+; AVX1-NEXT: vpaddb %xmm0, %xmm1, %xmm0
+; AVX1-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX1-NEXT: vpaddb %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vpxor %xmm1, %xmm1, %xmm1
+; AVX1-NEXT: vpsadbw %xmm1, %xmm0, %xmm0
+; AVX1-NEXT: vmovd %xmm0, %eax
+; AVX1-NEXT: # kill: def $al killed $al killed $eax
+; AVX1-NEXT: vzeroupper
+; AVX1-NEXT: ret{{[l|q]}}
+;
+; AVX2-LABEL: test_v64i8_v32i8_hi:
+; AVX2: # %bb.0:
+; AVX2-NEXT: vextracti128 $1, %ymm1, %xmm0
+; AVX2-NEXT: vpaddb %xmm0, %xmm1, %xmm0
+; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX2-NEXT: vpaddb %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vpxor %xmm1, %xmm1, %xmm1
+; AVX2-NEXT: vpsadbw %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovd %xmm0, %eax
+; AVX2-NEXT: # kill: def $al killed $al killed $eax
+; AVX2-NEXT: vzeroupper
+; AVX2-NEXT: ret{{[l|q]}}
+;
+; AVX512-LABEL: test_v64i8_v32i8_hi:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vextracti64x4 $1, %zmm0, %ymm0
+; AVX512-NEXT: vextracti128 $1, %ymm0, %xmm1
+; AVX512-NEXT: vpaddb %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpshufd {{.*#+}} xmm1 = xmm0[2,3,2,3]
+; AVX512-NEXT: vpaddb %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vpxor %xmm1, %xmm1, %xmm1
+; AVX512-NEXT: vpsadbw %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovd %xmm0, %eax
+; AVX512-NEXT: # kill: def $al killed $al killed $eax
+; AVX512-NEXT: vzeroupper
+; AVX512-NEXT: retq
+ %v = shufflevector <64 x i8> %a0, <64 x i8> poison, <32 x i32> <i32 32, i32 33, i32 34, i32 35, i32 36, i32 37, i32 38, i32 39, i32 40, i32 41, i32 42, i32 43, i32 44, i32 45, i32 46, i32 47, i32 48, i32 49, i32 50, i32 51, i32 52, i32 53, i32 54, i32 55, i32 56, i32 57, i32 58, i32 59, i32 60, i32 61, i32 62, i32 63>
+ %r = call i8 @llvm.vector.reduce.add.v32i8(<32 x i8> %v)
+ ret i8 %r
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; X64-AVX1-FAST: {{.*}}
+; X64-AVX1-SLOW: {{.*}}
+; X64-SSE2: {{.*}}
+; X64-SSE4: {{.*}}
+; X86-AVX1-FAST: {{.*}}
+; X86-AVX1-SLOW: {{.*}}
diff --git a/llvm/test/Transforms/InstCombine/and-fcmp.ll b/llvm/test/Transforms/InstCombine/and-fcmp.ll
index 99adb49a579ec..c6f1e635ce5ce 100644
--- a/llvm/test/Transforms/InstCombine/and-fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/and-fcmp.ll
@@ -12,12 +12,10 @@ define i1 @PR1738(double %x, double %y) {
ret i1 %and
}
-; TODO: this can be supported by freezing %y
define i1 @PR1738_logical(double %x, double %y) {
; CHECK-LABEL: @PR1738_logical(
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord double [[Y:%.*]], 0.000000e+00
-; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
+; CHECK-NEXT: [[Y_FR:%.*]] = freeze double [[Y:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = fcmp ord double [[X:%.*]], [[Y_FR]]
; CHECK-NEXT: ret i1 [[AND]]
;
%cmp1 = fcmp ord double %x, 0.0
@@ -103,12 +101,10 @@ define i1 @PR41069_commute(i1 %z, float %c, float %d) {
ret i1 %r
}
-; TODO: this should be fixed using freeze
define i1 @PR41069_commute_logical(i1 %z, float %c, float %d) {
; CHECK-LABEL: @PR41069_commute_logical(
-; CHECK-NEXT: [[ORD1:%.*]] = fcmp ninf ord float [[C:%.*]], 0.000000e+00
-; CHECK-NEXT: [[ORD2:%.*]] = fcmp reassoc ninf ord float [[D:%.*]], 0.000000e+00
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[ORD2]], i1 [[ORD1]], i1 false
+; CHECK-NEXT: [[C_FR:%.*]] = freeze float [[C:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = fcmp ord float [[D:%.*]], [[C_FR]]
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i1 [[Z:%.*]], i1 false
; CHECK-NEXT: ret i1 [[R]]
;
@@ -205,12 +201,10 @@ define i1 @fcmp_ord_nonzero(float %x, float %y) {
ret i1 %and
}
-; TODO: this can be supported by freezing %y
define i1 @fcmp_ord_nonzero_logical(float %x, float %y) {
; CHECK-LABEL: @fcmp_ord_nonzero_logical(
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord float [[Y:%.*]], 0.000000e+00
-; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
+; CHECK-NEXT: [[Y_FR:%.*]] = freeze float [[Y:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = fcmp ord float [[X:%.*]], [[Y_FR]]
; CHECK-NEXT: ret i1 [[AND]]
;
%cmp1 = fcmp ord float %x, 1.0
diff --git a/llvm/test/Transforms/InstCombine/or-fcmp.ll b/llvm/test/Transforms/InstCombine/or-fcmp.ll
index 193fe4b5cc722..99f8b687fd603 100644
--- a/llvm/test/Transforms/InstCombine/or-fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/or-fcmp.ll
@@ -12,12 +12,10 @@ define i1 @PR1738(double %x, double %y) {
ret i1 %or
}
-; TODO: this can be fixed by freezing %y
define i1 @PR1738_logical(double %x, double %y) {
; CHECK-LABEL: @PR1738_logical(
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno double [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno double [[Y:%.*]], 0.000000e+00
-; CHECK-NEXT: [[OR:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
+; CHECK-NEXT: [[Y_FR:%.*]] = freeze double [[Y:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = fcmp uno double [[X:%.*]], [[Y_FR]]
; CHECK-NEXT: ret i1 [[OR]]
;
%cmp1 = fcmp uno double %x, 0.0
@@ -183,12 +181,10 @@ define i1 @fcmp_uno_nonzero(float %x, float %y) {
ret i1 %or
}
-; TODO: this can be fixed by freezing %y
define i1 @fcmp_uno_nonzero_logical(float %x, float %y) {
; CHECK-LABEL: @fcmp_uno_nonzero_logical(
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno float [[Y:%.*]], 0.000000e+00
-; CHECK-NEXT: [[OR:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
+; CHECK-NEXT: [[Y_FR:%.*]] = freeze float [[Y:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = fcmp uno float [[X:%.*]], [[Y_FR]]
; CHECK-NEXT: ret i1 [[OR]]
;
%cmp1 = fcmp uno float %x, 1.0
diff --git a/llvm/unittests/Support/GlobPatternTest.cpp b/llvm/unittests/Support/GlobPatternTest.cpp
index 872a21e948d7a..35423e37a3ae0 100644
--- a/llvm/unittests/Support/GlobPatternTest.cpp
+++ b/llvm/unittests/Support/GlobPatternTest.cpp
@@ -327,6 +327,30 @@ TEST_F(GlobPatternTest, PrefixSuffix) {
ASSERT_TRUE((bool)Pat);
EXPECT_EQ("", Pat->prefix());
EXPECT_EQ("cd", Pat->suffix());
+
+ Pat = GlobPattern::create("ab/cd", /*MaxSubPatterns=*/{},
+ /*SlashAgnostic=*/true);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_EQ("ab", Pat->prefix());
+ EXPECT_EQ("cd", Pat->suffix());
+
+ Pat = GlobPattern::create("ab\\cd", /*MaxSubPatterns=*/{},
+ /*SlashAgnostic=*/true);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_EQ("ab", Pat->prefix());
+ EXPECT_EQ("d", Pat->suffix());
+
+ Pat = GlobPattern::create("ab/cd", /*MaxSubPatterns=*/{},
+ /*SlashAgnostic=*/false);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_EQ("ab/cd", Pat->prefix());
+ EXPECT_EQ("", Pat->suffix());
+
+ Pat = GlobPattern::create("ab\\cd", /*MaxSubPatterns=*/{},
+ /*SlashAgnostic=*/false);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_EQ("ab", Pat->prefix());
+ EXPECT_EQ("d", Pat->suffix());
}
TEST_F(GlobPatternTest, Substr) {
@@ -393,6 +417,26 @@ TEST_F(GlobPatternTest, Substr) {
Pat = GlobPattern::create("a*bcdef{g}*h");
ASSERT_TRUE((bool)Pat);
EXPECT_EQ("bcdef", Pat->longest_substr());
+
+ Pat = GlobPattern::create("a*bc/de*f", /*MaxSubPatterns=*/{},
+ /*SlashAgnostic=*/true);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_EQ("bc", Pat->longest_substr());
+
+ Pat = GlobPattern::create("a*bc\\de*f", /*MaxSubPatterns=*/{},
+ /*SlashAgnostic=*/true);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_EQ("bc", Pat->longest_substr());
+
+ Pat = GlobPattern::create("a*bc/de*f", /*MaxSubPatterns=*/{},
+ /*SlashAgnostic=*/false);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_EQ("bc/de", Pat->longest_substr());
+
+ Pat = GlobPattern::create("a*bc\\de*f", /*MaxSubPatterns=*/{},
+ /*SlashAgnostic=*/false);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_EQ("bc", Pat->longest_substr());
}
TEST_F(GlobPatternTest, Pathological) {
@@ -409,4 +453,22 @@ TEST_F(GlobPatternTest, Pathological) {
EXPECT_FALSE(Pat->match(S));
EXPECT_TRUE(Pat->match(S + 'b'));
}
+
+TEST_F(GlobPatternTest, SlashAgnosticMatch) {
+ auto Pat1 = GlobPattern::create("foo\\\\bar[a\\\\-z]", 1024,
+ /*SlashAgnostic=*/true);
+ ASSERT_TRUE((bool)Pat1);
+ EXPECT_TRUE(Pat1->match("foo/bar\\"));
+ EXPECT_TRUE(Pat1->match("foo/barb"));
+ EXPECT_TRUE(Pat1->match("foo/bar/"));
+}
+
+TEST_F(GlobPatternTest, SlashAgnosticMatchInverted) {
+ auto Pat = GlobPattern::create("foo\\\\bar[^a\\\\-z]", 1024,
+ /*SlashAgnostic=*/true);
+ ASSERT_TRUE((bool)Pat);
+ EXPECT_FALSE(Pat->match("foo/bar/"));
+ EXPECT_FALSE(Pat->match("foo/barb"));
+ EXPECT_TRUE(Pat->match("foo/bar1"));
+}
}
More information about the llvm-branch-commits
mailing list