]> granicus.if.org Git - clang/commitdiff
[complex] Teach the other two binary operators on complex numbers (==
authorChandler Carruth <chandlerc@gmail.com>
Sat, 11 Oct 2014 11:03:30 +0000 (11:03 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sat, 11 Oct 2014 11:03:30 +0000 (11:03 +0000)
and !=) to support mixed complex and real operand types.

This requires removing an assert from SemaChecking, and adding support
both to the constant evaluator and the code generator to synthesize the
imaginary part when needed. This seemed somewhat cleaner than having
just the comparison operators force real-to-complex conversions.

I've added test cases for these operations. I'm really terrified that
there were *no* tests in-tree which exercised this.

This turned up when trying to build R after my change to the complex
type lowering.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219570 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprConstant.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Sema/SemaChecking.cpp
test/CodeGen/complex-math.c
test/SemaCXX/complex-folding.cpp

index db300c4fec4e4a8610a0816d32c01dd8a34d5ccc..532720666bc8b7b56e1f8f51d5dd732e61a08c7c 100644 (file)
@@ -6780,15 +6780,27 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
   QualType LHSTy = E->getLHS()->getType();
   QualType RHSTy = E->getRHS()->getType();
 
-  if (LHSTy->isAnyComplexType()) {
-    assert(RHSTy->isAnyComplexType() && "Invalid comparison");
+  if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) {
     ComplexValue LHS, RHS;
-
-    bool LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
+    bool LHSOK;
+    if (E->getLHS()->getType()->isRealFloatingType()) {
+      LHSOK = EvaluateFloat(E->getLHS(), LHS.FloatReal, Info);
+      if (LHSOK) {
+        LHS.makeComplexFloat();
+        LHS.FloatImag = APFloat(LHS.FloatReal.getSemantics());
+      }
+    } else {
+      LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
+    }
     if (!LHSOK && !Info.keepEvaluatingAfterFailure())
       return false;
 
-    if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
+    if (E->getRHS()->getType()->isRealFloatingType()) {
+      if (!EvaluateFloat(E->getRHS(), RHS.FloatReal, Info) || !LHSOK)
+        return false;
+      RHS.makeComplexFloat();
+      RHS.FloatImag = APFloat(RHS.FloatReal.getSemantics());
+    } else if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
       return false;
 
     if (LHS.isComplexFloat()) {
index abde51f29e4f3f04c1ba2886ba68dd1b54824168..ac6afe484536ba74bb22fd8a6b149c7408f9e49f 100644 (file)
@@ -2754,6 +2754,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
   TestAndClearIgnoreResultAssign();
   Value *Result;
   QualType LHSTy = E->getLHS()->getType();
+  QualType RHSTy = E->getRHS()->getType();
   if (const MemberPointerType *MPT = LHSTy->getAs<MemberPointerType>()) {
     assert(E->getOpcode() == BO_EQ ||
            E->getOpcode() == BO_NE);
@@ -2761,7 +2762,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
     Value *RHS = CGF.EmitScalarExpr(E->getRHS());
     Result = CGF.CGM.getCXXABI().EmitMemberPointerComparison(
                    CGF, LHS, RHS, MPT, E->getOpcode() == BO_NE);
-  } else if (!LHSTy->isAnyComplexType()) {
+  } else if (!LHSTy->isAnyComplexType() && !RHSTy->isAnyComplexType()) {
     Value *LHS = Visit(E->getLHS());
     Value *RHS = Visit(E->getRHS());
 
@@ -2849,10 +2850,27 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
 
   } else {
     // Complex Comparison: can only be an equality comparison.
-    CodeGenFunction::ComplexPairTy LHS = CGF.EmitComplexExpr(E->getLHS());
-    CodeGenFunction::ComplexPairTy RHS = CGF.EmitComplexExpr(E->getRHS());
-
-    QualType CETy = LHSTy->getAs<ComplexType>()->getElementType();
+    CodeGenFunction::ComplexPairTy LHS, RHS;
+    QualType CETy;
+    if (auto *CTy = LHSTy->getAs<ComplexType>()) {
+      LHS = CGF.EmitComplexExpr(E->getLHS());
+      CETy = CTy->getElementType();
+    } else {
+      LHS.first = Visit(E->getLHS());
+      LHS.second = llvm::Constant::getNullValue(LHS.first->getType());
+      CETy = LHSTy;
+    }
+    if (auto *CTy = RHSTy->getAs<ComplexType>()) {
+      RHS = CGF.EmitComplexExpr(E->getRHS());
+      assert(CGF.getContext().hasSameUnqualifiedType(CETy,
+                                                     CTy->getElementType()) &&
+             "The element types must always match.");
+    } else {
+      RHS.first = Visit(E->getRHS());
+      RHS.second = llvm::Constant::getNullValue(RHS.first->getType());
+      assert(CGF.getContext().hasSameUnqualifiedType(CETy, RHSTy) &&
+             "The element types must always match.");
+    }
 
     Value *ResultR, *ResultI;
     if (CETy->isRealFloatingType()) {
index a856c98bf052f2c44514dc434528c8748801ea78..58c626351f9eca4d89e84b0293c386ff1701ee41 100644 (file)
@@ -5890,8 +5890,13 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
 static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
   // The type the comparison is being performed in.
   QualType T = E->getLHS()->getType();
-  assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
-         && "comparison with mismatched types");
+
+  // Only analyze comparison operators where both sides have been converted to
+  // the same type.
+  if (!S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType()))
+    return AnalyzeImpConvsInComparison(S, E);
+
+  // Don't analyze value-dependent comparisons directly.
   if (E->isValueDependent())
     return AnalyzeImpConvsInComparison(S, E);
 
index ca04e8d94d168b4804b20155296cd8d4b6a01cdb..27540c78f77e4d8c491b6d8a10c3af71fdbd2d81 100644 (file)
@@ -367,3 +367,54 @@ long double _Complex div_long_double_cc(long double _Complex a, long double _Com
   // X86: ret
   return a / b;
 }
+
+// Comparison operators don't rely on library calls or have interseting math
+// properties, but test that mixed types work correctly here.
+_Bool eq_float_cr(float _Complex a, float b) {
+  // X86-LABEL: @eq_float_cr(
+  // X86: fcmp oeq
+  // X86: fcmp oeq
+  // X86: and i1
+  // X86: ret
+  return a == b;
+}
+_Bool eq_float_rc(float a, float _Complex b) {
+  // X86-LABEL: @eq_float_rc(
+  // X86: fcmp oeq
+  // X86: fcmp oeq
+  // X86: and i1
+  // X86: ret
+  return a == b;
+}
+_Bool eq_float_cc(float _Complex a, float _Complex b) {
+  // X86-LABEL: @eq_float_cc(
+  // X86: fcmp oeq
+  // X86: fcmp oeq
+  // X86: and i1
+  // X86: ret
+  return a == b;
+}
+_Bool ne_float_cr(float _Complex a, float b) {
+  // X86-LABEL: @ne_float_cr(
+  // X86: fcmp une
+  // X86: fcmp une
+  // X86: or i1
+  // X86: ret
+  return a != b;
+}
+_Bool ne_float_rc(float a, float _Complex b) {
+  // X86-LABEL: @ne_float_rc(
+  // X86: fcmp une
+  // X86: fcmp une
+  // X86: or i1
+  // X86: ret
+  return a != b;
+}
+_Bool ne_float_cc(float _Complex a, float _Complex b) {
+  // X86-LABEL: @ne_float_cc(
+  // X86: fcmp une
+  // X86: fcmp une
+  // X86: or i1
+  // X86: ret
+  return a != b;
+}
index 6a77bfdb31038ecd5f33e175527cba74e794aa25..1c2f9c73eb313c4da37b3d5212ee261cf2f432a3 100644 (file)
@@ -3,6 +3,14 @@
 // Test the constant folding of builtin complex numbers.
 
 static_assert((0.0 + 0.0j) == (0.0 + 0.0j));
+static_assert((0.0 + 0.0j) != (0.0 + 0.0j)); // expected-error {{static_assert}}
+
+static_assert((0.0 + 0.0j) == 0.0);
+static_assert(0.0 == (0.0 + 0.0j));
+static_assert(0.0 == 0.0j);
+static_assert((0.0 + 1.0j) != 0.0);
+static_assert(1.0 != (0.0 + 0.0j));
+static_assert(0.0 != 1.0j);
 
 // Walk around the complex plane stepping between angular differences and
 // equality.