[clang] 6c18f7d - For PR46800, implement the GCC __builtin_complex builtin.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 22 13:43:26 PDT 2020
Author: Richard Smith
Date: 2020-07-22T13:43:10-07:00
New Revision: 6c18f7db73a08f1ae39a76a86b414c5b0c24ee86
URL: https://github.com/llvm/llvm-project/commit/6c18f7db73a08f1ae39a76a86b414c5b0c24ee86
DIFF: https://github.com/llvm/llvm-project/commit/6c18f7db73a08f1ae39a76a86b414c5b0c24ee86.diff
LOG: For PR46800, implement the GCC __builtin_complex builtin.
glibc's implementation of the CMPLX macro uses it (with -fgnuc-version
set to 4.7 or later).
Added:
clang/test/CodeGen/builtin-complex.c
clang/test/CodeGen/complex-builtins-3.c
Modified:
clang/docs/LanguageExtensions.rst
clang/include/clang/Basic/Builtins.def
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/AST/ExprConstant.cpp
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/Sema/DeclSpec.cpp
clang/lib/Sema/SemaChecking.cpp
clang/test/Sema/Float16.c
clang/test/Sema/builtins.c
clang/test/Sema/fp16-sema.c
clang/test/SemaCXX/builtins.cpp
Removed:
clang/test/CodeGen/complex-builtints.c
################################################################################
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 06ecc186c7dc..e12bc2ce9633 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1719,6 +1719,9 @@ This extension also works in C++ mode, as far as that goes, but does not apply
to the C++ ``std::complex``. (In C++11, list initialization allows the same
syntax to be used with ``std::complex`` with the same meaning.)
+For GCC compatibility, ``__builtin_complex(re, im)`` can also be used to
+construct a complex number from the given real and imaginary components.
+
Builtin Functions
=================
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index 1416a64543a4..fb5b7ec22d07 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -395,6 +395,9 @@ BUILTIN(__builtin_ctanh, "XdXd", "Fne")
BUILTIN(__builtin_ctanhf, "XfXf", "Fne")
BUILTIN(__builtin_ctanhl, "XLdXLd", "Fne")
+// GCC-compatible C99 CMPLX implementation.
+BUILTIN(__builtin_complex, "v.", "nct")
+
// FP Comparisons.
BUILTIN(__builtin_isgreater , "i.", "Fnct")
BUILTIN(__builtin_isgreaterequal, "i.", "Fnct")
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2e0791526aec..adfd4c207da8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8148,6 +8148,10 @@ def warn_cast_pointer_from_sel : Warning<
def warn_function_def_in_objc_container : Warning<
"function definition inside an Objective-C container is deprecated">,
InGroup<FunctionDefInObjCContainer>;
+def err_typecheck_call_requires_real_fp : Error<
+ "argument type %0 is not a real floating point type">;
+def err_typecheck_call_
diff erent_arg_types : Error<
+ "arguments are of
diff erent types%
diff { ($ vs $)|}0,1">;
def warn_cast_calling_conv : Warning<
"cast between incompatible calling conventions '%0' and '%1'; "
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 376765dc1138..0721720f7908 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12172,6 +12172,7 @@ class Sema final {
bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
+ bool SemaBuiltinComplex(CallExpr *TheCall);
bool SemaBuiltinVSX(CallExpr *TheCall);
bool SemaBuiltinOSLogFormat(CallExpr *TheCall);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 5f8ad18c0ed2..d0587cb723bc 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13281,6 +13281,7 @@ class ComplexExprEvaluator
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitCallExpr(const CallExpr *E);
};
} // end anonymous namespace
@@ -13749,6 +13750,23 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
return ExprEvaluatorBaseTy::VisitInitListExpr(E);
}
+bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ switch (E->getBuiltinCallee()) {
+ case Builtin::BI__builtin_complex:
+ Result.makeComplexFloat();
+ if (!EvaluateFloat(E->getArg(0), Result.FloatReal, Info))
+ return false;
+ if (!EvaluateFloat(E->getArg(1), Result.FloatImag, Info))
+ return false;
+ return true;
+
+ default:
+ break;
+ }
+
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+}
+
//===----------------------------------------------------------------------===//
// Atomic expression evaluation, essentially just handling the NonAtomicToAtomic
// implicit conversion.
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f0191112074b..d572de1b8b79 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1978,6 +1978,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *Result = Builder.CreateSelect(CmpResult, NegOp, ArgValue, "abs");
return RValue::get(Result);
}
+ case Builtin::BI__builtin_complex: {
+ Value *Real = EmitScalarExpr(E->getArg(0));
+ Value *Imag = EmitScalarExpr(E->getArg(1));
+ return RValue::getComplex({Real, Imag});
+ }
case Builtin::BI__builtin_conj:
case Builtin::BI__builtin_conjf:
case Builtin::BI__builtin_conjl:
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index f4c30c90ad27..f553b5ca6079 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -1279,6 +1279,7 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
S.Diag(TSTLoc, diag::ext_integer_complex);
} else if (TypeSpecType != TST_float && TypeSpecType != TST_double &&
TypeSpecType != TST_float128) {
+ // FIXME: _Float16, __fp16?
S.Diag(TSCLoc, diag::err_invalid_complex_spec)
<< getSpecifierName((TST)TypeSpecType, Policy);
TypeSpecComplex = TSC_unspecified;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 252690b436e3..f445272b020b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1582,6 +1582,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (checkArgCount(*this, TheCall, 1)) return true;
TheCall->setType(Context.IntTy);
break;
+ case Builtin::BI__builtin_complex:
+ if (SemaBuiltinComplex(TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_constant_p: {
if (checkArgCount(*this, TheCall, 1)) return true;
ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
@@ -5786,6 +5790,61 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
return false;
}
+/// Perform semantic analysis for a call to __builtin_complex.
+bool Sema::SemaBuiltinComplex(CallExpr *TheCall) {
+ if (checkArgCount(*this, TheCall, 2))
+ return true;
+
+ bool Dependent = false;
+ for (unsigned I = 0; I != 2; ++I) {
+ Expr *Arg = TheCall->getArg(I);
+ QualType T = Arg->getType();
+ if (T->isDependentType()) {
+ Dependent = true;
+ continue;
+ }
+
+ // Despite supporting _Complex int, GCC requires a real floating point type
+ // for the operands of __builtin_complex.
+ if (!T->isRealFloatingType()) {
+ return Diag(Arg->getBeginLoc(), diag::err_typecheck_call_requires_real_fp)
+ << Arg->getType() << Arg->getSourceRange();
+ }
+
+ ExprResult Converted = DefaultLvalueConversion(Arg);
+ if (Converted.isInvalid())
+ return true;
+ TheCall->setArg(I, Converted.get());
+ }
+
+ if (Dependent) {
+ TheCall->setType(Context.DependentTy);
+ return false;
+ }
+
+ Expr *Real = TheCall->getArg(0);
+ Expr *Imag = TheCall->getArg(1);
+ if (!Context.hasSameType(Real->getType(), Imag->getType())) {
+ return Diag(Real->getBeginLoc(),
+ diag::err_typecheck_call_
diff erent_arg_types)
+ << Real->getType() << Imag->getType()
+ << Real->getSourceRange() << Imag->getSourceRange();
+ }
+
+ // We don't allow _Complex _Float16 nor _Complex __fp16 as type specifiers;
+ // don't allow this builtin to form those types either.
+ // FIXME: Should we allow these types?
+ if (Real->getType()->isFloat16Type())
+ return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
+ << "_Float16";
+ if (Real->getType()->isHalfType())
+ return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
+ << "half";
+
+ TheCall->setType(Context.getComplexType(Real->getType()));
+ return false;
+}
+
// Customized Sema Checking for VSX builtins that have the following signature:
// vector [...] builtinName(vector [...], vector [...], const int);
// Which takes the same type of vectors (any legal vector type) for the first
diff --git a/clang/test/CodeGen/builtin-complex.c b/clang/test/CodeGen/builtin-complex.c
new file mode 100644
index 000000000000..cf97b18d8747
--- /dev/null
+++ b/clang/test/CodeGen/builtin-complex.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-linux -w -S -o - -emit-llvm -DT=float %s | FileCheck %s --check-prefixes=CHECK,CHECK-FLOAT
+// RUN: %clang_cc1 -triple x86_64-linux -w -S -o - -emit-llvm -DT=double %s | FileCheck %s --check-prefixes=CHECK,CHECK-DOUBLE
+// RUN: %clang_cc1 -triple x86_64-linux -w -S -o - -emit-llvm -DT="long double" %s | FileCheck %s --check-prefixes=CHECK,CHECK-FP80
+// RUN: %clang_cc1 -triple x86_64-linux -w -S -o - -emit-llvm -DT=__float128 %s | FileCheck %s --check-prefixes=CHECK,CHECK-FP128
+// FIXME: If we start to support _Complex __fp16 or _Complex _Float16, add tests for them too.
+
+// CHECK-FLOAT: @global = global { [[T:float]], [[T]] } { [[T]] 1.0{{.*}}, [[T]] 2.0{{.*}} }
+// CHECK-DOUBLE: @global = global { [[T:double]], [[T]] } { [[T]] 1.0{{.*}}, [[T]] 2.0{{.*}} }
+// CHECK-FP80: @global = global { [[T:x86_fp80]], [[T]] } { [[T]] 0xK3FFF8000000000000000, [[T]] 0xK40008000000000000000 }
+// CHECK-FP128: @global = global { [[T:fp128]], [[T]] } { [[T]] 0xL00000000000000003FFF000000000000, [[T]] 0xL00000000000000004000000000000000 }
+_Complex T global = __builtin_complex(1.0, 2.0);
+
+// CHECK-LABEL: @test
+_Complex T test(T a, T b) {
+ return __builtin_complex(a, b);
+ // CHECK: %[[A:.*]] = load [[T]], [[T]]* %a.addr,
+ // CHECK: %[[B:.*]] = load [[T]], [[T]]* %b.addr,
+ // CHECK: %[[RET_RE:.*]] = getelementptr inbounds { [[T]], [[T]] }, { [[T]], [[T]] }* %[[RET:[^,]*]], i32 0, i32 0
+ // CHECK: %[[RET_IM:.*]] = getelementptr inbounds { [[T]], [[T]] }, { [[T]], [[T]] }* %[[RET]], i32 0, i32 1
+ // CHECK: store [[T]] %[[A]], [[T]]* %[[RET_RE]],
+ // CHECK: store [[T]] %[[B]], [[T]]* %[[RET_IM]],
+}
diff --git a/clang/test/CodeGen/complex-builtints.c b/clang/test/CodeGen/complex-builtins-3.c
similarity index 100%
rename from clang/test/CodeGen/complex-builtints.c
rename to clang/test/CodeGen/complex-builtins-3.c
diff --git a/clang/test/Sema/Float16.c b/clang/test/Sema/Float16.c
index bdfb01702c37..872bd732bd41 100644
--- a/clang/test/Sema/Float16.c
+++ b/clang/test/Sema/Float16.c
@@ -3,9 +3,16 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s -DHAVE
// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s -DHAVE
-#ifdef HAVE
-// expected-no-diagnostics
-#else
+#ifndef HAVE
// expected-error at +2{{_Float16 is not supported on this target}}
#endif // HAVE
_Float16 f;
+
+#ifdef HAVE
+// FIXME: Should this be valid?
+_Complex _Float16 a; // expected-error {{'_Complex _Float16' is invalid}}
+void builtin_complex() {
+ _Float16 a = 0;
+ (void)__builtin_complex(a, a); // expected-error {{'_Complex _Float16' is invalid}}
+}
+#endif
diff --git a/clang/test/Sema/builtins.c b/clang/test/Sema/builtins.c
index 90c033e47cd1..4b445724f712 100644
--- a/clang/test/Sema/builtins.c
+++ b/clang/test/Sema/builtins.c
@@ -356,3 +356,22 @@ int test_cxx_builtin() {
// expected-error at +1 {{use of unknown builtin '__builtin_is_constant_evaluated'}}
return __builtin_is_constant_evaluated();
}
+
+void test_builtin_complex() {
+ __builtin_complex(); // expected-error {{too few}}
+ __builtin_complex(1); // expected-error {{too few}}
+ __builtin_complex(1, 2, 3); // expected-error {{too many}}
+
+ _Static_assert(_Generic(__builtin_complex(1.0f, 2.0f), _Complex float: 1, default: 0), "");
+ _Static_assert(_Generic(__builtin_complex(1.0, 2.0), _Complex double: 1, default: 0), "");
+ _Static_assert(_Generic(__builtin_complex(1.0l, 2.0l), _Complex long double: 1, default: 0), "");
+
+ __builtin_complex(1, 2); // expected-error {{argument type 'int' is not a real floating point type}}
+ __builtin_complex(1, 2.0); // expected-error {{argument type 'int' is not a real floating point type}}
+ __builtin_complex(1.0, 2); // expected-error {{argument type 'int' is not a real floating point type}}
+
+ __builtin_complex(1.0, 2.0f); // expected-error {{arguments are of
diff erent types ('double' vs 'float')}}
+ __builtin_complex(1.0f, 2.0); // expected-error {{arguments are of
diff erent types ('float' vs 'double')}}
+}
+
+_Complex double builtin_complex_static_init = __builtin_complex(1.0, 2.0);
diff --git a/clang/test/Sema/fp16-sema.c b/clang/test/Sema/fp16-sema.c
index e678f9a829e4..b0f6348a52a4 100644
--- a/clang/test/Sema/fp16-sema.c
+++ b/clang/test/Sema/fp16-sema.c
@@ -28,3 +28,9 @@ extern __fp16 *(*gf1) (void);
typedef __fp16 (*tf1) (void); // expected-error {{function return value cannot have __fp16 type; did you forget * ?}}
typedef __fp16 *(*tg1) (void);
+void testComplex() {
+ // FIXME: Should these be valid?
+ _Complex __fp16 a; // expected-error {{'_Complex half' is invalid}}
+ __fp16 b;
+ a = __builtin_complex(b, b); // expected-error {{'_Complex half' is invalid}}
+}
diff --git a/clang/test/SemaCXX/builtins.cpp b/clang/test/SemaCXX/builtins.cpp
index d08e673c04b7..80f75c8232c2 100644
--- a/clang/test/SemaCXX/builtins.cpp
+++ b/clang/test/SemaCXX/builtins.cpp
@@ -144,3 +144,12 @@ void test_noexcept(int *i) {
}
#undef TEST_TYPE
} // end namespace test_launder
+
+template<typename T> void test_builtin_complex(T v, double d) {
+ (void)__builtin_complex(v, d); // expected-error {{
diff erent types}} expected-error {{not a real floating}}
+ (void)__builtin_complex(d, v); // expected-error {{
diff erent types}} expected-error {{not a real floating}}
+ (void)__builtin_complex(v, v); // expected-error {{not a real floating}}
+}
+template void test_builtin_complex(double, double);
+template void test_builtin_complex(float, double); // expected-note {{instantiation of}}
+template void test_builtin_complex(int, double); // expected-note {{instantiation of}}
More information about the cfe-commits
mailing list