OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 /* Generate all possible instructions that a decoder can decode. | |
8 * Group the instruction stream into files for processing them in parallel. | |
9 */ | |
10 #include <assert.h> | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <sys/types.h> | |
14 #include <sys/stat.h> | |
15 #include <unistd.h> | |
16 | |
17 #include "test_dfa.h" | |
18 | |
19 | |
20 const int kInstsPerFile = 1000000; | |
21 const uint16_t kInvalidState = UINT16_MAX; | |
22 | |
23 /* The list of error codes. */ | |
24 const int kErrArgc = 1; | |
25 const int kErrCannotStat = 2; | |
26 const int kErrNotADir = 3; | |
27 const int kErrChortBuf = 4; | |
28 const int kErrOpenOutput = 5; | |
29 | |
30 static void InitStates() { | |
31 int i, t; | |
32 | |
33 for (i = 0; i < NumStates(); i++) { | |
34 for (t = 0; t < 256; t++) { | |
35 states[i].transitions[t] = kInvalidState; | |
36 } | |
37 } | |
38 } | |
39 | |
40 /* Adds an edge with a range of bytes. For use in definitions generated by the | |
41 * DFA parser. */ | |
42 void AddRange(int state_idx, | |
43 uint8_t byte_begin, | |
44 uint8_t byte_end, | |
45 uint16_t target) { | |
46 int i; | |
47 | |
48 assert(0 <= state_idx && state_idx < NumStates()); | |
49 for (i = byte_begin; i <= byte_end; i++) { | |
50 states[state_idx].transitions[i] = target; | |
51 } | |
52 } | |
53 | |
54 /* The global instruction bytes that are updated as we traverse the graph. */ | |
55 enum {kMaxInstLength = 15}; | |
56 uint8_t inst_bytes[kMaxInstLength]; | |
57 int inst_len = 0; | |
58 | |
59 static bool AllTransitionsEqual(struct state st) { | |
60 int i; | |
61 | |
62 for (i = 0; i < 256; i++) { | |
63 if (st.transitions[i] != st.transitions[0]) { | |
64 return false; | |
65 } | |
66 } | |
67 return true; | |
68 } | |
69 | |
70 enum {kMaxFileNameLength = 500}; | |
71 | |
72 struct output_state { | |
73 uint64_t insts_done; | |
74 uint32_t file_count; | |
75 FILE* asmfile; | |
76 char fname[kMaxFileNameLength]; | |
77 const char* output_dir; | |
78 }; | |
79 | |
80 static void OutputSetFilename(struct output_state *out) { | |
81 int amount; | |
82 amount = snprintf(out->fname, | |
83 kMaxFileNameLength, | |
84 "%s/_test_dfa_insts_%05d.s", | |
85 out->output_dir, | |
86 out->file_count); | |
87 if (kMaxFileNameLength <= amount || amount < 0) { | |
88 fprintf(stderr, "error: buffer too short to contain a file name\n"); | |
89 exit(kErrChortBuf); | |
90 } | |
91 } | |
92 | |
93 static void OutputOpenCurrent(struct output_state *out) { | |
94 out->asmfile = fopen(out->fname, "w"); | |
95 if (out->asmfile == NULL) { | |
96 perror("fopen"); | |
97 exit(kErrOpenOutput); | |
98 } | |
99 fprintf(out->asmfile, " .text\n"); | |
100 } | |
101 | |
102 static void OutputInit(struct output_state *out, const char* output_dir) { | |
103 out->output_dir = output_dir; | |
104 out->insts_done = 0; | |
105 out->file_count = 0; | |
106 OutputSetFilename(out); | |
107 OutputOpenCurrent(out); | |
108 } | |
109 | |
110 void OutputCloseCurrent(struct output_state *out) { | |
111 fclose(out->asmfile); | |
112 printf("%s\n", out->fname); | |
113 fflush(stdout); | |
114 } | |
115 | |
116 /* Writes one instruction to the current output file. Start the new file if the | |
117 * current one exceeds the maximum number of instructions. */ | |
118 static void OutputWriteInstruction(struct output_state *out) { | |
119 int i; | |
120 | |
121 assert(inst_len); | |
122 if ((out->insts_done != 0) && | |
123 (out->insts_done % kInstsPerFile == 0)) { | |
124 OutputCloseCurrent(out); | |
125 out->file_count++; | |
126 OutputSetFilename(out); | |
127 OutputOpenCurrent(out); | |
128 } | |
129 fprintf(out->asmfile, " .byte 0x%.2x", inst_bytes[0]); | |
130 for (i = 1; i < inst_len; i++) { | |
131 fprintf(out->asmfile, ",0x%.2x", inst_bytes[i]); | |
132 } | |
133 fprintf(out->asmfile, "\n"); | |
134 out->insts_done++; | |
135 } | |
136 | |
137 static struct output_state g_output; | |
138 | |
139 /* The main loop to traverse all possible paths from the begin state, record | |
140 * transition bytes and output the whole instruction as soon as we reach a final | |
141 * state. If we are in a multibyte field that the decoder should not care | |
142 * about, we generate 0x01, 0x23, 0x45, ... as the field bytes. */ | |
143 static void TraverseStates(uint16_t entry, bool in_anyfield) { | |
144 int i; | |
145 uint8_t prev_byte; | |
146 struct state st = states[entry]; | |
147 uint16_t st2; | |
148 | |
149 if (st.is_final) { | |
150 OutputWriteInstruction(&g_output); | |
151 /* Some final states have outgoing transitions, so we have to continue | |
152 iterating through them. */ | |
153 } | |
154 if (!in_anyfield) { | |
155 if (st.anyfield_begin) { | |
156 /* We are in the state that starts anyfield. If it is a one-byte field, | |
157 then recursive call is not anyfield. */ | |
158 inst_bytes[inst_len++] = 0x01; | |
159 if (st.anyfield_end) { | |
160 TraverseStates(st.transitions[0], false); | |
161 } else { | |
162 TraverseStates(st.transitions[0], true); | |
163 } | |
164 inst_len--; | |
165 } else { | |
166 /* Traverse all available transitions in the node. */ | |
167 for (i = 0; i < 256; i++) { | |
168 st2 = st.transitions[i]; | |
169 if (st2 != kInvalidState) { | |
170 assert(st2 < NumStates()); | |
171 inst_bytes[inst_len++] = i; | |
172 TraverseStates(st2, false); | |
173 inst_len--; | |
174 } | |
175 } | |
176 } | |
177 } else { | |
178 /* Continue anyfield traversal. */ | |
179 assert(AllTransitionsEqual(st)); | |
180 prev_byte = inst_bytes[inst_len - 1]; | |
181 inst_bytes[inst_len++] = prev_byte + 0x22; | |
182 if (st.anyfield_end) { | |
183 TraverseStates(st.transitions[0], false); | |
184 } else { | |
185 TraverseStates(st.transitions[0], true); | |
186 } | |
187 inst_len--; | |
188 } | |
189 } | |
190 | |
191 int main(int argc, char* argv[]) { | |
192 struct stat st; | |
193 char* output_dir; | |
194 | |
195 if (argc != 2) { | |
196 fprintf(stderr, "usage: %s outdir\n", argv[0]); | |
197 return kErrArgc; | |
198 } | |
199 output_dir = argv[1]; | |
200 if (stat(output_dir, &st) == -1) { | |
201 fprintf(stderr, "error: could not stat %s\n", output_dir); | |
202 return kErrCannotStat; | |
203 } | |
204 if (!S_ISDIR(st.st_mode)) { | |
205 fprintf(stderr, "error: not a directory: %s\n", output_dir); | |
206 return kErrNotADir; | |
207 } | |
208 | |
209 InitStates(); | |
210 InitTransitions(); | |
211 OutputInit(&g_output, output_dir); | |
212 TraverseStates(start_state, false); | |
213 OutputCloseCurrent(&g_output); | |
214 return 0; | |
215 } | |
OLD | NEW |