Skip to content

[AIX] Lower intrinsic __builtin_cpu_is into AIX platform-specific code. #80069

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 7 commits into from
Feb 22, 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
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10347,6 +10347,8 @@ def err_x86_builtin_tile_arg_duplicate : Error<

def err_builtin_target_unsupported : Error<
"builtin is not supported on this target">;
def err_builtin_aix_os_unsupported : Error<
"this builtin is available only on AIX 7.2 and later operating systems">;
def err_builtin_longjmp_unsupported : Error<
"__builtin_longjmp is not supported for the current target">;
def err_builtin_setjmp_unsupported : Error<
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,16 @@ 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)
return llvm::StringSwitch<bool>(CPUName)
#include "llvm/TargetParser/PPCTargetParser.def"
.Default(false);
}

assert(Triple.isOSLinux() &&
"__builtin_cpu_is() is only supported for AIX and Linux.");
#define PPC_LNX_CPU(NAME, NUM) .Case(NAME, true)
return llvm::StringSwitch<bool>(CPUName)
#include "llvm/TargetParser/PPCTargetParser.def"
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,16 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {

// 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.
static constexpr int MINIMUM_AIX_OS_MAJOR = 7;
static constexpr int MINIMUM_AIX_OS_MINOR = 2;
bool supportsCpuSupports() const override { return getTriple().isOSGlibc(); }
bool supportsCpuIs() const override { return getTriple().isOSGlibc(); }
bool supportsCpuIs() const override {
llvm::Triple Triple = getTriple();
// AIX 7.2 is the minimum requirement to support __builtin_cpu_is().
return Triple.isOSGlibc() ||
(Triple.isOSAIX() &&
!Triple.isOSVersionLT(MINIMUM_AIX_OS_MAJOR, MINIMUM_AIX_OS_MINOR));
}
bool validateCpuSupports(StringRef Feature) const override;
bool validateCpuIs(StringRef Name) const override;
};
Expand Down
47 changes: 47 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16542,12 +16542,59 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,

Intrinsic::ID ID = Intrinsic::not_intrinsic;

#include "llvm/TargetParser/PPCTargetParser.def"
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 getting a bit tangled. Can you please provide two static functions:
EmitPPCAIXCpuIDFunc(...), EmitPPCLinuxCpuIDFunc(...) and just call the right one from here.

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 think the function is too short, It not worth to have a two separate static functions. and I reorganize the code in other way.

auto GenAIXPPCBuiltinCpuExpr = [&](unsigned SupportMethod, unsigned FieldIdx,
unsigned 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.");

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)};

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));
};

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();
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) =
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})
#include "llvm/TargetParser/PPCTargetParser.def"
);
return GenAIXPPCBuiltinCpuExpr(IsCpuSupport, FieldIdx, CompareOp,
CpuIdValue);
}

assert(Triple.isOSLinux() &&
"__builtin_cpu_is() is only supported for AIX and Linux.");
unsigned NumCPUID = StringSwitch<unsigned>(CPUStr)
#define PPC_LNX_CPU(Name, NumericID) .Case(Name, NumericID)
#include "llvm/TargetParser/PPCTargetParser.def"
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2165,7 +2165,10 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
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)
return S.Diag(TheCall->getBeginLoc(),
TI.getTriple().isOSAIX()
? diag::err_builtin_aix_os_unsupported
: diag::err_builtin_target_unsupported)
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());

Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts();
Expand Down
71 changes: 71 additions & 0 deletions clang/test/CodeGen/aix-builtin-cpu-is.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc970\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc-cell-be\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppca2\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc405\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc440\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc464\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"ppc476\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power4\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power5\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power5+\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power6\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power6x\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s

// RUN: echo "int main() { return __builtin_cpu_is(\"power7\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=32768 \
// RUN: --check-prefix=CHECKOP

// RUN: echo "int main() { return __builtin_cpu_is(\"power8\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=65536 \
// RUN: --check-prefix=CHECKOP

// RUN: echo "int main() { return __builtin_cpu_is(\"power9\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=131072\
// RUN: --check-prefix=CHECKOP

// RUN: echo "int main() { return __builtin_cpu_is(\"power10\");}" > %t.c
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=262144 \
// RUN: --check-prefix=CHECKOP

// CHECK: define i32 @main() #0 {
// CHECK-NEXT: entry:
// CHECK-NEXT: %retval = alloca i32, align 4
// CHECK-NEXT: store i32 0, ptr %retval, align 4
// CHECK-NEXT: ret i32 0
// CHECK-NEXT: }

// CHECKOP: @_system_configuration = external global { i32, 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: %1 = icmp eq i32 %0, [[VALUE]]
// CHECKOP-NEXT: %conv = zext i1 %1 to i32
// CHECKOP-NEXT: ret i32 %conv
// CHECKOP-NEXT: }


6 changes: 6 additions & 0 deletions clang/test/Sema/aix-builtin-cpu-unsupports.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -triple powerpc-ibm-aix7.1.0.0 -verify %s

int main(void) {
if (__builtin_cpu_is("power8")) // expected-error {{this builtin is available only on AIX 7.2 and later operating systems}}
return 1;
}
57 changes: 57 additions & 0 deletions llvm/include/llvm/TargetParser/PPCTargetParser.def
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,61 @@ PPC_LNX_CPU("power10",47)
#undef PPC_LNX_DEFINE_OFFSETS
#undef PPC_LNX_FEATURE
#undef PPC_LNX_CPU

// Definition of the following values are found in the AIX header
// file: </usr/include/sys/systemcfg.h>.
#ifndef AIX_POWERPC_USE_SYS_CONF
#define AIX_POWERPC_USE_SYS_CONF
#define AIX_SYSCON_IMPL_IDX 1
#define AIX_PPC7_VALUE 0x00008000
#define AIX_PPC8_VALUE 0x00010000
#define AIX_PPC9_VALUE 0x00020000
#define AIX_PPC10_VALUE 0x00040000

// Supported SUPPORT_METHOD values.
#define AIX_BUILTIN_PPC_TRUE 1
#define AIX_BUILTIN_PPC_FALSE 0
#define USE_SYS_CONF 2

// Supported COMPARE_OP values.
#define COMP_EQ 0

#endif

// The value of SUPPORT_METHOD can be AIX_BUILTIN_PPC_TRUE,
// AIX_BUILTIN_PPC_FALSE, or USE_SYS_CONF.
// When the value of SUPPORT_METHOD is USE_SYS_CONF, the return value
// depends on the result of comparing the data member of
// _system_configuration specified by INDEX with a certain value.

Copy link
Contributor

Choose a reason for hiding this comment

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

Remove this new line, to clearly show that the comment is applicable to this define specifically.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this new line should still be removed.

Copy link
Contributor

Choose a reason for hiding this comment

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

agreed

#ifndef PPC_AIX_CPU
#define PPC_AIX_CPU(NAME, SUPPORT_METHOD, INDEX, COMPARE_OP, VALUE)
#endif

// __builtin_cpu_is() is supported only on Power7 and up.
PPC_AIX_CPU("power4",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("ppc970",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("power5",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("power5+",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("power6",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("ppc-cell-be",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("power6x",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("ppca2",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("ppc405",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("ppc440",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("ppc464",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("ppc476",AIX_BUILTIN_PPC_FALSE,0,0,0)
PPC_AIX_CPU("power7",USE_SYS_CONF,AIX_SYSCON_IMPL_IDX,COMP_EQ,AIX_PPC7_VALUE)
PPC_AIX_CPU("power8",USE_SYS_CONF,AIX_SYSCON_IMPL_IDX,COMP_EQ,AIX_PPC8_VALUE)
PPC_AIX_CPU("power9",USE_SYS_CONF,AIX_SYSCON_IMPL_IDX,COMP_EQ,AIX_PPC9_VALUE)
PPC_AIX_CPU("power10",USE_SYS_CONF,AIX_SYSCON_IMPL_IDX,COMP_EQ,AIX_PPC10_VALUE)
#undef PPC_AIX_CPU

// PPC_SYSTEMCONFIG_TYPE defines the IR data structure of kernel variable
// `_system_configuration`, that is found in the AIX OS header file: </usr/include/sys/systemcfg.h>.
#ifndef PPC_SYSTEMCONFIG_TYPE
#define PPC_SYSTEMCONFIG_TYPE \
Int32Ty, Int32Ty, Int32Ty
#endif

#endif // !PPC_TGT_PARSER_UNDEF_MACROS