Skip to content

Commit

Permalink
[PowerPC][X86] Make cpu id builtins target independent and lower for …
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
3 people committed Jan 26, 2024
1 parent c177507 commit 67c1c1d
Show file tree
Hide file tree
Showing 17 changed files with 589 additions and 82 deletions.
20 changes: 20 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
7 changes: 0 additions & 7 deletions clang/include/clang/Basic/BuiltinsX86.def
Original file line number Diff line number Diff line change
Expand Up @@ -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:", "")
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,12 @@ class TargetInfo : public TransferrableTargetInfo,
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; }
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,13 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
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 {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
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;
Expand Down
43 changes: 40 additions & 3 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
102 changes: 55 additions & 47 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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))
Expand Down

0 comments on commit 67c1c1d

Please sign in to comment.