Skip to content

Commit 67c1c1d

Browse files
nemanjaiNemanja IvanovicNemanja Ivanovic
authored
[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 <[email protected]> Co-authored-by: Nemanja Ivanovic <[email protected]>
1 parent c177507 commit 67c1c1d

File tree

17 files changed

+589
-82
lines changed

17 files changed

+589
-82
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,26 @@ def RotateRight : BitInt8_16_32_64BuiltinsTemplate, Builtin {
727727
// FIXME: The builtins marked FunctionWithBuiltinPrefix below should be
728728
// merged with the library definitions. They are currently not because
729729
// the attributes are different.
730+
731+
// Builtins for checking CPU features based on the GCC builtins.
732+
def BuiltinCPUIs : Builtin {
733+
let Spellings = ["__builtin_cpu_is"];
734+
let Attributes = [NoThrow, Const];
735+
let Prototype = "bool(char const*)";
736+
}
737+
738+
def BuiltinCPUSupports : Builtin {
739+
let Spellings = ["__builtin_cpu_supports"];
740+
let Attributes = [NoThrow, Const];
741+
let Prototype = "bool(char const*)";
742+
}
743+
744+
def BuiltinCPUInit : Builtin {
745+
let Spellings = ["__builtin_cpu_init"];
746+
let Attributes = [NoThrow];
747+
let Prototype = "void()";
748+
}
749+
730750
def BuiltinCalloc : Builtin {
731751
let Spellings = ["__builtin_calloc"];
732752
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];

clang/include/clang/Basic/BuiltinsX86.def

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,6 @@
2626
# define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS)
2727
#endif
2828

29-
// Miscellaneous builtin for checking x86 cpu features.
30-
// TODO: Make this somewhat generic so that other backends
31-
// can use it?
32-
BUILTIN(__builtin_cpu_init, "v", "n")
33-
BUILTIN(__builtin_cpu_supports, "bcC*", "nc")
34-
BUILTIN(__builtin_cpu_is, "bcC*", "nc")
35-
3629
// Undefined Values
3730
//
3831
TARGET_BUILTIN(__builtin_ia32_undef128, "V2d", "ncV:128:", "")

clang/include/clang/Basic/TargetInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,12 @@ class TargetInfo : public TransferrableTargetInfo,
14321432
getTriple().isOSFreeBSD());
14331433
}
14341434

1435+
// Identify whether this target supports __builtin_cpu_supports and
1436+
// __builtin_cpu_is.
1437+
virtual bool supportsCpuSupports() const { return false; }
1438+
virtual bool supportsCpuIs() const { return false; }
1439+
virtual bool supportsCpuInit() const { return false; }
1440+
14351441
// Validate the contents of the __builtin_cpu_supports(const char*)
14361442
// argument.
14371443
virtual bool validateCpuSupports(StringRef Name) const { return false; }

clang/lib/Basic/Targets/PPC.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,3 +903,17 @@ ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
903903
return llvm::ArrayRef(BuiltinInfo,
904904
clang::PPC::LastTSBuiltin - Builtin::FirstTSBuiltin);
905905
}
906+
907+
bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const {
908+
#define PPC_LNX_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN) .Case(NAME, true)
909+
return llvm::StringSwitch<bool>(FeatureStr)
910+
#include "llvm/TargetParser/PPCTargetParser.def"
911+
.Default(false);
912+
}
913+
914+
bool PPCTargetInfo::validateCpuIs(StringRef CPUName) const {
915+
#define PPC_LNX_CPU(NAME, NUM) .Case(NAME, true)
916+
return llvm::StringSwitch<bool>(CPUName)
917+
#include "llvm/TargetParser/PPCTargetParser.def"
918+
.Default(false);
919+
}

clang/lib/Basic/Targets/PPC.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,13 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
359359
bool isSPRegName(StringRef RegName) const override {
360360
return RegName.equals("r1") || RegName.equals("x1");
361361
}
362+
363+
// We support __builtin_cpu_supports/__builtin_cpu_is on targets that
364+
// have Glibc since it is Glibc that provides the HWCAP[2] in the auxv.
365+
bool supportsCpuSupports() const override { return getTriple().isOSGlibc(); }
366+
bool supportsCpuIs() const override { return getTriple().isOSGlibc(); }
367+
bool validateCpuSupports(StringRef Feature) const override;
368+
bool validateCpuIs(StringRef Name) const override;
362369
};
363370

364371
class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo {

clang/lib/Basic/Targets/X86.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
220220
return RegName.equals("esp") || RegName.equals("rsp");
221221
}
222222

223+
bool supportsCpuSupports() const override { return true; }
224+
bool supportsCpuIs() const override { return true; }
225+
bool supportsCpuInit() const override { return true; }
226+
223227
bool validateCpuSupports(StringRef FeatureStr) const override;
224228

225229
bool validateCpuIs(StringRef FeatureStr) const override;

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14053,11 +14053,11 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
1405314053

1405414054
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
1405514055
const CallExpr *E) {
14056-
if (BuiltinID == X86::BI__builtin_cpu_is)
14056+
if (BuiltinID == Builtin::BI__builtin_cpu_is)
1405714057
return EmitX86CpuIs(E);
14058-
if (BuiltinID == X86::BI__builtin_cpu_supports)
14058+
if (BuiltinID == Builtin::BI__builtin_cpu_supports)
1405914059
return EmitX86CpuSupports(E);
14060-
if (BuiltinID == X86::BI__builtin_cpu_init)
14060+
if (BuiltinID == Builtin::BI__builtin_cpu_init)
1406114061
return EmitX86CpuInit();
1406214062

1406314063
// Handle MSVC intrinsics before argument evaluation to prevent double
@@ -16545,6 +16545,43 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
1654516545
switch (BuiltinID) {
1654616546
default: return nullptr;
1654716547

16548+
case Builtin::BI__builtin_cpu_is: {
16549+
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
16550+
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
16551+
unsigned NumCPUID = StringSwitch<unsigned>(CPUStr)
16552+
#define PPC_LNX_CPU(Name, NumericID) .Case(Name, NumericID)
16553+
#include "llvm/TargetParser/PPCTargetParser.def"
16554+
.Default(-1U);
16555+
assert(NumCPUID < -1U && "Invalid CPU name. Missed by SemaChecking?");
16556+
Value *Op0 = llvm::ConstantInt::get(Int32Ty, PPC_FAWORD_CPUID);
16557+
llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld);
16558+
Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_is");
16559+
return Builder.CreateICmpEQ(TheCall,
16560+
llvm::ConstantInt::get(Int32Ty, NumCPUID));
16561+
}
16562+
case Builtin::BI__builtin_cpu_supports: {
16563+
unsigned FeatureWord;
16564+
unsigned BitMask;
16565+
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
16566+
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
16567+
std::tie(FeatureWord, BitMask) =
16568+
StringSwitch<std::pair<unsigned, unsigned>>(CPUStr)
16569+
#define PPC_LNX_FEATURE(Name, Description, EnumName, Bitmask, FA_WORD) \
16570+
.Case(Name, {FA_WORD, Bitmask})
16571+
#include "llvm/TargetParser/PPCTargetParser.def"
16572+
.Default({0, 0});
16573+
assert(BitMask && "Invalid target feature string. Missed by SemaChecking?");
16574+
Value *Op0 = llvm::ConstantInt::get(Int32Ty, FeatureWord);
16575+
llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld);
16576+
Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_supports");
16577+
Value *Mask =
16578+
Builder.CreateAnd(TheCall, llvm::ConstantInt::get(Int32Ty, BitMask));
16579+
return Builder.CreateICmpNE(Mask, llvm::Constant::getNullValue(Int32Ty));
16580+
#undef PPC_FAWORD_HWCAP
16581+
#undef PPC_FAWORD_HWCAP2
16582+
#undef PPC_FAWORD_CPUID
16583+
}
16584+
1654816585
// __builtin_ppc_get_timebase is GCC 4.8+'s PowerPC-specific name for what we
1654916586
// call __builtin_readcyclecounter.
1655016587
case PPC::BI__builtin_ppc_get_timebase:

clang/lib/Sema/SemaChecking.cpp

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,6 +2143,48 @@ static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc,
21432143
return false;
21442144
}
21452145

2146+
/// SemaBuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *).
2147+
/// This checks that the target supports the builtin and that the string
2148+
/// argument is constant and valid.
2149+
static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
2150+
const TargetInfo *AuxTI, unsigned BuiltinID) {
2151+
assert((BuiltinID == Builtin::BI__builtin_cpu_supports ||
2152+
BuiltinID == Builtin::BI__builtin_cpu_is) &&
2153+
"Expecting __builtin_cpu_...");
2154+
2155+
bool IsCPUSupports = BuiltinID == Builtin::BI__builtin_cpu_supports;
2156+
const TargetInfo *TheTI = &TI;
2157+
auto SupportsBI = [=](const TargetInfo *TInfo) {
2158+
return TInfo && ((IsCPUSupports && TInfo->supportsCpuSupports()) ||
2159+
(!IsCPUSupports && TInfo->supportsCpuIs()));
2160+
};
2161+
if (!SupportsBI(&TI) && SupportsBI(AuxTI))
2162+
TheTI = AuxTI;
2163+
2164+
if (IsCPUSupports && !TheTI->supportsCpuSupports())
2165+
return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
2166+
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
2167+
if (!IsCPUSupports && !TheTI->supportsCpuIs())
2168+
return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
2169+
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
2170+
2171+
Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts();
2172+
// Check if the argument is a string literal.
2173+
if (!isa<StringLiteral>(Arg))
2174+
return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
2175+
<< Arg->getSourceRange();
2176+
2177+
// Check the contents of the string.
2178+
StringRef Feature = cast<StringLiteral>(Arg)->getString();
2179+
if (IsCPUSupports && !TheTI->validateCpuSupports(Feature))
2180+
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
2181+
<< Arg->getSourceRange();
2182+
if (!IsCPUSupports && !TheTI->validateCpuIs(Feature))
2183+
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
2184+
<< Arg->getSourceRange();
2185+
return false;
2186+
}
2187+
21462188
ExprResult
21472189
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
21482190
CallExpr *TheCall) {
@@ -2171,6 +2213,19 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
21712213

21722214
FPOptions FPO;
21732215
switch (BuiltinID) {
2216+
case Builtin::BI__builtin_cpu_supports:
2217+
case Builtin::BI__builtin_cpu_is:
2218+
if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall,
2219+
Context.getAuxTargetInfo(), BuiltinID))
2220+
return ExprError();
2221+
break;
2222+
case Builtin::BI__builtin_cpu_init:
2223+
if (!Context.getTargetInfo().supportsCpuInit()) {
2224+
Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
2225+
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
2226+
return ExprError();
2227+
}
2228+
break;
21742229
case Builtin::BI__builtin___CFStringMakeConstantString:
21752230
// CFStringMakeConstantString is currently not implemented for GOFF (i.e.,
21762231
// on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported
@@ -6216,47 +6271,6 @@ bool Sema::CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI,
62166271
return false;
62176272
}
62186273

6219-
/// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *).
6220-
/// This checks that the target supports __builtin_cpu_supports and
6221-
/// that the string argument is constant and valid.
6222-
static bool SemaBuiltinCpuSupports(Sema &S, const TargetInfo &TI,
6223-
CallExpr *TheCall) {
6224-
Expr *Arg = TheCall->getArg(0);
6225-
6226-
// Check if the argument is a string literal.
6227-
if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
6228-
return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
6229-
<< Arg->getSourceRange();
6230-
6231-
// Check the contents of the string.
6232-
StringRef Feature =
6233-
cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
6234-
if (!TI.validateCpuSupports(Feature))
6235-
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
6236-
<< Arg->getSourceRange();
6237-
return false;
6238-
}
6239-
6240-
/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *).
6241-
/// This checks that the target supports __builtin_cpu_is and
6242-
/// that the string argument is constant and valid.
6243-
static bool SemaBuiltinCpuIs(Sema &S, const TargetInfo &TI, CallExpr *TheCall) {
6244-
Expr *Arg = TheCall->getArg(0);
6245-
6246-
// Check if the argument is a string literal.
6247-
if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
6248-
return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
6249-
<< Arg->getSourceRange();
6250-
6251-
// Check the contents of the string.
6252-
StringRef Feature =
6253-
cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
6254-
if (!TI.validateCpuIs(Feature))
6255-
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
6256-
<< Arg->getSourceRange();
6257-
return false;
6258-
}
6259-
62606274
// Check if the rounding mode is legal.
62616275
bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
62626276
// Indicates if this instruction has rounding control or just SAE.
@@ -6731,12 +6745,6 @@ static bool isX86_32Builtin(unsigned BuiltinID) {
67316745

67326746
bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
67336747
CallExpr *TheCall) {
6734-
if (BuiltinID == X86::BI__builtin_cpu_supports)
6735-
return SemaBuiltinCpuSupports(*this, TI, TheCall);
6736-
6737-
if (BuiltinID == X86::BI__builtin_cpu_is)
6738-
return SemaBuiltinCpuIs(*this, TI, TheCall);
6739-
67406748
// Check for 32-bit only builtins on a 64-bit target.
67416749
const llvm::Triple &TT = TI.getTriple();
67426750
if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID))

0 commit comments

Comments
 (0)