[PowerPC][X86] Make cpu id builtins target independent and lower for PPC (#68919)
Make __builtin_cpu_{init|supports|is} target independent and provide an
opt-in query for targets that want to support it. Each target is still
responsible for their specific lowering/code-gen. Also provide code-gen
for PowerPC.
I originally proposed this in https://reviews.llvm.org/D152914 and this
addresses the comments I received there.
---------
Co-authored-by: Nemanja Ivanovic <nemanjaivanovic@nemanjas-air.kpn>
Co-authored-by: Nemanja Ivanovic <nemanja@synopsys.com>
This commit is contained in:
@@ -727,6 +727,26 @@ def RotateRight : BitInt8_16_32_64BuiltinsTemplate, Builtin {
|
||||
// FIXME: The builtins marked FunctionWithBuiltinPrefix below should be
|
||||
// merged with the library definitions. They are currently not because
|
||||
// the attributes are different.
|
||||
|
||||
// Builtins for checking CPU features based on the GCC builtins.
|
||||
def BuiltinCPUIs : Builtin {
|
||||
let Spellings = ["__builtin_cpu_is"];
|
||||
let Attributes = [NoThrow, Const];
|
||||
let Prototype = "bool(char const*)";
|
||||
}
|
||||
|
||||
def BuiltinCPUSupports : Builtin {
|
||||
let Spellings = ["__builtin_cpu_supports"];
|
||||
let Attributes = [NoThrow, Const];
|
||||
let Prototype = "bool(char const*)";
|
||||
}
|
||||
|
||||
def BuiltinCPUInit : Builtin {
|
||||
let Spellings = ["__builtin_cpu_init"];
|
||||
let Attributes = [NoThrow];
|
||||
let Prototype = "void()";
|
||||
}
|
||||
|
||||
def BuiltinCalloc : Builtin {
|
||||
let Spellings = ["__builtin_calloc"];
|
||||
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
|
||||
|
||||
@@ -26,13 +26,6 @@
|
||||
# define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
// Miscellaneous builtin for checking x86 cpu features.
|
||||
// TODO: Make this somewhat generic so that other backends
|
||||
// can use it?
|
||||
BUILTIN(__builtin_cpu_init, "v", "n")
|
||||
BUILTIN(__builtin_cpu_supports, "bcC*", "nc")
|
||||
BUILTIN(__builtin_cpu_is, "bcC*", "nc")
|
||||
|
||||
// Undefined Values
|
||||
//
|
||||
TARGET_BUILTIN(__builtin_ia32_undef128, "V2d", "ncV:128:", "")
|
||||
|
||||
@@ -1432,6 +1432,12 @@ public:
|
||||
getTriple().isOSFreeBSD());
|
||||
}
|
||||
|
||||
// Identify whether this target supports __builtin_cpu_supports and
|
||||
// __builtin_cpu_is.
|
||||
virtual bool supportsCpuSupports() const { return false; }
|
||||
virtual bool supportsCpuIs() const { return false; }
|
||||
virtual bool supportsCpuInit() const { return false; }
|
||||
|
||||
// Validate the contents of the __builtin_cpu_supports(const char*)
|
||||
// argument.
|
||||
virtual bool validateCpuSupports(StringRef Name) const { return false; }
|
||||
|
||||
@@ -903,3 +903,17 @@ ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
|
||||
return llvm::ArrayRef(BuiltinInfo,
|
||||
clang::PPC::LastTSBuiltin - Builtin::FirstTSBuiltin);
|
||||
}
|
||||
|
||||
bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const {
|
||||
#define PPC_LNX_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN) .Case(NAME, true)
|
||||
return llvm::StringSwitch<bool>(FeatureStr)
|
||||
#include "llvm/TargetParser/PPCTargetParser.def"
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
bool PPCTargetInfo::validateCpuIs(StringRef CPUName) const {
|
||||
#define PPC_LNX_CPU(NAME, NUM) .Case(NAME, true)
|
||||
return llvm::StringSwitch<bool>(CPUName)
|
||||
#include "llvm/TargetParser/PPCTargetParser.def"
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
@@ -359,6 +359,13 @@ public:
|
||||
bool isSPRegName(StringRef RegName) const override {
|
||||
return RegName.equals("r1") || RegName.equals("x1");
|
||||
}
|
||||
|
||||
// We support __builtin_cpu_supports/__builtin_cpu_is on targets that
|
||||
// have Glibc since it is Glibc that provides the HWCAP[2] in the auxv.
|
||||
bool supportsCpuSupports() const override { return getTriple().isOSGlibc(); }
|
||||
bool supportsCpuIs() const override { return getTriple().isOSGlibc(); }
|
||||
bool validateCpuSupports(StringRef Feature) const override;
|
||||
bool validateCpuIs(StringRef Name) const override;
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo {
|
||||
|
||||
@@ -220,6 +220,10 @@ public:
|
||||
return RegName.equals("esp") || RegName.equals("rsp");
|
||||
}
|
||||
|
||||
bool supportsCpuSupports() const override { return true; }
|
||||
bool supportsCpuIs() const override { return true; }
|
||||
bool supportsCpuInit() const override { return true; }
|
||||
|
||||
bool validateCpuSupports(StringRef FeatureStr) const override;
|
||||
|
||||
bool validateCpuIs(StringRef FeatureStr) const override;
|
||||
|
||||
@@ -14053,11 +14053,11 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
|
||||
|
||||
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E) {
|
||||
if (BuiltinID == X86::BI__builtin_cpu_is)
|
||||
if (BuiltinID == Builtin::BI__builtin_cpu_is)
|
||||
return EmitX86CpuIs(E);
|
||||
if (BuiltinID == X86::BI__builtin_cpu_supports)
|
||||
if (BuiltinID == Builtin::BI__builtin_cpu_supports)
|
||||
return EmitX86CpuSupports(E);
|
||||
if (BuiltinID == X86::BI__builtin_cpu_init)
|
||||
if (BuiltinID == Builtin::BI__builtin_cpu_init)
|
||||
return EmitX86CpuInit();
|
||||
|
||||
// Handle MSVC intrinsics before argument evaluation to prevent double
|
||||
@@ -16545,6 +16545,43 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
|
||||
switch (BuiltinID) {
|
||||
default: return nullptr;
|
||||
|
||||
case Builtin::BI__builtin_cpu_is: {
|
||||
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
|
||||
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
|
||||
unsigned NumCPUID = StringSwitch<unsigned>(CPUStr)
|
||||
#define PPC_LNX_CPU(Name, NumericID) .Case(Name, NumericID)
|
||||
#include "llvm/TargetParser/PPCTargetParser.def"
|
||||
.Default(-1U);
|
||||
assert(NumCPUID < -1U && "Invalid CPU name. Missed by SemaChecking?");
|
||||
Value *Op0 = llvm::ConstantInt::get(Int32Ty, PPC_FAWORD_CPUID);
|
||||
llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld);
|
||||
Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_is");
|
||||
return Builder.CreateICmpEQ(TheCall,
|
||||
llvm::ConstantInt::get(Int32Ty, NumCPUID));
|
||||
}
|
||||
case Builtin::BI__builtin_cpu_supports: {
|
||||
unsigned FeatureWord;
|
||||
unsigned BitMask;
|
||||
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
|
||||
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
|
||||
std::tie(FeatureWord, BitMask) =
|
||||
StringSwitch<std::pair<unsigned, unsigned>>(CPUStr)
|
||||
#define PPC_LNX_FEATURE(Name, Description, EnumName, Bitmask, FA_WORD) \
|
||||
.Case(Name, {FA_WORD, Bitmask})
|
||||
#include "llvm/TargetParser/PPCTargetParser.def"
|
||||
.Default({0, 0});
|
||||
assert(BitMask && "Invalid target feature string. Missed by SemaChecking?");
|
||||
Value *Op0 = llvm::ConstantInt::get(Int32Ty, FeatureWord);
|
||||
llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld);
|
||||
Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_supports");
|
||||
Value *Mask =
|
||||
Builder.CreateAnd(TheCall, llvm::ConstantInt::get(Int32Ty, BitMask));
|
||||
return Builder.CreateICmpNE(Mask, llvm::Constant::getNullValue(Int32Ty));
|
||||
#undef PPC_FAWORD_HWCAP
|
||||
#undef PPC_FAWORD_HWCAP2
|
||||
#undef PPC_FAWORD_CPUID
|
||||
}
|
||||
|
||||
// __builtin_ppc_get_timebase is GCC 4.8+'s PowerPC-specific name for what we
|
||||
// call __builtin_readcyclecounter.
|
||||
case PPC::BI__builtin_ppc_get_timebase:
|
||||
|
||||
@@ -2143,6 +2143,48 @@ static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// SemaBuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *).
|
||||
/// This checks that the target supports the builtin and that the string
|
||||
/// argument is constant and valid.
|
||||
static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
|
||||
const TargetInfo *AuxTI, unsigned BuiltinID) {
|
||||
assert((BuiltinID == Builtin::BI__builtin_cpu_supports ||
|
||||
BuiltinID == Builtin::BI__builtin_cpu_is) &&
|
||||
"Expecting __builtin_cpu_...");
|
||||
|
||||
bool IsCPUSupports = BuiltinID == Builtin::BI__builtin_cpu_supports;
|
||||
const TargetInfo *TheTI = &TI;
|
||||
auto SupportsBI = [=](const TargetInfo *TInfo) {
|
||||
return TInfo && ((IsCPUSupports && TInfo->supportsCpuSupports()) ||
|
||||
(!IsCPUSupports && TInfo->supportsCpuIs()));
|
||||
};
|
||||
if (!SupportsBI(&TI) && SupportsBI(AuxTI))
|
||||
TheTI = AuxTI;
|
||||
|
||||
if (IsCPUSupports && !TheTI->supportsCpuSupports())
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
|
||||
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
|
||||
if (!IsCPUSupports && !TheTI->supportsCpuIs())
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
|
||||
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
|
||||
|
||||
Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts();
|
||||
// Check if the argument is a string literal.
|
||||
if (!isa<StringLiteral>(Arg))
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
|
||||
<< Arg->getSourceRange();
|
||||
|
||||
// Check the contents of the string.
|
||||
StringRef Feature = cast<StringLiteral>(Arg)->getString();
|
||||
if (IsCPUSupports && !TheTI->validateCpuSupports(Feature))
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
|
||||
<< Arg->getSourceRange();
|
||||
if (!IsCPUSupports && !TheTI->validateCpuIs(Feature))
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
|
||||
<< Arg->getSourceRange();
|
||||
return false;
|
||||
}
|
||||
|
||||
ExprResult
|
||||
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
||||
CallExpr *TheCall) {
|
||||
@@ -2171,6 +2213,19 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
||||
|
||||
FPOptions FPO;
|
||||
switch (BuiltinID) {
|
||||
case Builtin::BI__builtin_cpu_supports:
|
||||
case Builtin::BI__builtin_cpu_is:
|
||||
if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall,
|
||||
Context.getAuxTargetInfo(), BuiltinID))
|
||||
return ExprError();
|
||||
break;
|
||||
case Builtin::BI__builtin_cpu_init:
|
||||
if (!Context.getTargetInfo().supportsCpuInit()) {
|
||||
Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
|
||||
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
|
||||
return ExprError();
|
||||
}
|
||||
break;
|
||||
case Builtin::BI__builtin___CFStringMakeConstantString:
|
||||
// CFStringMakeConstantString is currently not implemented for GOFF (i.e.,
|
||||
// on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported
|
||||
@@ -6216,47 +6271,6 @@ bool Sema::CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *).
|
||||
/// This checks that the target supports __builtin_cpu_supports and
|
||||
/// that the string argument is constant and valid.
|
||||
static bool SemaBuiltinCpuSupports(Sema &S, const TargetInfo &TI,
|
||||
CallExpr *TheCall) {
|
||||
Expr *Arg = TheCall->getArg(0);
|
||||
|
||||
// Check if the argument is a string literal.
|
||||
if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
|
||||
<< Arg->getSourceRange();
|
||||
|
||||
// Check the contents of the string.
|
||||
StringRef Feature =
|
||||
cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
|
||||
if (!TI.validateCpuSupports(Feature))
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
|
||||
<< Arg->getSourceRange();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *).
|
||||
/// This checks that the target supports __builtin_cpu_is and
|
||||
/// that the string argument is constant and valid.
|
||||
static bool SemaBuiltinCpuIs(Sema &S, const TargetInfo &TI, CallExpr *TheCall) {
|
||||
Expr *Arg = TheCall->getArg(0);
|
||||
|
||||
// Check if the argument is a string literal.
|
||||
if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
|
||||
<< Arg->getSourceRange();
|
||||
|
||||
// Check the contents of the string.
|
||||
StringRef Feature =
|
||||
cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
|
||||
if (!TI.validateCpuIs(Feature))
|
||||
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
|
||||
<< Arg->getSourceRange();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the rounding mode is legal.
|
||||
bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
|
||||
// Indicates if this instruction has rounding control or just SAE.
|
||||
@@ -6731,12 +6745,6 @@ static bool isX86_32Builtin(unsigned BuiltinID) {
|
||||
|
||||
bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
|
||||
CallExpr *TheCall) {
|
||||
if (BuiltinID == X86::BI__builtin_cpu_supports)
|
||||
return SemaBuiltinCpuSupports(*this, TI, TheCall);
|
||||
|
||||
if (BuiltinID == X86::BI__builtin_cpu_is)
|
||||
return SemaBuiltinCpuIs(*this, TI, TheCall);
|
||||
|
||||
// Check for 32-bit only builtins on a 64-bit target.
|
||||
const llvm::Triple &TT = TI.getTriple();
|
||||
if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID))
|
||||
|
||||
@@ -1,12 +1,42 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm < %s| FileCheck %s
|
||||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s | \
|
||||
// RUN: FileCheck %s --check-prefix=CHECK-X86
|
||||
// RUN: %clang_cc1 -triple ppc64le-linux-gnu -emit-llvm -o - %s | FileCheck %s \
|
||||
// RUN: --check-prefix=CHECK-PPC
|
||||
|
||||
#ifndef __PPC__
|
||||
|
||||
// Test that we have the structure definition, the gep offsets, the name of the
|
||||
// global, the bit grab, and the icmp correct.
|
||||
extern void a(const char *);
|
||||
|
||||
// CHECK: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] }
|
||||
// CHECK: @__cpu_features2 = external dso_local global [3 x i32]
|
||||
|
||||
// CHECK-X86-LABEL: define dso_local i32 @main(
|
||||
// CHECK-X86-SAME: ) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-X86-NEXT: entry:
|
||||
// CHECK-X86-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
|
||||
// CHECK-X86-NEXT: store i32 0, ptr [[RETVAL]], align 4
|
||||
// CHECK-X86-NEXT: call void @__cpu_indicator_init()
|
||||
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0), align 4
|
||||
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 256
|
||||
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 256
|
||||
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
||||
// CHECK-X86-NEXT: br i1 [[TMP3]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
||||
// CHECK-X86: if.then:
|
||||
// CHECK-X86-NEXT: call void @a(ptr noundef @.str)
|
||||
// CHECK-X86-NEXT: br label [[IF_END]]
|
||||
// CHECK-X86: if.end:
|
||||
// CHECK-X86-NEXT: [[TMP4:%.*]] = load i32, ptr @__cpu_features2, align 4
|
||||
// CHECK-X86-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], 1
|
||||
// CHECK-X86-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 1
|
||||
// CHECK-X86-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]]
|
||||
// CHECK-X86-NEXT: br i1 [[TMP7]], label [[IF_THEN1:%.*]], label [[IF_END2:%.*]]
|
||||
// CHECK-X86: if.then1:
|
||||
// CHECK-X86-NEXT: call void @a(ptr noundef @.str.1)
|
||||
// CHECK-X86-NEXT: br label [[IF_END2]]
|
||||
// CHECK-X86: if.end2:
|
||||
// CHECK-X86-NEXT: ret i32 0
|
||||
//
|
||||
int main(void) {
|
||||
__builtin_cpu_init();
|
||||
|
||||
@@ -15,38 +45,117 @@ int main(void) {
|
||||
if (__builtin_cpu_supports("sse4.2"))
|
||||
a("sse4.2");
|
||||
|
||||
// CHECK: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0)
|
||||
// CHECK: [[AND:%[^ ]+]] = and i32 [[LOAD]], 256
|
||||
// CHECK: = icmp eq i32 [[AND]], 256
|
||||
|
||||
if (__builtin_cpu_supports("gfni"))
|
||||
a("gfni");
|
||||
|
||||
// CHECK: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_features2
|
||||
// CHECK: [[AND:%[^ ]+]] = and i32 [[LOAD]], 1
|
||||
// CHECK: = icmp eq i32 [[AND]], 1
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// CHECK: declare dso_local void @__cpu_indicator_init()
|
||||
|
||||
// CHECK-LABEL: define{{.*}} @baseline(
|
||||
// CHECK: [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 1)
|
||||
// CHECK-NEXT: and i32 [[LOAD]], -2147483648
|
||||
// CHECK-X86-LABEL: define dso_local i32 @baseline(
|
||||
// CHECK-X86-SAME: ) #[[ATTR0]] {
|
||||
// CHECK-X86-NEXT: entry:
|
||||
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 1), align 4
|
||||
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], -2147483648
|
||||
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], -2147483648
|
||||
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
||||
// CHECK-X86-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32
|
||||
// CHECK-X86-NEXT: ret i32 [[CONV]]
|
||||
//
|
||||
int baseline() { return __builtin_cpu_supports("x86-64"); }
|
||||
|
||||
// CHECK-LABEL: define{{.*}} @v2(
|
||||
// CHECK: [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2)
|
||||
// CHECK-NEXT: and i32 [[LOAD]], 1
|
||||
// CHECK-X86-LABEL: define dso_local i32 @v2(
|
||||
// CHECK-X86-SAME: ) #[[ATTR0]] {
|
||||
// CHECK-X86-NEXT: entry:
|
||||
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
|
||||
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 1
|
||||
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1
|
||||
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
||||
// CHECK-X86-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32
|
||||
// CHECK-X86-NEXT: ret i32 [[CONV]]
|
||||
//
|
||||
int v2() { return __builtin_cpu_supports("x86-64-v2"); }
|
||||
|
||||
// CHECK-LABEL: define{{.*}} @v3(
|
||||
// CHECK: [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2)
|
||||
// CHECK-NEXT: and i32 [[LOAD]], 2
|
||||
// CHECK-X86-LABEL: define dso_local i32 @v3(
|
||||
// CHECK-X86-SAME: ) #[[ATTR0]] {
|
||||
// CHECK-X86-NEXT: entry:
|
||||
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
|
||||
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 2
|
||||
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 2
|
||||
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
||||
// CHECK-X86-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32
|
||||
// CHECK-X86-NEXT: ret i32 [[CONV]]
|
||||
//
|
||||
int v3() { return __builtin_cpu_supports("x86-64-v3"); }
|
||||
|
||||
// CHECK-LABEL: define{{.*}} @v4(
|
||||
// CHECK: [[LOAD:%.*]] = load i32, ptr getelementptr inbounds ([[[#]] x i32], ptr @__cpu_features2, i32 0, i32 2)
|
||||
// CHECK-NEXT: and i32 [[LOAD]], 4
|
||||
// CHECK-X86-LABEL: define dso_local i32 @v4(
|
||||
// CHECK-X86-SAME: ) #[[ATTR0]] {
|
||||
// CHECK-X86-NEXT: entry:
|
||||
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
|
||||
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 4
|
||||
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 4
|
||||
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
||||
// CHECK-X86-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32
|
||||
// CHECK-X86-NEXT: ret i32 [[CONV]]
|
||||
//
|
||||
int v4() { return __builtin_cpu_supports("x86-64-v4"); }
|
||||
#else
|
||||
// CHECK-PPC-LABEL: define dso_local signext i32 @test(
|
||||
// CHECK-PPC-SAME: i32 noundef signext [[A:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-PPC-NEXT: entry:
|
||||
// CHECK-PPC-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
|
||||
// CHECK-PPC-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
|
||||
// CHECK-PPC-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-PPC-NEXT: [[CPU_SUPPORTS:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 2)
|
||||
// CHECK-PPC-NEXT: [[TMP0:%.*]] = and i32 [[CPU_SUPPORTS]], 8388608
|
||||
// CHECK-PPC-NEXT: [[TMP1:%.*]] = icmp ne i32 [[TMP0]], 0
|
||||
// CHECK-PPC-NEXT: br i1 [[TMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
||||
// CHECK-PPC: if.then:
|
||||
// CHECK-PPC-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
||||
// CHECK-PPC-NEXT: store i32 [[TMP2]], ptr [[RETVAL]], align 4
|
||||
// CHECK-PPC-NEXT: br label [[RETURN:%.*]]
|
||||
// CHECK-PPC: if.else:
|
||||
// CHECK-PPC-NEXT: [[CPU_SUPPORTS1:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 1)
|
||||
// CHECK-PPC-NEXT: [[TMP3:%.*]] = and i32 [[CPU_SUPPORTS1]], 67108864
|
||||
// CHECK-PPC-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 0
|
||||
// CHECK-PPC-NEXT: br i1 [[TMP4]], label [[IF_THEN2:%.*]], label [[IF_ELSE3:%.*]]
|
||||
// CHECK-PPC: if.then2:
|
||||
// CHECK-PPC-NEXT: [[TMP5:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
||||
// CHECK-PPC-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 5
|
||||
// CHECK-PPC-NEXT: store i32 [[SUB]], ptr [[RETVAL]], align 4
|
||||
// CHECK-PPC-NEXT: br label [[RETURN]]
|
||||
// CHECK-PPC: if.else3:
|
||||
// CHECK-PPC-NEXT: [[CPU_IS:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
|
||||
// CHECK-PPC-NEXT: [[TMP6:%.*]] = icmp eq i32 [[CPU_IS]], 39
|
||||
// CHECK-PPC-NEXT: br i1 [[TMP6]], label [[IF_THEN4:%.*]], label [[IF_END:%.*]]
|
||||
// CHECK-PPC: if.then4:
|
||||
// CHECK-PPC-NEXT: [[TMP7:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
||||
// CHECK-PPC-NEXT: [[TMP8:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
||||
// CHECK-PPC-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP7]], [[TMP8]]
|
||||
// CHECK-PPC-NEXT: store i32 [[ADD]], ptr [[RETVAL]], align 4
|
||||
// CHECK-PPC-NEXT: br label [[RETURN]]
|
||||
// CHECK-PPC: if.end:
|
||||
// CHECK-PPC-NEXT: br label [[IF_END5:%.*]]
|
||||
// CHECK-PPC: if.end5:
|
||||
// CHECK-PPC-NEXT: br label [[IF_END6:%.*]]
|
||||
// CHECK-PPC: if.end6:
|
||||
// CHECK-PPC-NEXT: [[TMP9:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
||||
// CHECK-PPC-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP9]], 5
|
||||
// CHECK-PPC-NEXT: store i32 [[ADD7]], ptr [[RETVAL]], align 4
|
||||
// CHECK-PPC-NEXT: br label [[RETURN]]
|
||||
// CHECK-PPC: return:
|
||||
// CHECK-PPC-NEXT: [[TMP10:%.*]] = load i32, ptr [[RETVAL]], align 4
|
||||
// CHECK-PPC-NEXT: ret i32 [[TMP10]]
|
||||
//
|
||||
int test(int a) {
|
||||
if (__builtin_cpu_supports("arch_3_00")) // HWCAP2
|
||||
return a;
|
||||
else if (__builtin_cpu_supports("mmu")) // HWCAP
|
||||
return a - 5;
|
||||
else if (__builtin_cpu_is("power7")) // CPUID
|
||||
return a + a;
|
||||
return a + 5;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux-gnu -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -triple powerpc64le-linux-gnu -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -triple aarch64-linux-gnu -verify %s
|
||||
|
||||
extern void a(const char *);
|
||||
|
||||
@@ -27,11 +27,13 @@ int main(void) {
|
||||
(void)__builtin_cpu_supports("x86-64-v4");
|
||||
(void)__builtin_cpu_supports("x86-64-v5"); // expected-error {{invalid cpu feature string for builtin}}
|
||||
#else
|
||||
if (__builtin_cpu_supports("vsx")) // expected-error {{use of unknown builtin}}
|
||||
if (__builtin_cpu_supports("aes")) // expected-error {{builtin is not supported on this target}}
|
||||
a("vsx");
|
||||
|
||||
if (__builtin_cpu_is("pwr9")) // expected-error {{use of unknown builtin}}
|
||||
if (__builtin_cpu_is("cortex-x3")) // expected-error {{builtin is not supported on this target}}
|
||||
a("pwr9");
|
||||
|
||||
__builtin_cpu_init(); // expected-error {{builtin is not supported on this target}}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -215,6 +215,15 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.".
|
||||
[llvm_float_ty],
|
||||
[llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty],
|
||||
[IntrNoMem]>;
|
||||
// Load of a value provided by the system library at a fixed address. Used for
|
||||
// accessing things like the HWCAP word provided by Glibc. The immediate
|
||||
// argument is not an address but a value defined in
|
||||
// include/llvm/TargetParser/PPCTargetParser.def. Each of the values provided
|
||||
// by Glibc is a 32-bit word.
|
||||
def int_ppc_fixed_addr_ld
|
||||
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty],
|
||||
[IntrInaccessibleMemOnly, ImmArg<ArgIndex<0>>]>;
|
||||
|
||||
}
|
||||
|
||||
let TargetPrefix = "ppc" in { // All PPC intrinsics start with "llvm.ppc.".
|
||||
|
||||
129
llvm/include/llvm/TargetParser/PPCTargetParser.def
Normal file
129
llvm/include/llvm/TargetParser/PPCTargetParser.def
Normal file
@@ -0,0 +1,129 @@
|
||||
//===- PPCTargetParser.def - PPC target parsing defines ---------*- C++ -*-===//
|
||||
//
|
||||
// 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 file provides defines to build up the PPC target parser's logic.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// NOTE: NO INCLUDE GUARD DESIRED!
|
||||
|
||||
#ifdef PPC_TGT_PARSER_UNDEF_MACROS
|
||||
#undef PPC_LNX_FEATURE
|
||||
#undef PPC_LNX_CPU
|
||||
#undef PPC_FAWORD_HWCAP
|
||||
#undef PPC_FAWORD_HWCAP2
|
||||
#undef PPC_FAWORD_CPUID
|
||||
#undef PPC_HWCAP_OFFSET_LE32
|
||||
#undef PPC_HWCAP_OFFSET_LE64
|
||||
#undef PPC_HWCAP_OFFSET_BE32
|
||||
#undef PPC_HWCAP_OFFSET_BE64
|
||||
#undef PPC_HWCAP2_OFFSET_LE32
|
||||
#undef PPC_HWCAP2_OFFSET_LE64
|
||||
#undef PPC_HWCAP2_OFFSET_BE32
|
||||
#undef PPC_HWCAP2_OFFSET_BE64
|
||||
#undef PPC_CPUID_OFFSET_LE32
|
||||
#undef PPC_CPUID_OFFSET_LE64
|
||||
#undef PPC_CPUID_OFFSET_BE32
|
||||
#undef PPC_CPUID_OFFSET_BE64
|
||||
#else
|
||||
#ifndef PPC_LNX_FEATURE
|
||||
#define PPC_LNX_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN)
|
||||
#endif
|
||||
#ifndef PPC_LNX_CPU
|
||||
#define PPC_LNX_CPU(NAME, NUM)
|
||||
#endif
|
||||
#ifndef PPC_FAWORD_HWCAP
|
||||
#define PPC_FAWORD_HWCAP 1
|
||||
#endif
|
||||
#ifndef PPC_FAWORD_HWCAP2
|
||||
#define PPC_FAWORD_HWCAP2 2
|
||||
#endif
|
||||
#ifndef PPC_FAWORD_CPUID
|
||||
#define PPC_FAWORD_CPUID 3
|
||||
#endif
|
||||
|
||||
// PPC_LNX_FEATURE(Name, Description, EnumName, BitMask, PPC_FAWORD_WORD)
|
||||
PPC_LNX_FEATURE("4xxmac","4xx CPU has a Multiply Accumulator",PPCF_4XXMAC,0x02000000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("altivec","CPU has a SIMD/Vector Unit",PPCF_ALTIVEC,0x10000000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("arch_2_05","CPU supports ISA 205 (eg, POWER6)",PPCF_ARCH205,0x00001000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("arch_2_06","CPU supports ISA 206 (eg, POWER7)",PPCF_ARCH206,0x00000100,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("arch_2_07","CPU supports ISA 207 (eg, POWER8)",PPCF_ARCH207,0x80000000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("arch_3_00","CPU supports ISA 30 (eg, POWER9)",PPCF_ARCH30,0x00800000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("arch_3_1","CPU supports ISA 31 (eg, POWER10)",PPCF_ARCH31,0x00040000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("archpmu","CPU supports the set of compatible performance monitoring events",PPCF_ARCHPMU,0x00000040,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("booke","CPU supports the Embedded ISA category",PPCF_BOOKE,0x00008000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("cellbe","CPU has a CELL broadband engine",PPCF_CELLBE,0x00010000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("darn","CPU supports the darn (deliver a random number) instruction",PPCF_DARN,0x00200000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("dfp","CPU has a decimal floating point unit",PPCF_DFP,0x00000400,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("dscr","CPU supports the data stream control register",PPCF_DSCR,0x20000000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("ebb","CPU supports event base branching",PPCF_EBB,0x10000000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("efpdouble","CPU has a SPE double precision floating point unit",PPCF_EFPDOUBLE,0x00200000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("efpsingle","CPU has a SPE single precision floating point unit",PPCF_EFPSINGLE,0x00400000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("fpu","CPU has a floating point unit",PPCF_FPU,0x08000000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("htm","CPU has hardware transaction memory instructions",PPCF_HTM,0x40000000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("htm-nosc","Kernel aborts hardware transactions when a syscall is made",PPCF_HTM_NOSC,0x01000000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("htm-no-suspend","CPU supports hardware transaction memory but does not support the tsuspend instruction.",PPCF_HTM_NO_SUSPEND,0x00080000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("ic_snoop","CPU supports icache snooping capabilities",PPCF_IC_SNOOP,0x00002000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("ieee128","CPU supports 128-bit IEEE binary floating point instructions",PPCF_IEEE128,0x00400000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("isel","CPU supports the integer select instruction",PPCF_ISEL,0x08000000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("mma","CPU supports the matrix-multiply assist instructions",PPCF_MMA,0x00020000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("mmu","CPU has a memory management unit",PPCF_MMU,0x04000000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("notb","CPU does not have a timebase (eg, 601 and 403gx)",PPCF_NOTB,0x00100000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("pa6t","CPU supports the PA Semi 6T CORE ISA",PPCF_PA6T,0x00000800,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("power4","CPU supports ISA 200 (eg, POWER4)",PPCF_POWER4,0x00080000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("power5","CPU supports ISA 202 (eg, POWER5)",PPCF_POWER5,0x00040000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("power5+","CPU supports ISA 203 (eg, POWER5+)",PPCF_POWER5P,0x00020000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("power6x","CPU supports ISA 205 (eg, POWER6) extended opcodes mffgpr and mftgpr.",PPCF_POWER6X,0x00000200,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("ppc32","CPU supports 32-bit mode execution",PPCF_PPC32,0x80000000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("ppc601","CPU supports the old POWER ISA (eg, 601)",PPCF_PPC601,0x20000000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("ppc64","CPU supports 64-bit mode execution",PPCF_PPC64,0x40000000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("ppcle","CPU supports a little-endian mode that uses address swizzling",PPCF_PPCLE,0x00000001,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("scv","Kernel supports system call vectored",PPCF_SCV,0x00100000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("smt","CPU support simultaneous multi-threading",PPCF_SMT,0x00004000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("spe","CPU has a signal processing extension unit",PPCF_SPE,0x00800000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("tar","CPU supports the target address register",PPCF_TAR,0x04000000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("true_le","CPU supports true little-endian mode",PPCF_TRUE_LE,0x00000002,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("ucache","CPU has unified I/D cache",PPCF_UCACHE,0x01000000,PPC_FAWORD_HWCAP)
|
||||
PPC_LNX_FEATURE("vcrypto","CPU supports the vector cryptography instructions",PPCF_VCRYPTO,0x02000000,PPC_FAWORD_HWCAP2)
|
||||
PPC_LNX_FEATURE("vsx","CPU supports the vector-scalar extension",PPCF_VSX,0x00000080,PPC_FAWORD_HWCAP)
|
||||
|
||||
// PPC_LNX_CPU(Name, NumericID)
|
||||
PPC_LNX_CPU("power4",32)
|
||||
PPC_LNX_CPU("ppc970",33)
|
||||
PPC_LNX_CPU("power5",34)
|
||||
PPC_LNX_CPU("power5+",35)
|
||||
PPC_LNX_CPU("power6",36)
|
||||
PPC_LNX_CPU("ppc-cell-be",37)
|
||||
PPC_LNX_CPU("power6x",38)
|
||||
PPC_LNX_CPU("power7",39)
|
||||
PPC_LNX_CPU("ppca2",40)
|
||||
PPC_LNX_CPU("ppc405",41)
|
||||
PPC_LNX_CPU("ppc440",42)
|
||||
PPC_LNX_CPU("ppc464",43)
|
||||
PPC_LNX_CPU("ppc476",44)
|
||||
PPC_LNX_CPU("power8",45)
|
||||
PPC_LNX_CPU("power9",46)
|
||||
PPC_LNX_CPU("power10",47)
|
||||
#ifdef PPC_LNX_DEFINE_OFFSETS
|
||||
# define PPC_HWCAP_OFFSET_LE32 -0x703C
|
||||
# define PPC_HWCAP_OFFSET_LE64 -0x7064
|
||||
# define PPC_HWCAP_OFFSET_BE32 -0x7040
|
||||
# define PPC_HWCAP_OFFSET_BE64 -0x7068
|
||||
# define PPC_HWCAP2_OFFSET_LE32 -0x7040
|
||||
# define PPC_HWCAP2_OFFSET_LE64 -0x7068
|
||||
# define PPC_HWCAP2_OFFSET_BE32 -0x703C
|
||||
# define PPC_HWCAP2_OFFSET_BE64 -0x7064
|
||||
# define PPC_CPUID_OFFSET_LE32 -0x7034
|
||||
# define PPC_CPUID_OFFSET_LE64 -0x705C
|
||||
# define PPC_CPUID_OFFSET_BE32 -0x7034
|
||||
# define PPC_CPUID_OFFSET_BE64 -0x705C
|
||||
#endif
|
||||
#undef PPC_LNX_DEFINE_OFFSETS
|
||||
#undef PPC_LNX_FEATURE
|
||||
#undef PPC_LNX_CPU
|
||||
#endif // !PPC_TGT_PARSER_UNDEF_MACROS
|
||||
@@ -1821,6 +1821,14 @@ void PPCLinuxAsmPrinter::emitEndOfAsmFile(Module &M) {
|
||||
PPCTargetStreamer *TS =
|
||||
static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer());
|
||||
|
||||
// If we are using any values provided by Glibc at fixed addresses,
|
||||
// we need to ensure that the Glibc used at link time actually provides
|
||||
// those values. All versions of Glibc that do will define the symbol
|
||||
// named "__parse_hwcap_and_convert_at_platform".
|
||||
if (static_cast<const PPCTargetMachine &>(TM).hasGlibcHWCAPAccess())
|
||||
OutStreamer->emitSymbolValue(
|
||||
GetExternalSymbolSymbol("__parse_hwcap_and_convert_at_platform"),
|
||||
MAI->getCodePointerSize());
|
||||
emitGNUAttributes(M);
|
||||
|
||||
if (!TOC.empty()) {
|
||||
|
||||
@@ -1079,6 +1079,7 @@ bool PPCInstrInfo::isReallyTriviallyReMaterializable(
|
||||
case PPC::ADDIStocHA8:
|
||||
case PPC::ADDItocL:
|
||||
case PPC::LOAD_STACK_GUARD:
|
||||
case PPC::PPCLdFixedAddr:
|
||||
case PPC::XXLXORz:
|
||||
case PPC::XXLXORspz:
|
||||
case PPC::XXLXORdpz:
|
||||
@@ -3099,6 +3100,46 @@ bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
||||
.addReg(Reg);
|
||||
return true;
|
||||
}
|
||||
case PPC::PPCLdFixedAddr: {
|
||||
assert(Subtarget.getTargetTriple().isOSGlibc() &&
|
||||
"Only targets with Glibc expected to contain PPCLdFixedAddr");
|
||||
int64_t Offset = 0;
|
||||
const unsigned Reg = Subtarget.isPPC64() ? PPC::X13 : PPC::R2;
|
||||
MI.setDesc(get(PPC::LWZ));
|
||||
uint64_t FAType = MI.getOperand(1).getImm();
|
||||
#undef PPC_LNX_FEATURE
|
||||
#undef PPC_LNX_CPU
|
||||
#define PPC_LNX_DEFINE_OFFSETS
|
||||
#include "llvm/TargetParser/PPCTargetParser.def"
|
||||
bool IsLE = Subtarget.isLittleEndian();
|
||||
bool Is64 = Subtarget.isPPC64();
|
||||
if (FAType == PPC_FAWORD_HWCAP) {
|
||||
if (IsLE)
|
||||
Offset = Is64 ? PPC_HWCAP_OFFSET_LE64 : PPC_HWCAP_OFFSET_LE32;
|
||||
else
|
||||
Offset = Is64 ? PPC_HWCAP_OFFSET_BE64 : PPC_HWCAP_OFFSET_BE32;
|
||||
} else if (FAType == PPC_FAWORD_HWCAP2) {
|
||||
if (IsLE)
|
||||
Offset = Is64 ? PPC_HWCAP2_OFFSET_LE64 : PPC_HWCAP2_OFFSET_LE32;
|
||||
else
|
||||
Offset = Is64 ? PPC_HWCAP2_OFFSET_BE64 : PPC_HWCAP2_OFFSET_BE32;
|
||||
} else if (FAType == PPC_FAWORD_CPUID) {
|
||||
if (IsLE)
|
||||
Offset = Is64 ? PPC_CPUID_OFFSET_LE64 : PPC_CPUID_OFFSET_LE32;
|
||||
else
|
||||
Offset = Is64 ? PPC_CPUID_OFFSET_BE64 : PPC_CPUID_OFFSET_BE32;
|
||||
}
|
||||
assert(Offset && "Do not know the offset for this fixed addr load");
|
||||
MI.removeOperand(1);
|
||||
Subtarget.getTargetMachine().setGlibcHWCAPAccess();
|
||||
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
|
||||
.addImm(Offset)
|
||||
.addReg(Reg);
|
||||
return true;
|
||||
#define PPC_TGT_PARSER_UNDEF_MACROS
|
||||
#include "llvm/TargetParser/PPCTargetParser.def"
|
||||
#undef PPC_TGT_PARSER_UNDEF_MACROS
|
||||
}
|
||||
case PPC::DFLOADf32:
|
||||
case PPC::DFLOADf64:
|
||||
case PPC::DFSTOREf32:
|
||||
|
||||
@@ -4830,6 +4830,9 @@ def RLWNMbm : PPCAsmPseudo<"rlwnm $rA, $rS, $n, $b",
|
||||
(ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
|
||||
def RLWNMbm_rec : PPCAsmPseudo<"rlwnm. $rA, $rS, $n, $b",
|
||||
(ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
|
||||
def PPCLdFixedAddr :
|
||||
PPCPostRAExpPseudo<(outs gprc:$rT), (ins i32imm:$imm), "#FA_LOAD",
|
||||
[(set i32:$rT, (int_ppc_fixed_addr_ld timm:$imm))]>;
|
||||
|
||||
// These generic branch instruction forms are used for the assembler parser only.
|
||||
// Defs and Uses are conservative, since we don't know the BO value.
|
||||
|
||||
@@ -32,6 +32,7 @@ private:
|
||||
std::unique_ptr<TargetLoweringObjectFile> TLOF;
|
||||
PPCABI TargetABI;
|
||||
Endian Endianness = Endian::NOT_DETECTED;
|
||||
mutable bool HasGlibcHWCAPAccess = false;
|
||||
|
||||
mutable StringMap<std::unique_ptr<PPCSubtarget>> SubtargetMap;
|
||||
|
||||
@@ -64,6 +65,8 @@ public:
|
||||
const TargetSubtargetInfo *STI) const override;
|
||||
|
||||
bool isELFv2ABI() const { return TargetABI == PPC_ABI_ELFv2; }
|
||||
bool hasGlibcHWCAPAccess() const { return HasGlibcHWCAPAccess; }
|
||||
void setGlibcHWCAPAccess(bool Val = true) const { HasGlibcHWCAPAccess = Val; }
|
||||
bool isPPC64() const {
|
||||
const Triple &TT = getTargetTriple();
|
||||
return (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le);
|
||||
|
||||
114
llvm/test/CodeGen/PowerPC/cpu-supports.ll
Normal file
114
llvm/test/CodeGen/PowerPC/cpu-supports.ll
Normal file
@@ -0,0 +1,114 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: llc -mcpu=pwr9 -ppc-asm-full-reg-names \
|
||||
; RUN: -mtriple=powerpc64-linux-gnu < %s | FileCheck %s \
|
||||
; RUN: -check-prefix=BE64
|
||||
; RUN: llc -mcpu=pwr9 -ppc-asm-full-reg-names \
|
||||
; RUN: -mtriple=powerpc-linux-gnu < %s | FileCheck %s \
|
||||
; RUN: -check-prefix=BE32
|
||||
; RUN: llc -mcpu=pwr9 -ppc-asm-full-reg-names \
|
||||
; RUN: -mtriple=powerpc64le-linux-gnu < %s | FileCheck %s \
|
||||
; RUN: -check-prefix=LE
|
||||
define dso_local signext i32 @test(i32 noundef signext %a) local_unnamed_addr #0 {
|
||||
; BE64-LABEL: test:
|
||||
; BE64: # %bb.0: # %entry
|
||||
; BE64-NEXT: lwz r4, -28772(r13)
|
||||
; BE64-NEXT: andis. r4, r4, 128
|
||||
; BE64-NEXT: bne cr0, .LBB0_3
|
||||
; BE64-NEXT: # %bb.1: # %if.else
|
||||
; BE64-NEXT: lwz r4, -28776(r13)
|
||||
; BE64-NEXT: andis. r4, r4, 1024
|
||||
; BE64-NEXT: bne cr0, .LBB0_4
|
||||
; BE64-NEXT: # %bb.2: # %if.else3
|
||||
; BE64-NEXT: lwz r4, -28764(r13)
|
||||
; BE64-NEXT: cmplwi r4, 39
|
||||
; BE64-NEXT: addi r4, r3, 5
|
||||
; BE64-NEXT: slwi r3, r3, 1
|
||||
; BE64-NEXT: iseleq r3, r3, r4
|
||||
; BE64-NEXT: .LBB0_3: # %return
|
||||
; BE64-NEXT: extsw r3, r3
|
||||
; BE64-NEXT: blr
|
||||
; BE64-NEXT: .LBB0_4: # %if.then2
|
||||
; BE64-NEXT: addi r3, r3, -5
|
||||
; BE64-NEXT: extsw r3, r3
|
||||
; BE64-NEXT: blr
|
||||
; BE64: .quad __parse_hwcap_and_convert_at_platform
|
||||
;
|
||||
; BE32-LABEL: test:
|
||||
; BE32: # %bb.0: # %entry
|
||||
; BE32-NEXT: lwz r4, -28732(r2)
|
||||
; BE32-NEXT: andis. r4, r4, 128
|
||||
; BE32-NEXT: bnelr cr0
|
||||
; BE32-NEXT: # %bb.1: # %if.else
|
||||
; BE32-NEXT: lwz r4, -28736(r2)
|
||||
; BE32-NEXT: andis. r4, r4, 1024
|
||||
; BE32-NEXT: bne cr0, .LBB0_3
|
||||
; BE32-NEXT: # %bb.2: # %if.else3
|
||||
; BE32-NEXT: lwz r4, -28724(r2)
|
||||
; BE32-NEXT: cmplwi r4, 39
|
||||
; BE32-NEXT: addi r4, r3, 5
|
||||
; BE32-NEXT: slwi r3, r3, 1
|
||||
; BE32-NEXT: iseleq r3, r3, r4
|
||||
; BE32-NEXT: blr
|
||||
; BE32-NEXT: .LBB0_3: # %if.then2
|
||||
; BE32-NEXT: addi r3, r3, -5
|
||||
; BE32-NEXT: blr
|
||||
; BE32: .long __parse_hwcap_and_convert_at_platform
|
||||
;
|
||||
; LE-LABEL: test:
|
||||
; LE: # %bb.0: # %entry
|
||||
; LE-NEXT: lwz r4, -28776(r13)
|
||||
; LE-NEXT: andis. r4, r4, 128
|
||||
; LE-NEXT: bne cr0, .LBB0_3
|
||||
; LE-NEXT: # %bb.1: # %if.else
|
||||
; LE-NEXT: lwz r4, -28772(r13)
|
||||
; LE-NEXT: andis. r4, r4, 1024
|
||||
; LE-NEXT: bne cr0, .LBB0_4
|
||||
; LE-NEXT: # %bb.2: # %if.else3
|
||||
; LE-NEXT: lwz r4, -28764(r13)
|
||||
; LE-NEXT: cmplwi r4, 39
|
||||
; LE-NEXT: addi r4, r3, 5
|
||||
; LE-NEXT: slwi r3, r3, 1
|
||||
; LE-NEXT: iseleq r3, r3, r4
|
||||
; LE-NEXT: .LBB0_3: # %return
|
||||
; LE-NEXT: extsw r3, r3
|
||||
; LE-NEXT: blr
|
||||
; LE-NEXT: .LBB0_4: # %if.then2
|
||||
; LE-NEXT: addi r3, r3, -5
|
||||
; LE-NEXT: extsw r3, r3
|
||||
; LE-NEXT: blr
|
||||
; LE: .quad __parse_hwcap_and_convert_at_platform
|
||||
entry:
|
||||
%cpu_supports = tail call i32 @llvm.ppc.fixed.addr.ld(i32 2)
|
||||
%0 = and i32 %cpu_supports, 8388608
|
||||
%.not = icmp eq i32 %0, 0
|
||||
br i1 %.not, label %if.else, label %return
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%cpu_supports1 = tail call i32 @llvm.ppc.fixed.addr.ld(i32 1)
|
||||
%1 = and i32 %cpu_supports1, 67108864
|
||||
%.not12 = icmp eq i32 %1, 0
|
||||
br i1 %.not12, label %if.else3, label %if.then2
|
||||
|
||||
if.then2: ; preds = %if.else
|
||||
%sub = add nsw i32 %a, -5
|
||||
br label %return
|
||||
|
||||
if.else3: ; preds = %if.else
|
||||
%cpu_is = tail call i32 @llvm.ppc.fixed.addr.ld(i32 3)
|
||||
%2 = icmp eq i32 %cpu_is, 39
|
||||
br i1 %2, label %if.then4, label %if.end6
|
||||
|
||||
if.then4: ; preds = %if.else3
|
||||
%add = shl nsw i32 %a, 1
|
||||
br label %return
|
||||
|
||||
if.end6: ; preds = %if.else3
|
||||
%add7 = add nsw i32 %a, 5
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry, %if.end6, %if.then4, %if.then2
|
||||
%retval.0 = phi i32 [ %sub, %if.then2 ], [ %add, %if.then4 ], [ %add7, %if.end6 ], [ %a, %entry ]
|
||||
ret i32 %retval.0
|
||||
}
|
||||
|
||||
declare i32 @llvm.ppc.fixed.addr.ld(i32 immarg) #1
|
||||
Reference in New Issue
Block a user