#include #include #include #define DEFINE_SHIFT_SINGLE_COMMON(_name, _insn_str) \ static uint64_t _name(uint64_t op1, uint64_t op2, uint64_t *cc) \ { \ asm(" sll %[cc],28\n" \ " spm %[cc]\n" \ " " _insn_str "\n" \ " ipm %[cc]\n" \ " srl %[cc],28" \ : [op1] "+&r" (op1), \ [cc] "+&r" (*cc) \ : [op2] "r" (op2) \ : "cc"); \ return op1; \ } #define DEFINE_SHIFT_SINGLE_2(_insn, _offset) \ DEFINE_SHIFT_SINGLE_COMMON(_insn ## _ ## _offset, \ #_insn " %[op1]," #_offset "(%[op2])") #define DEFINE_SHIFT_SINGLE_3(_insn, _offset) \ DEFINE_SHIFT_SINGLE_COMMON(_insn ## _ ## _offset, \ #_insn " %[op1],%[op1]," #_offset "(%[op2])") #define DEFINE_SHIFT_DOUBLE(_insn, _offset) \ static uint64_t _insn ## _ ## _offset(uint64_t op1, uint64_t op2, \ uint64_t *cc) \ { \ uint32_t op1h = op1 >> 32; \ uint32_t op1l = op1 & 0xffffffff; \ register uint32_t r2 asm("2") = op1h; \ register uint32_t r3 asm("3") = op1l; \ \ asm(" sll %[cc],28\n" \ " spm %[cc]\n" \ " " #_insn " %[r2]," #_offset "(%[op2])\n" \ " ipm %[cc]\n" \ " srl %[cc],28" \ : [r2] "+&r" (r2), \ [r3] "+&r" (r3), \ [cc] "+&r" (*cc) \ : [op2] "r" (op2) \ : "cc"); \ op1h = r2; \ op1l = r3; \ return (((uint64_t)op1h) << 32) | op1l; \ } DEFINE_SHIFT_SINGLE_3(rll, 0x4cf3b); DEFINE_SHIFT_SINGLE_3(rllg, 0x697c9); DEFINE_SHIFT_SINGLE_2(sla, 0x4b0); DEFINE_SHIFT_SINGLE_2(sla, 0xd54); DEFINE_SHIFT_SINGLE_3(slak, 0x2832c); DEFINE_SHIFT_SINGLE_3(slag, 0x66cc4); DEFINE_SHIFT_SINGLE_3(slag, 0xd54); DEFINE_SHIFT_SINGLE_2(sll, 0xd04); DEFINE_SHIFT_SINGLE_3(sllk, 0x2699f); DEFINE_SHIFT_SINGLE_3(sllg, 0x59df9); DEFINE_SHIFT_SINGLE_2(sra, 0x67e); DEFINE_SHIFT_SINGLE_3(srak, 0x60943); DEFINE_SHIFT_SINGLE_3(srag, 0x6b048); DEFINE_SHIFT_SINGLE_2(srl, 0x035); DEFINE_SHIFT_SINGLE_3(srlk, 0x43dfc); DEFINE_SHIFT_SINGLE_3(srlg, 0x27227); DEFINE_SHIFT_DOUBLE(slda, 0x38b); DEFINE_SHIFT_DOUBLE(sldl, 0x031); DEFINE_SHIFT_DOUBLE(srda, 0x36f); DEFINE_SHIFT_DOUBLE(srdl, 0x99a); struct shift_test { const char *name; uint64_t (*insn)(uint64_t, uint64_t, uint64_t *); uint64_t op1; uint64_t op2; uint64_t exp_result; uint64_t exp_cc; }; static const struct shift_test tests[] = { { .name = "rll", .insn = rll_0x4cf3b, .op1 = 0xecbd589a45c248f5ull, .op2 = 0x62e5508ccb4c99fdull, .exp_result = 0xecbd589af545c248ull, .exp_cc = 0, }, { .name = "rllg", .insn = rllg_0x697c9, .op1 = 0xaa2d54c1b729f7f4ull, .op2 = 0x5ffcf7465f5cd71full, .exp_result = 0x29f7f4aa2d54c1b7ull, .exp_cc = 0, }, { .name = "sla-1", .insn = sla_0x4b0, .op1 = 0x8bf21fb67cca0e96ull, .op2 = 0x3ddf2f53347d3030ull, .exp_result = 0x8bf21fb600000000ull, .exp_cc = 3, }, { .name = "sla-2", .insn = sla_0xd54, .op1 = 0xe4faaed5def0e926ull, .op2 = 0x18d586fab239cbeeull, .exp_result = 0xe4faaed5fbc3a498ull, .exp_cc = 3, }, { .name = "slak", .insn = slak_0x2832c, .op1 = 0x7300bf78707f09f9ull, .op2 = 0x4d193b85bb5cb39bull, .exp_result = 0x7300bf783f84fc80ull, .exp_cc = 3, }, { .name = "slag-1", .insn = slag_0x66cc4, .op1 = 0xe805966de1a77762ull, .op2 = 0x0e92953f6aa91c6bull, .exp_result = 0xbbb1000000000000ull, .exp_cc = 3, }, { .name = "slag-2", .insn = slag_0xd54, .op1 = 0xdef0e92600000000ull, .op2 = 0x18d586fab239cbeeull, .exp_result = 0xfbc3a49800000000ull, .exp_cc = 3, }, { .name = "sll", .insn = sll_0xd04, .op1 = 0xb90281a3105939dfull, .op2 = 0xb5e4df7e082e4c5eull, .exp_result = 0xb90281a300000000ull, .exp_cc = 0, }, { .name = "sllk", .insn = sllk_0x2699f, .op1 = 0x777c6cf116f99557ull, .op2 = 0xe0556cf112e5a458ull, .exp_result = 0x777c6cf100000000ull, .exp_cc = 0, }, { .name = "sllg", .insn = sllg_0x59df9, .op1 = 0xcdf86cbfbc0f3557ull, .op2 = 0x325a45acf99c6d3dull, .exp_result = 0x55c0000000000000ull, .exp_cc = 0, }, { .name = "sra", .insn = sra_0x67e, .op1 = 0xb878f048d5354183ull, .op2 = 0x9e27d13195931f79ull, .exp_result = 0xb878f048ffffffffull, .exp_cc = 1, }, { .name = "srak", .insn = srak_0x60943, .op1 = 0xb6ceb5a429cedb35ull, .op2 = 0x352354900ae34d7aull, .exp_result = 0xb6ceb5a400000000ull, .exp_cc = 0, }, { .name = "srag", .insn = srag_0x6b048, .op1 = 0xd54dd4468676c63bull, .op2 = 0x84d026db7b4dca28ull, .exp_result = 0xffffffffffffd54dull, .exp_cc = 1, }, { .name = "srl", .insn = srl_0x035, .op1 = 0x09be503ef826815full, .op2 = 0xbba8d1a0e542d5c1ull, .exp_result = 0x9be503e00000000ull, .exp_cc = 0, }, { .name = "srlk", .insn = srlk_0x43dfc, .op1 = 0x540d6c8de71aee2aull, .op2 = 0x0000000000000000ull, .exp_result = 0x540d6c8d00000000ull, .exp_cc = 0, }, { .name = "srlg", .insn = srlg_0x27227, .op1 = 0x26f7123c1c447a34ull, .op2 = 0x0000000000000000ull, .exp_result = 0x00000000004dee24ull, .exp_cc = 0, }, { .name = "slda", .insn = slda_0x38b, .op1 = 0x7988f722dd5bbe7cull, .op2 = 0x9aed3f95b4d78cc2ull, .exp_result = 0x1ee45bab77cf8000ull, .exp_cc = 3, }, { .name = "sldl", .insn = sldl_0x031, .op1 = 0xaae2918dce2b049aull, .op2 = 0x0000000000000000ull, .exp_result = 0x0934000000000000ull, .exp_cc = 0, }, { .name = "srda", .insn = srda_0x36f, .op1 = 0x0cd4ed9228a50978ull, .op2 = 0x72b046f0848b8cc9ull, .exp_result = 0x000000000000000cull, .exp_cc = 2, }, { .name = "srdl", .insn = srdl_0x99a, .op1 = 0x1018611c41689a1dull, .op2 = 0x2907e150c50ba319ull, .exp_result = 0x0000000000000203ull, .exp_cc = 0, }, }; int main(void) { int ret = 0; size_t i; for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint64_t result; uint64_t cc = 0; result = tests[i].insn(tests[i].op1, tests[i].op2, &cc); if (result != tests[i].exp_result) { fprintf(stderr, "bad %s result:\n" "actual = 0x%" PRIx64 "\n" "expected = 0x%" PRIx64 "\n", tests[i].name, result, tests[i].exp_result); ret = 1; } if (cc != tests[i].exp_cc) { fprintf(stderr, "bad %s cc:\n" "actual = %" PRIu64 "\n" "expected = %" PRIu64 "\n", tests[i].name, cc, tests[i].exp_cc); ret = 1; } } return ret; }