1#include <stdint.h> 2#include <stdio.h> 3 4typedef struct { 5 uint64_t high; 6 uint64_t low; 7} __attribute__((aligned(16))) quad_word; 8 9 10/* CDSG needs quad-word alignment */ 11quad_word _op1, _op2, _op3; 12 13void 14test(quad_word op1_init, quad_word op2_init, quad_word op3_init, 15 int expected_cc) 16{ 17 quad_word op1_before, op2_before, op3_before; 18 int cc = 1 - expected_cc; 19 20 _op1 = op1_init; 21 _op2 = op2_init; 22 _op3 = op3_init; 23 24 op1_before = _op1; 25 op2_before = _op2; 26 op3_before = _op3; 27 28 printf("before op1 = (%#lx, %#lx)\n", _op1.high, _op1.low); 29 printf("before op2 = (%#lx, %#lx)\n", _op2.high, _op2.low); 30 printf("before op3 = (%#lx, %#lx)\n", _op3.high, _op3.low); 31 32 __asm__ volatile ( 33 "lmg %%r0,%%r1,%1\n\t" 34 "lmg %%r2,%%r3,%3\n\t" 35 "cdsg %%r0,%%r2,%2\n\t" // cdsg 1st,3rd,2nd 36 "stmg %%r0,%%r1,%1\n" // store r0,r1 to _op1 37 "stmg %%r2,%%r3,%3\n" // store r2,r3 to _op3 38 "ipm %0\n\t" 39 "srl %0,28\n\t" 40 : "=d" (cc), "+QS" (_op1), "+QS" (_op2), "+QS" (_op3) 41 : 42 : "r0", "r1", "r2", "r3", "cc"); 43 44 printf("after op1 = (%#lx, %#lx)\n", _op1.high, _op1.low); 45 printf("after op2 = (%#lx, %#lx)\n", _op2.high, _op2.low); 46 printf("after op3 = (%#lx, %#lx)\n", _op3.high, _op3.low); 47 printf("cc = %d\n", cc); 48 49 if (cc != expected_cc) { 50 printf("condition code is incorrect\n"); 51 } 52 53 // _op3 never changes 54 if (_op3.low != op3_before.low || _op3.high != op3_before.high) { 55 printf("operand #3 modified\n"); 56 } 57 58 if (expected_cc == 0) { 59 // 3rd operand stored at 2nd operand location 60 61 // _op1 did not change 62 if (_op1.low != op1_before.low || _op1.high != op1_before.high) { 63 printf("operand #1 modified\n"); 64 } 65 if (_op2.high != _op3.high || _op2.low != _op3.low) { 66 printf("operand #2 incorrect\n"); 67 } 68 } else { 69 // 2nd operand stored at 1st operand location 70 71 // _op2 did not change 72 if (_op2.low != op2_before.low || _op2.high != op2_before.high) { 73 printf("operand #2 modified\n"); 74 } 75 76 if (_op1.high != _op2.high || _op1.low != _op2.low) { 77 printf("operand #1 incorrect\n"); 78 } 79 } 80} 81 82int main () 83{ 84 quad_word op1, op2, op3; 85 86 // op1 == op2 87 op1.high = 0x0011223344556677ull; 88 op1.low = 0x8899aabbccddeeffull; 89 op2 = op1; 90 op3.high = op3.low = 0xdeadbeefdeadbabeull; 91 test(op1, op2, op3, 0); 92 93 // op1 != op2 (only MSB differs) 94 op1.high = 0x8000000000000000ull; 95 op1.low = 0x0000000000000000ull; 96 op2.high = 0; 97 op2.low = 1; 98 op3.high = op3.low = 0xdeadbeefdeadbabeull; 99 test(op1, op2, op3, 1); 100 101 // op1 != op2 (only LSB differs) 102 op1.high = 0x0000000000000000ull; 103 op1.low = 0x0000000000000001ull; 104 op2.high = 1; 105 op2.low = 0; 106 op3.high = op3.low = 0xdeadbeefdeadbabeull; 107 test(op1, op2, op3, 1); 108 109 return 0; 110} 111