leonardchan created this revision.
leonardchan added reviewers: rjmccall, bjope, ebevhan.
leonardchan added a project: clang.
leonardchan added a parent revision: D46917: [Fixed Point Arithmetic] 
Comparison and Unary Operations for Fixed Point Types.

This patch implements fixed point comparisons with other fixed point types and 
integers. This also provides constant expression evaluation for them.


Repository:
  rC Clang

https://reviews.llvm.org/D57219

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/test/Frontend/fixed_point_comparisons.c

Index: clang/test/Frontend/fixed_point_comparisons.c
===================================================================
--- /dev/null
+++ clang/test/Frontend/fixed_point_comparisons.c
@@ -0,0 +1,344 @@
+// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
+// RUN: %clang_cc1 -ffixed-point -fpadding-on-unsigned-fixed-point -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,UNSIGNED
+
+// Fixed point against other fixed point
+_Bool b_eq_true = 2.5hk == 2.5uhk;  // CHECK-DAG: @b_eq_true  = {{.*}}global i8 1, align 1
+_Bool b_eq_false = 2.5hk == 2.4uhk; // CHECK-DAG: @b_eq_false = {{.*}}global i8 0, align 1
+
+_Bool b_ne_true = 2.5hk != 2.4uhk;  // CHECK-DAG: @b_ne_true  = {{.*}}global i8 1, align 1
+_Bool b_ne_false = 2.5hk != 2.5uhk; // CHECK-DAG: @b_ne_false = {{.*}}global i8 0, align 1
+
+_Bool b_lt_true = 2.5hk < 2.75uhk; // CHECK-DAG: @b_lt_true  = {{.*}}global i8 1, align 1
+_Bool b_lt_false = 2.5hk < 2.5uhk; // CHECK-DAG: @b_lt_false = {{.*}}global i8 0, align 1
+
+_Bool b_le_true = 2.5hk <= 2.75uhk; // CHECK-DAG: @b_le_true  = {{.*}}global i8 1, align 1
+_Bool b_le_true2 = 2.5hk <= 2.5uhk; // CHECK-DAG: @b_le_true2 = {{.*}}global i8 1, align 1
+_Bool b_le_false = 2.5hk <= 2.4uhk; // CHECK-DAG: @b_le_false = {{.*}}global i8 0, align 1
+
+_Bool b_gt_true = 2.75hk > 2.5uhk;   // CHECK-DAG: @b_gt_true  = {{.*}}global i8 1, align 1
+_Bool b_gt_false = 2.75hk > 2.75uhk; // CHECK-DAG: @b_gt_false = {{.*}}global i8 0, align 1
+
+_Bool b_ge_true = 2.75hk >= 2.5uhk;   // CHECK-DAG: @b_ge_true  = {{.*}}global i8 1, align 1
+_Bool b_ge_true2 = 2.75hk >= 2.75uhk; // CHECK-DAG: @b_ge_true2 = {{.*}}global i8 1, align 1
+_Bool b_ge_false = 2.5hk >= 2.75uhk;  // CHECK-DAG: @b_ge_false = {{.*}}global i8 0, align 1
+
+// Fixed point against int
+_Bool b_ieq_true = 2.0hk == 2;  // CHECK-DAG: @b_ieq_true  = {{.*}}global i8 1, align 1
+_Bool b_ieq_false = 2.0hk == 3; // CHECK-DAG: @b_ieq_false = {{.*}}global i8 0, align 1
+
+_Bool b_ine_true = 2.0hk != 3;  // CHECK-DAG: @b_ine_true  = {{.*}}global i8 1, align 1
+_Bool b_ine_false = 2.0hk != 2; // CHECK-DAG: @b_ine_false = {{.*}}global i8 0, align 1
+
+_Bool b_ilt_true = 2.0hk < 3;  // CHECK-DAG: @b_ilt_true  = {{.*}}global i8 1, align 1
+_Bool b_ilt_false = 2.0hk < 2; // CHECK-DAG: @b_ilt_false = {{.*}}global i8 0, align 1
+
+_Bool b_ile_true = 2.0hk <= 3;  // CHECK-DAG: @b_ile_true  = {{.*}}global i8 1, align 1
+_Bool b_ile_true2 = 2.0hk <= 2; // CHECK-DAG: @b_ile_true2 = {{.*}}global i8 1, align 1
+_Bool b_ile_false = 2.0hk <= 1; // CHECK-DAG: @b_ile_false = {{.*}}global i8 0, align 1
+
+_Bool b_igt_true = 2.0hk > 1;  // CHECK-DAG: @b_igt_true  = {{.*}}global i8 1, align 1
+_Bool b_igt_false = 2.0hk > 2; // CHECK-DAG: @b_igt_false = {{.*}}global i8 0, align 1
+
+_Bool b_ige_true = 2.0hk >= 1;  // CHECK-DAG: @b_ige_true  = {{.*}}global i8 1, align 1
+_Bool b_ige_true2 = 2.0hk >= 2; // CHECK-DAG: @b_ige_true2 = {{.*}}global i8 1, align 1
+_Bool b_ige_false = 2.0hk >= 3; // CHECK-DAG: @b_ige_false = {{.*}}global i8 0, align 1
+
+// Different signage
+// Since we can have different precisions, non powers of 2 fractions may have
+// different actual values when being compared.
+_Bool b_sne_true = 2.6hk != 2.6uhk;
+// SIGNED-DAG:   @b_sne_true = {{.*}}global i8 1, align 1
+// UNSIGNED-DAG: @b_sne_true = {{.*}}global i8 0, align 1
+
+_Bool b_seq_true = 2.0hk == 2u;  // CHECK-DAG: @b_seq_true  = {{.*}}global i8 1, align 1
+_Bool b_seq_true2 = 2.0uhk == 2; // CHECK-DAG: @b_seq_true2 = {{.*}}global i8 1, align 1
+
+void TestComparisons() {
+  short _Accum sa;
+  _Accum a;
+  unsigned short _Accum usa;
+  unsigned _Accum ua;
+
+  // Each of these should be a fixed point conversion followed by the actual
+  // comparison operation.
+  sa == a;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp eq i32 [[UPSCALE_A]], [[A2]]
+
+  sa != a;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp ne i32 [[UPSCALE_A]], [[A2]]
+
+  sa > a;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp sgt i32 [[UPSCALE_A]], [[A2]]
+
+  sa >= a;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp sge i32 [[UPSCALE_A]], [[A2]]
+
+  sa < a;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp slt i32 [[UPSCALE_A]], [[A2]]
+
+  sa <= a;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp sle i32 [[UPSCALE_A]], [[A2]]
+
+  usa > ua;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %ua, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp ugt i32 [[UPSCALE_A]], [[A2]]
+
+  usa >= ua;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %ua, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp uge i32 [[UPSCALE_A]], [[A2]]
+
+  usa < ua;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %ua, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp ult i32 [[UPSCALE_A]], [[A2]]
+
+  usa <= ua;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %ua, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: {{.*}} = icmp ule i32 [[UPSCALE_A]], [[A2]]
+}
+
+void TestIntComparisons() {
+  short _Accum sa;
+  unsigned short _Accum usa;
+
+  int i;
+  unsigned int ui;
+  _Bool b;
+  char c;
+  short s;
+  enum E {
+    A = 2
+  } e;
+
+  // These comparisons shouldn't be that different from comparing against fixed
+  // point types with other fixed point types.
+  sa == i;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_I:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // CHECK-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // CHECK-NEXT: {{.*}} = icmp eq i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  sa != i;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_I:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // CHECK-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // CHECK-NEXT: {{.*}} = icmp ne i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  sa > i;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_I:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // CHECK-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // CHECK-NEXT: {{.*}} = icmp sgt i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  sa >= i;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_I:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // CHECK-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // CHECK-NEXT: {{.*}} = icmp sge i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  sa < i;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_I:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // CHECK-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // CHECK-NEXT: {{.*}} = icmp slt i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  sa <= i;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_I:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // CHECK-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // CHECK-NEXT: {{.*}} = icmp sle i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  usa > ui;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // SIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i40
+  // SIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i40
+  // SIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i40 [[RESIZE_I]], 8
+  // SIGNED-NEXT: {{.*}} = icmp ugt i40 [[RESIZE_A]], [[UPSCALE_I]]
+  // UNSIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i39
+  // UNSIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i39
+  // UNSIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // UNSIGNED-NEXT: {{.*}} = icmp ugt i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  usa >= ui;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // SIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i40
+  // SIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i40
+  // SIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i40 [[RESIZE_I]], 8
+  // SIGNED-NEXT: {{.*}} = icmp uge i40 [[RESIZE_A]], [[UPSCALE_I]]
+  // UNSIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i39
+  // UNSIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i39
+  // UNSIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // UNSIGNED-NEXT: {{.*}} = icmp uge i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  usa < ui;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // SIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i40
+  // SIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i40
+  // SIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i40 [[RESIZE_I]], 8
+  // SIGNED-NEXT: {{.*}} = icmp ult i40 [[RESIZE_A]], [[UPSCALE_I]]
+  // UNSIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i39
+  // UNSIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i39
+  // UNSIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // UNSIGNED-NEXT: {{.*}} = icmp ult i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  usa <= ui;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // SIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i40
+  // SIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i40
+  // SIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i40 [[RESIZE_I]], 8
+  // SIGNED-NEXT: {{.*}} = icmp ule i40 [[RESIZE_A]], [[UPSCALE_I]]
+  // UNSIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i39
+  // UNSIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i39
+  // UNSIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // UNSIGNED-NEXT: {{.*}} = icmp ule i39 [[RESIZE_A]], [[UPSCALE_I]]
+
+  // Allow for comparisons with other int like types. These are no different
+  // from comparing to an int other than varying sizes. The integer types are
+  // still converted to ints or unsigned ints from UsualUnaryConversions().
+  sa == b;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[B:%[0-9]+]] = load i8, i8* %b, align 1
+  // CHECK-NEXT: %tobool = trunc i8 [[B]] to i1
+  // CHECK-NEXT: [[CONV_B:%[a-z0-9]+]] = zext i1 %tobool to i32
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_B:%[a-z0-9]+]] = sext i32 [[CONV_B]] to i39
+  // CHECK-NEXT: [[UPSCALE_B:%[a-z0-9]+]] = shl i39 [[RESIZE_B]], 7
+  // CHECK-NEXT: {{.*}} = icmp eq i39 [[RESIZE_A]], [[UPSCALE_B]]
+
+  sa == c;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[C:%[0-9]+]] = load i8, i8* %c, align 1
+  // CHECK-NEXT: [[CONV_C:%[a-z0-9]+]] = sext i8 [[C]] to i32
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_C:%[a-z0-9]+]] = sext i32 [[CONV_C]] to i39
+  // CHECK-NEXT: [[UPSCALE_C:%[a-z0-9]+]] = shl i39 [[RESIZE_C]], 7
+  // CHECK-NEXT: {{.*}} = icmp eq i39 [[RESIZE_A]], [[UPSCALE_C]]
+
+  sa == s;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[S:%[0-9]+]] = load i16, i16* %s, align 2
+  // CHECK-NEXT: [[CONV_S:%[a-z0-9]+]] = sext i16 [[S]] to i32
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i39
+  // CHECK-NEXT: [[RESIZE_S:%[a-z0-9]+]] = sext i32 [[CONV_S]] to i39
+  // CHECK-NEXT: [[UPSCALE_S:%[a-z0-9]+]] = shl i39 [[RESIZE_S]], 7
+  // CHECK-NEXT: {{.*}} = icmp eq i39 [[RESIZE_A]], [[UPSCALE_S]]
+
+  // An enum value is IntegralCast to an unsigned int.
+  usa == e;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %e, align 4
+  // SIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i40
+  // SIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i40
+  // SIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i40 [[RESIZE_I]], 8
+  // SIGNED-NEXT: {{.*}} = icmp eq i40 [[RESIZE_A]], [[UPSCALE_I]]
+  // UNSIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i39
+  // UNSIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i39
+  // UNSIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // UNSIGNED-NEXT: {{.*}} = icmp eq i39 [[RESIZE_A]], [[UPSCALE_I]]
+}
+
+void TestComparisonSignage() {
+  short _Accum sa;
+  unsigned short _Accum usa;
+  int i;
+  unsigned int ui;
+
+  // Signed vs unsigned fixed point comparison
+  sa == usa;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i16, i16* %usa, align 2
+  // SIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i17
+  // SIGNED-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i17 [[RESIZE_A]], 1
+  // SIGNED-NEXT: [[RESIZE_A2:%[a-z0-9]+]] = zext i16 [[A2]] to i17
+  // SIGNED-NEXT: {{.*}} = icmp eq i17 [[UPSCALE_A]], [[RESIZE_A2]]
+  // UNSIGNED-NEXT: {{.*}} = icmp eq i16 [[A]], [[A2]]
+
+  // Signed int vs unsigned fixed point
+  sa == ui;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i40
+  // CHECK-NEXT: [[RESIZE_I:%[a-z0-9]+]] = zext i32 [[I]] to i40
+  // CHECK-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i40 [[RESIZE_I]], 7
+  // CHECK-NEXT: {{.*}} = icmp eq i40 [[RESIZE_A]], [[UPSCALE_I]]
+
+  // Signed fixed point vs unsigned int
+  usa == i;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
+  // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // SIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i40
+  // SIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = sext i32 [[I]] to i40
+  // SIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i40 [[RESIZE_I]], 8
+  // SIGNED-NEXT: {{.*}} = icmp eq i40 [[RESIZE_A]], [[UPSCALE_I]]
+  // UNSIGNED-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i39
+  // UNSIGNED-NEXT: [[RESIZE_I:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // UNSIGNED-NEXT: [[UPSCALE_I:%[a-z0-9]+]] = shl i39 [[RESIZE_I]], 7
+  // UNSIGNED-NEXT: {{.*}} = icmp eq i39 [[RESIZE_A]], [[UPSCALE_I]]
+}
+
+void StoreBooleanResult() {
+  short _Accum sa;
+  _Accum a;
+  int res;
+
+  // Check that the result can properly be stored as an int.
+  res = sa == a;
+  // CHECK:      [[A:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = sext i16 [[A]] to i32
+  // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
+  // CHECK-NEXT: [[RES:%[0-9]+]] = icmp eq i32 [[UPSCALE_A]], [[A2]]
+  // CHECK-NEXT: %conv = zext i1 [[RES]] to i32
+  // CHECK-NEXT: store i32 %conv, i32* %res, align 4
+}
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -125,11 +125,22 @@
     return true;
   }
 
-  /// Check if either operand is a fixed point type, in which case, this
+  /// Check if either operand is a fixed point type or integer type, with at
+  /// least one being a fixed point type. In any case, this
   /// operation did not follow usual arithmetic conversion and both operands may
   /// not be the same.
   bool isFixedPointBinOp() const {
-    return isa<BinaryOperator>(E) && Ty->isFixedPointType();
+    // We cannot simply check the result type since comparison operations return
+    // an int.
+    if (const auto *BinOp = dyn_cast<BinaryOperator>(E)) {
+      QualType LHSType = BinOp->getLHS()->getType();
+      QualType RHSType = BinOp->getRHS()->getType();
+      return (LHSType->isFixedPointType() &&
+              RHSType->isFixedPointOrIntegerType()) ||
+             (RHSType->isFixedPointType() &&
+              LHSType->isFixedPointOrIntegerType());
+    }
+    return false;
   }
 };
 
@@ -3371,8 +3382,6 @@
   using llvm::ConstantInt;
 
   const auto *BinOp = cast<BinaryOperator>(op.E);
-  assert((BinOp->getOpcode() == BO_Add || BinOp->getOpcode() == BO_Sub) &&
-         "Expected operation to be addition or subtraction");
 
   // The result is a fixed point type and at least one of the operands is fixed
   // point while the other is either fixed point or an int. This resulting type
@@ -3420,17 +3429,27 @@
     }
     break;
   }
-  case BO_Mul:
-  case BO_Div:
-  case BO_Shl:
-  case BO_Shr:
-  case BO_Cmp:
   case BO_LT:
+    return CommonFixedSema.isSigned() ? Builder.CreateICmpSLT(FullLHS, FullRHS)
+                                      : Builder.CreateICmpULT(FullLHS, FullRHS);
   case BO_GT:
+    return CommonFixedSema.isSigned() ? Builder.CreateICmpSGT(FullLHS, FullRHS)
+                                      : Builder.CreateICmpUGT(FullLHS, FullRHS);
   case BO_LE:
+    return CommonFixedSema.isSigned() ? Builder.CreateICmpSLE(FullLHS, FullRHS)
+                                      : Builder.CreateICmpULE(FullLHS, FullRHS);
   case BO_GE:
+    return CommonFixedSema.isSigned() ? Builder.CreateICmpSGE(FullLHS, FullRHS)
+                                      : Builder.CreateICmpUGE(FullLHS, FullRHS);
   case BO_EQ:
+    return Builder.CreateICmpEQ(FullLHS, FullRHS);
   case BO_NE:
+    return Builder.CreateICmpNE(FullLHS, FullRHS);
+  case BO_Mul:
+  case BO_Div:
+  case BO_Shl:
+  case BO_Shr:
+  case BO_Cmp:
   case BO_LAnd:
   case BO_LOr:
   case BO_MulAssign:
@@ -3713,8 +3732,9 @@
     Result = CGF.CGM.getCXXABI().EmitMemberPointerComparison(
                    CGF, LHS, RHS, MPT, E->getOpcode() == BO_NE);
   } else if (!LHSTy->isAnyComplexType() && !RHSTy->isAnyComplexType()) {
-    Value *LHS = Visit(E->getLHS());
-    Value *RHS = Visit(E->getRHS());
+    BinOpInfo BOInfo = EmitBinOps(E);
+    Value *LHS = BOInfo.LHS;
+    Value *RHS = BOInfo.RHS;
 
     // If AltiVec, the comparison results in a numeric type, so we use
     // intrinsics comparing vectors and giving 0 or 1 as a result
@@ -3792,7 +3812,9 @@
                                   E->getExprLoc());
     }
 
-    if (LHS->getType()->isFPOrFPVectorTy()) {
+    if (BOInfo.isFixedPointBinOp()) {
+      Result = EmitFixedPointBinOp(BOInfo);
+    } else if (LHS->getType()->isFPOrFPVectorTy()) {
       Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
     } else if (LHSTy->hasSignedIntegerRepresentation()) {
       Result = Builder.CreateICmp(SICmpOpc, LHS, RHS, "cmp");
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -9149,6 +9149,22 @@
     return Success(CCR::Equal, E);
   }
 
+  if (LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) {
+    APFixedPoint LHSFX(Info.Ctx.getFixedPointSemantics(LHSTy));
+    APFixedPoint RHSFX(Info.Ctx.getFixedPointSemantics(RHSTy));
+
+    bool LHSOK = EvaluateFixedPointOrInteger(E->getLHS(), LHSFX, Info);
+    if (!LHSOK && !Info.noteFailure())
+      return false;
+    if (!EvaluateFixedPointOrInteger(E->getRHS(), RHSFX, Info) || !LHSOK)
+      return false;
+    if (LHSFX < RHSFX)
+      return Success(CCR::Less, E);
+    if (LHSFX > RHSFX)
+      return Success(CCR::Greater, E);
+    return Success(CCR::Equal, E);
+  }
+
   if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) {
     ComplexValue LHS, RHS;
     bool LHSOK;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to