Author: Craig Topper
Date: 2026-08-19T08:46:39-07:00
New Revision: fd6d7a608909dc4ecea57e0155042d16f7b4e61a

URL: 
https://github.com/llvm/llvm-project/commit/fd6d7a608909dc4ecea57e0155042d16f7b4e61a
DIFF: 
https://github.com/llvm/llvm-project/commit/fd6d7a608909dc4ecea57e0155042d16f7b4e61a.diff

LOG: [RISCV] Use correct type for (u)int64_t in RVV intrinsics on OpenBSD 
(#217211)

The intrinsics are documented to use (u)int64_t for 64-bit scalars.

OpenBSD on RV64 uses long long for int64_t while Linux uses long. The
current code finds the first 64 bit type which is long for both OpenBSD
and Linux.

This patch looks up the type that corresponds to (u)int64_t.

Fixes #216531.

Assisted-by: Claude

Added: 
    clang/test/Sema/riscv-rvv-int64-scalar-type.c

Modified: 
    clang/lib/Sema/SemaRISCV.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp
index d4c6495fbacfb..f4f72a78e78a3 100644
--- a/clang/lib/Sema/SemaRISCV.cpp
+++ b/clang/lib/Sema/SemaRISCV.cpp
@@ -131,10 +131,24 @@ static QualType RVVType2Qual(ASTContext &Context, const 
RVVType *Type) {
     QT = Context.BoolTy;
     break;
   case ScalarTypeKind::SignedInteger:
-    QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), true);
+    // getIntTypeForBitwidth() picks a type purely by matching bit width, so
+    // on LP64 targets a 64-bit element would resolve to "long" even if the
+    // target's actual int64_t is "long long" (e.g. OpenBSD). Go through the
+    // target's Int64Type so this matches int64_t/uint64_t.
+    if (Type->getElementBitwidth() == 64)
+      QT = Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong
+               ? Context.LongTy
+               : Context.LongLongTy;
+    else
+      QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), true);
     break;
   case ScalarTypeKind::UnsignedInteger:
-    QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), false);
+    if (Type->getElementBitwidth() == 64)
+      QT = Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong
+               ? Context.UnsignedLongTy
+               : Context.UnsignedLongLongTy;
+    else
+      QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), false);
     break;
   case ScalarTypeKind::FloatE4M3:
   case ScalarTypeKind::FloatE5M2: {

diff  --git a/clang/test/Sema/riscv-rvv-int64-scalar-type.c 
b/clang/test/Sema/riscv-rvv-int64-scalar-type.c
new file mode 100644
index 0000000000000..ebe61314494e7
--- /dev/null
+++ b/clang/test/Sema/riscv-rvv-int64-scalar-type.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple riscv64-unknown-openbsd -target-feature +v 
-ffreestanding -fsyntax-only -verify=openbsd %s
+// RUN: %clang_cc1 -triple riscv64-none-linux-gnu -target-feature +v 
-ffreestanding -fsyntax-only -verify=linux %s
+
+// REQUIRES: riscv-registered-target
+
+// RVV intrinsics with a 64-bit scalar/pointer operand (e.g. vse64) must use
+// the target's actual uint64_t/int64_t type, not always "unsigned long":
+// OpenBSD defines uint64_t as "unsigned long long" on every architecture,
+// while riscv64-linux (LP64) defines it as "unsigned long".
+
+#include <stdint.h>
+#include <riscv_vector.h>
+
+// uint64_t* must be accepted on every target, regardless of whether the
+// target's uint64_t happens to be "unsigned long" or "unsigned long long".
+void test_uint64_ok(uint64_t *p, vuint64m1_t v, size_t vl) {
+  __riscv_vse64_v_u64m1(p, v, vl);
+}
+
+// "unsigned long *" is only the right type for the pointee on riscv64-linux
+// (where uint64_t is "unsigned long"); on OpenBSD, uint64_t is
+// "unsigned long long", so this should be an incompatible pointer type.
+void test_unsigned_long(unsigned long *p, vuint64m1_t v, size_t vl) {
+  __riscv_vse64_v_u64m1(p, v, vl);
+  // openbsd-error@-1 {{incompatible pointer types passing 'unsigned long *' 
to parameter of type 'unsigned long long *'}}
+  // openbsd-note@-2 {{passing argument to parameter here}}
+}
+
+// Conversely, "unsigned long long *" is only correct on OpenBSD; on
+// riscv64-linux, uint64_t is "unsigned long", so this should fail there.
+void test_unsigned_long_long(unsigned long long *p, vuint64m1_t v, size_t vl) {
+  __riscv_vse64_v_u64m1(p, v, vl);
+  // linux-error@-1 {{incompatible pointer types passing 'unsigned long long 
*' to parameter of type 'unsigned long *'}}
+  // linux-note@-2 {{passing argument to parameter here}}
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to