Skip to content

[clang] improve consistency with GCC vector comparison #148954

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

ImpleLee
Copy link

@ImpleLee ImpleLee commented Jul 15, 2025

fixes issue #132604

GCC's preference of vector comparison types should be int > signed char > short > long > long long, so I just duplicate that.
reference: gcc-help mailing list: https://gcc.gnu.org/pipermail/gcc-help/2025-July/144357.html

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 15, 2025

@llvm/pr-subscribers-clang

Author: Imple Lee (ImpleLee)

Changes

fixes issue #132604

GCC's order of types of vector comparison should be int > signed char > short > long > long long, so I just duplicate that.
reference: gcc-help mailing list: https://gcc.gnu.org/pipermail/gcc-help/2025-July/144357.html


Full diff: https://github.com/llvm/llvm-project/pull/148954.diff

3 Files Affected:

  • (modified) clang/lib/Sema/SemaExpr.cpp (+11-11)
  • (modified) clang/test/Sema/vector-gcc-compat.c (+4-2)
  • (modified) clang/test/Sema/vector-gcc-compat.cpp (+4-2)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a3f534ee6712e..8a81cda9912f7 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12901,24 +12901,24 @@ QualType Sema::GetSignedVectorType(QualType V) {
     return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
   }
 
-  if (TypeSize == Context.getTypeSize(Context.Int128Ty))
-    return Context.getVectorType(Context.Int128Ty, VTy->getNumElements(),
-                                 VectorKind::Generic);
-  if (TypeSize == Context.getTypeSize(Context.LongLongTy))
-    return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(),
-                                 VectorKind::Generic);
-  if (TypeSize == Context.getTypeSize(Context.LongTy))
-    return Context.getVectorType(Context.LongTy, VTy->getNumElements(),
-                                 VectorKind::Generic);
   if (TypeSize == Context.getTypeSize(Context.IntTy))
     return Context.getVectorType(Context.IntTy, VTy->getNumElements(),
                                  VectorKind::Generic);
+  if (TypeSize == Context.getTypeSize(Context.SignedCharTy))
+    return Context.getVectorType(Context.SignedCharTy, VTy->getNumElements(),
+                                 VectorKind::Generic);
   if (TypeSize == Context.getTypeSize(Context.ShortTy))
     return Context.getVectorType(Context.ShortTy, VTy->getNumElements(),
                                  VectorKind::Generic);
-  assert(TypeSize == Context.getTypeSize(Context.CharTy) &&
+  if (TypeSize == Context.getTypeSize(Context.LongTy))
+    return Context.getVectorType(Context.LongTy, VTy->getNumElements(),
+                                 VectorKind::Generic);
+  if (TypeSize == Context.getTypeSize(Context.LongLongTy))
+    return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(),
+                                 VectorKind::Generic);
+  assert(TypeSize == Context.getTypeSize(Context.Int128Ty) &&
          "Unhandled vector element size in vector compare");
-  return Context.getVectorType(Context.CharTy, VTy->getNumElements(),
+  return Context.getVectorType(Context.Int128Ty, VTy->getNumElements(),
                                VectorKind::Generic);
 }
 
diff --git a/clang/test/Sema/vector-gcc-compat.c b/clang/test/Sema/vector-gcc-compat.c
index 7764b3bf686ad..7d9d25019666c 100644
--- a/clang/test/Sema/vector-gcc-compat.c
+++ b/clang/test/Sema/vector-gcc-compat.c
@@ -3,6 +3,8 @@
 // Test the compatibility of clang's vector extensions with gcc's vector
 // extensions for C. Notably &&, ||, ?: and ! are not available.
 typedef long long v2i64 __attribute__((vector_size(16)));
+// this type is specifically used as the result type of comparison of v2i64
+typedef long v2i_long __attribute__((vector_size(16)));
 typedef int v2i32 __attribute__((vector_size(8)));
 typedef short v2i16 __attribute__((vector_size(4)));
 typedef char v2i8 __attribute__((vector_size(2)));
@@ -81,7 +83,7 @@ void arithmeticTest(void) {
 
 void comparisonTest(void) {
   v2i64 v2i64_a = (v2i64){0, 1};
-  v2i64 v2i64_r;
+  v2i_long v2i64_r;
 
   v2i64_r = v2i64_a == 1;
   v2i64_r = v2i64_a != 1;
@@ -166,7 +168,7 @@ void floatTestConstantComparison(void) {
 
 void doubleTestConstantComparison(void) {
   v2f64 v2f64_a = {0.4, 0.4};
-  v2i64 v2i64_r;
+  v2i_long v2i64_r;
   v2i64_r = v2f64_a > 0.4;
   v2i64_r = v2f64_a >= 0.4;
   v2i64_r = v2f64_a < 0.4;
diff --git a/clang/test/Sema/vector-gcc-compat.cpp b/clang/test/Sema/vector-gcc-compat.cpp
index 42c24d91ea8f3..e66cee128cd90 100644
--- a/clang/test/Sema/vector-gcc-compat.cpp
+++ b/clang/test/Sema/vector-gcc-compat.cpp
@@ -5,6 +5,8 @@
 // || operators work on vector types.
 
 typedef long long v2i64 __attribute__((vector_size(16))); // expected-warning {{'long long' is incompatible with C++98}}
+// this type is specifically used as the result type of comparison of v2i64
+typedef long v2i_long __attribute__((vector_size(16)));
 typedef int v2i32 __attribute__((vector_size(8)));
 typedef short v2i16 __attribute__((vector_size(4)));
 typedef char v2i8 __attribute__((vector_size(2)));
@@ -60,7 +62,7 @@ void arithmeticTest(void) {
 
 void comparisonTest(void) {
   v2i64 v2i64_a = (v2i64){0, 1}; // expected-warning {{compound literals are a C99-specific feature}}
-  v2i64 v2i64_r;
+  v2i_long v2i64_r;
 
   v2i64_r = v2i64_a == 1;
   v2i64_r = v2i64_a != 1;
@@ -141,7 +143,7 @@ void floatTestConstantComparison(void) {
 
 void doubleTestConstantComparison(void) {
   v2f64 v2f64_a = {0.4, 0.4};
-  v2i64 v2i64_r;
+  v2i_long v2i64_r;
   v2i64_r = v2f64_a > 0.4;
   v2i64_r = v2f64_a >= 0.4;
   v2i64_r = v2f64_a < 0.4;

@hstk30-hw hstk30-hw requested review from erichkeane and mizvekov July 16, 2025 08:14
if (TypeSize == Context.getTypeSize(Context.IntTy))
return Context.getVectorType(Context.IntTy, VTy->getNumElements(),
VectorKind::Generic);
if (TypeSize == Context.getTypeSize(Context.SignedCharTy))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the ordering of these matter since they are doing direct comparison of size? The only thing that seems to matter here is the order of long vs long-long, since they can be the same size, right? So only those two need to swap?

But otherwise putting these in any sort of order should have some sort of semblence of ordering if we're going for that. For example, int before char is... awkward. We should probably make sure we're doing this in the 'rank order' from C/C++.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several other inconsistencies:

  1. signed char should be used instead of char
  2. int should be prioritized over other types, so on ILP32 and LLP64, the resultant types should just be int instead of long.

Maybe it is better to just duplicate the GCC type order to ensure compatibility.

Copy link
Author

@ImpleLee ImpleLee Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think making int before char is awkward, but if we want to be totally consistent with GCC, following their rule is possibly the best way...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a better option is to communicate with GCC developers to decide a not-so-awkward (and also backward-compatible and explicit) rule.

@ImpleLee
Copy link
Author

Compared to int > signed char > short > long > long long, inconsistency happens when sizeof(int) == sizeof(short), which is true only in LP32 among currently widely accepted data models.

Looks like GCC uses the same order for __attribute__((mode)), so we get that attribute wrong in exactly the same way for LP32.

Maybe we should add a getGCCCompatibleIntTypeForBitwidth that prefers int over everything else, and use it in both places?

Originally posted by @zygoloid in #132604

I now prefer this proposal over the current PR. I will convert this PR into a draft PR when implementing it, and ask for review again after that.

@ImpleLee ImpleLee marked this pull request as draft July 17, 2025 19:12
@ImpleLee ImpleLee marked this pull request as ready for review July 19, 2025 16:14
@ImpleLee
Copy link
Author

ImpleLee commented Jul 19, 2025

Now I make a utility function getGCCCompatibleIntTypeForBitwidth for this type preference. It should also be used for mode attribute.

There is currently no test about this, but I don't know how to or even whether should I write relevant tests.

There are many other places in clang that uses ASTContext::getIntTypeForBitwidth or TargetInfo::getIntTypeByWidth, but I don't know whether they should switch to this function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants