Skip to content

Implement a subset of builtin_cpu_supports() features #82809

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,19 @@ ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
}

bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const {
llvm::Triple Triple = getTriple();
if (Triple.isOSAIX()) {
#define PPC_AIX_FEATURE(NAME, DESC, SUPPORT_METHOD, INDEX, MASK, COMP_OP, \
VALUE) \
.Case(NAME, true)
return llvm::StringSwitch<bool>(FeatureStr)
#include "llvm/TargetParser/PPCTargetParser.def"
.Default(false);
}

assert(Triple.isOSLinux() &&
"__builtin_cpu_supports() is only supported for AIX and Linux.");

#define PPC_LNX_FEATURE(NAME, DESC, ENUMNAME, ENUMVAL, HWCAPN) .Case(NAME, true)
return llvm::StringSwitch<bool>(FeatureStr)
#include "llvm/TargetParser/PPCTargetParser.def"
Expand All @@ -906,7 +919,7 @@ bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const {
bool PPCTargetInfo::validateCpuIs(StringRef CPUName) const {
llvm::Triple Triple = getTriple();
if (Triple.isOSAIX()) {
#define PPC_AIX_CPU(NAME, SUPPORT, INDEX, OP, VALUE) .Case(NAME, true)
#define PPC_AIX_CPU(NAME, SUPPORT_METHOD, INDEX, OP, VALUE) .Case(NAME, true)
return llvm::StringSwitch<bool>(CPUName)
#include "llvm/TargetParser/PPCTargetParser.def"
.Default(false);
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,14 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
// have Glibc since it is Glibc that provides the HWCAP[2] in the auxv.
static constexpr int MINIMUM_AIX_OS_MAJOR = 7;
static constexpr int MINIMUM_AIX_OS_MINOR = 2;
bool supportsCpuSupports() const override { return getTriple().isOSGlibc(); }
bool supportsCpuSupports() const override {
llvm::Triple Triple = getTriple();
// AIX 7.2 is the minimum requirement to support __builtin_cpu_supports().
return Triple.isOSGlibc() ||
(Triple.isOSAIX() &&
!Triple.isOSVersionLT(MINIMUM_AIX_OS_MAJOR, MINIMUM_AIX_OS_MINOR));
}

bool supportsCpuIs() const override {
llvm::Triple Triple = getTriple();
// AIX 7.2 is the minimum requirement to support __builtin_cpu_is().
Expand Down
95 changes: 70 additions & 25 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16570,32 +16570,53 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,

#include "llvm/TargetParser/PPCTargetParser.def"
auto GenAIXPPCBuiltinCpuExpr = [&](unsigned SupportMethod, unsigned FieldIdx,
Copy link
Member

Choose a reason for hiding this comment

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

This is now a very large lambda function AFAICT. Please extract it into a static function to aid readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am prefer to keep as lambda

  1. after delete the switch case part, the size of lambda reduce.
  2. if I create static function , there will many parameter to for the static function, I need to add builder, Int32Ty, Int64Ty etc as parameter.

unsigned CompOp,
unsigned Mask, CmpInst::Predicate CompOp,
unsigned OpValue) -> Value * {
if (SupportMethod == AIX_BUILTIN_PPC_FALSE)
return llvm::ConstantInt::getFalse(ConvertType(E->getType()));

if (SupportMethod == AIX_BUILTIN_PPC_TRUE)
return llvm::ConstantInt::getTrue(ConvertType(E->getType()));

assert(SupportMethod <= USE_SYS_CONF && "Invalid value for SupportMethod.");
assert((CompOp == COMP_EQ) && "Only equal comparisons are supported.");
assert(SupportMethod <= SYS_CALL && "Invalid value for SupportMethod.");

llvm::Value *FieldValue = nullptr;
if (SupportMethod == USE_SYS_CONF) {
llvm::Type *STy = llvm::StructType::get(PPC_SYSTEMCONFIG_TYPE);
llvm::Constant *SysConf =
CGM.CreateRuntimeVariable(STy, "_system_configuration");

// Grab the appropriate field from _system_configuration.
llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, FieldIdx)};

FieldValue = Builder.CreateGEP(STy, SysConf, Idxs);
FieldValue = Builder.CreateAlignedLoad(Int32Ty, FieldValue,
CharUnits::fromQuantity(4));
} else if (SupportMethod == SYS_CALL) {
llvm::FunctionType *FTy =
llvm::FunctionType::get(Int64Ty, Int32Ty, false);
llvm::FunctionCallee Func =
CGM.CreateRuntimeFunction(FTy, "getsystemcfg");

FieldValue =
Builder.CreateCall(Func, {ConstantInt::get(Int32Ty, FieldIdx)});
}
assert(FieldValue &&
"SupportMethod value is not defined in PPCTargetParser.def.");

llvm::Type *STy = llvm::StructType::get(PPC_SYSTEMCONFIG_TYPE);
llvm::Constant *SysConf =
CGM.CreateRuntimeVariable(STy, "_system_configuration");
if (Mask)
FieldValue = Builder.CreateAnd(FieldValue, Mask);

// Grab the appropriate field from _system_configuration.
llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, FieldIdx)};
llvm::Type *ValueType = FieldValue->getType();
bool IsValueType64Bit = ValueType->isIntegerTy(64);
assert(
(IsValueType64Bit || ValueType->isIntegerTy(32)) &&
"Only 32/64-bit integers are supported in GenAIXPPCBuiltinCpuExpr().");

llvm::Value *FieldValue = Builder.CreateGEP(STy, SysConf, Idxs);
FieldValue = Builder.CreateAlignedLoad(Int32Ty, FieldValue,
CharUnits::fromQuantity(4));
assert(FieldValue->getType()->isIntegerTy(32) &&
"Only 32-bit integers are supported in GenAIXPPCBuiltinCpuExpr().");
return Builder.CreateICmp(ICmpInst::ICMP_EQ, FieldValue,
ConstantInt::get(Int32Ty, OpValue));
return Builder.CreateICmp(
CompOp, FieldValue,
ConstantInt::get(IsValueType64Bit ? Int64Ty : Int32Ty, OpValue));
};

switch (BuiltinID) {
Expand All @@ -16607,15 +16628,18 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
llvm::Triple Triple = getTarget().getTriple();

if (Triple.isOSAIX()) {
unsigned IsCpuSupport, FieldIdx, CompareOp, CpuIdValue;
typedef std::tuple<unsigned, unsigned, unsigned, unsigned> CPUType;
std::tie(IsCpuSupport, FieldIdx, CompareOp, CpuIdValue) =
unsigned SupportMethod, FieldIdx, CpuIdValue;
CmpInst::Predicate CompareOp;
typedef std::tuple<unsigned, unsigned, CmpInst::Predicate, unsigned>
CPUType;
std::tie(SupportMethod, FieldIdx, CompareOp, CpuIdValue) =
static_cast<CPUType>(StringSwitch<CPUType>(CPUStr)
#define PPC_AIX_CPU(NAME, SUPPORT_MAGIC, INDEX, COMPARE_OP, VALUE) \
.Case(NAME, {SUPPORT_MAGIC, INDEX, COMPARE_OP, VALUE})
#define PPC_AIX_CPU(NAME, SUPPORT_METHOD, INDEX, COMPARE_OP, VALUE) \
.Case(NAME, {SUPPORT_METHOD, INDEX, COMPARE_OP, VALUE})
#include "llvm/TargetParser/PPCTargetParser.def"
);
return GenAIXPPCBuiltinCpuExpr(IsCpuSupport, FieldIdx, CompareOp,
.Default({AIX_BUILTIN_PPC_FALSE, 0,
CmpInst::Predicate(), 0}));
return GenAIXPPCBuiltinCpuExpr(SupportMethod, FieldIdx, 0, CompareOp,
CpuIdValue);
}

Expand All @@ -16633,10 +16657,31 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
llvm::ConstantInt::get(Int32Ty, NumCPUID));
}
case Builtin::BI__builtin_cpu_supports: {
unsigned FeatureWord;
unsigned BitMask;
llvm::Triple Triple = getTarget().getTriple();
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
if (Triple.isOSAIX()) {
unsigned SupportMethod, FieldIdx, Mask, Value;
CmpInst::Predicate CompOp;
typedef std::tuple<unsigned, unsigned, unsigned, CmpInst::Predicate,
unsigned>
CPUSupportType;
std::tie(SupportMethod, FieldIdx, Mask, CompOp, Value) =
static_cast<CPUSupportType>(StringSwitch<CPUSupportType>(CPUStr)
#define PPC_AIX_FEATURE(NAME, DESC, SUPPORT_METHOD, INDEX, MASK, COMP_OP, \
VALUE) \
.Case(NAME, {SUPPORT_METHOD, INDEX, MASK, COMP_OP, VALUE})
#include "llvm/TargetParser/PPCTargetParser.def"
.Default({AIX_BUILTIN_PPC_FALSE, 0, 0,
CmpInst::Predicate(), 0}));
return GenAIXPPCBuiltinCpuExpr(SupportMethod, FieldIdx, Mask, CompOp,
Value);
}

assert(Triple.isOSLinux() &&
"__builtin_cpu_supports() is only supported for AIX and Linux.");
unsigned FeatureWord;
unsigned BitMask;
std::tie(FeatureWord, BitMask) =
StringSwitch<std::pair<unsigned, unsigned>>(CPUStr)
#define PPC_LNX_FEATURE(Name, Description, EnumName, Bitmask, FA_WORD) \
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2162,10 +2162,8 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
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())
if ((!IsCPUSupports && !TheTI->supportsCpuIs()) ||
(IsCPUSupports && !TheTI->supportsCpuSupports()))
return S.Diag(TheCall->getBeginLoc(),
TI.getTriple().isOSAIX()
? diag::err_builtin_aix_os_unsupported
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/aix-builtin-cpu-is.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@
// CHECK-NEXT: ret i32 0
// CHECK-NEXT: }

// CHECKOP: @_system_configuration = external global { i32, i32, i32 }
// CHECKOP: @_system_configuration = external global { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i64, i32, i32, i32, i32, i64, i64, i64, i64, i32, i32, i32, i32, i32, i32, i64, i32, i8, i8, i8, i8, i32, i32, i16, i16, [3 x i32], i32 }
// CHECKOP: define i32 @main() #0 {
// CHECKOP-NEXT: entry:
// CHECKOP-NEXT: %retval = alloca i32, align 4
// CHECKOP-NEXT: store i32 0, ptr %retval, align 4
// CHECKOP-NEXT: %0 = load i32, ptr getelementptr inbounds ({ i32, i32, i32 }, ptr @_system_configuration, i32 0, i32 1), align 4
// CHECKOP-NEXT: %0 = load i32, ptr getelementptr inbounds ({ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i64, i32, i32, i32, i32, i64, i64, i64, i64, i32, i32, i32, i32, i32, i32, i64, i32, i8, i8, i8, i8, i32, i32, i16, i16, [3 x i32], i32 }, ptr @_system_configuration, i32 0, i32 1), align 4
// CHECKOP-NEXT: %1 = icmp eq i32 %0, [[VALUE]]
// CHECKOP-NEXT: %conv = zext i1 %1 to i32
// CHECKOP-NEXT: ret i32 %conv
Expand Down
Loading