From 4978296cd8e4d10724cfa41f0308d256c0fd490c Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 6 Jan 2020 16:33:05 +0000 Subject: [PATCH] [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 --- clang/include/clang/Basic/arm_mve_defs.td | 5 +- .../CodeGen/arm-mve-intrinsics/scatter-gather.c | 60 +++++++++++----------- clang/test/Sema/arm-mve-immediates.c | 28 +++++++--- clang/utils/TableGen/MveEmitter.cpp | 11 +++- .../Thumb2/mve-intrinsics/scatter-gather.ll | 48 ++++++++--------- 5 files changed, 86 insertions(+), 66 deletions(-) diff --git a/clang/include/clang/Basic/arm_mve_defs.td b/clang/include/clang/Basic/arm_mve_defs.td index 939d5eb..6fba88d 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> { // imm_mem7bit 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 - : Immediate> { + : Immediate> { let extra = !if(!eq(membytes, 1), ?, "Multiple"); let extraarg = !cast(membytes); } diff --git a/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c b/clang/test/CodeGen/arm-mve-intrinsics/scatter-gather.c index 8bf2111..564965a 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 45b2357..54cdb96 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 ae4c9b2..6f3fd25 100644 --- a/clang/utils/TableGen/MveEmitter.cpp +++ b/clang/utils/TableGen/MveEmitter.cpp @@ -861,6 +861,13 @@ public: } 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 SemaChecks; @@ -895,8 +902,8 @@ public: 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 5e19f81..7eac790 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 } -- 2.7.4