Zhi An Ng | 109a5eb | 2022-01-20 09:35:12 -0800 | [diff] [blame] | 1 | // Copyright 2022 Google LLC |
| 2 | // |
| 3 | // This source code is licensed under the BSD-style license found in the |
| 4 | // LICENSE file in the root directory of this source tree. |
| 5 | |
| 6 | #include <xnnpack/aarch64-assembler.h> |
| 7 | #include <xnnpack/allocator.h> |
| 8 | #include <xnnpack/common.h> |
| 9 | |
Zhi An Ng | 0ba29e7 | 2022-01-20 11:26:01 -0800 | [diff] [blame] | 10 | #include "assembler-helpers.h" |
Zhi An Ng | 109a5eb | 2022-01-20 09:35:12 -0800 | [diff] [blame] | 11 | #include <gtest/gtest.h> |
| 12 | |
| 13 | namespace xnnpack { |
| 14 | namespace aarch64 { |
| 15 | |
| 16 | TEST(AArch64Assembler, Initialization) { |
| 17 | xnn_code_buffer b; |
| 18 | xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE); |
| 19 | Assembler a(&b); |
| 20 | ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b)); |
| 21 | } |
| 22 | |
Zhi An Ng | 65ccb13 | 2022-01-20 16:16:47 -0800 | [diff] [blame] | 23 | TEST(AArch64Assembler, BaseInstructionEncoding) { |
| 24 | xnn_code_buffer b; |
| 25 | xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE); |
| 26 | Assembler a(&b); |
| 27 | |
| 28 | CHECK_ENCODING(0xA9403FEE, a.ldp(x14, x15, mem[sp])); |
| 29 | CHECK_ENCODING(0xA8C13FEE, a.ldp(x14, x15, mem[sp], 16)); |
| 30 | CHECK_ENCODING(0xA9413FEE, a.ldp(x14, x15, mem[sp, 16])); |
| 31 | CHECK_ENCODING(0xA9603FEE, a.ldp(x14, x15, mem[sp, -512])); |
| 32 | CHECK_ENCODING(0xA95FBFEE, a.ldp(x14, x15, mem[sp, 504])); |
| 33 | EXPECT_ERROR(Error::kInvalidOperand, a.ldp(x14, x15, mem[sp], 15)); |
| 34 | EXPECT_ERROR(Error::kInvalidOperand, a.ldp(x14, x15, mem[sp], -520)); |
| 35 | EXPECT_ERROR(Error::kInvalidOperand, a.ldp(x14, x15, mem[sp], 512)); |
| 36 | EXPECT_ERROR(Error::kInvalidOperand, a.ldp(x14, x15, mem[sp, 16], 16)); |
| 37 | |
| 38 | CHECK_ENCODING(0xF9400BE8, a.ldr(x8, mem[sp, 16])); |
| 39 | CHECK_ENCODING(0xF97FFFE8, a.ldr(x8, mem[sp, 32760])); |
| 40 | EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, mem[sp, -8])); |
| 41 | EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, mem[sp, 7])); |
| 42 | EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, mem[sp, 32768])); |
| 43 | EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, MemOperand(sp, 16, AddressingMode::kPostIndex))); |
| 44 | |
Zhi An Ng | 234d6b4 | 2022-01-20 16:31:33 -0800 | [diff] [blame] | 45 | CHECK_ENCODING(0xF98000A0, a.prfm(PLDL1KEEP, mem[x5])); |
| 46 | EXPECT_ERROR(Error::kInvalidOperand, a.prfm(PLDL1KEEP, mem[x5, -8])); |
| 47 | EXPECT_ERROR(Error::kInvalidOperand, a.prfm(PLDL1KEEP, mem[x5, 32761])); |
| 48 | |
Zhi An Ng | e2dc2ec | 2022-01-20 17:05:33 -0800 | [diff] [blame] | 49 | CHECK_ENCODING(0xF1008040, a.subs(x0, x2, 32)); |
| 50 | CHECK_ENCODING(0xF13FFC40, a.subs(x0, x2, 4095)); |
| 51 | EXPECT_ERROR(Error::kInvalidOperand, a.subs(x0, x2, -32)); |
| 52 | EXPECT_ERROR(Error::kInvalidOperand, a.subs(x0, x2, 4096)); |
| 53 | |
Zhi An Ng | 65ccb13 | 2022-01-20 16:16:47 -0800 | [diff] [blame] | 54 | ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b)); |
| 55 | } |
| 56 | |
| 57 | TEST(AArch64Assembler, SIMDInstructionEncoding) { |
Zhi An Ng | 0ba29e7 | 2022-01-20 11:26:01 -0800 | [diff] [blame] | 58 | xnn_code_buffer b; |
| 59 | xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE); |
| 60 | Assembler a(&b); |
| 61 | |
Zhi An Ng | 6e68f54 | 2022-01-20 15:18:57 -0800 | [diff] [blame] | 62 | CHECK_ENCODING(0x0CDF7060, a.ld1({v0.v8b()}, mem[x3], 8)); |
| 63 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v8b()}, mem[x3], 16)); |
| 64 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v16b()}, mem[x3], 8)); |
| 65 | |
| 66 | CHECK_ENCODING(0x0CDFA060, a.ld1({v0.v8b(), v1.v8b()}, mem[x3], 16)); |
| 67 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v8b(), v1.v8b()}, mem[x3], 32)); |
| 68 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v16b(), v1.v16b()}, mem[x3], 16)); |
| 69 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v8b(), v2.v8b()}, mem[x3], 16)); |
| 70 | |
| 71 | CHECK_ENCODING(0x4CDF61F0, a.ld1({v16.v16b(), v17.v16b(), v18.v16b()}, mem[x15], 48)); |
| 72 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v16.v8b(), v17.v16b(), v18.v16b()}, mem[x15], 48)); |
| 73 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v16.v16b(), v17.v16b(), v18.v8b()}, mem[x15], 48)); |
| 74 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v16.v16b(), v17.v16b(), v18.v16b()}, mem[x15], 24)); |
| 75 | EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v16.v8b(), v17.v8b(), v18.v8b()}, mem[x15], 48)); |
| 76 | |
Zhi An Ng | 5702efb | 2022-01-20 14:04:20 -0800 | [diff] [blame] | 77 | CHECK_ENCODING(0x4D60C902, a.ld2r({v2.v4s(), v3.v4s()}, mem[x8])); |
| 78 | EXPECT_ERROR(Error::kInvalidOperand, a.ld2r({v2.v4s(), v3.v4s()}, mem[x8, 16])); |
| 79 | EXPECT_ERROR(Error::kInvalidOperand, a.ld2r({v2.v4s(), v4.v4s()}, mem[x8, 16])); |
Zhi An Ng | 6e68f54 | 2022-01-20 15:18:57 -0800 | [diff] [blame] | 80 | EXPECT_ERROR(Error::kInvalidOperand, a.ld2r({v2.v4s(), v3.v8b()}, mem[x8])); |
Zhi An Ng | 5702efb | 2022-01-20 14:04:20 -0800 | [diff] [blame] | 81 | |
Zhi An Ng | 65ccb13 | 2022-01-20 16:16:47 -0800 | [diff] [blame] | 82 | CHECK_ENCODING(0x4F000405, a.movi(v5.v4s(), 0)); |
| 83 | CHECK_ENCODING(0x4F008405, a.movi(v5.v8h(), 0)); |
| 84 | CHECK_ENCODING(0x4F00E405, a.movi(v5.v16b(), 0)); |
| 85 | EXPECT_ERROR(Error::kUnimplemented, a.movi(v5.v16b(), 0xFF)); |
Zhi An Ng | 04cdc41 | 2022-01-20 11:37:49 -0800 | [diff] [blame] | 86 | |
Zhi An Ng | 0ba29e7 | 2022-01-20 11:26:01 -0800 | [diff] [blame] | 87 | ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b)); |
| 88 | } |
| 89 | |
Zhi An Ng | f67f1be | 2022-01-21 10:06:54 -0800 | [diff] [blame^] | 90 | TEST(AArch64Assembler, Label) { |
| 91 | xnn_code_buffer b; |
| 92 | xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE); |
| 93 | Assembler a(&b); |
| 94 | |
| 95 | Label l1; |
| 96 | a.movi(v0.v4s(), 0); |
| 97 | |
| 98 | // Branch to unbound label. |
| 99 | auto b1 = a.offset<uint32_t*>(); |
| 100 | a.b_eq(l1); |
| 101 | |
| 102 | a.movi(v1.v4s(), 0); |
| 103 | |
| 104 | auto b2 = a.offset<uint32_t*>(); |
| 105 | a.b_ne(l1); |
| 106 | |
| 107 | a.movi(v2.v4s(), 0); |
| 108 | |
| 109 | a.bind(l1); |
| 110 | |
| 111 | // Check that b1 and b2 are both patched after binding l1. |
| 112 | EXPECT_INSTR(0x54000080, *b1); |
| 113 | EXPECT_INSTR(0x54000041, *b2); |
| 114 | |
| 115 | a.movi(v3, 0); |
| 116 | |
| 117 | // Branch to bound label. |
| 118 | auto b3 = a.offset<uint32_t*>(); |
| 119 | a.b_hi(l1); |
| 120 | auto b4 = a.offset<uint32_t*>(); |
| 121 | a.b_hs(l1); |
| 122 | auto b5 = a.offset<uint32_t*>(); |
| 123 | a.b_lo(l1); |
| 124 | |
| 125 | EXPECT_INSTR(0x54FFFFE8, *b3); |
| 126 | EXPECT_INSTR(0x54FFFFC2, *b4); |
| 127 | EXPECT_INSTR(0x54FFFFA3, *b5); |
| 128 | |
| 129 | // Binding a bound label is an error. |
| 130 | a.bind(l1); |
| 131 | EXPECT_ERROR(Error::kLabelAlreadyBound, a.bind(l1)); |
| 132 | |
| 133 | // Check for bind failure due to too many users of label. |
| 134 | Label lfail; |
| 135 | a.reset(); |
| 136 | // Arbitrary high number of users that we probably won't support. |
| 137 | for (int i = 0; i < 1000; i++) { |
| 138 | a.b_eq(lfail); |
| 139 | } |
| 140 | EXPECT_EQ(Error::kLabelHasTooManyUsers, a.error()); |
| 141 | |
| 142 | ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b)); |
| 143 | } |
| 144 | |
Zhi An Ng | 109a5eb | 2022-01-20 09:35:12 -0800 | [diff] [blame] | 145 | } // namespace aarch64 |
| 146 | } // namespace xnnpack |