aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/docs/LanguageExtensions.rst3
-rw-r--r--clang/include/clang/Basic/Builtins.def3
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--clang/include/clang/Sema/Sema.h1
-rw-r--r--clang/lib/AST/ExprConstant.cpp18
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp5
-rw-r--r--clang/lib/Sema/DeclSpec.cpp1
-rw-r--r--clang/lib/Sema/SemaChecking.cpp59
-rw-r--r--clang/test/CodeGen/builtin-complex.c22
-rw-r--r--clang/test/CodeGen/complex-builtins-3.c (renamed from clang/test/CodeGen/complex-builtints.c)0
-rw-r--r--clang/test/Sema/Float16.c13
-rw-r--r--clang/test/Sema/builtins.c19
-rw-r--r--clang/test/Sema/fp16-sema.c6
-rw-r--r--clang/test/SemaCXX/builtins.cpp9
14 files changed, 160 insertions, 3 deletions
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 06ecc18..e12bc2c 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 1416a64..fb5b7ec 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 2e07915..adfd4c2 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_different_arg_types : Error<
+ "arguments are of different 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 376765d..0721720 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12172,6 +12172,7 @@ private:
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 5f8ad18..d0587cb7 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13281,6 +13281,7 @@ public:
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 f019111..d572de1 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 f4c30c9..f553b5c 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 252690b4..f445272 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_different_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 0000000..cf97b18
--- /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
index 09219cf..09219cf 100644
--- a/clang/test/CodeGen/complex-builtints.c
+++ b/clang/test/CodeGen/complex-builtins-3.c
diff --git a/clang/test/Sema/Float16.c b/clang/test/Sema/Float16.c
index bdfb017..872bd73 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@+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 90c033e..4b44572 100644
--- a/clang/test/Sema/builtins.c
+++ b/clang/test/Sema/builtins.c
@@ -356,3 +356,22 @@ int test_cxx_builtin() {
// expected-error@+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 different types ('double' vs 'float')}}
+ __builtin_complex(1.0f, 2.0); // expected-error {{arguments are of different 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 e678f9a..b0f6348a 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 d08e673..80f75c8 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 {{different types}} expected-error {{not a real floating}}
+ (void)__builtin_complex(d, v); // expected-error {{different 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}}