Hi,
The attached patch adds value-range info for __builtin_tolower and
__builtin_toupper.
In the patch, I have just settled for anti-range ~['a', 'z'] for
return value of toupper.
Would that be correct albeit imprecise ?

A more precise range would be:
[0, UCHAR_MAX] intersect ~['a', 'z'] union EOF
as mentioned in PR.
I am not sure though if it's possible for a SSA_NAME to have multiple
disjoint ranges ?

Bootstrap+tested on x86_64-unknown-linux-gnu.

Thanks,
Prathamesh
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr78888.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr78888.c
new file mode 100644
index 00000000000..2bcddf1f2c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr78888.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp-slim" } */
+
+void g (int x)
+{
+  if (__builtin_toupper ((unsigned char)x) == 'a')
+    __builtin_abort ();
+}
+
+void h (int x)
+{
+  if (__builtin_tolower ((unsigned char)x) == 'A')
+    __builtin_abort ();
+}
+
+/* { dg-final { scan-tree-dump-not "__builtin_abort" "evrp" } } */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 79a29bf0efb..7137a4c52ec 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -3778,6 +3778,19 @@ extract_range_basic (value_range *vr, gimple *stmt)
                return;
              }
          break;
+       case CFN_BUILT_IN_TOUPPER:
+       case CFN_BUILT_IN_TOLOWER:
+         if (tree lhs = gimple_call_lhs (stmt))
+           {
+             tree type = TREE_TYPE (lhs);
+             unsigned char min = (cfn == CFN_BUILT_IN_TOUPPER) ? 'a' : 'A';
+             unsigned char max = (cfn == CFN_BUILT_IN_TOUPPER) ? 'z' : 'Z';
+             tree range_min = build_int_cstu (type, min);
+             tree range_max = build_int_cstu (type, max);
+             set_value_range (vr, VR_ANTI_RANGE, range_min, range_max, NULL);
+             return;
+           }
+         break;
        default:
          break;
        }

Reply via email to