[llvm] 4978296 - [ARM, MVE] Support -ve offsets in gather-load intrinsics.

Simon Tatham via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 6 08:33:58 PST 2020


Author: Simon Tatham
Date: 2020-01-06T16:33:07Z
New Revision: 4978296cd8e4d10724cfa41f0308d256c0fd490c

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

LOG: [ARM,MVE] Support -ve offsets in gather-load intrinsics.

Summary:
The ACLE intrinsics with `gather_base` or `scatter_base` in the name
are wrappers on the MVE load/store instructions that take a vector of
base addresses and an immediate offset. The immediate offset can be up
to 127 times the alignment unit, and it can be positive or negative.

At the MC layer, we got that right. But in the Sema error checking for
the wrapping intrinsics, the offset was erroneously constrained to be
positive.

To fix this I've adjusted the `imm_mem7bit` class in the Tablegen that
defines the intrinsics. But that causes integer literals like
`0xfffffffffffffe04` to appear in the autogenerated calls to
`SemaBuiltinConstantArgRange`, which provokes a compiler warning
because that's out of the non-overflowing range of an `int64_t`. So
I've also tweaked `MveEmitter` to emit that as `-0x1fc` instead.

Updated the tests of the Sema checks themselves, and also adjusted a
random sample of the CodeGen tests to actually use negative offsets
and prove they get all the way through code generation without causing
a crash.

Reviewers: dmgreen, miyuki, MarkMurrayARM

Reviewed By: dmgreen

Subscribers: kristof.beyls, cfe-commits, llvm-commits

Tags: #clang, #llvm

Differential Revision: https://reviews.llvm.org/D72268

Added: 
    

Modified: 
    clang/include/clang/Basic/arm_mve_defs.td
    clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c
    clang/test/Sema/arm-mve-immediates.c
    clang/utils/TableGen/MveEmitter.cpp
    llvm/test/CodeGen/Thumb2/mve-intrinsics/scatter-gather.ll

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/arm_mve_defs.td b/clang/include/clang/Basic/arm_mve_defs.td
index 939d5eb0cd6b..6fba88df34bf 100644
--- a/clang/include/clang/Basic/arm_mve_defs.td
+++ b/clang/include/clang/Basic/arm_mve_defs.td
@@ -345,9 +345,10 @@ def imm_1248 : Immediate<u32, IB_ConstRange<1, 8>> {
 
 // imm_mem7bit<n> is a valid immediate offset for a load/store intrinsic whose
 // memory access size is n bytes (e.g. 1 for vldrb_[whatever], 2 for vldrh,
-// ...). The set of valid immediates for these is {0*n, 1*n, ..., 127*n}.
+// ...). The set of valid immediates for these is {-127*n, ..., -1*n, 0*n, 1*n,
+// ..., 127*n}.
 class imm_mem7bit<int membytes>
-  : Immediate<sint, IB_ConstRange<0, !mul(membytes, 127)>> {
+  : Immediate<sint, IB_ConstRange<!mul(membytes, -127), !mul(membytes, 127)>> {
   let extra = !if(!eq(membytes, 1), ?, "Multiple");
   let extraarg = !cast<string>(membytes);
 }

diff  --git a/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c b/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c
index 8bf2111a9e63..564965acc04d 100644
--- a/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c
+++ b/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c
@@ -196,12 +196,12 @@ int64x2_t test_vldrdq_gather_base_s64(uint64x2_t addr)
 
 // CHECK-LABEL: @test_vldrdq_gather_base_u64(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call <2 x i64> @llvm.arm.mve.vldr.gather.base.v2i64.v2i64(<2 x i64> [[ADDR:%.*]], i32 336)
+// CHECK-NEXT:    [[TMP0:%.*]] = call <2 x i64> @llvm.arm.mve.vldr.gather.base.v2i64.v2i64(<2 x i64> [[ADDR:%.*]], i32 -336)
 // CHECK-NEXT:    ret <2 x i64> [[TMP0]]
 //
 uint64x2_t test_vldrdq_gather_base_u64(uint64x2_t addr)
 {
-    return vldrdq_gather_base_u64(addr, 0x150);
+    return vldrdq_gather_base_u64(addr, -0x150);
 }
 
 // CHECK-LABEL: @test_vldrdq_gather_base_wb_s64(
@@ -221,7 +221,7 @@ int64x2_t test_vldrdq_gather_base_wb_s64(uint64x2_t *addr)
 // CHECK-LABEL: @test_vldrdq_gather_base_wb_u64(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i64>, <2 x i64>* [[ADDR:%.*]], align 8
-// CHECK-NEXT:    [[TMP1:%.*]] = call { <2 x i64>, <2 x i64> } @llvm.arm.mve.vldr.gather.base.wb.v2i64.v2i64(<2 x i64> [[TMP0]], i32 328)
+// CHECK-NEXT:    [[TMP1:%.*]] = call { <2 x i64>, <2 x i64> } @llvm.arm.mve.vldr.gather.base.wb.v2i64.v2i64(<2 x i64> [[TMP0]], i32 -328)
 // CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { <2 x i64>, <2 x i64> } [[TMP1]], 1
 // CHECK-NEXT:    store <2 x i64> [[TMP2]], <2 x i64>* [[ADDR]], align 8
 // CHECK-NEXT:    [[TMP3:%.*]] = extractvalue { <2 x i64>, <2 x i64> } [[TMP1]], 0
@@ -229,7 +229,7 @@ int64x2_t test_vldrdq_gather_base_wb_s64(uint64x2_t *addr)
 //
 uint64x2_t test_vldrdq_gather_base_wb_u64(uint64x2_t *addr)
 {
-    return vldrdq_gather_base_wb_u64(addr, 0x148);
+    return vldrdq_gather_base_wb_u64(addr, -0x148);
 }
 
 // CHECK-LABEL: @test_vldrdq_gather_base_wb_z_s64(
@@ -280,12 +280,12 @@ int64x2_t test_vldrdq_gather_base_z_s64(uint64x2_t addr, mve_pred16_t p)
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = zext i16 [[P:%.*]] to i32
 // CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]])
-// CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i64> @llvm.arm.mve.vldr.gather.base.predicated.v2i64.v2i64.v4i1(<2 x i64> [[ADDR:%.*]], i32 1000, <4 x i1> [[TMP1]])
+// CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i64> @llvm.arm.mve.vldr.gather.base.predicated.v2i64.v2i64.v4i1(<2 x i64> [[ADDR:%.*]], i32 -1000, <4 x i1> [[TMP1]])
 // CHECK-NEXT:    ret <2 x i64> [[TMP2]]
 //
 uint64x2_t test_vldrdq_gather_base_z_u64(uint64x2_t addr, mve_pred16_t p)
 {
-    return vldrdq_gather_base_z_u64(addr, 0x3e8, p);
+    return vldrdq_gather_base_z_u64(addr, -0x3e8, p);
 }
 
 // CHECK-LABEL: @test_vldrdq_gather_offset_s64(
@@ -741,7 +741,7 @@ uint32x4_t test_vldrwq_gather_base_u32(uint32x4_t addr)
 // CHECK-LABEL: @test_vldrwq_gather_base_wb_f32(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[ADDR:%.*]], align 8
-// CHECK-NEXT:    [[TMP1:%.*]] = call { <4 x float>, <4 x i32> } @llvm.arm.mve.vldr.gather.base.wb.v4f32.v4i32(<4 x i32> [[TMP0]], i32 64)
+// CHECK-NEXT:    [[TMP1:%.*]] = call { <4 x float>, <4 x i32> } @llvm.arm.mve.vldr.gather.base.wb.v4f32.v4i32(<4 x i32> [[TMP0]], i32 -64)
 // CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[TMP1]], 1
 // CHECK-NEXT:    store <4 x i32> [[TMP2]], <4 x i32>* [[ADDR]], align 8
 // CHECK-NEXT:    [[TMP3:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[TMP1]], 0
@@ -749,7 +749,7 @@ uint32x4_t test_vldrwq_gather_base_u32(uint32x4_t addr)
 //
 float32x4_t test_vldrwq_gather_base_wb_f32(uint32x4_t *addr)
 {
-    return vldrwq_gather_base_wb_f32(addr, 0x40);
+    return vldrwq_gather_base_wb_f32(addr, -0x40);
 }
 
 // CHECK-LABEL: @test_vldrwq_gather_base_wb_s32(
@@ -785,7 +785,7 @@ uint32x4_t test_vldrwq_gather_base_wb_u32(uint32x4_t *addr)
 // CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[ADDR:%.*]], align 8
 // CHECK-NEXT:    [[TMP1:%.*]] = zext i16 [[P:%.*]] to i32
 // CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP1]])
-// CHECK-NEXT:    [[TMP3:%.*]] = call { <4 x float>, <4 x i32> } @llvm.arm.mve.vldr.gather.base.wb.predicated.v4f32.v4i32.v4i1(<4 x i32> [[TMP0]], i32 352, <4 x i1> [[TMP2]])
+// CHECK-NEXT:    [[TMP3:%.*]] = call { <4 x float>, <4 x i32> } @llvm.arm.mve.vldr.gather.base.wb.predicated.v4f32.v4i32.v4i1(<4 x i32> [[TMP0]], i32 -352, <4 x i1> [[TMP2]])
 // CHECK-NEXT:    [[TMP4:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[TMP3]], 1
 // CHECK-NEXT:    store <4 x i32> [[TMP4]], <4 x i32>* [[ADDR]], align 8
 // CHECK-NEXT:    [[TMP5:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[TMP3]], 0
@@ -793,7 +793,7 @@ uint32x4_t test_vldrwq_gather_base_wb_u32(uint32x4_t *addr)
 //
 float32x4_t test_vldrwq_gather_base_wb_z_f32(uint32x4_t *addr, mve_pred16_t p)
 {
-    return vldrwq_gather_base_wb_z_f32(addr, 0x160, p);
+    return vldrwq_gather_base_wb_z_f32(addr, -0x160, p);
 }
 
 // CHECK-LABEL: @test_vldrwq_gather_base_wb_z_s32(
@@ -856,12 +856,12 @@ int32x4_t test_vldrwq_gather_base_z_s32(uint32x4_t addr, mve_pred16_t p)
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = zext i16 [[P:%.*]] to i32
 // CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]])
-// CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i32> @llvm.arm.mve.vldr.gather.base.predicated.v4i32.v4i32.v4i1(<4 x i32> [[ADDR:%.*]], i32 300, <4 x i1> [[TMP1]])
+// CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i32> @llvm.arm.mve.vldr.gather.base.predicated.v4i32.v4i32.v4i1(<4 x i32> [[ADDR:%.*]], i32 -300, <4 x i1> [[TMP1]])
 // CHECK-NEXT:    ret <4 x i32> [[TMP2]]
 //
 uint32x4_t test_vldrwq_gather_base_z_u32(uint32x4_t addr, mve_pred16_t p)
 {
-    return vldrwq_gather_base_z_u32(addr, 0x12c, p);
+    return vldrwq_gather_base_z_u32(addr, -0x12c, p);
 }
 
 // CHECK-LABEL: @test_vldrwq_gather_offset_f32(
@@ -1272,15 +1272,15 @@ void test_vstrdq_scatter_base_s64(uint64x2_t addr, int64x2_t value)
 
 // CHECK-LABEL: @test_vstrdq_scatter_base_u64(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @llvm.arm.mve.vstr.scatter.base.v2i64.v2i64(<2 x i64> [[ADDR:%.*]], i32 472, <2 x i64> [[VALUE:%.*]])
+// CHECK-NEXT:    call void @llvm.arm.mve.vstr.scatter.base.v2i64.v2i64(<2 x i64> [[ADDR:%.*]], i32 -472, <2 x i64> [[VALUE:%.*]])
 // CHECK-NEXT:    ret void
 //
 void test_vstrdq_scatter_base_u64(uint64x2_t addr, uint64x2_t value)
 {
 #ifdef POLYMORPHIC
-    vstrdq_scatter_base(addr, 0x1d8, value);
+    vstrdq_scatter_base(addr, -0x1d8, value);
 #else /* POLYMORPHIC */
-    vstrdq_scatter_base_u64(addr, 0x1d8, value);
+    vstrdq_scatter_base_u64(addr, -0x1d8, value);
 #endif /* POLYMORPHIC */
 }
 
@@ -1339,16 +1339,16 @@ void test_vstrdq_scatter_base_wb_s64(uint64x2_t *addr, int64x2_t value)
 // CHECK-LABEL: @test_vstrdq_scatter_base_wb_u64(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i64>, <2 x i64>* [[ADDR:%.*]], align 8
-// CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i64> @llvm.arm.mve.vstr.scatter.base.wb.v2i64.v2i64(<2 x i64> [[TMP0]], i32 168, <2 x i64> [[VALUE:%.*]])
+// CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i64> @llvm.arm.mve.vstr.scatter.base.wb.v2i64.v2i64(<2 x i64> [[TMP0]], i32 -168, <2 x i64> [[VALUE:%.*]])
 // CHECK-NEXT:    store <2 x i64> [[TMP1]], <2 x i64>* [[ADDR]], align 8
 // CHECK-NEXT:    ret void
 //
 void test_vstrdq_scatter_base_wb_u64(uint64x2_t *addr, uint64x2_t value)
 {
 #ifdef POLYMORPHIC
-    vstrdq_scatter_base_wb(addr, 0xa8, value);
+    vstrdq_scatter_base_wb(addr, -0xa8, value);
 #else /* POLYMORPHIC */
-    vstrdq_scatter_base_wb_u64(addr, 0xa8, value);
+    vstrdq_scatter_base_wb_u64(addr, -0xa8, value);
 #endif /* POLYMORPHIC */
 }
 
@@ -1790,15 +1790,15 @@ void test_vstrwq_scatter_base_f32(uint32x4_t addr, float32x4_t value)
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = zext i16 [[P:%.*]] to i32
 // CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]])
-// CHECK-NEXT:    call void @llvm.arm.mve.vstr.scatter.base.predicated.v4i32.v4f32.v4i1(<4 x i32> [[ADDR:%.*]], i32 400, <4 x float> [[VALUE:%.*]], <4 x i1> [[TMP1]])
+// CHECK-NEXT:    call void @llvm.arm.mve.vstr.scatter.base.predicated.v4i32.v4f32.v4i1(<4 x i32> [[ADDR:%.*]], i32 -400, <4 x float> [[VALUE:%.*]], <4 x i1> [[TMP1]])
 // CHECK-NEXT:    ret void
 //
 void test_vstrwq_scatter_base_p_f32(uint32x4_t addr, float32x4_t value, mve_pred16_t p)
 {
 #ifdef POLYMORPHIC
-    vstrwq_scatter_base_p(addr, 0x190, value, p);
+    vstrwq_scatter_base_p(addr, -0x190, value, p);
 #else /* POLYMORPHIC */
-    vstrwq_scatter_base_p_f32(addr, 0x190, value, p);
+    vstrwq_scatter_base_p_f32(addr, -0x190, value, p);
 #endif /* POLYMORPHIC */
 }
 
@@ -1822,15 +1822,15 @@ void test_vstrwq_scatter_base_p_s32(uint32x4_t addr, int32x4_t value, mve_pred16
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = zext i16 [[P:%.*]] to i32
 // CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]])
-// CHECK-NEXT:    call void @llvm.arm.mve.vstr.scatter.base.predicated.v4i32.v4i32.v4i1(<4 x i32> [[ADDR:%.*]], i32 376, <4 x i32> [[VALUE:%.*]], <4 x i1> [[TMP1]])
+// CHECK-NEXT:    call void @llvm.arm.mve.vstr.scatter.base.predicated.v4i32.v4i32.v4i1(<4 x i32> [[ADDR:%.*]], i32 -376, <4 x i32> [[VALUE:%.*]], <4 x i1> [[TMP1]])
 // CHECK-NEXT:    ret void
 //
 void test_vstrwq_scatter_base_p_u32(uint32x4_t addr, uint32x4_t value, mve_pred16_t p)
 {
 #ifdef POLYMORPHIC
-    vstrwq_scatter_base_p(addr, 0x178, value, p);
+    vstrwq_scatter_base_p(addr, -0x178, value, p);
 #else /* POLYMORPHIC */
-    vstrwq_scatter_base_p_u32(addr, 0x178, value, p);
+    vstrwq_scatter_base_p_u32(addr, -0x178, value, p);
 #endif /* POLYMORPHIC */
 }
 
@@ -1865,16 +1865,16 @@ void test_vstrwq_scatter_base_u32(uint32x4_t addr, uint32x4_t value)
 // CHECK-LABEL: @test_vstrwq_scatter_base_wb_f32(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[ADDR:%.*]], align 8
-// CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.arm.mve.vstr.scatter.base.wb.v4i32.v4f32(<4 x i32> [[TMP0]], i32 412, <4 x float> [[VALUE:%.*]])
+// CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.arm.mve.vstr.scatter.base.wb.v4i32.v4f32(<4 x i32> [[TMP0]], i32 -412, <4 x float> [[VALUE:%.*]])
 // CHECK-NEXT:    store <4 x i32> [[TMP1]], <4 x i32>* [[ADDR]], align 8
 // CHECK-NEXT:    ret void
 //
 void test_vstrwq_scatter_base_wb_f32(uint32x4_t *addr, float32x4_t value)
 {
 #ifdef POLYMORPHIC
-    vstrwq_scatter_base_wb(addr, 0x19c, value);
+    vstrwq_scatter_base_wb(addr, -0x19c, value);
 #else /* POLYMORPHIC */
-    vstrwq_scatter_base_wb_f32(addr, 0x19c, value);
+    vstrwq_scatter_base_wb_f32(addr, -0x19c, value);
 #endif /* POLYMORPHIC */
 }
 
@@ -1935,16 +1935,16 @@ void test_vstrwq_scatter_base_wb_p_u32(uint32x4_t *addr, uint32x4_t value, mve_p
 // CHECK-LABEL: @test_vstrwq_scatter_base_wb_s32(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[ADDR:%.*]], align 8
-// CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.arm.mve.vstr.scatter.base.wb.v4i32.v4i32(<4 x i32> [[TMP0]], i32 152, <4 x i32> [[VALUE:%.*]])
+// CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.arm.mve.vstr.scatter.base.wb.v4i32.v4i32(<4 x i32> [[TMP0]], i32 -152, <4 x i32> [[VALUE:%.*]])
 // CHECK-NEXT:    store <4 x i32> [[TMP1]], <4 x i32>* [[ADDR]], align 8
 // CHECK-NEXT:    ret void
 //
 void test_vstrwq_scatter_base_wb_s32(uint32x4_t *addr, int32x4_t value)
 {
 #ifdef POLYMORPHIC
-    vstrwq_scatter_base_wb(addr, 0x98, value);
+    vstrwq_scatter_base_wb(addr, -0x98, value);
 #else /* POLYMORPHIC */
-    vstrwq_scatter_base_wb_s32(addr, 0x98, value);
+    vstrwq_scatter_base_wb_s32(addr, -0x98, value);
 #endif /* POLYMORPHIC */
 }
 

diff  --git a/clang/test/Sema/arm-mve-immediates.c b/clang/test/Sema/arm-mve-immediates.c
index 45b2357a600a..54cdb96efcd3 100644
--- a/clang/test/Sema/arm-mve-immediates.c
+++ b/clang/test/Sema/arm-mve-immediates.c
@@ -11,8 +11,11 @@ void test_load_offsets(uint32x4_t addr32, uint64x2_t addr64)
   vldrdq_gather_base_s64(addr64, 125*8);
   vldrdq_gather_base_s64(addr64, 126*8);
   vldrdq_gather_base_s64(addr64, 127*8);
-  vldrdq_gather_base_s64(addr64, -8); // expected-error {{argument value -8 is outside the valid range [0, 1016]}}
-  vldrdq_gather_base_s64(addr64, 128*8); // expected-error {{argument value 1024 is outside the valid range [0, 1016]}}
+  vldrdq_gather_base_s64(addr64, -125*8);
+  vldrdq_gather_base_s64(addr64, -126*8);
+  vldrdq_gather_base_s64(addr64, -127*8);
+  vldrdq_gather_base_s64(addr64, 128*8); // expected-error {{argument value 1024 is outside the valid range [-1016, 1016]}}
+  vldrdq_gather_base_s64(addr64, -128*8); // expected-error {{argument value -1024 is outside the valid range [-1016, 1016]}}
   vldrdq_gather_base_s64(addr64, 4); // expected-error {{argument should be a multiple of 8}}
   vldrdq_gather_base_s64(addr64, 1); // expected-error {{argument should be a multiple of 8}}
 
@@ -23,8 +26,11 @@ void test_load_offsets(uint32x4_t addr32, uint64x2_t addr64)
   vldrwq_gather_base_s32(addr32, 125*4);
   vldrwq_gather_base_s32(addr32, 126*4);
   vldrwq_gather_base_s32(addr32, 127*4);
-  vldrwq_gather_base_s32(addr32, -4); // expected-error {{argument value -4 is outside the valid range [0, 508]}}
-  vldrwq_gather_base_s32(addr32, 128*4); // expected-error {{argument value 512 is outside the valid range [0, 508]}}
+  vldrwq_gather_base_s32(addr32, -125*4);
+  vldrwq_gather_base_s32(addr32, -126*4);
+  vldrwq_gather_base_s32(addr32, -127*4);
+  vldrwq_gather_base_s32(addr32, 128*4); // expected-error {{argument value 512 is outside the valid range [-508, 508]}}
+  vldrwq_gather_base_s32(addr32, -128*4); // expected-error {{argument value -512 is outside the valid range [-508, 508]}}
   vldrwq_gather_base_s32(addr32, 2); // expected-error {{argument should be a multiple of 4}}
   vldrwq_gather_base_s32(addr32, 1); // expected-error {{argument should be a multiple of 4}}
 
@@ -37,8 +43,11 @@ void test_load_offsets(uint32x4_t addr32, uint64x2_t addr64)
   vstrdq_scatter_base(addr64, 125*8, addr64);
   vstrdq_scatter_base(addr64, 126*8, addr64);
   vstrdq_scatter_base(addr64, 127*8, addr64);
-  vstrdq_scatter_base(addr64, -8, addr64); // expected-error {{argument value -8 is outside the valid range [0, 1016]}}
-  vstrdq_scatter_base(addr64, 128*8, addr64); // expected-error {{argument value 1024 is outside the valid range [0, 1016]}}
+  vstrdq_scatter_base(addr64, -125*8, addr64);
+  vstrdq_scatter_base(addr64, -126*8, addr64);
+  vstrdq_scatter_base(addr64, -127*8, addr64);
+  vstrdq_scatter_base(addr64, 128*8, addr64); // expected-error {{argument value 1024 is outside the valid range [-1016, 1016]}}
+  vstrdq_scatter_base(addr64, -128*8, addr64); // expected-error {{argument value -1024 is outside the valid range [-1016, 1016]}}
   vstrdq_scatter_base(addr64, 4, addr64); // expected-error {{argument should be a multiple of 8}}
   vstrdq_scatter_base(addr64, 1, addr64); // expected-error {{argument should be a multiple of 8}}
 
@@ -49,8 +58,11 @@ void test_load_offsets(uint32x4_t addr32, uint64x2_t addr64)
   vstrwq_scatter_base(addr32, 125*4, addr32);
   vstrwq_scatter_base(addr32, 126*4, addr32);
   vstrwq_scatter_base(addr32, 127*4, addr32);
-  vstrwq_scatter_base(addr32, -4, addr32); // expected-error {{argument value -4 is outside the valid range [0, 508]}}
-  vstrwq_scatter_base(addr32, 128*4, addr32); // expected-error {{argument value 512 is outside the valid range [0, 508]}}
+  vstrwq_scatter_base(addr32, -125*4, addr32);
+  vstrwq_scatter_base(addr32, -126*4, addr32);
+  vstrwq_scatter_base(addr32, -127*4, addr32);
+  vstrwq_scatter_base(addr32, 128*4, addr32); // expected-error {{argument value 512 is outside the valid range [-508, 508]}}
+  vstrwq_scatter_base(addr32, -128*4, addr32); // expected-error {{argument value -512 is outside the valid range [-508, 508]}}
   vstrwq_scatter_base(addr32, 2, addr32); // expected-error {{argument should be a multiple of 4}}
   vstrwq_scatter_base(addr32, 1, addr32); // expected-error {{argument should be a multiple of 4}}
 }

diff  --git a/clang/utils/TableGen/MveEmitter.cpp b/clang/utils/TableGen/MveEmitter.cpp
index ae4c9b218f85..6f3fd2522ce6 100644
--- a/clang/utils/TableGen/MveEmitter.cpp
+++ b/clang/utils/TableGen/MveEmitter.cpp
@@ -861,6 +861,13 @@ class ACLEIntrinsic {
   }
   bool hasCode() const { return Code != nullptr; }
 
+  static std::string signedHexLiteral(const llvm::APInt &iOrig) {
+    llvm::APInt i = iOrig.trunc(64);
+    SmallString<40> s;
+    i.toString(s, 16, true, true);
+    return s.str();
+  }
+
   std::string genSema() const {
     std::vector<std::string> SemaChecks;
 
@@ -895,8 +902,8 @@ class ACLEIntrinsic {
         SemaChecks.push_back("SemaBuiltinConstantArg(TheCall, " + Index + ")");
       else
         SemaChecks.push_back("SemaBuiltinConstantArgRange(TheCall, " + Index +
-                             ", 0x" + lo.toString(16, true) + ", 0x" +
-                             hi.toString(16, true) + ")");
+                             ", " + signedHexLiteral(lo) + ", " +
+                             signedHexLiteral(hi) + ")");
 
       if (!IA.ExtraCheckType.empty()) {
         std::string Suffix;

diff  --git a/llvm/test/CodeGen/Thumb2/mve-intrinsics/scatter-gather.ll b/llvm/test/CodeGen/Thumb2/mve-intrinsics/scatter-gather.ll
index 5e19f81cbf54..7eac79094f59 100644
--- a/llvm/test/CodeGen/Thumb2/mve-intrinsics/scatter-gather.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-intrinsics/scatter-gather.ll
@@ -191,11 +191,11 @@ declare <2 x i64> @llvm.arm.mve.vldr.gather.base.v2i64.v2i64(<2 x i64>, i32)
 define arm_aapcs_vfpcc <2 x i64> @test_vldrdq_gather_base_u64(<2 x i64> %addr) {
 ; CHECK-LABEL: test_vldrdq_gather_base_u64:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vldrd.u64 q1, [q0, #336]
+; CHECK-NEXT:    vldrd.u64 q1, [q0, #-336]
 ; CHECK-NEXT:    vmov q0, q1
 ; CHECK-NEXT:    bx lr
 entry:
-  %0 = call <2 x i64> @llvm.arm.mve.vldr.gather.base.v2i64.v2i64(<2 x i64> %addr, i32 336)
+  %0 = call <2 x i64> @llvm.arm.mve.vldr.gather.base.v2i64.v2i64(<2 x i64> %addr, i32 -336)
   ret <2 x i64> %0
 }
 
@@ -221,12 +221,12 @@ define arm_aapcs_vfpcc <2 x i64> @test_vldrdq_gather_base_wb_u64(<2 x i64>* %add
 ; CHECK-LABEL: test_vldrdq_gather_base_wb_u64:
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vldrw.u32 q0, [r0]
-; CHECK-NEXT:    vldrd.u64 q1, [q0, #328]!
+; CHECK-NEXT:    vldrd.u64 q1, [q0, #-328]!
 ; CHECK-NEXT:    vstrw.32 q1, [r0]
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = load <2 x i64>, <2 x i64>* %addr, align 8
-  %1 = call { <2 x i64>, <2 x i64> } @llvm.arm.mve.vldr.gather.base.wb.v2i64.v2i64(<2 x i64> %0, i32 328)
+  %1 = call { <2 x i64>, <2 x i64> } @llvm.arm.mve.vldr.gather.base.wb.v2i64.v2i64(<2 x i64> %0, i32 -328)
   %2 = extractvalue { <2 x i64>, <2 x i64> } %1, 1
   store <2 x i64> %2, <2 x i64>* %addr, align 8
   %3 = extractvalue { <2 x i64>, <2 x i64> } %1, 0
@@ -297,13 +297,13 @@ define arm_aapcs_vfpcc <2 x i64> @test_vldrdq_gather_base_z_u64(<2 x i64> %addr,
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vmsr p0, r0
 ; CHECK-NEXT:    vpst
-; CHECK-NEXT:    vldrdt.u64 q1, [q0, #1000]
+; CHECK-NEXT:    vldrdt.u64 q1, [q0, #-1000]
 ; CHECK-NEXT:    vmov q0, q1
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = zext i16 %p to i32
   %1 = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %0)
-  %2 = call <2 x i64> @llvm.arm.mve.vldr.gather.base.predicated.v2i64.v2i64.v4i1(<2 x i64> %addr, i32 1000, <4 x i1> %1)
+  %2 = call <2 x i64> @llvm.arm.mve.vldr.gather.base.predicated.v2i64.v2i64.v4i1(<2 x i64> %addr, i32 -1000, <4 x i1> %1)
   ret <2 x i64> %2
 }
 
@@ -728,12 +728,12 @@ define arm_aapcs_vfpcc <4 x float> @test_vldrwq_gather_base_wb_f32(<4 x i32>* %a
 ; CHECK-LABEL: test_vldrwq_gather_base_wb_f32:
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vldrw.u32 q0, [r0]
-; CHECK-NEXT:    vldrw.u32 q1, [q0, #64]!
+; CHECK-NEXT:    vldrw.u32 q1, [q0, #-64]!
 ; CHECK-NEXT:    vstrw.32 q1, [r0]
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = load <4 x i32>, <4 x i32>* %addr, align 8
-  %1 = call { <4 x float>, <4 x i32> } @llvm.arm.mve.vldr.gather.base.wb.v4f32.v4i32(<4 x i32> %0, i32 64)
+  %1 = call { <4 x float>, <4 x i32> } @llvm.arm.mve.vldr.gather.base.wb.v4f32.v4i32(<4 x i32> %0, i32 -64)
   %2 = extractvalue { <4 x float>, <4 x i32> } %1, 1
   store <4 x i32> %2, <4 x i32>* %addr, align 8
   %3 = extractvalue { <4 x float>, <4 x i32> } %1, 0
@@ -782,14 +782,14 @@ define arm_aapcs_vfpcc <4 x float> @test_vldrwq_gather_base_wb_z_f32(<4 x i32>*
 ; CHECK-NEXT:    vmsr p0, r1
 ; CHECK-NEXT:    vldrw.u32 q0, [r0]
 ; CHECK-NEXT:    vpst
-; CHECK-NEXT:    vldrwt.u32 q1, [q0, #352]!
+; CHECK-NEXT:    vldrwt.u32 q1, [q0, #-352]!
 ; CHECK-NEXT:    vstrw.32 q1, [r0]
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = load <4 x i32>, <4 x i32>* %addr, align 8
   %1 = zext i16 %p to i32
   %2 = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %1)
-  %3 = call { <4 x float>, <4 x i32> } @llvm.arm.mve.vldr.gather.base.wb.predicated.v4f32.v4i32.v4i1(<4 x i32> %0, i32 352, <4 x i1> %2)
+  %3 = call { <4 x float>, <4 x i32> } @llvm.arm.mve.vldr.gather.base.wb.predicated.v4f32.v4i32.v4i1(<4 x i32> %0, i32 -352, <4 x i1> %2)
   %4 = extractvalue { <4 x float>, <4 x i32> } %3, 1
   store <4 x i32> %4, <4 x i32>* %addr, align 8
   %5 = extractvalue { <4 x float>, <4 x i32> } %3, 0
@@ -845,13 +845,13 @@ define arm_aapcs_vfpcc <4 x float> @test_vldrwq_gather_base_z_f32(<4 x i32> %add
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vmsr p0, r0
 ; CHECK-NEXT:    vpst
-; CHECK-NEXT:    vldrwt.u32 q1, [q0, #300]
+; CHECK-NEXT:    vldrwt.u32 q1, [q0, #-300]
 ; CHECK-NEXT:    vmov q0, q1
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = zext i16 %p to i32
   %1 = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %0)
-  %2 = call <4 x float> @llvm.arm.mve.vldr.gather.base.predicated.v4f32.v4i32.v4i1(<4 x i32> %addr, i32 300, <4 x i1> %1)
+  %2 = call <4 x float> @llvm.arm.mve.vldr.gather.base.predicated.v4f32.v4i32.v4i1(<4 x i32> %addr, i32 -300, <4 x i1> %1)
   ret <4 x float> %2
 }
 
@@ -1254,10 +1254,10 @@ declare void @llvm.arm.mve.vstr.scatter.base.v2i64.v2i64(<2 x i64>, i32, <2 x i6
 define arm_aapcs_vfpcc void @test_vstrdq_scatter_base_u64(<2 x i64> %addr, <2 x i64> %value) {
 ; CHECK-LABEL: test_vstrdq_scatter_base_u64:
 ; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vstrd.64 q1, [q0, #472]
+; CHECK-NEXT:    vstrd.64 q1, [q0, #-472]
 ; CHECK-NEXT:    bx lr
 entry:
-  call void @llvm.arm.mve.vstr.scatter.base.v2i64.v2i64(<2 x i64> %addr, i32 472, <2 x i64> %value)
+  call void @llvm.arm.mve.vstr.scatter.base.v2i64.v2i64(<2 x i64> %addr, i32 -472, <2 x i64> %value)
   ret void
 }
 
@@ -1319,12 +1319,12 @@ define arm_aapcs_vfpcc void @test_vstrdq_scatter_base_wb_u64(<2 x i64>* %addr, <
 ; CHECK-LABEL: test_vstrdq_scatter_base_wb_u64:
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vldrw.u32 q1, [r0]
-; CHECK-NEXT:    vstrd.64 q0, [q1, #168]!
+; CHECK-NEXT:    vstrd.64 q0, [q1, #-168]!
 ; CHECK-NEXT:    vstrw.32 q1, [r0]
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = load <2 x i64>, <2 x i64>* %addr, align 8
-  %1 = call <2 x i64> @llvm.arm.mve.vstr.scatter.base.wb.v2i64.v2i64(<2 x i64> %0, i32 168, <2 x i64> %value)
+  %1 = call <2 x i64> @llvm.arm.mve.vstr.scatter.base.wb.v2i64.v2i64(<2 x i64> %0, i32 -168, <2 x i64> %value)
   store <2 x i64> %1, <2 x i64>* %addr, align 8
   ret void
 }
@@ -1698,12 +1698,12 @@ define arm_aapcs_vfpcc void @test_vstrwq_scatter_base_p_f32(<4 x i32> %addr, <4
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vmsr p0, r0
 ; CHECK-NEXT:    vpst
-; CHECK-NEXT:    vstrwt.32 q1, [q0, #400]
+; CHECK-NEXT:    vstrwt.32 q1, [q0, #-400]
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = zext i16 %p to i32
   %1 = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %0)
-  call void @llvm.arm.mve.vstr.scatter.base.predicated.v4i32.v4f32.v4i1(<4 x i32> %addr, i32 400, <4 x float> %value, <4 x i1> %1)
+  call void @llvm.arm.mve.vstr.scatter.base.predicated.v4i32.v4f32.v4i1(<4 x i32> %addr, i32 -400, <4 x float> %value, <4 x i1> %1)
   ret void
 }
 
@@ -1730,12 +1730,12 @@ define arm_aapcs_vfpcc void @test_vstrwq_scatter_base_p_u32(<4 x i32> %addr, <4
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vmsr p0, r0
 ; CHECK-NEXT:    vpst
-; CHECK-NEXT:    vstrwt.32 q1, [q0, #376]
+; CHECK-NEXT:    vstrwt.32 q1, [q0, #-376]
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = zext i16 %p to i32
   %1 = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 %0)
-  call void @llvm.arm.mve.vstr.scatter.base.predicated.v4i32.v4i32.v4i1(<4 x i32> %addr, i32 376, <4 x i32> %value, <4 x i1> %1)
+  call void @llvm.arm.mve.vstr.scatter.base.predicated.v4i32.v4i32.v4i1(<4 x i32> %addr, i32 -376, <4 x i32> %value, <4 x i1> %1)
   ret void
 }
 
@@ -1765,12 +1765,12 @@ define arm_aapcs_vfpcc void @test_vstrwq_scatter_base_wb_f32(<4 x i32>* %addr, <
 ; CHECK-LABEL: test_vstrwq_scatter_base_wb_f32:
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vldrw.u32 q1, [r0]
-; CHECK-NEXT:    vstrw.32 q0, [q1, #412]!
+; CHECK-NEXT:    vstrw.32 q0, [q1, #-412]!
 ; CHECK-NEXT:    vstrw.32 q1, [r0]
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = load <4 x i32>, <4 x i32>* %addr, align 8
-  %1 = call <4 x i32> @llvm.arm.mve.vstr.scatter.base.wb.v4i32.v4f32(<4 x i32> %0, i32 412, <4 x float> %value)
+  %1 = call <4 x i32> @llvm.arm.mve.vstr.scatter.base.wb.v4i32.v4f32(<4 x i32> %0, i32 -412, <4 x float> %value)
   store <4 x i32> %1, <4 x i32>* %addr, align 8
   ret void
 }
@@ -1839,12 +1839,12 @@ define arm_aapcs_vfpcc void @test_vstrwq_scatter_base_wb_s32(<4 x i32>* %addr, <
 ; CHECK-LABEL: test_vstrwq_scatter_base_wb_s32:
 ; CHECK:       @ %bb.0: @ %entry
 ; CHECK-NEXT:    vldrw.u32 q1, [r0]
-; CHECK-NEXT:    vstrw.32 q0, [q1, #152]!
+; CHECK-NEXT:    vstrw.32 q0, [q1, #-152]!
 ; CHECK-NEXT:    vstrw.32 q1, [r0]
 ; CHECK-NEXT:    bx lr
 entry:
   %0 = load <4 x i32>, <4 x i32>* %addr, align 8
-  %1 = call <4 x i32> @llvm.arm.mve.vstr.scatter.base.wb.v4i32.v4i32(<4 x i32> %0, i32 152, <4 x i32> %value)
+  %1 = call <4 x i32> @llvm.arm.mve.vstr.scatter.base.wb.v4i32.v4i32(<4 x i32> %0, i32 -152, <4 x i32> %value)
   store <4 x i32> %1, <4 x i32>* %addr, align 8
   ret void
 }


        


More information about the llvm-commits mailing list