1#include <stdint.h>
2#include <inttypes.h>
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6#include "opcodes.h"
7
8#ifndef M3
9#define M3 0
10#endif
11
12/* The abstracted result of an CU24 insn */
13typedef struct {
14   uint64_t addr1;  // target
15   uint64_t len1;
16   uint64_t addr2;  // source
17   uint64_t len2;
18   uint32_t cc;
19} cu24_t;
20
21/* Define various input buffers. */
22
23/* Single UTF-16 value */
24uint16_t pattern1[] = {
25   0x0000, 0xd7ff,    /* [0000 ... d7ff]  corner cases */
26   0xdc00, 0xffff,    /* [dc00 ... ffff]  corner cases */
27   0x0047, 0x0156, 0x1245, 0xa021, 0xfffe /* misc */
28};
29
30/* UTF-16 surrogate pair */
31uint16_t pattern2[] = {
32   0xd800, 0xdc00,    /* left  corner case */
33   0xdbff, 0xdfff,    /* right corner case */
34   0xdada, 0xdddd, 0xdeaf, 0xdcdc  /* misc */
35};
36
37/* Invalid low surrogate */
38uint16_t invalid[] = { 0xd801, 0x0098 };
39
40/* Mixed bytes */
41uint16_t mixed[] = {
42   0x0078,
43   0x0200,
44   0xffff,
45   0xd800, 0xdc01,
46   0xde00, 0xdd00,
47   0xc0c0
48};
49
50/* This is the buffer for the converted bytes. */
51uint32_t buff[1000];  /* Large so we con'don't have to worry about it */
52
53
54static cu24_t
55do_cu24(uint32_t *dst, uint64_t dst_len, uint16_t *src, uint64_t src_len)
56{
57   int cc = 42;
58   cu24_t regs;
59
60   /* build up the register pairs */
61   register uint16_t *source     asm("4") = src;
62   register uint64_t  source_len asm("5") = src_len;
63   register uint32_t *dest       asm("2") = dst;
64   register uint64_t  dest_len   asm("3") = dst_len;
65
66   asm volatile(
67                CU24(M3,2,4)
68                "ipm %2\n\t"
69                "srl %2,28\n\t"
70                : "+d"(dest), "+d"(source), "=d"(cc),
71                  "+d"(source_len), "+d"(dest_len)
72                :
73                : "memory", "cc");
74
75   /* Capture register contents at end of cu24 */
76   regs.addr1 = (uint64_t)dest;
77   regs.len1  = dest_len;
78   regs.addr2 = (uint64_t)source;
79   regs.len2  = source_len;
80   regs.cc = cc;
81
82   return regs;
83}
84
85void
86run_test(uint32_t *dst, uint64_t dst_len, uint16_t *src, uint64_t src_len)
87{
88   int i;
89   cu24_t result;
90
91   result = do_cu24(dst, dst_len, src, src_len);
92
93   // Write out the converted byte, if any
94   printf("UTF32: ");
95   if (dst_len - result.len1 == 0)
96      printf(" <none>");
97   else {
98      uint64_t num_bytes = dst_len - result.len1;
99
100      /* The number of bytes that were written must be divisible by 4 */
101      if (num_bytes % 4 != 0)
102         fprintf(stderr, "*** number of bytes is not a multiple of 4\n");
103
104      for (i = 0; i < num_bytes / 4; i++) {
105         printf(" %02x", dst[i]);
106      }
107   }
108   printf("\n");
109
110   printf("  cc = %d\n", result.cc);
111   if (dst != NULL)
112      printf("  dst address difference: %"PRId64, result.addr1 - (uint64_t)dst);
113   printf("  dst len: %"PRId64"\n", result.len1);
114
115   if (src != NULL)
116      printf("  src address difference: %"PRId64, result.addr2 - (uint64_t)src);
117   printf("  src len: %"PRId64"\n", result.len2);
118}
119
120int main()
121{
122   /* Length == 0, no memory should be read or written */
123   printf("\n------------- test1 ----------------\n");
124   run_test(NULL, 0, NULL, 0);
125
126   /* Test exhaustion of source length (source bytes are valid) */
127   printf("\n------------- test2.1 ----------------\n");
128
129   /* No character will be written to BUFF, i.e. loop in jitted code
130      is not iterated */
131   run_test(buff, sizeof buff, NULL,     1);
132   run_test(buff, sizeof buff, pattern1, 1);
133   run_test(buff, sizeof buff, pattern2, 1);
134   run_test(buff, sizeof buff, pattern2, 2);
135   run_test(buff, sizeof buff, pattern2, 3);
136
137   printf("\n------------- test2.2 ----------------\n");
138   /* At least one character will be written to BUFF, i.e. loop in jitted
139      code is iterated */
140   run_test(buff, sizeof buff, pattern1, 3);
141   run_test(buff, sizeof buff, pattern1, 5);
142   run_test(buff, sizeof buff, pattern2, 2);
143   run_test(buff, sizeof buff, pattern2, 5);
144   run_test(buff, sizeof buff, pattern2, 7);
145
146   /* Test exhaustion of destination length (source bytes are valid) */
147   printf("\n------------- test3.1 ----------------\n");
148
149   /* No character will be written to BUFF, i.e. loop in jitted code
150      is not iterated */
151
152   /* Want to write 4 bytes at a time */
153   run_test(NULL, 0, pattern1, sizeof pattern1);
154   run_test(NULL, 1, pattern1, sizeof pattern1);
155   run_test(NULL, 2, pattern1, sizeof pattern1);
156   run_test(NULL, 3, pattern1, sizeof pattern1);
157
158   printf("\n------------- test3.2 ----------------\n");
159   /* At least one character will be written to BUFF, i.e. loop in jitted
160      code is iterated */
161   run_test(buff, 4, pattern1, sizeof pattern1);
162   run_test(buff, 5, pattern1, sizeof pattern1);
163   run_test(buff, 6, pattern1, sizeof pattern1);
164   run_test(buff, 7, pattern1, sizeof pattern1);
165
166   /* When both operands are exhausted, cc=0 takes precedence.
167      (test1 tests this for len == 0) */
168   printf("\n------------- test4 ----------------\n");
169   run_test(buff, 4, pattern1, 2);   // no iteration
170   run_test(buff, 8, pattern1, 4);   // iteration
171
172   /* Input has invalid low surrogate. */
173   printf("\n------------- test5 ----------------\n");
174   run_test(buff, sizeof buff, invalid, sizeof invalid);
175   run_test(buff, 0, invalid, sizeof invalid);
176
177   /* Convert all pattern buffers */
178   printf("\n------------- test6 ----------------\n");
179   run_test(buff, sizeof buff, pattern1, sizeof pattern1);
180   run_test(buff, sizeof buff, pattern2, sizeof pattern2);
181
182   return 0;
183}
184