llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: 陈子昂 (Michael-Chen-NJU)

<details>
<summary>Changes</summary>

This patch implements all packed widening convert intrinsics using general 
vector operations. Low widening conversions use `__builtin_convertvector`, 
while high-half conversions use general shuffles.

The generated code for high-half conversions is correct but not yet optimal.

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


3 Files Affected:

- (modified) clang/lib/Headers/riscv_packed_simd.h (+27) 
- (modified) clang/test/CodeGen/RISCV/rvp-intrinsics.c (+162) 
- (added) llvm/test/CodeGen/RISCV/rvp-widening-convert.ll (+63) 


``````````diff
diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index b4de186ac9575..21953fdee1fce 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -120,6 +120,20 @@ typedef uint32_t uint32x2_t 
__attribute__((__vector_size__(8)));
     return builtin(__rs1);                                                     
\
   }
 
+#define __packed_widen_convert(name, rty, ty)                                  
\
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          
\
+    return __builtin_convertvector(__rs1, rty);                                
\
+  }
+#define __packed_widen_high2(name, rty, ty)                                    
\
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          
\
+    return (rty)__builtin_shufflevector((ty){0}, __rs1, 0, 2, 1, 3);           
\
+  }
+#define __packed_widen_high4(name, rty, ty)                                    
\
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          
\
+    return (rty)__builtin_shufflevector((ty){0}, __rs1, 0, 4, 1, 5, 2, 6, 3,   
\
+                                        7);                                    
\
+  }
+
 /* Packed Reverse: reverse the order of the elements. Lowered to a single
  * rev8/rev16/ppairoe.* by the backend's packed reverse-shuffle handling. */
 #define __packed_reverse2(name, ty)                                            
\
@@ -455,6 +469,16 @@ __packed_unary_op(pnot_u16x4, uint16x4_t, ~)
 __packed_unary_op(pnot_i32x2, int32x2_t, ~)
 __packed_unary_op(pnot_u32x2, uint32x2_t, ~)
 
+/* Packed Widening Convert */
+__packed_widen_convert(pwcvt_i16x4, int16x4_t, int8x4_t)
+__packed_widen_convert(pwcvt_i32x2, int32x2_t, int16x2_t)
+__packed_widen_convert(pwcvtu_u16x4, uint16x4_t, uint8x4_t)
+__packed_widen_convert(pwcvtu_u32x2, uint32x2_t, uint16x2_t)
+__packed_widen_high4(pwcvth_i16x4, int16x4_t, int8x4_t)
+__packed_widen_high4(pwcvth_u16x4, uint16x4_t, uint8x4_t)
+__packed_widen_high2(pwcvth_i32x2, int32x2_t, int16x2_t)
+__packed_widen_high2(pwcvth_u32x2, uint32x2_t, uint16x2_t)
+
 /* Packed Reverse (32-bit) */
 __packed_reverse4(prev_i8x4, int8x4_t)
 __packed_reverse4(prev_u8x4, uint8x4_t)
@@ -597,6 +621,9 @@ __packed_psabs(psabs_i16x4, int16x4_t, 
__builtin_riscv_psabs_i16x4)
 #undef __packed_reduction
 #undef __packed_merge_builtin
 #undef __packed_psabs
+#undef __packed_widen_convert
+#undef __packed_widen_high2
+#undef __packed_widen_high4
 #undef __packed_reverse2
 #undef __packed_reverse4
 #undef __packed_reverse8
diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics.c 
b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
index 504e88e7ec096..2244cc816913d 100644
--- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c
+++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
@@ -7031,3 +7031,165 @@ int8x8_t test_psabs_i8x8(int8x8_t rs1) {
 int16x4_t test_psabs_i16x4(int16x4_t rs1) {
   return __riscv_psabs_i16x4(rs1);
 }
+
+/* Packed Widening Convert */
+
+// RV32-LABEL: define dso_local i64 @test_pwcvt_i16x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[CONV_I:%.*]] = sext <4 x i8> [[TMP0]] to <4 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[CONV_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvt_i16x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[CONV_I:%.*]] = sext <4 x i8> [[TMP0]] to <4 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[CONV_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+int16x4_t test_pwcvt_i16x4(int8x4_t rs1) {
+  return __riscv_pwcvt_i16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvt_i32x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[CONV_I:%.*]] = sext <2 x i16> [[TMP0]] to <2 x i32>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[CONV_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvt_i32x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[CONV_I:%.*]] = sext <2 x i16> [[TMP0]] to <2 x i32>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[CONV_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+int32x2_t test_pwcvt_i32x2(int16x2_t rs1) {
+  return __riscv_pwcvt_i32x2(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvtu_u16x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[CONV_I:%.*]] = zext <4 x i8> [[TMP0]] to <4 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[CONV_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvtu_u16x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[CONV_I:%.*]] = zext <4 x i8> [[TMP0]] to <4 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[CONV_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+uint16x4_t test_pwcvtu_u16x4(uint8x4_t rs1) {
+  return __riscv_pwcvtu_u16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvtu_u32x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[CONV_I:%.*]] = zext <2 x i16> [[TMP0]] to <2 x i32>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[CONV_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvtu_u32x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[CONV_I:%.*]] = zext <2 x i16> [[TMP0]] to <2 x i32>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[CONV_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+uint32x2_t test_pwcvtu_u32x2(uint16x2_t rs1) {
+  return __riscv_pwcvtu_u32x2(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvth_i16x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i8> zeroinitializer, 
<4 x i8> [[TMP0]], <8 x i32> <i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, 
i32 7>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <8 x i8> [[SHUFFLE_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvth_i16x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i8> zeroinitializer, 
<4 x i8> [[TMP0]], <8 x i32> <i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, 
i32 7>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <8 x i8> [[SHUFFLE_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+int16x4_t test_pwcvth_i16x4(int8x4_t rs1) {
+  return __riscv_pwcvth_i16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvth_u16x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i8> zeroinitializer, 
<4 x i8> [[TMP0]], <8 x i32> <i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, 
i32 7>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <8 x i8> [[SHUFFLE_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvth_u16x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i8> zeroinitializer, 
<4 x i8> [[TMP0]], <8 x i32> <i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, 
i32 7>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <8 x i8> [[SHUFFLE_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+uint16x4_t test_pwcvth_u16x4(uint8x4_t rs1) {
+  return __riscv_pwcvth_u16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvth_i32x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i16> zeroinitializer, 
<2 x i16> [[TMP0]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvth_i32x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i16> zeroinitializer, 
<2 x i16> [[TMP0]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+int32x2_t test_pwcvth_i32x2(int16x2_t rs1) {
+  return __riscv_pwcvth_i32x2(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvth_u32x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i16> zeroinitializer, 
<2 x i16> [[TMP0]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvth_u32x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i16> zeroinitializer, 
<2 x i16> [[TMP0]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+uint32x2_t test_pwcvth_u32x2(uint16x2_t rs1) {
+  return __riscv_pwcvth_u32x2(rs1);
+}
diff --git a/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll 
b/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll
new file mode 100644
index 0000000000000..717c5bec5647f
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll
@@ -0,0 +1,63 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; Low widening conversions are covered by rvp-simd-64.ll. This file covers
+; widening conversions that place the source in the high half of each element.
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-p,+m,+zbb \
+; RUN:   -verify-machineinstrs < %s | \
+; RUN:   FileCheck %s --check-prefixes=CHECK,RV32
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-p,+m,+zbb \
+; RUN:   -verify-machineinstrs < %s | \
+; RUN:   FileCheck %s --check-prefixes=CHECK,RV64
+
+define <4 x i16> @test_pwcvth_v4i8(<4 x i8> %a) {
+; RV32-LABEL: test_pwcvth_v4i8:
+; RV32:       # %bb.0:
+; RV32-NEXT:    srli a1, a0, 24
+; RV32-NEXT:    srli a2, a0, 16
+; RV32-NEXT:    srli a3, a0, 8
+; RV32-NEXT:    ppaire.b a1, zero, a1
+; RV32-NEXT:    ppaire.b a2, zero, a2
+; RV32-NEXT:    ppaire.b a0, zero, a0
+; RV32-NEXT:    ppaire.b a3, zero, a3
+; RV32-NEXT:    pack a1, a2, a1
+; RV32-NEXT:    pack a0, a0, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvth_v4i8:
+; RV64:       # %bb.0:
+; RV64-NEXT:    srli a1, a0, 24
+; RV64-NEXT:    srli a2, a0, 16
+; RV64-NEXT:    srli a3, a0, 8
+; RV64-NEXT:    ppaire.b a1, zero, a1
+; RV64-NEXT:    ppaire.b a2, zero, a2
+; RV64-NEXT:    ppaire.b a0, zero, a0
+; RV64-NEXT:    ppaire.b a3, zero, a3
+; RV64-NEXT:    ppaire.h a1, a2, a1
+; RV64-NEXT:    ppaire.h a0, a0, a3
+; RV64-NEXT:    pack a0, a0, a1
+; RV64-NEXT:    ret
+  %shuffle = shufflevector <4 x i8> zeroinitializer, <4 x i8> %a, <8 x i32> 
<i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, i32 7>
+  %res = bitcast <8 x i8> %shuffle to <4 x i16>
+  ret <4 x i16> %res
+}
+
+define <2 x i32> @test_pwcvth_v2i16(<2 x i16> %a) {
+; RV32-LABEL: test_pwcvth_v2i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    srli a1, a0, 16
+; RV32-NEXT:    pack a0, zero, a0
+; RV32-NEXT:    pack a1, zero, a1
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvth_v2i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    srli a1, a0, 16
+; RV64-NEXT:    ppaire.h a0, zero, a0
+; RV64-NEXT:    ppaire.h a1, zero, a1
+; RV64-NEXT:    pack a0, a0, a1
+; RV64-NEXT:    ret
+  %shuffle = shufflevector <2 x i16> zeroinitializer, <2 x i16> %a, <4 x i32> 
<i32 0, i32 2, i32 1, i32 3>
+  %res = bitcast <4 x i16> %shuffle to <2 x i32>
+  ret <2 x i32> %res
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add 
tests below this line:
+; CHECK: {{.*}}

``````````

</details>


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

Reply via email to