Skip to content

Commit 5b8e560

Browse files
authored
[AIX] Lower intrinsic __builtin_cpu_is into AIX platform-specific code. (#80069)
On AIX OS, __builtin_cpu_is() references the runtime external variable _system_configuration from /usr/include/sys/systemcfg.h. ref issue: #80042
1 parent 770fd38 commit 5b8e560

File tree

8 files changed

+206
-2
lines changed

8 files changed

+206
-2
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10364,6 +10364,8 @@ def err_x86_builtin_tile_arg_duplicate : Error<
1036410364

1036510365
def err_builtin_target_unsupported : Error<
1036610366
"builtin is not supported on this target">;
10367+
def err_builtin_aix_os_unsupported : Error<
10368+
"this builtin is available only on AIX 7.2 and later operating systems">;
1036710369
def err_builtin_longjmp_unsupported : Error<
1036810370
"__builtin_longjmp is not supported for the current target">;
1036910371
def err_builtin_setjmp_unsupported : Error<

clang/lib/Basic/Targets/PPC.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,16 @@ bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const {
904904
}
905905

906906
bool PPCTargetInfo::validateCpuIs(StringRef CPUName) const {
907+
llvm::Triple Triple = getTriple();
908+
if (Triple.isOSAIX()) {
909+
#define PPC_AIX_CPU(NAME, SUPPORT, INDEX, OP, VALUE) .Case(NAME, true)
910+
return llvm::StringSwitch<bool>(CPUName)
911+
#include "llvm/TargetParser/PPCTargetParser.def"
912+
.Default(false);
913+
}
914+
915+
assert(Triple.isOSLinux() &&
916+
"__builtin_cpu_is() is only supported for AIX and Linux.");
907917
#define PPC_LNX_CPU(NAME, NUM) .Case(NAME, true)
908918
return llvm::StringSwitch<bool>(CPUName)
909919
#include "llvm/TargetParser/PPCTargetParser.def"

clang/lib/Basic/Targets/PPC.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,16 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
362362

363363
// We support __builtin_cpu_supports/__builtin_cpu_is on targets that
364364
// have Glibc since it is Glibc that provides the HWCAP[2] in the auxv.
365+
static constexpr int MINIMUM_AIX_OS_MAJOR = 7;
366+
static constexpr int MINIMUM_AIX_OS_MINOR = 2;
365367
bool supportsCpuSupports() const override { return getTriple().isOSGlibc(); }
366-
bool supportsCpuIs() const override { return getTriple().isOSGlibc(); }
368+
bool supportsCpuIs() const override {
369+
llvm::Triple Triple = getTriple();
370+
// AIX 7.2 is the minimum requirement to support __builtin_cpu_is().
371+
return Triple.isOSGlibc() ||
372+
(Triple.isOSAIX() &&
373+
!Triple.isOSVersionLT(MINIMUM_AIX_OS_MAJOR, MINIMUM_AIX_OS_MINOR));
374+
}
367375
bool validateCpuSupports(StringRef Feature) const override;
368376
bool validateCpuIs(StringRef Name) const override;
369377
};

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16542,12 +16542,59 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
1654216542

1654316543
Intrinsic::ID ID = Intrinsic::not_intrinsic;
1654416544

16545+
#include "llvm/TargetParser/PPCTargetParser.def"
16546+
auto GenAIXPPCBuiltinCpuExpr = [&](unsigned SupportMethod, unsigned FieldIdx,
16547+
unsigned CompOp,
16548+
unsigned OpValue) -> Value * {
16549+
if (SupportMethod == AIX_BUILTIN_PPC_FALSE)
16550+
return llvm::ConstantInt::getFalse(ConvertType(E->getType()));
16551+
16552+
if (SupportMethod == AIX_BUILTIN_PPC_TRUE)
16553+
return llvm::ConstantInt::getTrue(ConvertType(E->getType()));
16554+
16555+
assert(SupportMethod <= USE_SYS_CONF && "Invalid value for SupportMethod.");
16556+
assert((CompOp == COMP_EQ) && "Only equal comparisons are supported.");
16557+
16558+
llvm::Type *STy = llvm::StructType::get(PPC_SYSTEMCONFIG_TYPE);
16559+
llvm::Constant *SysConf =
16560+
CGM.CreateRuntimeVariable(STy, "_system_configuration");
16561+
16562+
// Grab the appropriate field from _system_configuration.
16563+
llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0),
16564+
ConstantInt::get(Int32Ty, FieldIdx)};
16565+
16566+
llvm::Value *FieldValue = Builder.CreateGEP(STy, SysConf, Idxs);
16567+
FieldValue = Builder.CreateAlignedLoad(Int32Ty, FieldValue,
16568+
CharUnits::fromQuantity(4));
16569+
assert(FieldValue->getType()->isIntegerTy(32) &&
16570+
"Only 32-bit integers are supported in GenAIXPPCBuiltinCpuExpr().");
16571+
return Builder.CreateICmp(ICmpInst::ICMP_EQ, FieldValue,
16572+
ConstantInt::get(Int32Ty, OpValue));
16573+
};
16574+
1654516575
switch (BuiltinID) {
1654616576
default: return nullptr;
1654716577

1654816578
case Builtin::BI__builtin_cpu_is: {
1654916579
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
1655016580
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
16581+
llvm::Triple Triple = getTarget().getTriple();
16582+
16583+
if (Triple.isOSAIX()) {
16584+
unsigned IsCpuSupport, FieldIdx, CompareOp, CpuIdValue;
16585+
typedef std::tuple<unsigned, unsigned, unsigned, unsigned> CPUType;
16586+
std::tie(IsCpuSupport, FieldIdx, CompareOp, CpuIdValue) =
16587+
static_cast<CPUType>(StringSwitch<CPUType>(CPUStr)
16588+
#define PPC_AIX_CPU(NAME, SUPPORT_MAGIC, INDEX, COMPARE_OP, VALUE) \
16589+
.Case(NAME, {SUPPORT_MAGIC, INDEX, COMPARE_OP, VALUE})
16590+
#include "llvm/TargetParser/PPCTargetParser.def"
16591+
);
16592+
return GenAIXPPCBuiltinCpuExpr(IsCpuSupport, FieldIdx, CompareOp,
16593+
CpuIdValue);
16594+
}
16595+
16596+
assert(Triple.isOSLinux() &&
16597+
"__builtin_cpu_is() is only supported for AIX and Linux.");
1655116598
unsigned NumCPUID = StringSwitch<unsigned>(CPUStr)
1655216599
#define PPC_LNX_CPU(Name, NumericID) .Case(Name, NumericID)
1655316600
#include "llvm/TargetParser/PPCTargetParser.def"

clang/lib/Sema/SemaChecking.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2165,7 +2165,10 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
21652165
return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
21662166
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
21672167
if (!IsCPUSupports && !TheTI->supportsCpuIs())
2168-
return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
2168+
return S.Diag(TheCall->getBeginLoc(),
2169+
TI.getTriple().isOSAIX()
2170+
? diag::err_builtin_aix_os_unsupported
2171+
: diag::err_builtin_target_unsupported)
21692172
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
21702173

21712174
Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts();
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc970\");}" > %t.c
2+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
3+
4+
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc-cell-be\");}" > %t.c
5+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
6+
7+
// RUN: echo "int main() { return __builtin_cpu_is(\"ppca2\");}" > %t.c
8+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
9+
10+
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc405\");}" > %t.c
11+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
12+
13+
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc440\");}" > %t.c
14+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
15+
16+
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc464\");}" > %t.c
17+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
18+
19+
// RUN: echo "int main() { return __builtin_cpu_is(\"ppc476\");}" > %t.c
20+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
21+
22+
// RUN: echo "int main() { return __builtin_cpu_is(\"power4\");}" > %t.c
23+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
24+
25+
// RUN: echo "int main() { return __builtin_cpu_is(\"power5\");}" > %t.c
26+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
27+
28+
// RUN: echo "int main() { return __builtin_cpu_is(\"power5+\");}" > %t.c
29+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
30+
31+
// RUN: echo "int main() { return __builtin_cpu_is(\"power6\");}" > %t.c
32+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
33+
34+
// RUN: echo "int main() { return __builtin_cpu_is(\"power6x\");}" > %t.c
35+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s
36+
37+
// RUN: echo "int main() { return __builtin_cpu_is(\"power7\");}" > %t.c
38+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=32768 \
39+
// RUN: --check-prefix=CHECKOP
40+
41+
// RUN: echo "int main() { return __builtin_cpu_is(\"power8\");}" > %t.c
42+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=65536 \
43+
// RUN: --check-prefix=CHECKOP
44+
45+
// RUN: echo "int main() { return __builtin_cpu_is(\"power9\");}" > %t.c
46+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=131072\
47+
// RUN: --check-prefix=CHECKOP
48+
49+
// RUN: echo "int main() { return __builtin_cpu_is(\"power10\");}" > %t.c
50+
// RUN: %clang_cc1 -triple powerpc-ibm-aix7.2.0.0 -emit-llvm -o - %t.c | FileCheck %s -DVALUE=262144 \
51+
// RUN: --check-prefix=CHECKOP
52+
53+
// CHECK: define i32 @main() #0 {
54+
// CHECK-NEXT: entry:
55+
// CHECK-NEXT: %retval = alloca i32, align 4
56+
// CHECK-NEXT: store i32 0, ptr %retval, align 4
57+
// CHECK-NEXT: ret i32 0
58+
// CHECK-NEXT: }
59+
60+
// CHECKOP: @_system_configuration = external global { i32, i32, i32 }
61+
// CHECKOP: define i32 @main() #0 {
62+
// CHECKOP-NEXT: entry:
63+
// CHECKOP-NEXT: %retval = alloca i32, align 4
64+
// CHECKOP-NEXT: store i32 0, ptr %retval, align 4
65+
// CHECKOP-NEXT: %0 = load i32, ptr getelementptr inbounds ({ i32, i32, i32 }, ptr @_system_configuration, i32 0, i32 1), align 4
66+
// CHECKOP-NEXT: %1 = icmp eq i32 %0, [[VALUE]]
67+
// CHECKOP-NEXT: %conv = zext i1 %1 to i32
68+
// CHECKOP-NEXT: ret i32 %conv
69+
// CHECKOP-NEXT: }
70+
71+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %clang_cc1 -fsyntax-only -triple powerpc-ibm-aix7.1.0.0 -verify %s
2+
3+
int main(void) {
4+
if (__builtin_cpu_is("power8")) // expected-error {{this builtin is available only on AIX 7.2 and later operating systems}}
5+
return 1;
6+
}

llvm/include/llvm/TargetParser/PPCTargetParser.def

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,61 @@ PPC_LNX_CPU("power10",47)
126126
#undef PPC_LNX_DEFINE_OFFSETS
127127
#undef PPC_LNX_FEATURE
128128
#undef PPC_LNX_CPU
129+
130+
// Definition of the following values are found in the AIX header
131+
// file: </usr/include/sys/systemcfg.h>.
132+
#ifndef AIX_POWERPC_USE_SYS_CONF
133+
#define AIX_POWERPC_USE_SYS_CONF
134+
#define AIX_SYSCON_IMPL_IDX 1
135+
#define AIX_PPC7_VALUE 0x00008000
136+
#define AIX_PPC8_VALUE 0x00010000
137+
#define AIX_PPC9_VALUE 0x00020000
138+
#define AIX_PPC10_VALUE 0x00040000
139+
140+
// Supported SUPPORT_METHOD values.
141+
#define AIX_BUILTIN_PPC_TRUE 1
142+
#define AIX_BUILTIN_PPC_FALSE 0
143+
#define USE_SYS_CONF 2
144+
145+
// Supported COMPARE_OP values.
146+
#define COMP_EQ 0
147+
148+
#endif
149+
150+
// The value of SUPPORT_METHOD can be AIX_BUILTIN_PPC_TRUE,
151+
// AIX_BUILTIN_PPC_FALSE, or USE_SYS_CONF.
152+
// When the value of SUPPORT_METHOD is USE_SYS_CONF, the return value
153+
// depends on the result of comparing the data member of
154+
// _system_configuration specified by INDEX with a certain value.
155+
156+
#ifndef PPC_AIX_CPU
157+
#define PPC_AIX_CPU(NAME, SUPPORT_METHOD, INDEX, COMPARE_OP, VALUE)
158+
#endif
159+
160+
// __builtin_cpu_is() is supported only on Power7 and up.
161+
PPC_AIX_CPU("power4",AIX_BUILTIN_PPC_FALSE,0,0,0)
162+
PPC_AIX_CPU("ppc970",AIX_BUILTIN_PPC_FALSE,0,0,0)
163+
PPC_AIX_CPU("power5",AIX_BUILTIN_PPC_FALSE,0,0,0)
164+
PPC_AIX_CPU("power5+",AIX_BUILTIN_PPC_FALSE,0,0,0)
165+
PPC_AIX_CPU("power6",AIX_BUILTIN_PPC_FALSE,0,0,0)
166+
PPC_AIX_CPU("ppc-cell-be",AIX_BUILTIN_PPC_FALSE,0,0,0)
167+
PPC_AIX_CPU("power6x",AIX_BUILTIN_PPC_FALSE,0,0,0)
168+
PPC_AIX_CPU("ppca2",AIX_BUILTIN_PPC_FALSE,0,0,0)
169+
PPC_AIX_CPU("ppc405",AIX_BUILTIN_PPC_FALSE,0,0,0)
170+
PPC_AIX_CPU("ppc440",AIX_BUILTIN_PPC_FALSE,0,0,0)
171+
PPC_AIX_CPU("ppc464",AIX_BUILTIN_PPC_FALSE,0,0,0)
172+
PPC_AIX_CPU("ppc476",AIX_BUILTIN_PPC_FALSE,0,0,0)
173+
PPC_AIX_CPU("power7",USE_SYS_CONF,AIX_SYSCON_IMPL_IDX,COMP_EQ,AIX_PPC7_VALUE)
174+
PPC_AIX_CPU("power8",USE_SYS_CONF,AIX_SYSCON_IMPL_IDX,COMP_EQ,AIX_PPC8_VALUE)
175+
PPC_AIX_CPU("power9",USE_SYS_CONF,AIX_SYSCON_IMPL_IDX,COMP_EQ,AIX_PPC9_VALUE)
176+
PPC_AIX_CPU("power10",USE_SYS_CONF,AIX_SYSCON_IMPL_IDX,COMP_EQ,AIX_PPC10_VALUE)
177+
#undef PPC_AIX_CPU
178+
179+
// PPC_SYSTEMCONFIG_TYPE defines the IR data structure of kernel variable
180+
// `_system_configuration`, that is found in the AIX OS header file: </usr/include/sys/systemcfg.h>.
181+
#ifndef PPC_SYSTEMCONFIG_TYPE
182+
#define PPC_SYSTEMCONFIG_TYPE \
183+
Int32Ty, Int32Ty, Int32Ty
184+
#endif
185+
129186
#endif // !PPC_TGT_PARSER_UNDEF_MACROS

0 commit comments

Comments
 (0)