1*9e05c084SJon Chesterfield //===--- amdgpu/impl/msgpack.cpp ---------------------------------- C++ -*-===//
2*9e05c084SJon Chesterfield //
3*9e05c084SJon Chesterfield // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*9e05c084SJon Chesterfield // See https://llvm.org/LICENSE.txt for license information.
5*9e05c084SJon Chesterfield // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*9e05c084SJon Chesterfield //
7*9e05c084SJon Chesterfield //===----------------------------------------------------------------------===//
8d0b31295SJon Chesterfield #include <cassert>
9d0b31295SJon Chesterfield #include <cstdint>
10d0b31295SJon Chesterfield #include <cstring>
11d0b31295SJon Chesterfield #include <functional>
12d0b31295SJon Chesterfield #include <string>
13d0b31295SJon Chesterfield 
14d0b31295SJon Chesterfield #include "msgpack.h"
15d0b31295SJon Chesterfield 
16d0b31295SJon Chesterfield namespace msgpack {
17d0b31295SJon Chesterfield 
internal_error()18d0b31295SJon Chesterfield [[noreturn]] void internal_error() {
19d0b31295SJon Chesterfield   printf("internal error\n");
20d0b31295SJon Chesterfield   exit(1);
21d0b31295SJon Chesterfield }
22d0b31295SJon Chesterfield 
type_name(type ty)23d0b31295SJon Chesterfield const char *type_name(type ty) {
24d0b31295SJon Chesterfield   switch (ty) {
25d0b31295SJon Chesterfield #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
26d0b31295SJon Chesterfield   case NAME:                                                                   \
27d0b31295SJon Chesterfield     return #NAME;
28d0b31295SJon Chesterfield #include "msgpack.def"
29d0b31295SJon Chesterfield #undef X
30d0b31295SJon Chesterfield   }
31d0b31295SJon Chesterfield   internal_error();
32d0b31295SJon Chesterfield }
33d0b31295SJon Chesterfield 
bytes_used_fixed(msgpack::type ty)34d0b31295SJon Chesterfield unsigned bytes_used_fixed(msgpack::type ty) {
35d0b31295SJon Chesterfield   using namespace msgpack;
36d0b31295SJon Chesterfield   switch (ty) {
37d0b31295SJon Chesterfield #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
38d0b31295SJon Chesterfield   case NAME:                                                                   \
39d0b31295SJon Chesterfield     return WIDTH;
40d0b31295SJon Chesterfield #include "msgpack.def"
41d0b31295SJon Chesterfield #undef X
42d0b31295SJon Chesterfield   }
43d0b31295SJon Chesterfield   internal_error();
44d0b31295SJon Chesterfield }
45d0b31295SJon Chesterfield 
parse_type(unsigned char x)46d0b31295SJon Chesterfield msgpack::type parse_type(unsigned char x) {
47d0b31295SJon Chesterfield 
48d0b31295SJon Chesterfield #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
49d0b31295SJon Chesterfield   if (x >= LOWER && x <= UPPER) {                                              \
50d0b31295SJon Chesterfield     return NAME;                                                               \
51d0b31295SJon Chesterfield   } else
52d0b31295SJon Chesterfield #include "msgpack.def"
53d0b31295SJon Chesterfield #undef X
54d0b31295SJon Chesterfield   { internal_error(); }
55d0b31295SJon Chesterfield }
56d0b31295SJon Chesterfield 
bitcast(T x)57d0b31295SJon Chesterfield template <typename T, typename R> R bitcast(T x) {
58d0b31295SJon Chesterfield   static_assert(sizeof(T) == sizeof(R), "");
59d0b31295SJon Chesterfield   R tmp;
60d0b31295SJon Chesterfield   memcpy(&tmp, &x, sizeof(T));
61d0b31295SJon Chesterfield   return tmp;
62d0b31295SJon Chesterfield }
63d0b31295SJon Chesterfield template int64_t bitcast<uint64_t, int64_t>(uint64_t);
64d0b31295SJon Chesterfield } // namespace msgpack
65d0b31295SJon Chesterfield 
66d0b31295SJon Chesterfield // Helper functions for reading additional payload from the header
67d0b31295SJon Chesterfield // Depending on the type, this can be a number of bytes, elements,
68d0b31295SJon Chesterfield // key-value pairs or an embedded integer.
69d0b31295SJon Chesterfield // Each takes a pointer to the start of the header and returns a uint64_t
70d0b31295SJon Chesterfield 
71d0b31295SJon Chesterfield namespace {
72d0b31295SJon Chesterfield namespace payload {
read_zero(const unsigned char *)73d0b31295SJon Chesterfield uint64_t read_zero(const unsigned char *) { return 0; }
74d0b31295SJon Chesterfield 
75d0b31295SJon Chesterfield // Read the first byte and zero/sign extend it
read_embedded_u8(const unsigned char * start)76d0b31295SJon Chesterfield uint64_t read_embedded_u8(const unsigned char *start) { return start[0]; }
read_embedded_s8(const unsigned char * start)77d0b31295SJon Chesterfield uint64_t read_embedded_s8(const unsigned char *start) {
78d0b31295SJon Chesterfield   int64_t res = msgpack::bitcast<uint8_t, int8_t>(start[0]);
79d0b31295SJon Chesterfield   return msgpack::bitcast<int64_t, uint64_t>(res);
80d0b31295SJon Chesterfield }
81d0b31295SJon Chesterfield 
82d0b31295SJon Chesterfield // Read a masked part of the first byte
read_via_mask_0x1(const unsigned char * start)83d0b31295SJon Chesterfield uint64_t read_via_mask_0x1(const unsigned char *start) { return *start & 0x1u; }
read_via_mask_0xf(const unsigned char * start)84d0b31295SJon Chesterfield uint64_t read_via_mask_0xf(const unsigned char *start) { return *start & 0xfu; }
read_via_mask_0x1f(const unsigned char * start)85d0b31295SJon Chesterfield uint64_t read_via_mask_0x1f(const unsigned char *start) {
86d0b31295SJon Chesterfield   return *start & 0x1fu;
87d0b31295SJon Chesterfield }
88d0b31295SJon Chesterfield 
89d0b31295SJon Chesterfield // Read 1/2/4/8 bytes immediately following the type byte and zero/sign extend
90d0b31295SJon Chesterfield // Big endian format.
read_size_field_u8(const unsigned char * from)91d0b31295SJon Chesterfield uint64_t read_size_field_u8(const unsigned char *from) {
92d0b31295SJon Chesterfield   from++;
93d0b31295SJon Chesterfield   return from[0];
94d0b31295SJon Chesterfield }
95d0b31295SJon Chesterfield 
96d0b31295SJon Chesterfield // TODO: detect whether host is little endian or not, and whether the intrinsic
97d0b31295SJon Chesterfield // is available. And probably use the builtin to test the diy
98d0b31295SJon Chesterfield const bool use_bswap = false;
99d0b31295SJon Chesterfield 
read_size_field_u16(const unsigned char * from)100d0b31295SJon Chesterfield uint64_t read_size_field_u16(const unsigned char *from) {
101d0b31295SJon Chesterfield   from++;
102d0b31295SJon Chesterfield   if (use_bswap) {
103d0b31295SJon Chesterfield     uint16_t b;
104d0b31295SJon Chesterfield     memcpy(&b, from, 2);
105d0b31295SJon Chesterfield     return __builtin_bswap16(b);
106d0b31295SJon Chesterfield   } else {
107d0b31295SJon Chesterfield     return (from[0] << 8u) | from[1];
108d0b31295SJon Chesterfield   }
109d0b31295SJon Chesterfield }
read_size_field_u32(const unsigned char * from)110d0b31295SJon Chesterfield uint64_t read_size_field_u32(const unsigned char *from) {
111d0b31295SJon Chesterfield   from++;
112d0b31295SJon Chesterfield   if (use_bswap) {
113d0b31295SJon Chesterfield     uint32_t b;
114d0b31295SJon Chesterfield     memcpy(&b, from, 4);
115d0b31295SJon Chesterfield     return __builtin_bswap32(b);
116d0b31295SJon Chesterfield   } else {
117d0b31295SJon Chesterfield     return (from[0] << 24u) | (from[1] << 16u) | (from[2] << 8u) |
118d0b31295SJon Chesterfield            (from[3] << 0u);
119d0b31295SJon Chesterfield   }
120d0b31295SJon Chesterfield }
read_size_field_u64(const unsigned char * from)121d0b31295SJon Chesterfield uint64_t read_size_field_u64(const unsigned char *from) {
122d0b31295SJon Chesterfield   from++;
123d0b31295SJon Chesterfield   if (use_bswap) {
124d0b31295SJon Chesterfield     uint64_t b;
125d0b31295SJon Chesterfield     memcpy(&b, from, 8);
126d0b31295SJon Chesterfield     return __builtin_bswap64(b);
127d0b31295SJon Chesterfield   } else {
128d0b31295SJon Chesterfield     return ((uint64_t)from[0] << 56u) | ((uint64_t)from[1] << 48u) |
129d0b31295SJon Chesterfield            ((uint64_t)from[2] << 40u) | ((uint64_t)from[3] << 32u) |
130d0b31295SJon Chesterfield            (from[4] << 24u) | (from[5] << 16u) | (from[6] << 8u) |
131d0b31295SJon Chesterfield            (from[7] << 0u);
132d0b31295SJon Chesterfield   }
133d0b31295SJon Chesterfield }
134d0b31295SJon Chesterfield 
read_size_field_s8(const unsigned char * from)135d0b31295SJon Chesterfield uint64_t read_size_field_s8(const unsigned char *from) {
136d0b31295SJon Chesterfield   uint8_t u = read_size_field_u8(from);
137d0b31295SJon Chesterfield   int64_t res = msgpack::bitcast<uint8_t, int8_t>(u);
138d0b31295SJon Chesterfield   return msgpack::bitcast<int64_t, uint64_t>(res);
139d0b31295SJon Chesterfield }
read_size_field_s16(const unsigned char * from)140d0b31295SJon Chesterfield uint64_t read_size_field_s16(const unsigned char *from) {
141d0b31295SJon Chesterfield   uint16_t u = read_size_field_u16(from);
142d0b31295SJon Chesterfield   int64_t res = msgpack::bitcast<uint16_t, int16_t>(u);
143d0b31295SJon Chesterfield   return msgpack::bitcast<int64_t, uint64_t>(res);
144d0b31295SJon Chesterfield }
read_size_field_s32(const unsigned char * from)145d0b31295SJon Chesterfield uint64_t read_size_field_s32(const unsigned char *from) {
146d0b31295SJon Chesterfield   uint32_t u = read_size_field_u32(from);
147d0b31295SJon Chesterfield   int64_t res = msgpack::bitcast<uint32_t, int32_t>(u);
148d0b31295SJon Chesterfield   return msgpack::bitcast<int64_t, uint64_t>(res);
149d0b31295SJon Chesterfield }
read_size_field_s64(const unsigned char * from)150d0b31295SJon Chesterfield uint64_t read_size_field_s64(const unsigned char *from) {
151d0b31295SJon Chesterfield   uint64_t u = read_size_field_u64(from);
152d0b31295SJon Chesterfield   int64_t res = msgpack::bitcast<uint64_t, int64_t>(u);
153d0b31295SJon Chesterfield   return msgpack::bitcast<int64_t, uint64_t>(res);
154d0b31295SJon Chesterfield }
155d0b31295SJon Chesterfield } // namespace payload
156d0b31295SJon Chesterfield } // namespace
157d0b31295SJon Chesterfield 
158d0b31295SJon Chesterfield namespace msgpack {
159d0b31295SJon Chesterfield 
payload_info(msgpack::type ty)160d0b31295SJon Chesterfield payload_info_t payload_info(msgpack::type ty) {
161d0b31295SJon Chesterfield   using namespace msgpack;
162d0b31295SJon Chesterfield   switch (ty) {
163d0b31295SJon Chesterfield #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
164d0b31295SJon Chesterfield   case NAME:                                                                   \
165d0b31295SJon Chesterfield     return payload::PAYLOAD;
166d0b31295SJon Chesterfield #include "msgpack.def"
167d0b31295SJon Chesterfield #undef X
168d0b31295SJon Chesterfield   }
169d0b31295SJon Chesterfield   internal_error();
170d0b31295SJon Chesterfield }
171d0b31295SJon Chesterfield 
172d0b31295SJon Chesterfield } // namespace msgpack
173d0b31295SJon Chesterfield 
skip_next_message(const unsigned char * start,const unsigned char * end)174d0b31295SJon Chesterfield const unsigned char *msgpack::skip_next_message(const unsigned char *start,
175d0b31295SJon Chesterfield                                                 const unsigned char *end) {
176d0b31295SJon Chesterfield   class f : public functors_defaults<f> {};
177d0b31295SJon Chesterfield   return handle_msgpack({start, end}, f());
178d0b31295SJon Chesterfield }
179d0b31295SJon Chesterfield 
180d0b31295SJon Chesterfield namespace msgpack {
message_is_string(byte_range bytes,const char * needle)181d0b31295SJon Chesterfield bool message_is_string(byte_range bytes, const char *needle) {
182d0b31295SJon Chesterfield   bool matched = false;
183d0b31295SJon Chesterfield   size_t needleN = strlen(needle);
184d0b31295SJon Chesterfield 
185d0b31295SJon Chesterfield   foronly_string(bytes, [=, &matched](size_t N, const unsigned char *str) {
186d0b31295SJon Chesterfield     if (N == needleN) {
187d0b31295SJon Chesterfield       if (memcmp(needle, str, N) == 0) {
188d0b31295SJon Chesterfield         matched = true;
189d0b31295SJon Chesterfield       }
190d0b31295SJon Chesterfield     }
191d0b31295SJon Chesterfield   });
192d0b31295SJon Chesterfield   return matched;
193d0b31295SJon Chesterfield }
194d0b31295SJon Chesterfield 
dump(byte_range bytes)195d0b31295SJon Chesterfield void dump(byte_range bytes) {
196d0b31295SJon Chesterfield   struct inner : functors_defaults<inner> {
197d0b31295SJon Chesterfield     inner(unsigned indent) : indent(indent) {}
198d0b31295SJon Chesterfield     const unsigned by = 2;
199d0b31295SJon Chesterfield     unsigned indent = 0;
200d0b31295SJon Chesterfield 
201d0b31295SJon Chesterfield     void handle_string(size_t N, const unsigned char *bytes) {
202d0b31295SJon Chesterfield       char *tmp = (char *)malloc(N + 1);
203d0b31295SJon Chesterfield       memcpy(tmp, bytes, N);
204d0b31295SJon Chesterfield       tmp[N] = '\0';
205d0b31295SJon Chesterfield       printf("\"%s\"", tmp);
206d0b31295SJon Chesterfield       free(tmp);
207d0b31295SJon Chesterfield     }
208d0b31295SJon Chesterfield 
209d0b31295SJon Chesterfield     void handle_signed(int64_t x) { printf("%ld", x); }
210d0b31295SJon Chesterfield     void handle_unsigned(uint64_t x) { printf("%lu", x); }
211d0b31295SJon Chesterfield 
212d0b31295SJon Chesterfield     const unsigned char *handle_array(uint64_t N, byte_range bytes) {
213d0b31295SJon Chesterfield       printf("\n%*s[\n", indent, "");
214d0b31295SJon Chesterfield       indent += by;
215d0b31295SJon Chesterfield 
216d0b31295SJon Chesterfield       for (uint64_t i = 0; i < N; i++) {
217d0b31295SJon Chesterfield         indent += by;
218d0b31295SJon Chesterfield         printf("%*s", indent, "");
219d0b31295SJon Chesterfield         const unsigned char *next = handle_msgpack<inner>(bytes, {indent});
220d0b31295SJon Chesterfield         printf(",\n");
221d0b31295SJon Chesterfield         indent -= by;
222d0b31295SJon Chesterfield         bytes.start = next;
223d0b31295SJon Chesterfield         if (!next) {
224d0b31295SJon Chesterfield           break;
225d0b31295SJon Chesterfield         }
226d0b31295SJon Chesterfield       }
227d0b31295SJon Chesterfield       indent -= by;
228d0b31295SJon Chesterfield       printf("%*s]", indent, "");
229d0b31295SJon Chesterfield 
230d0b31295SJon Chesterfield       return bytes.start;
231d0b31295SJon Chesterfield     }
232d0b31295SJon Chesterfield 
233d0b31295SJon Chesterfield     const unsigned char *handle_map(uint64_t N, byte_range bytes) {
234d0b31295SJon Chesterfield       printf("\n%*s{\n", indent, "");
235d0b31295SJon Chesterfield       indent += by;
236d0b31295SJon Chesterfield 
237d0b31295SJon Chesterfield       for (uint64_t i = 0; i < 2 * N; i += 2) {
238d0b31295SJon Chesterfield         const unsigned char *start_key = bytes.start;
239d0b31295SJon Chesterfield         printf("%*s", indent, "");
240d0b31295SJon Chesterfield         const unsigned char *end_key =
241d0b31295SJon Chesterfield             handle_msgpack<inner>({start_key, bytes.end}, {indent});
242d0b31295SJon Chesterfield         if (!end_key) {
243d0b31295SJon Chesterfield           break;
244d0b31295SJon Chesterfield         }
245d0b31295SJon Chesterfield 
246d0b31295SJon Chesterfield         printf(" : ");
247d0b31295SJon Chesterfield 
248d0b31295SJon Chesterfield         const unsigned char *start_value = end_key;
249d0b31295SJon Chesterfield         const unsigned char *end_value =
250d0b31295SJon Chesterfield             handle_msgpack<inner>({start_value, bytes.end}, {indent});
251d0b31295SJon Chesterfield 
252d0b31295SJon Chesterfield         if (!end_value) {
253d0b31295SJon Chesterfield           break;
254d0b31295SJon Chesterfield         }
255d0b31295SJon Chesterfield 
256d0b31295SJon Chesterfield         printf(",\n");
257d0b31295SJon Chesterfield         bytes.start = end_value;
258d0b31295SJon Chesterfield       }
259d0b31295SJon Chesterfield 
260d0b31295SJon Chesterfield       indent -= by;
261d0b31295SJon Chesterfield       printf("%*s}", indent, "");
262d0b31295SJon Chesterfield 
263d0b31295SJon Chesterfield       return bytes.start;
264d0b31295SJon Chesterfield     }
265d0b31295SJon Chesterfield   };
266d0b31295SJon Chesterfield 
267d0b31295SJon Chesterfield   handle_msgpack<inner>(bytes, {0});
268d0b31295SJon Chesterfield   printf("\n");
269d0b31295SJon Chesterfield }
270d0b31295SJon Chesterfield 
271d0b31295SJon Chesterfield } // namespace msgpack
272