| 1 | #include <inttypes.h> |
| 2 | #include <stdint.h> |
| 3 | #include <stdio.h> |
| 4 | |
| 5 | #define DEFINE_SHIFT_SINGLE_COMMON(_name, _insn_str) \ |
| 6 | static uint64_t _name(uint64_t op1, uint64_t op2, uint64_t *cc) \ |
| 7 | { \ |
| 8 | asm(" sll %[cc],28\n" \ |
| 9 | " spm %[cc]\n" \ |
| 10 | " " _insn_str "\n" \ |
| 11 | " ipm %[cc]\n" \ |
| 12 | " srl %[cc],28" \ |
| 13 | : [op1] "+&r" (op1), \ |
| 14 | [cc] "+&r" (*cc) \ |
| 15 | : [op2] "r" (op2) \ |
| 16 | : "cc"); \ |
| 17 | return op1; \ |
| 18 | } |
| 19 | #define DEFINE_SHIFT_SINGLE_2(_insn, _offset) \ |
| 20 | DEFINE_SHIFT_SINGLE_COMMON(_insn ## _ ## _offset, \ |
| 21 | #_insn " %[op1]," #_offset "(%[op2])") |
| 22 | #define DEFINE_SHIFT_SINGLE_3(_insn, _offset) \ |
| 23 | DEFINE_SHIFT_SINGLE_COMMON(_insn ## _ ## _offset, \ |
| 24 | #_insn " %[op1],%[op1]," #_offset "(%[op2])") |
| 25 | #define DEFINE_SHIFT_DOUBLE(_insn, _offset) \ |
| 26 | static uint64_t _insn ## _ ## _offset(uint64_t op1, uint64_t op2, \ |
| 27 | uint64_t *cc) \ |
| 28 | { \ |
| 29 | uint32_t op1h = op1 >> 32; \ |
| 30 | uint32_t op1l = op1 & 0xffffffff; \ |
| 31 | register uint32_t r2 asm("2") = op1h; \ |
| 32 | register uint32_t r3 asm("3") = op1l; \ |
| 33 | \ |
| 34 | asm(" sll %[cc],28\n" \ |
| 35 | " spm %[cc]\n" \ |
| 36 | " " #_insn " %[r2]," #_offset "(%[op2])\n" \ |
| 37 | " ipm %[cc]\n" \ |
| 38 | " srl %[cc],28" \ |
| 39 | : [r2] "+&r" (r2), \ |
| 40 | [r3] "+&r" (r3), \ |
| 41 | [cc] "+&r" (*cc) \ |
| 42 | : [op2] "r" (op2) \ |
| 43 | : "cc"); \ |
| 44 | op1h = r2; \ |
| 45 | op1l = r3; \ |
| 46 | return (((uint64_t)op1h) << 32) | op1l; \ |
| 47 | } |
| 48 | |
| 49 | DEFINE_SHIFT_SINGLE_3(rll, 0x4cf3b); |
| 50 | DEFINE_SHIFT_SINGLE_3(rllg, 0x697c9); |
| 51 | DEFINE_SHIFT_SINGLE_2(sla, 0x4b0); |
| 52 | DEFINE_SHIFT_SINGLE_2(sla, 0xd54); |
| 53 | DEFINE_SHIFT_SINGLE_3(slak, 0x2832c); |
| 54 | DEFINE_SHIFT_SINGLE_3(slag, 0x66cc4); |
| 55 | DEFINE_SHIFT_SINGLE_3(slag, 0xd54); |
| 56 | DEFINE_SHIFT_SINGLE_2(sll, 0xd04); |
| 57 | DEFINE_SHIFT_SINGLE_3(sllk, 0x2699f); |
| 58 | DEFINE_SHIFT_SINGLE_3(sllg, 0x59df9); |
| 59 | DEFINE_SHIFT_SINGLE_2(sra, 0x67e); |
| 60 | DEFINE_SHIFT_SINGLE_3(srak, 0x60943); |
| 61 | DEFINE_SHIFT_SINGLE_3(srag, 0x6b048); |
| 62 | DEFINE_SHIFT_SINGLE_2(srl, 0x035); |
| 63 | DEFINE_SHIFT_SINGLE_3(srlk, 0x43dfc); |
| 64 | DEFINE_SHIFT_SINGLE_3(srlg, 0x27227); |
| 65 | DEFINE_SHIFT_DOUBLE(slda, 0x38b); |
| 66 | DEFINE_SHIFT_DOUBLE(sldl, 0x031); |
| 67 | DEFINE_SHIFT_DOUBLE(srda, 0x36f); |
| 68 | DEFINE_SHIFT_DOUBLE(srdl, 0x99a); |
| 69 | |
| 70 | struct shift_test { |
| 71 | const char *name; |
| 72 | uint64_t (*insn)(uint64_t, uint64_t, uint64_t *); |
| 73 | uint64_t op1; |
| 74 | uint64_t op2; |
| 75 | uint64_t exp_result; |
| 76 | uint64_t exp_cc; |
| 77 | }; |
| 78 | |
| 79 | static const struct shift_test tests[] = { |
| 80 | { |
| 81 | .name = "rll", |
| 82 | .insn = rll_0x4cf3b, |
| 83 | .op1 = 0xecbd589a45c248f5ull, |
| 84 | .op2 = 0x62e5508ccb4c99fdull, |
| 85 | .exp_result = 0xecbd589af545c248ull, |
| 86 | .exp_cc = 0, |
| 87 | }, |
| 88 | { |
| 89 | .name = "rllg", |
| 90 | .insn = rllg_0x697c9, |
| 91 | .op1 = 0xaa2d54c1b729f7f4ull, |
| 92 | .op2 = 0x5ffcf7465f5cd71full, |
| 93 | .exp_result = 0x29f7f4aa2d54c1b7ull, |
| 94 | .exp_cc = 0, |
| 95 | }, |
| 96 | { |
| 97 | .name = "sla-1", |
| 98 | .insn = sla_0x4b0, |
| 99 | .op1 = 0x8bf21fb67cca0e96ull, |
| 100 | .op2 = 0x3ddf2f53347d3030ull, |
| 101 | .exp_result = 0x8bf21fb600000000ull, |
| 102 | .exp_cc = 3, |
| 103 | }, |
| 104 | { |
| 105 | .name = "sla-2", |
| 106 | .insn = sla_0xd54, |
| 107 | .op1 = 0xe4faaed5def0e926ull, |
| 108 | .op2 = 0x18d586fab239cbeeull, |
| 109 | .exp_result = 0xe4faaed5fbc3a498ull, |
| 110 | .exp_cc = 3, |
| 111 | }, |
| 112 | { |
| 113 | .name = "slak", |
| 114 | .insn = slak_0x2832c, |
| 115 | .op1 = 0x7300bf78707f09f9ull, |
| 116 | .op2 = 0x4d193b85bb5cb39bull, |
| 117 | .exp_result = 0x7300bf783f84fc80ull, |
| 118 | .exp_cc = 3, |
| 119 | }, |
| 120 | { |
| 121 | .name = "slag-1", |
| 122 | .insn = slag_0x66cc4, |
| 123 | .op1 = 0xe805966de1a77762ull, |
| 124 | .op2 = 0x0e92953f6aa91c6bull, |
| 125 | .exp_result = 0xbbb1000000000000ull, |
| 126 | .exp_cc = 3, |
| 127 | }, |
| 128 | { |
| 129 | .name = "slag-2", |
| 130 | .insn = slag_0xd54, |
| 131 | .op1 = 0xdef0e92600000000ull, |
| 132 | .op2 = 0x18d586fab239cbeeull, |
| 133 | .exp_result = 0xfbc3a49800000000ull, |
| 134 | .exp_cc = 3, |
| 135 | }, |
| 136 | { |
| 137 | .name = "sll", |
| 138 | .insn = sll_0xd04, |
| 139 | .op1 = 0xb90281a3105939dfull, |
| 140 | .op2 = 0xb5e4df7e082e4c5eull, |
| 141 | .exp_result = 0xb90281a300000000ull, |
| 142 | .exp_cc = 0, |
| 143 | }, |
| 144 | { |
| 145 | .name = "sllk", |
| 146 | .insn = sllk_0x2699f, |
| 147 | .op1 = 0x777c6cf116f99557ull, |
| 148 | .op2 = 0xe0556cf112e5a458ull, |
| 149 | .exp_result = 0x777c6cf100000000ull, |
| 150 | .exp_cc = 0, |
| 151 | }, |
| 152 | { |
| 153 | .name = "sllg", |
| 154 | .insn = sllg_0x59df9, |
| 155 | .op1 = 0xcdf86cbfbc0f3557ull, |
| 156 | .op2 = 0x325a45acf99c6d3dull, |
| 157 | .exp_result = 0x55c0000000000000ull, |
| 158 | .exp_cc = 0, |
| 159 | }, |
| 160 | { |
| 161 | .name = "sra", |
| 162 | .insn = sra_0x67e, |
| 163 | .op1 = 0xb878f048d5354183ull, |
| 164 | .op2 = 0x9e27d13195931f79ull, |
| 165 | .exp_result = 0xb878f048ffffffffull, |
| 166 | .exp_cc = 1, |
| 167 | }, |
| 168 | { |
| 169 | .name = "srak", |
| 170 | .insn = srak_0x60943, |
| 171 | .op1 = 0xb6ceb5a429cedb35ull, |
| 172 | .op2 = 0x352354900ae34d7aull, |
| 173 | .exp_result = 0xb6ceb5a400000000ull, |
| 174 | .exp_cc = 0, |
| 175 | }, |
| 176 | { |
| 177 | .name = "srag", |
| 178 | .insn = srag_0x6b048, |
| 179 | .op1 = 0xd54dd4468676c63bull, |
| 180 | .op2 = 0x84d026db7b4dca28ull, |
| 181 | .exp_result = 0xffffffffffffd54dull, |
| 182 | .exp_cc = 1, |
| 183 | }, |
| 184 | { |
| 185 | .name = "srl", |
| 186 | .insn = srl_0x035, |
| 187 | .op1 = 0x09be503ef826815full, |
| 188 | .op2 = 0xbba8d1a0e542d5c1ull, |
| 189 | .exp_result = 0x9be503e00000000ull, |
| 190 | .exp_cc = 0, |
| 191 | }, |
| 192 | { |
| 193 | .name = "srlk", |
| 194 | .insn = srlk_0x43dfc, |
| 195 | .op1 = 0x540d6c8de71aee2aull, |
| 196 | .op2 = 0x0000000000000000ull, |
| 197 | .exp_result = 0x540d6c8d00000000ull, |
| 198 | .exp_cc = 0, |
| 199 | }, |
| 200 | { |
| 201 | .name = "srlg", |
| 202 | .insn = srlg_0x27227, |
| 203 | .op1 = 0x26f7123c1c447a34ull, |
| 204 | .op2 = 0x0000000000000000ull, |
| 205 | .exp_result = 0x00000000004dee24ull, |
| 206 | .exp_cc = 0, |
| 207 | }, |
| 208 | { |
| 209 | .name = "slda", |
| 210 | .insn = slda_0x38b, |
| 211 | .op1 = 0x7988f722dd5bbe7cull, |
| 212 | .op2 = 0x9aed3f95b4d78cc2ull, |
| 213 | .exp_result = 0x1ee45bab77cf8000ull, |
| 214 | .exp_cc = 3, |
| 215 | }, |
| 216 | { |
| 217 | .name = "sldl", |
| 218 | .insn = sldl_0x031, |
| 219 | .op1 = 0xaae2918dce2b049aull, |
| 220 | .op2 = 0x0000000000000000ull, |
| 221 | .exp_result = 0x0934000000000000ull, |
| 222 | .exp_cc = 0, |
| 223 | }, |
| 224 | { |
| 225 | .name = "srda", |
| 226 | .insn = srda_0x36f, |
| 227 | .op1 = 0x0cd4ed9228a50978ull, |
| 228 | .op2 = 0x72b046f0848b8cc9ull, |
| 229 | .exp_result = 0x000000000000000cull, |
| 230 | .exp_cc = 2, |
| 231 | }, |
| 232 | { |
| 233 | .name = "srdl", |
| 234 | .insn = srdl_0x99a, |
| 235 | .op1 = 0x1018611c41689a1dull, |
| 236 | .op2 = 0x2907e150c50ba319ull, |
| 237 | .exp_result = 0x0000000000000203ull, |
| 238 | .exp_cc = 0, |
| 239 | }, |
| 240 | }; |
| 241 | |
| 242 | int main(void) |
| 243 | { |
| 244 | int ret = 0; |
| 245 | size_t i; |
| 246 | |
| 247 | for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { |
| 248 | uint64_t result; |
| 249 | uint64_t cc = 0; |
| 250 | |
| 251 | result = tests[i].insn(tests[i].op1, tests[i].op2, &cc); |
| 252 | if (result != tests[i].exp_result) { |
| 253 | fprintf(stderr, |
| 254 | "bad %s result:\n" |
| 255 | "actual = 0x%" PRIx64 "\n" |
| 256 | "expected = 0x%" PRIx64 "\n", |
| 257 | tests[i].name, result, tests[i].exp_result); |
| 258 | ret = 1; |
| 259 | } |
| 260 | if (cc != tests[i].exp_cc) { |
| 261 | fprintf(stderr, |
| 262 | "bad %s cc:\n" |
| 263 | "actual = %" PRIu64 "\n" |
| 264 | "expected = %" PRIu64 "\n", |
| 265 | tests[i].name, cc, tests[i].exp_cc); |
| 266 | ret = 1; |
| 267 | } |
| 268 | } |
| 269 | return ret; |
| 270 | } |