| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| // RUN: %clang_cc1 -std=c23 -verify -triple x86_64 -pedantic -Wno-conversion -Wno-constant-conversion %s | ||
|
|
||
| /* WG14 N3018: Full | ||
| * The constexpr specifier for object definitions | ||
| */ | ||
|
|
||
| #define ULLONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL) | ||
| #define UINT_MAX (__INT_MAX__ *2U +1U) | ||
|
|
||
| void Example0() { | ||
| constexpr unsigned int minusOne = -1; | ||
| // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'const unsigned int'}} | ||
| constexpr unsigned int uint_max = -1U; | ||
| constexpr double onethird = 1.0/3.0; | ||
| constexpr double onethirdtrunc = (double)(1.0/3.0); | ||
|
|
||
| constexpr char string[] = { "\xFF", }; | ||
| constexpr unsigned char ucstring[] = { "\xFF", }; | ||
| // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'const unsigned char'}} | ||
| constexpr char string1[] = { -1, 0, }; | ||
| constexpr unsigned char ucstring1[] = { -1, 0, }; | ||
| // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'const unsigned char'}} | ||
|
|
||
| // TODO: Make sure these work correctly once char8_t and _Decimal are supported | ||
| // constexpr char8_t u8string[] = { 255, 0, }; // ok | ||
| // constexpr char8_t u8string[] = { u8"\xFF", }; // ok | ||
| // constexpr _Decimal32 small = DEC64_TRUE_MIN * 0;// constraint violation | ||
| } | ||
|
|
||
| void Example1() { | ||
| constexpr int K = 47; | ||
| enum { | ||
| A = K, | ||
| }; | ||
| constexpr int L = K; | ||
| static int b = K + 1; | ||
| int array[K]; | ||
| _Static_assert(K == 47); | ||
| } | ||
|
|
||
| constexpr int K = 47; | ||
| static const int b = K + 1; | ||
|
|
||
| void Example2() { | ||
| constexpr int A = 42LL; | ||
| constexpr signed short B = ULLONG_MAX; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 18446744073709551615 which is not exactly representable in type 'const short'}} | ||
| constexpr float C = 47u; | ||
|
|
||
| constexpr float D = 432000000; | ||
| constexpr float E = 1.0 / 3.0; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 3.333333e-01 which is not exactly representable in type 'const float'}} | ||
| constexpr float F = 1.0f / 3.0f; | ||
| } | ||
|
|
||
|
|
||
| void Example3() { | ||
| constexpr static unsigned short array[] = { | ||
| 3000, | ||
| 300000, | ||
| // expected-error@-1 {{constexpr initializer evaluates to 300000 which is not exactly representable in type 'const unsigned short'}} | ||
| -1 | ||
| // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'const unsigned short'}} | ||
| }; | ||
|
|
||
| constexpr static unsigned short array1[] = { | ||
| 3000, | ||
| 3000, | ||
| -1 | ||
| // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'const unsigned short'}} | ||
| }; | ||
|
|
||
| struct S { | ||
| int x, y; | ||
| }; | ||
| constexpr struct S s = { | ||
| .x = __INT_MAX__, | ||
| .y = UINT_MAX, | ||
| // expected-error@-1 {{constexpr initializer evaluates to 4294967295 which is not exactly representable in type 'int'}} | ||
| }; | ||
| } | ||
|
|
||
| void Example4() { | ||
| struct s { void *p; }; | ||
| constexpr struct s A = { nullptr }; | ||
| constexpr struct s B = A; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
|
|
||
| namespace dr438 { // dr438: 2.7 | ||
|
|
||
| void f() { | ||
| long A[2]; | ||
| A[0] = 0; | ||
| A[A[0]] = 1; | ||
| } | ||
|
|
||
| } // namespace dr438 | ||
|
|
||
| // CHECK-LABEL: define {{.*}} void @dr438::f()() | ||
| // CHECK: [[A:%.+]] = alloca [2 x i64] | ||
| // CHECK: {{.+}} = getelementptr inbounds [2 x i64], ptr [[A]], i64 0, i64 0 | ||
| // CHECK: [[ARRAYIDX1:%.+]] = getelementptr inbounds [2 x i64], ptr [[A]], i64 0, i64 0 | ||
| // CHECK-NEXT: [[TEMPIDX:%.+]] = load i64, ptr [[ARRAYIDX1]] | ||
| // CHECK-NEXT: [[ARRAYIDX2:%.+]] = getelementptr inbounds [2 x i64], ptr [[A]], i64 0, i64 [[TEMPIDX]] | ||
| // CHECK-LABEL: } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| // RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
|
|
||
| namespace dr439 { // dr439: 2.7 | ||
|
|
||
| void f() { | ||
| int* p1 = new int; | ||
| const int* p2 = static_cast<const int*>(static_cast<void *>(p1)); | ||
| bool b = p1 == p2; // b will have the value true. | ||
| } | ||
|
|
||
| } // namespace dr439 | ||
|
|
||
| // We're checking that p2 was copied from p1, and then was carried over | ||
| // to the comparison without change. | ||
|
|
||
| // CHECK-LABEL: define {{.*}} void @dr439::f()() | ||
| // CHECK: [[P1:%.+]] = alloca ptr, align 8 | ||
| // CHECK-NEXT: [[P2:%.+]] = alloca ptr, align 8 | ||
| // CHECK: [[TEMP0:%.+]] = load ptr, ptr [[P1]] | ||
| // CHECK-NEXT: store ptr [[TEMP0:%.+]], ptr [[P2]] | ||
| // CHECK-NEXT: [[TEMP1:%.+]] = load ptr, ptr [[P1]] | ||
| // CHECK-NEXT: [[TEMP2:%.+]] = load ptr, ptr [[P2]] | ||
| // CHECK-NEXT: {{.*}} = icmp eq ptr [[TEMP1]], [[TEMP2]] | ||
| // CHECK-LABEL: } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
|
|
||
| namespace dr441 { // dr441: 2.7 | ||
|
|
||
| struct A { | ||
| A() {} | ||
| }; | ||
|
|
||
| A dynamic_init; | ||
| int i; | ||
| int& ir = i; | ||
| int* ip = &i; | ||
|
|
||
| } // namespace dr441 | ||
|
|
||
| // CHECK-DAG: @dr441::dynamic_init = global %"struct.dr441::A" zeroinitializer | ||
| // CHECK-DAG: @dr441::i = global i32 0 | ||
| // CHECK-DAG: @dr441::ir = constant ptr @dr441::i | ||
| // CHECK-DAG: @dr441::ip = global ptr @dr441::i | ||
| // CHECK-DAG: @llvm.global_ctors = appending global [{{.+}}] [{ {{.+}} } { {{.+}}, ptr @_GLOBAL__sub_I_dr441.cpp, {{.+}} }] | ||
|
|
||
| // CHECK-LABEL: define {{.*}} void @__cxx_global_var_init() | ||
| // CHECK-NEXT: entry: | ||
| // CHECK-NEXT: call void @dr441::A::A()({{.*}} @dr441::dynamic_init) | ||
| // CHECK-NEXT: ret void | ||
| // CHECK-NEXT: } | ||
|
|
||
| // CHECK-LABEL: define {{.*}} void @_GLOBAL__sub_I_dr441.cpp() | ||
| // CHECK-NEXT: entry: | ||
| // CHECK-NEXT: call void @__cxx_global_var_init() | ||
| // CHECK-NEXT: ret void | ||
| // CHECK-NEXT: } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| // RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
|
|
||
| #if __cplusplus == 199711L | ||
| #define NOTHROW throw() | ||
| #else | ||
| #define NOTHROW noexcept(true) | ||
| #endif | ||
|
|
||
| namespace dr462 { // dr462: 2.7 | ||
|
|
||
| struct A { | ||
| ~A() NOTHROW {} | ||
| }; | ||
|
|
||
| extern void full_expr_fence() NOTHROW; | ||
|
|
||
| void f() { | ||
| const A& r = (3, A()); | ||
| full_expr_fence(); | ||
| } | ||
|
|
||
| } // namespace dr462 | ||
|
|
||
| // CHECK-LABEL: define {{.*}} void @dr462::f()() | ||
| // CHECK: call void @dr462::full_expr_fence()() | ||
| // CHECK: call void @dr462::A::~A() | ||
| // CHECK-LABEL: } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| // RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
|
|
||
| #if __cplusplus == 199711L | ||
| #define NOTHROW throw() | ||
| #else | ||
| #define NOTHROW noexcept(true) | ||
| #endif | ||
|
|
||
| namespace std { | ||
| struct type_info { | ||
| const char* name() const NOTHROW; | ||
| }; | ||
| } | ||
|
|
||
| namespace dr492 { // dr492: 2.7 | ||
|
|
||
| void f() { | ||
| typeid(int).name(); | ||
| typeid(const int).name(); | ||
| typeid(volatile int).name(); | ||
| typeid(const volatile int).name(); | ||
| } | ||
|
|
||
| } // namespace dr492 | ||
|
|
||
| // CHECK-LABEL: define {{.*}} void @dr492::f()() | ||
| // CHECK: {{.*}} = call {{.*}} @std::type_info::name() const({{.*}} @typeinfo for int) | ||
| // CHECK-NEXT: {{.*}} = call {{.*}} @std::type_info::name() const({{.*}} @typeinfo for int) | ||
| // CHECK-NEXT: {{.*}} = call {{.*}} @std::type_info::name() const({{.*}} @typeinfo for int) | ||
| // CHECK-NEXT: {{.*}} = call {{.*}} @std::type_info::name() const({{.*}} @typeinfo for int) | ||
| // CHECK-LABEL: } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| // RUN: rm -rf %t | ||
| // RUN: mkdir -p %t | ||
| // RUN: split-file %s %t | ||
| // | ||
| // RUN: %clang_cc1 -std=c++20 %t/Invisible.cppm -emit-module-interface -o %t/Invisible.pcm | ||
| // RUN: %clang_cc1 -std=c++20 %t/Other.cppm -emit-module-interface -fprebuilt-module-path=%t \ | ||
| // RUN: -o %t/Other.pcm | ||
| // RUN: %clang_cc1 -std=c++20 %t/Another.cppm -emit-module-interface -o %t/Another.pcm | ||
| // RUN: %clang_cc1 -std=c++20 %t/A-interface.cppm -emit-module-interface \ | ||
| // RUN: -fprebuilt-module-path=%t -o %t/A-interface.pcm | ||
| // RUN: %clang_cc1 -std=c++20 %t/A-interface2.cppm -emit-module-interface \ | ||
| // RUN: -fprebuilt-module-path=%t -o %t/A-interface2.pcm | ||
| // RUN: %clang_cc1 -std=c++20 %t/A-interface3.cppm -emit-module-interface \ | ||
| // RUN: -fprebuilt-module-path=%t -o %t/A-interface3.pcm | ||
| // RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-module-interface \ | ||
| // RUN: -fprebuilt-module-path=%t -o %t/A.pcm | ||
|
|
||
| // RUN: %clang_cc1 -std=c++20 %t/A.cpp -fprebuilt-module-path=%t -fsyntax-only -verify | ||
| // RUN: %clang_cc1 -std=c++20 %t/A-impl.cppm -fprebuilt-module-path=%t -fsyntax-only -verify | ||
|
|
||
| // RUN: %clang_cc1 -std=c++20 %t/A-impl2.cppm -fprebuilt-module-path=%t -fsyntax-only -verify | ||
|
|
||
| //--- Invisible.cppm | ||
| export module Invisible; | ||
| export void invisible() {} | ||
|
|
||
| //--- Other.cppm | ||
| export module Other; | ||
| import Invisible; | ||
| export void other() {} | ||
|
|
||
| //--- Another.cppm | ||
| export module Another; | ||
| export void another() {} | ||
|
|
||
| //--- A-interface.cppm | ||
| export module A:interface; | ||
| import Other; | ||
| export void a_interface() {} | ||
|
|
||
| //--- A-interface2.cppm | ||
| export module A:interface2; | ||
| import Another; | ||
| export void a_interface2() {} | ||
|
|
||
| //--- A-interface3.cppm | ||
| export module A:interface3; | ||
| import :interface; | ||
| import :interface2; | ||
| export void a_interface3() {} | ||
|
|
||
| //--- A.cppm | ||
| export module A; | ||
| import Another; | ||
| import :interface; | ||
| import :interface2; | ||
| import :interface3; | ||
|
|
||
| export void a() {} | ||
| export void impl(); | ||
|
|
||
| //--- A.cpp | ||
| module A; | ||
| void impl() { | ||
| a_interface(); | ||
| a_interface2(); | ||
| a_interface3(); | ||
|
|
||
| other(); | ||
| another(); | ||
|
|
||
| invisible(); // expected-error {{declaration of 'invisible' must be imported from module 'Invisible' before it is required}} | ||
| // expected-note@* {{declaration here is not visible}} | ||
| } | ||
|
|
||
| //--- A-impl.cppm | ||
| module A:impl; | ||
| import :interface3; | ||
|
|
||
| void impl_part() { | ||
| a_interface(); | ||
| a_interface2(); | ||
| a_interface3(); | ||
|
|
||
| other(); | ||
| another(); | ||
|
|
||
| invisible(); // expected-error {{declaration of 'invisible' must be imported from module 'Invisible' before it is required}} | ||
| // expected-note@* {{declaration here is not visible}} | ||
| } | ||
|
|
||
| //--- A-impl2.cppm | ||
| module A:impl2; | ||
| import A; | ||
|
|
||
| void impl_part2() { | ||
| a(); | ||
| impl(); | ||
|
|
||
| a_interface(); | ||
| a_interface2(); | ||
| a_interface3(); | ||
|
|
||
| other(); | ||
| another(); | ||
|
|
||
| invisible(); // expected-error {{declaration of 'invisible' must be imported from module 'Invisible' before it is required}} | ||
| // expected-note@* {{declaration here is not visible}} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // RUN: %clang_cc1 -fsyntax-only -verify=c23 -std=c23 %s -Wpre-c2x-compat | ||
| // RUN: %clang_cc1 -fsyntax-only -verify=c17 -std=c17 %s | ||
|
|
||
| constexpr int a = 0; // c17-error {{unknown type name 'constexpr'}} \ | ||
| c23-warning {{'constexpr' is incompatible with C standards before C23}} | ||
|
|
||
| void func(int array[constexpr]); // c23-error {{expected expression}} \ | ||
| // c17-error {{use of undeclared}} | ||
|
|
||
| _Atomic constexpr int b = 0; // c23-error {{constexpr variable cannot have type 'const _Atomic(int)'}} \ | ||
| // c23-warning {{'constexpr' is incompatible with C standards before C23}} \ | ||
| // c17-error {{unknown type name 'constexpr'}} | ||
|
|
||
| int static constexpr c = 1; // c17-error {{expected ';' after top level declarator}} \ | ||
| // c23-warning {{'constexpr' is incompatible with C standards before C23}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,359 @@ | ||
| // RUN: %clang_cc1 -std=c23 -verify -triple x86_64 -pedantic -Wno-conversion -Wno-constant-conversion -Wno-div-by-zero %s | ||
|
|
||
| // Check that constexpr only applies to variables. | ||
| constexpr void f0() {} // expected-error {{'constexpr' can only be used in variable declarations}} | ||
| constexpr const int f1() { return 0; } // expected-error {{'constexpr' can only be used in variable declarations}} | ||
|
|
||
| constexpr struct S1 { int f; }; //expected-error {{struct cannot be marked constexpr}} | ||
| constexpr struct S2 ; // expected-error {{struct cannot be marked constexpr}} | ||
| constexpr union U1; // expected-error {{union cannot be marked constexpr}} | ||
| constexpr union U2 {int a; float b;}; // expected-error {{union cannot be marked constexpr}} | ||
| constexpr enum E1 {A = 1, B = 2} ; // expected-error {{enum cannot be marked constexpr}} | ||
| struct S3 { | ||
| static constexpr int f = 0; // expected-error {{type name does not allow storage class}} | ||
| // expected-error@-1 {{type name does not allow constexpr}} | ||
| // expected-error@-2 {{expected ';' at end}} | ||
| constexpr int f1 = 0; | ||
| // expected-error@-1 {{type name does not allow constexpr}} | ||
| // expected-error@-2 {{expected ';' at end}} | ||
| }; | ||
|
|
||
| constexpr; // expected-error {{'constexpr' can only be used in variable declarations}} | ||
| constexpr int V1 = 3; | ||
| constexpr float V2 = 7.0; | ||
| int V3 = (constexpr)3; // expected-error {{expected expression}} | ||
|
|
||
| void f2() { | ||
| constexpr int a = 0; | ||
| constexpr float b = 1.7f; | ||
| } | ||
|
|
||
| // Check how constexpr works with other storage-class specifiers. | ||
| constexpr auto V4 = 1; | ||
| constexpr static auto V5 = 1; | ||
| constexpr static const auto V6 = 1; | ||
| constexpr static const int V7 = 1; | ||
| constexpr static int V8 = 1; | ||
| constexpr auto Ulong = 1L; | ||
| constexpr auto CompoundLiteral = (int){13}; | ||
| constexpr auto DoubleCast = (double)(1 / 3); | ||
| constexpr auto String = "this is a string"; // expected-error {{constexpr pointer initializer is not null}} | ||
| constexpr signed auto Long = 1L; // expected-error {{'auto' cannot be signed or unsigned}} | ||
| _Static_assert(_Generic(Ulong, long : 1)); | ||
| _Static_assert(_Generic(CompoundLiteral, int : 1)); | ||
| _Static_assert(_Generic(DoubleCast, double : 1)); | ||
| _Static_assert(_Generic(String, char* : 1)); | ||
|
|
||
| typedef constexpr int Foo; // expected-error {{typedef cannot be constexpr}} | ||
| constexpr typedef int Bar; // expected-error {{typedef cannot be constexpr}} | ||
|
|
||
| void f3(constexpr register int P1) { // expected-error {{function parameter cannot be constexpr}} | ||
| constexpr register int V9 = 0; | ||
| constexpr register auto V10 = 0.0; | ||
| } | ||
|
|
||
| constexpr thread_local int V11 = 38; // expected-error {{cannot combine with previous '_Thread_local' declaration specifier}} | ||
| constexpr static thread_local double V12 = 38; // expected-error {{cannot combine with previous '_Thread_local' declaration specifier}} | ||
| constexpr extern thread_local char V13; // expected-error {{cannot combine with previous '_Thread_local' declaration specifier}} | ||
| // expected-error@-1 {{cannot combine with previous 'extern' declaration specifier}} | ||
| // expected-error@-2 {{constexpr variable declaration must be a definition}} | ||
| constexpr thread_local short V14 = 38; // expected-error {{cannot combine with previous '_Thread_local' declaration specifier}} | ||
|
|
||
| // Check how constexpr works with qualifiers. | ||
| constexpr _Atomic int V15 = 0; // expected-error {{constexpr variable cannot have type 'const _Atomic(int)'}} | ||
| constexpr _Atomic(int) V16 = 0; // expected-error {{constexpr variable cannot have type 'const _Atomic(int)'}} | ||
|
|
||
| constexpr volatile int V17 = 0; // expected-error {{constexpr variable cannot have type 'const volatile int'}} | ||
|
|
||
| constexpr int * restrict V18 = 0; // expected-error {{constexpr variable cannot have type 'int *const restrict'}} | ||
|
|
||
| constexpr extern char Oops = 1; // expected-error {{cannot combine with previous 'extern' declaration specifier}} \ | ||
| // expected-warning {{'extern' variable has an initializer}} | ||
|
|
||
| constexpr int * restrict * Oops1 = 0; | ||
|
|
||
| typedef _Atomic(int) TheA; | ||
| typedef volatile short TheV; | ||
| typedef float * restrict TheR; | ||
|
|
||
| constexpr TheA V19[3] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'const TheA[3]' (aka 'const _Atomic(int)[3]')}} | ||
| constexpr TheV V20[3] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'const TheV[3]' (aka 'const volatile short[3]')}} | ||
| constexpr TheR V21[3] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'const TheR[3]' (aka 'float *restrict const[3]')}} | ||
|
|
||
| struct HasA { | ||
| TheA f; | ||
| int b; | ||
| }; | ||
|
|
||
| struct HasV { | ||
| float b; | ||
| TheV f; | ||
| }; | ||
|
|
||
| struct HasR { | ||
| short b; | ||
| int a; | ||
| TheR f; | ||
| }; | ||
|
|
||
| constexpr struct HasA V22[2] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'TheA' (aka '_Atomic(int)')}} | ||
| constexpr struct HasV V23[2] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'TheV' (aka 'volatile short')}} | ||
| constexpr struct HasR V24[2] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'TheR' (aka 'float *restrict')}} | ||
|
|
||
| union U3 { | ||
| float a; | ||
| union { | ||
| struct HasA f; | ||
| struct HasR f1; | ||
| }; | ||
| }; | ||
|
|
||
| constexpr union U3 V25 = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'TheA' (aka '_Atomic(int)')}} | ||
| constexpr union U3 V26[8] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'TheA' (aka '_Atomic(int)')}} | ||
|
|
||
| struct S4 { | ||
| union U3 f[3]; | ||
| }; | ||
|
|
||
| constexpr struct S4 V27 = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'TheA' (aka '_Atomic(int)')}} | ||
| constexpr const int V28 = 28; | ||
|
|
||
| struct S { | ||
| union { | ||
| volatile int i; | ||
| }; | ||
| int j; | ||
| }; | ||
|
|
||
| constexpr struct S s = {}; // expected-error {{constexpr variable cannot have type 'volatile int'}} | ||
|
|
||
| // Check that constexpr variable must have a valid initializer which is a | ||
| // constant expression. | ||
| constexpr int V29; | ||
| // expected-error@-1 {{constexpr variable 'V29' must be initialized by a constant expression}} | ||
|
|
||
| struct S5 { | ||
| int f; | ||
| }; | ||
|
|
||
| constexpr struct S5 V30; | ||
| // expected-error@-1 {{constexpr variable 'V30' must be initialized by a constant expression}} | ||
| constexpr struct S5 V31 = {}; | ||
|
|
||
| int randomFoo() { return 7; } | ||
|
|
||
| constexpr float V32 = randomFoo(); | ||
| // expected-error@-1 {{constexpr variable 'V32' must be initialized by a constant expression}} | ||
|
|
||
| const int V33 = 4; | ||
| const int V34 = 0; | ||
| const int V35 = 2; | ||
|
|
||
| constexpr int V36 = V33 / V34; | ||
| // expected-error@-1 {{constexpr variable 'V36' must be initialized by a constant expression}} | ||
| constexpr int V37 = V33 / V35; | ||
| // expected-error@-1 {{constexpr variable 'V37' must be initialized by a constant expression}} | ||
| constexpr int V38 = 3; | ||
| constexpr int V39 = V38 / V38; | ||
| constexpr int V40 = V38 / 2; | ||
| constexpr int V41 = V38 / 0; | ||
| // expected-error@-1 {{constexpr variable 'V41' must be initialized by a constant expression}} | ||
| // expected-note@-2 {{division by zero}} | ||
| constexpr int V42 = V38 & 0; | ||
|
|
||
| constexpr struct S5 V43 = { randomFoo() }; | ||
| // expected-error@-1 {{constexpr variable 'V43' must be initialized by a constant expression}} | ||
| constexpr struct S5 V44 = { 0 }; | ||
| constexpr struct S5 V45 = { V38 / 0 }; | ||
| // expected-error@-1 {{constexpr variable 'V45' must be initialized by a constant expression}} | ||
| // expected-note@-2 {{division by zero}} | ||
|
|
||
| constexpr float V46[3] = {randomFoo() }; | ||
| // expected-error@-1 {{constexpr variable 'V46' must be initialized by a constant expression}} | ||
| constexpr struct S5 V47[3] = {randomFoo() }; | ||
| // expected-error@-1 {{constexpr variable 'V47' must be initialized by a constant expression}} | ||
|
|
||
| const static int V48 = V38; | ||
| constexpr static int V49 = V48; | ||
| // expected-error@-1 {{constexpr variable 'V49' must be initialized by a constant expression}} | ||
|
|
||
| void f4(const int P1) { | ||
| constexpr int V = P1; | ||
| // expected-error@-1 {{constexpr variable 'V' must be initialized by a constant expression}} | ||
|
|
||
| constexpr int V1 = 12; | ||
| constexpr const int *V2 = &V1; | ||
| // expected-error@-1 {{constexpr variable 'V2' must be initialized by a constant expression}} | ||
| } | ||
|
|
||
| // Check that initializer for constexpr variable should match the type of the | ||
| // variable and is exactly representable int the variable's type. | ||
|
|
||
| struct S6 { | ||
| unsigned char a; | ||
| }; | ||
|
|
||
| struct S7 { | ||
| union { | ||
| float a; | ||
| }; | ||
| unsigned int b; | ||
| }; | ||
|
|
||
| struct S8 { | ||
| unsigned char a[3]; | ||
| unsigned int b[3]; | ||
| }; | ||
|
|
||
| constexpr struct S8 DesigInit = {.b = {299, 7, 8}, .a = {-1, 7, 8}}; | ||
| // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'unsigned char'}} | ||
|
|
||
| void f5() { | ||
| constexpr char V50 = 300; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 300 which is not exactly representable in type 'const char'}} | ||
| constexpr float V51 = 1.0 / 3.0; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 3.333333e-01 which is not exactly representable in type 'const float'}} | ||
| constexpr float V52 = 0.7; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 7.000000e-01 which is not exactly representable in type 'const float'}} | ||
| constexpr float V53 = 1.0f / 3.0f; | ||
| constexpr float V54 = 432000000000; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 432000000000 which is not exactly representable in type 'const float'}} | ||
| constexpr unsigned char V55[] = { | ||
| "\xAF", | ||
| // expected-error@-1 {{constexpr initializer evaluates to -81 which is not exactly representable in type 'const unsigned char'}} | ||
| }; | ||
|
|
||
| constexpr unsigned char V56[] = { | ||
| u8"\xAF", | ||
| }; | ||
| constexpr struct S6 V57 = {299}; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 299 which is not exactly representable in type 'unsigned char'}} | ||
| constexpr struct S6 V58 = {-299}; | ||
| // expected-error@-1 {{constexpr initializer evaluates to -299 which is not exactly representable in type 'unsigned char'}} | ||
| constexpr double V59 = 0.5; | ||
| constexpr double V60 = 1.0; | ||
| constexpr float V61 = V59 / V60; | ||
| constexpr double V62 = 1.7; | ||
| constexpr float V63 = V59 / V62; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 2.941176e-01 which is not exactly representable in type 'const float'}} | ||
|
|
||
| constexpr unsigned char V64 = '\xAF'; | ||
| // expected-error@-1 {{constexpr initializer evaluates to -81 which is not exactly representable in type 'const unsigned char'}} | ||
| constexpr unsigned char V65 = u8'\xAF'; | ||
|
|
||
| constexpr char V66[3] = {300}; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 300 which is not exactly representable in type 'const char'}} | ||
| constexpr struct S6 V67[3] = {300}; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 300 which is not exactly representable in type 'unsigned char'}} | ||
|
|
||
| constexpr struct S7 V68 = {0.3, -1 }; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 3.000000e-01 which is not exactly representable in type 'float'}} | ||
| // expected-error@-2 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'unsigned int'}} | ||
| constexpr struct S7 V69 = {0.5, -1 }; | ||
| // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'unsigned int'}} | ||
| constexpr struct S7 V70[3] = {{123456789}}; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 123456789 which is not exactly representable in type 'float'}} | ||
|
|
||
| constexpr int V71 = 0.3; | ||
| // expected-error@-1 {{constexpr initializer for type 'const int' is of type 'double'}} | ||
| constexpr int V72 = V59; | ||
| // expected-error@-1 {{constexpr initializer for type 'const int' is of type 'const double'}} | ||
| constexpr struct S6 V73 = {V59}; | ||
| // expected-error@-1 {{constexpr initializer for type 'unsigned char' is of type 'const double'}} | ||
|
|
||
| constexpr float V74 = 1; | ||
| constexpr float V75 = V59; | ||
| constexpr unsigned int V76[3] = {0.5}; | ||
| // expected-error@-1 {{constexpr initializer for type 'const unsigned int' is of type 'double'}} | ||
|
|
||
| constexpr _Complex float V77 = 0; | ||
| constexpr float V78 = V77; | ||
| // expected-error@-1 {{constexpr initializer for type 'const float' is of type 'const _Complex float'}} | ||
| constexpr int V79 = V77; | ||
| // expected-error@-1 {{constexpr initializer for type 'const int' is of type 'const _Complex float'}} | ||
|
|
||
| } | ||
|
|
||
| constexpr char string[] = "test""ing this out\xFF"; | ||
| constexpr unsigned char ustring[] = "test""ing this out\xFF"; | ||
| // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'const unsigned char'}} | ||
| constexpr char u8string[] = u8"test"u8"ing this out\xFF"; | ||
| // expected-error@-1 {{constexpr initializer evaluates to 255 which is not exactly representable in type 'const char'}} | ||
| constexpr unsigned char u8ustring[] = u8"test"u8"ing this out\xFF"; | ||
| constexpr unsigned short uustring[] = u"test"u"ing this out\xFF"; | ||
| constexpr unsigned int Ustring[] = U"test"U"ing this out\xFF"; | ||
| constexpr unsigned char Arr2[6][6] = { | ||
| {"ek\xFF"}, {"ek\xFF"} | ||
| // expected-error@-1 2{{constexpr initializer evaluates to -1 which is not exactly representable in type 'const unsigned char'}} | ||
| }; | ||
|
|
||
| constexpr int i = (12); | ||
| constexpr int j = (i); | ||
| constexpr unsigned jneg = (-i); | ||
| // expected-error@-1 {{constexpr initializer evaluates to -12 which is not exactly representable in type 'const unsigned int'}} | ||
|
|
||
| // Check that initializer for pointer constexpr variable should be null. | ||
| constexpr int V80 = 3; | ||
| constexpr const int *V81 = &V80; | ||
| // expected-error@-1 {{constexpr pointer initializer is not null}} | ||
| constexpr int *V82 = 0; | ||
| constexpr int *V83 = V82; | ||
| constexpr int *V84 = 42; | ||
| // expected-error@-1 {{constexpr variable 'V84' must be initialized by a constant expression}} | ||
| // expected-note@-2 {{this conversion is not allowed in a constant expression}} | ||
| // expected-error@-3 {{constexpr pointer initializer is not null}} | ||
| constexpr int *V85 = nullptr; | ||
|
|
||
| // Check that constexpr variables should not be VLAs. | ||
| void f6(const int P1) { | ||
| constexpr int V86[P1] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'const int[P1]'}} | ||
| const int V87 = 3; | ||
| constexpr int V88[V87] = {}; | ||
| // expected-warning@-1 {{variable length array folded to constant array as an extension}} | ||
| int V89 = 7; | ||
| constexpr int V90[V89] = {}; | ||
| // expected-error@-1 {{constexpr variable cannot have type 'const int[V89]'}} | ||
| } | ||
|
|
||
| void f7(int n, int array[n]) { | ||
| constexpr typeof(array) foo = 0; // Accepted because array is a pointer type, not a VLA type | ||
| int (*(*fp)(int n))[n]; | ||
| constexpr typeof(fp) bar = 0; // expected-error {{constexpr variable cannot have type 'const typeof (fp)' (aka 'int (*(*const)(int))[n]')}} | ||
| } | ||
|
|
||
| // Check how constexpr works with NaNs and infinities. | ||
| #define FLT_NAN __builtin_nanf("1") | ||
| #define DBL_NAN __builtin_nan("1") | ||
| #define LD_NAN __builtin_nanf("1") | ||
| #define FLT_SNAN __builtin_nansf("1") | ||
| #define DBL_SNAN __builtin_nans("1") | ||
| #define LD_SNAN __builtin_nansl("1") | ||
| #define INF __builtin_inf() | ||
| void infsNaNs() { | ||
| // Inf and quiet NaN is always fine, signaling NaN must have the same type. | ||
| constexpr float fl0 = INF; | ||
| constexpr float fl1 = (long double)INF; | ||
| constexpr float fl2 = (long double)FLT_NAN; | ||
| constexpr float fl3 = FLT_NAN; | ||
| constexpr float fl5 = DBL_NAN; | ||
| constexpr float fl6 = LD_NAN; | ||
| constexpr float fl7 = DBL_SNAN; // expected-error {{constexpr initializer evaluates to nan which is not exactly representable in type 'const float'}} | ||
| constexpr float fl8 = LD_SNAN; // expected-error {{constexpr initializer evaluates to nan which is not exactly representable in type 'const float'}} | ||
|
|
||
| constexpr double db0 = FLT_NAN; | ||
| constexpr double db2 = DBL_NAN; | ||
| constexpr double db3 = DBL_SNAN; | ||
| constexpr double db4 = FLT_SNAN; // expected-error {{constexpr initializer evaluates to nan which is not exactly representable in type 'const double'}} | ||
| constexpr double db5 = LD_SNAN; // expected-error {{constexpr initializer evaluates to nan which is not exactly representable in type 'const double'}} | ||
| constexpr double db6 = INF; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| ! RUN: bbc -emit-fir %s -o - | FileCheck %s | ||
| ! RUN: bbc --math-runtime=precise -emit-fir %s -o - | FileCheck %s | ||
| ! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s | ||
|
|
||
| ! CHECK: fir.call @_FortranAcqpowi({{.*}}){{.*}}: (!fir.complex<16>, i32) -> !fir.complex<16> | ||
| complex(16) :: a | ||
| integer(4) :: b | ||
| b = a ** b | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| ! RUN: bbc -emit-fir %s -o - | FileCheck %s | ||
| ! RUN: bbc --math-runtime=precise -emit-fir %s -o - | FileCheck %s | ||
| ! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s | ||
|
|
||
| ! CHECK: fir.call @_FortranAcqpowk({{.*}}){{.*}}: (!fir.complex<16>, i64) -> !fir.complex<16> | ||
| complex(16) :: a | ||
| integer(8) :: b | ||
| b = a ** b | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,246 @@ | ||
| .. _libc_gpu_building: | ||
|
|
||
| ====================== | ||
| Building libs for GPUs | ||
| ====================== | ||
|
|
||
| .. contents:: Table of Contents | ||
| :depth: 4 | ||
| :local: | ||
|
|
||
| Building the GPU C library | ||
| ========================== | ||
|
|
||
| This document will present recipes to build the LLVM C library targeting a GPU | ||
| architecture. The GPU build uses the same :ref:`cross build<full_cross_build>` | ||
| support as the other targets. However, the GPU target has the restriction that | ||
| it *must* be built with an up-to-date ``clang`` compiler. This is because the | ||
| GPU target uses several compiler extensions to target GPU architectures. | ||
|
|
||
| The LLVM C library currently supports two GPU targets. This is either | ||
| ``nvptx64-nvidia-cuda`` for NVIDIA GPUs or ``amdgcn-amd-amdhsa`` for AMD GPUs. | ||
| Targeting these architectures is done through ``clang``'s cross-compiling | ||
| support using the ``--target=<triple>`` flag. The following sections will | ||
| describe how to build the GPU support specifically. | ||
|
|
||
| Once you have finished building, refer to :ref:`libc_gpu_usage` to get started | ||
| with the newly built C library. | ||
|
|
||
| Standard runtimes build | ||
| ----------------------- | ||
|
|
||
| The simplest way to build the GPU libc is to use the existing LLVM runtimes | ||
| support. This will automatically handle bootstrapping an up-to-date ``clang`` | ||
| compiler and using it to build the C library. The following CMake invocation | ||
| will instruct it to build the ``libc`` runtime targeting both AMD and NVIDIA | ||
| GPUs. | ||
|
|
||
| .. code-block:: sh | ||
| $> cd llvm-project # The llvm-project checkout | ||
| $> mkdir build | ||
| $> cd build | ||
| $> cmake ../llvm -G Ninja \ | ||
| -DLLVM_ENABLE_PROJECTS="clang;lld" \ | ||
| -DLLVM_ENABLE_RUNTIMES="openmp" \ | ||
| -DCMAKE_BUILD_TYPE=<Debug|Release> \ # Select build type | ||
| -DCMAKE_INSTALL_PREFIX=<PATH> \ # Where the libraries will live | ||
| -DRUNTIMES_nvptx64-nvidia-cuda_LLVM_ENABLE_RUNTIMES=libc \ | ||
| -DRUNTIMES_amdgcn-amd-amdhsa_LLVM_ENABLE_RUNTIMES=libc \ | ||
| -DLLVM_RUNTIME_TARGETS="default;amdgcn-amd-amdhsa;nvptx64-nvidia-cuda" | ||
| $> ninja install | ||
| We need ``clang`` to build the GPU C library and ``lld`` to link AMDGPU | ||
| executables, so we enable them in ``LLVM_ENABLE_PROJECTS``. We add ``openmp`` to | ||
| ``LLVM_ENABLED_RUNTIMES`` so it is built for the default target and provides | ||
| OpenMP support. We then set ``RUNTIMES_<triple>_LLVM_ENABLE_RUNTIMES`` to enable | ||
| ``libc`` for the GPU targets. The ``LLVM_RUNTIME_TARGETS`` sets the enabled | ||
| targets to build, in this case we want the default target and the GPU targets. | ||
| Note that if ``libc`` were included in ``LLVM_ENABLE_RUNTIMES`` it would build | ||
| targeting the default host environment as well. | ||
|
|
||
| Runtimes cross build | ||
| -------------------- | ||
|
|
||
| For users wanting more direct control over the build process, the build steps | ||
| can be done manually instead. This build closely follows the instructions in the | ||
| :ref:`main documentation<runtimes_cross_build>` but is specialized for the GPU | ||
| build. We follow the same steps to first build the libc tools and a suitable | ||
| compiler. These tools must all be up-to-date with the libc source. | ||
|
|
||
| .. code-block:: sh | ||
| $> cd llvm-project # The llvm-project checkout | ||
| $> mkdir build-libc-tools # A different build directory for the build tools | ||
| $> cd build-libc-tools | ||
| $> HOST_C_COMPILER=<C compiler for the host> # For example "clang" | ||
| $> HOST_CXX_COMPILER=<C++ compiler for the host> # For example "clang++" | ||
| $> cmake ../llvm \ | ||
| -G Ninja \ | ||
| -DLLVM_ENABLE_PROJECTS="clang;libc" \ | ||
| -DCMAKE_C_COMPILER=$HOST_C_COMPILER \ | ||
| -DCMAKE_CXX_COMPILER=$HOST_CXX_COMPILER \ | ||
| -DLLVM_LIBC_FULL_BUILD=ON \ | ||
| -DLIBC_HDRGEN_ONLY=ON \ # Only build the 'libc-hdrgen' tool | ||
| -DCMAKE_BUILD_TYPE=Release # Release suggested to make "clang" fast | ||
| $> ninja # Build the 'clang' compiler | ||
| $> ninja libc-hdrgen # Build the 'libc-hdrgen' tool | ||
| Once this has finished the build directory should contain the ``clang`` compiler | ||
| and the ``libc-hdrgen`` executable. We will use the ``clang`` compiler to build | ||
| the GPU code and the ``libc-hdrgen`` tool to create the necessary headers. We | ||
| use these tools to bootstrap the build out of the runtimes directory targeting a | ||
| GPU architecture. | ||
|
|
||
| .. code-block:: sh | ||
| $> cd llvm-project # The llvm-project checkout | ||
| $> mkdir build # A different build directory for the build tools | ||
| $> cd build | ||
| $> TARGET_TRIPLE=<amdgcn-amd-amdhsa or nvptx64-nvidia-cuda> | ||
| $> TARGET_C_COMPILER=</path/to/clang> | ||
| $> TARGET_CXX_COMPILER=</path/to/clang++> | ||
| $> HDRGEN=</path/to/libc-hdrgen> | ||
| $> cmake ../runtimes \ # Point to the runtimes build | ||
| -G Ninja \ | ||
| -DLLVM_ENABLE_RUNTIMES=libc \ | ||
| -DCMAKE_C_COMPILER=$TARGET_C_COMPILER \ | ||
| -DCMAKE_CXX_COMPILER=$TARGET_CXX_COMPILER \ | ||
| -DLLVM_LIBC_FULL_BUILD=ON \ | ||
| -DLLVM_RUNTIMES_TARGET=$TARGET_TRIPLE \ | ||
| -DLIBC_HDRGEN_EXE=$HDRGEN \ | ||
| -DCMAKE_BUILD_TYPE=Release | ||
| $> ninja install | ||
| The above steps will result in a build targeting one of the supported GPU | ||
| architectures. Building for multiple targets requires separate CMake | ||
| invocations. | ||
|
|
||
| Standalone cross build | ||
| ---------------------- | ||
|
|
||
| The GPU build can also be targeted directly as long as the compiler used is a | ||
| supported ``clang`` compiler. This method is generally not recommended as it can | ||
| only target a single GPU architecture. | ||
|
|
||
| .. code-block:: sh | ||
| $> cd llvm-project # The llvm-project checkout | ||
| $> mkdir build # A different build directory for the build tools | ||
| $> cd build | ||
| $> CLANG_C_COMPILER=</path/to/clang> # Must be a trunk build | ||
| $> CLANG_CXX_COMPILER=</path/to/clang++> # Must be a trunk build | ||
| $> TARGET_TRIPLE=<amdgcn-amd-amdhsa or nvptx64-nvidia-cuda> | ||
| $> cmake ../llvm \ # Point to the llvm directory | ||
| -G Ninja \ | ||
| -DLLVM_ENABLE_PROJECTS=libc \ | ||
| -DCMAKE_C_COMPILER=$CLANG_C_COMPILER \ | ||
| -DCMAKE_CXX_COMPILER=$CLANG_CXX_COMPILER \ | ||
| -DLLVM_LIBC_FULL_BUILD=ON \ | ||
| -DLIBC_TARGET_TRIPLE=$TARGET_TRIPLE \ | ||
| -DCMAKE_BUILD_TYPE=Release | ||
| $> ninja install | ||
| This will build and install the GPU C library along with all the other LLVM | ||
| libraries. | ||
|
|
||
| Build overview | ||
| ============== | ||
|
|
||
| Once installed, the GPU build will create several files used for different | ||
| targets. This section will briefly describe their purpose. | ||
|
|
||
| **lib/<host-triple>/libcgpu-amdgpu.a or lib/libcgpu-amdgpu.a** | ||
| A static library containing fat binaries supporting AMD GPUs. These are built | ||
| using the support described in the `clang documentation | ||
| <https://clang.llvm.org/docs/OffloadingDesign.html>`_. These are intended to | ||
| be static libraries included natively for offloading languages like CUDA, HIP, | ||
| or OpenMP. This implements the standard C library. | ||
|
|
||
| **lib/<host-triple>/libmgpu-amdgpu.a or lib/libmgpu-amdgpu.a** | ||
| A static library containing fat binaries that implements the standard math | ||
| library for AMD GPUs. | ||
|
|
||
| **lib/<host-triple>/libcgpu-nvptx.a or lib/libcgpu-nvptx.a** | ||
| A static library containing fat binaries that implement the standard C library | ||
| for NVIDIA GPUs. | ||
|
|
||
| **lib/<host-triple>/libmgpu-nvptx.a or lib/libmgpu-nvptx.a** | ||
| A static library containing fat binaries that implement the standard math | ||
| library for NVIDIA GPUs. | ||
|
|
||
| **include/<target-triple>** | ||
| The include directory where all of the generated headers for the target will | ||
| go. These definitions are strictly for the GPU when being targeted directly. | ||
|
|
||
| **lib/clang/<llvm-major-version>/include/llvm-libc-wrappers/llvm-libc-decls** | ||
| These are wrapper headers created for offloading languages like CUDA, HIP, or | ||
| OpenMP. They contain functions supported in the GPU libc along with attributes | ||
| and metadata that declare them on the target device and make them compatible | ||
| with the host headers. | ||
|
|
||
| **lib/<target-triple>/libc.a** | ||
| The main C library static archive containing LLVM-IR targeting the given GPU. | ||
| It can be linked directly or inspected depending on the target support. | ||
|
|
||
| **lib/<target-triple>/libm.a** | ||
| The C library static archive providing implementations of the standard math | ||
| functions. | ||
|
|
||
| **lib/<target-triple>/libc.bc** | ||
| An alternate form of the library provided as a single LLVM-IR bitcode blob. | ||
| This can be used similarly to NVIDIA's or AMD's device libraries. | ||
|
|
||
| **lib/<target-triple>/libm.bc** | ||
| An alternate form of the library provided as a single LLVM-IR bitcode blob | ||
| containing the standard math functions. | ||
|
|
||
| **lib/<target-triple>/crt1.o** | ||
| An LLVM-IR file containing startup code to call the ``main`` function on the | ||
| GPU. This is used similarly to the standard C library startup object. | ||
|
|
||
| **bin/amdhsa-loader** | ||
| A binary utility used to launch executables compiled targeting the AMD GPU. | ||
| This will be included if the build system found the ``hsa-runtime64`` library | ||
| either in ``/opt/rocm`` or the current CMake installation directory. This is | ||
| required to build the GPU tests .See the :ref:`libc GPU usage<libc_gpu_usage>` | ||
| for more information. | ||
|
|
||
| **bin/nvptx-loader** | ||
| A binary utility used to launch executables compiled targeting the NVIDIA GPU. | ||
| This will be included if the build system found the CUDA driver API. This is | ||
| required for building tests. | ||
|
|
||
| **include/llvm-libc-rpc-server.h** | ||
| A header file containing definitions that can be used to interface with the | ||
| :ref:`RPC server<libc_gpu_rpc>`. | ||
|
|
||
| **lib/libllvmlibc_rpc_server.a** | ||
| The static library containing the implementation of the RPC server. This can | ||
| be used to enable host services for anyone looking to interface with the | ||
| :ref:`RPC client<libc_gpu_rpc>`. | ||
|
|
||
| CMake options | ||
| ============= | ||
|
|
||
| This section briefly lists a few of the CMake variables that specifically | ||
| control the GPU build of the C library. | ||
|
|
||
| **LLVM_LIBC_FULL_BUILD**:BOOL | ||
| This flag controls whether or not the libc build will generate its own | ||
| headers. This must always be on when targeting the GPU. | ||
|
|
||
| **LIBC_GPU_TEST_ARCHITECTURE**:STRING | ||
| Sets the architecture used to build the GPU tests for, such as ``gfx90a`` or | ||
| ``sm_80`` for AMD and NVIDIA GPUs respectively. The default behavior is to | ||
| detect the system's GPU architecture using the ``native`` option. If this | ||
| option is not set and a GPU was not detected the tests will not be built. | ||
|
|
||
| **LIBC_GPU_TEST_JOBS**:STRING | ||
| Sets the number of threads used to run GPU tests. The GPU test suite will | ||
| commonly run out of resources if this is not constrained so it is recommended | ||
| to keep it low. The default value is a single thread. | ||
|
|
||
| **LIBC_GPU_LOADER_EXECUTABLE**:STRING | ||
| Overrides the default loader used for running GPU tests. If this is not | ||
| provided the standard one will be built. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,8 +12,9 @@ learn more about this project. | |
|
|
||
| .. toctree:: | ||
|
|
||
| building | ||
| using | ||
| support | ||
| rpc | ||
| testing | ||
| motivation | ||