blob: 03e115b9c08855127d42ef3903f8a1a267850748 [file] [log] [blame]
Dan Bornsteind12de172010-12-02 15:21:59 -08001# Copyright (C) 2007 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Dan Bornstein973171b2010-12-03 13:01:06 -080015#
Dan Bornsteind12de172010-12-02 15:21:59 -080016# Awk helper script for opcode-gen.
Dan Bornstein973171b2010-12-03 13:01:06 -080017#
18
19#
20# Initialization.
21#
Dan Bornsteind12de172010-12-02 15:21:59 -080022
23BEGIN {
24 MAX_OPCODE = 65535;
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -080025 MAX_PACKED_OPCODE = 511;
Elliott Hughesab35b502012-01-04 15:38:58 -080026 MAX_PACKED_OPCODE = 255; # TODO: Not for long!
Dan Bornsteind12de172010-12-02 15:21:59 -080027 initIndexTypes();
28 initFlags();
29 if (readBytecodes()) exit 1;
30 deriveOpcodeChains();
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -080031 createPackedTables();
Dan Bornsteind12de172010-12-02 15:21:59 -080032 consumeUntil = "";
Dan Bornstein973171b2010-12-03 13:01:06 -080033 emission = "";
Dan Bornsteind12de172010-12-02 15:21:59 -080034}
35
Dan Bornstein973171b2010-12-03 13:01:06 -080036#
37# General control (must appear above directive handlers).
38#
39
40# Clear out the preexisting output within a directive section.
Dan Bornsteind12de172010-12-02 15:21:59 -080041consumeUntil != "" {
42 if (index($0, consumeUntil) != 0) {
43 consumeUntil = "";
Dan Bornstein973171b2010-12-03 13:01:06 -080044 print;
Dan Bornsteind12de172010-12-02 15:21:59 -080045 }
Dan Bornstein973171b2010-12-03 13:01:06 -080046
47 next;
Dan Bornsteind12de172010-12-02 15:21:59 -080048}
49
Dan Bornstein973171b2010-12-03 13:01:06 -080050# Detect directives.
Dan Bornsteina277f142010-12-03 15:11:55 -080051/BEGIN\([a-z-]*\)/ {
52 i = match($0, /BEGIN\([a-z-]*\)/);
Dan Bornstein973171b2010-12-03 13:01:06 -080053 emission = substr($0, i + 6, RLENGTH - 7);
54 consumeUntil = "END(" emission ")";
55 emissionHandled = 0;
Dan Bornstein9dc57d32010-12-03 17:58:01 -080056}
57
58# Most lines just get copied from the source as-is, including the start
59# comment for directives.
60{
Dan Bornsteind12de172010-12-02 15:21:59 -080061 print;
Dan Bornstein973171b2010-12-03 13:01:06 -080062}
63
64#
65# Handlers for all of the directives.
66#
67
68emission == "opcodes" {
69 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -080070
71 for (i = 0; i <= MAX_OPCODE; i++) {
72 if (isUnused(i) || isOptimized(i)) continue;
73 printf(" public static final int %s = 0x%s;\n",
74 constName[i], hex[i]);
75 }
Dan Bornsteind12de172010-12-02 15:21:59 -080076}
77
Dan Bornstein973171b2010-12-03 13:01:06 -080078emission == "first-opcodes" {
79 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -080080
81 for (i = 0; i <= MAX_OPCODE; i++) {
82 if (isUnused(i) || isOptimized(i)) continue;
83 if (isFirst[i] == "true") {
Dan Bornstein7ba91292011-01-30 14:05:39 -080084 printf(" // Opcodes.%s\n", constName[i]);
Dan Bornsteind12de172010-12-02 15:21:59 -080085 }
86 }
Dan Bornsteind12de172010-12-02 15:21:59 -080087}
88
Dan Bornstein973171b2010-12-03 13:01:06 -080089emission == "dops" {
90 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -080091
92 for (i = 0; i <= MAX_OPCODE; i++) {
93 if (isUnused(i) || isOptimized(i)) continue;
94
95 nextOp = nextOpcode[i];
96 nextOp = (nextOp == -1) ? "NO_NEXT" : constName[nextOp];
97
98 printf(" public static final Dop %s =\n" \
Dan Bornstein7ba91292011-01-30 14:05:39 -080099 " new Dop(Opcodes.%s, Opcodes.%s,\n" \
Dan Bornsteina754fbb2011-02-02 11:45:53 -0800100 " Opcodes.%s, Form%s.THE_ONE, %s);\n\n",
Dan Bornsteind12de172010-12-02 15:21:59 -0800101 constName[i], constName[i], family[i], nextOp, format[i],
Dan Bornsteina754fbb2011-02-02 11:45:53 -0800102 hasResult[i]);
Dan Bornsteind12de172010-12-02 15:21:59 -0800103 }
Dan Bornsteind12de172010-12-02 15:21:59 -0800104}
105
Dan Bornstein3c5df372011-01-25 16:39:12 -0800106emission == "opcode-info-defs" {
107 emissionHandled = 1;
108
109 for (i = 0; i <= MAX_OPCODE; i++) {
110 if (isUnused(i) || isOptimized(i)) continue;
111
Dan Bornsteinf67b6af2011-02-02 14:01:52 -0800112 itype = toupper(indexType[i]);
113 gsub(/-/, "_", itype);
Dan Bornstein3c5df372011-01-25 16:39:12 -0800114
115 printf(" public static final Info %s =\n" \
Dan Bornsteina754fbb2011-02-02 11:45:53 -0800116 " new Info(Opcodes.%s, \"%s\",\n" \
Dan Bornsteinf67b6af2011-02-02 14:01:52 -0800117 " InstructionCodec.FORMAT_%s, IndexType.%s);\n\n", \
Dan Bornsteina754fbb2011-02-02 11:45:53 -0800118 constName[i], constName[i], name[i], toupper(format[i]), itype);
Dan Bornstein3c5df372011-01-25 16:39:12 -0800119 }
120}
121
122emission == "dops-init" || emission == "opcode-info-init" {
Dan Bornstein973171b2010-12-03 13:01:06 -0800123 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -0800124
125 for (i = 0; i <= MAX_OPCODE; i++) {
126 if (isUnused(i) || isOptimized(i)) continue;
127 printf(" set(%s);\n", constName[i]);
128 }
Dan Bornsteind12de172010-12-02 15:21:59 -0800129}
130
Dan Bornstein973171b2010-12-03 13:01:06 -0800131emission == "libcore-opcodes" {
132 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -0800133
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800134 for (i = 0; i <= MAX_OPCODE; i++) {
135 if (isUnused(i) || isOptimized(i)) continue;
Dan Bornstein21f322d2010-12-03 13:16:08 -0800136 printf(" int OP_%-28s = 0x%04x;\n", constName[i], i);
Dan Bornsteind12de172010-12-02 15:21:59 -0800137 }
Dan Bornsteind12de172010-12-02 15:21:59 -0800138}
139
Dan Bornstein973171b2010-12-03 13:01:06 -0800140emission == "libcore-maximum-values" {
141 emissionHandled = 1;
Dan Bornsteind12de172010-12-02 15:21:59 -0800142
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800143 printf(" MAXIMUM_VALUE = %d;\n", MAX_OPCODE);
144 printf(" MAXIMUM_PACKED_VALUE = %d;\n", MAX_PACKED_OPCODE);
Dan Bornsteind12de172010-12-02 15:21:59 -0800145}
146
Dan Bornstein9dc57d32010-12-03 17:58:01 -0800147# Handle the end of directive processing (must appear after the directive
148# clauses).
Dan Bornstein973171b2010-12-03 13:01:06 -0800149emission != "" {
150 if (!emissionHandled) {
151 printf("WARNING: unknown tag \"%s\"\n", emission) >"/dev/stderr";
152 consumeUntil = "";
153 }
154
155 emission = "";
Dan Bornsteind12de172010-12-02 15:21:59 -0800156}
157
Dan Bornstein973171b2010-12-03 13:01:06 -0800158#
159# Helper functions.
160#
161
Dan Bornsteind12de172010-12-02 15:21:59 -0800162# Helper to print out an element in a multi-column fashion. It returns
163# the (one-based) column number that the next element will be printed
164# in.
165function colPrint(value, isLast, col, numCols, colWidth, linePrefix) {
166 isLast = (isLast || (col == numCols));
167 printf("%s%-*s%s",
168 (col == 1) ? linePrefix : " ",
169 isLast ? 1 : colWidth, value,
170 isLast ? "\n" : "");
171
172 return (col % numCols) + 1;
173}
174
175# Read the bytecode description file.
176function readBytecodes(i, parts, line, cmd, status, count) {
177 # locals: parts, line, cmd, status, count
178 for (;;) {
179 # Read a line.
180 status = getline line <bytecodeFile;
181 if (status == 0) break;
182 if (status < 0) {
183 print "trouble reading bytecode file";
184 exit 1;
185 }
186
187 # Clean up the line and extract the command.
188 gsub(/ */, " ", line);
189 sub(/ *#.*$/, "", line);
190 sub(/ $/, "", line);
191 sub(/^ /, "", line);
192 count = split(line, parts);
193 if (count == 0) continue; # Blank or comment line.
194 cmd = parts[1];
195 sub(/^[a-z][a-z]* */, "", line); # Remove the command from line.
196
197 if (cmd == "op") {
198 status = defineOpcode(line);
199 } else if (cmd == "format") {
200 status = defineFormat(line);
201 } else {
202 status = -1;
203 }
204
205 if (status != 0) {
Dan Bornstein973171b2010-12-03 13:01:06 -0800206 printf("syntax error on line: %s\n", line) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800207 return 1;
208 }
209 }
210
211 return 0;
212}
213
214# Define an opcode.
215function defineOpcode(line, count, parts, idx) {
216 # locals: count, parts, idx
217 count = split(line, parts);
218 if (count != 6) return -1;
219 idx = parseHex(parts[1]);
220 if (idx < 0) return -1;
221
222 # Extract directly specified values from the line.
223 hex[idx] = parts[1];
224 name[idx] = parts[2];
225 format[idx] = parts[3];
226 hasResult[idx] = (parts[4] == "n") ? "false" : "true";
227 indexType[idx] = parts[5];
228 flags[idx] = parts[6];
229
230 # Calculate derived values.
231
232 constName[idx] = toupper(name[idx]);
Dan Bornstein9dc57d32010-12-03 17:58:01 -0800233 gsub("[/-]", "_", constName[idx]); # Dash and slash become underscore.
Dan Bornsteind12de172010-12-02 15:21:59 -0800234 gsub("[+^]", "", constName[idx]); # Plus and caret are removed.
235 split(name[idx], parts, "/");
236
237 family[idx] = toupper(parts[1]);
238 gsub("-", "_", family[idx]); # Dash becomes underscore.
239 gsub("[+^]", "", family[idx]); # Plus and caret are removed.
240
241 split(format[idx], parts, ""); # Width is the first format char.
242 width[idx] = parts[1];
243
244 # This association is used when computing "next" opcodes.
245 familyFormat[family[idx],format[idx]] = idx;
246
247 # Verify values.
248
249 if (nextFormat[format[idx]] == "") {
Dan Bornstein973171b2010-12-03 13:01:06 -0800250 printf("unknown format: %s\n", format[idx]) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800251 return 1;
252 }
253
254 if (indexTypeValues[indexType[idx]] == "") {
Dan Bornstein973171b2010-12-03 13:01:06 -0800255 printf("unknown index type: %s\n", indexType[idx]) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800256 return 1;
257 }
258
259 if (flagsToC(flags[idx]) == "") {
Dan Bornstein973171b2010-12-03 13:01:06 -0800260 printf("bogus flags: %s\n", flags[idx]) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800261 return 1;
262 }
263
264 return 0;
265}
266
267# Define a format family.
268function defineFormat(line, count, parts, i) {
269 # locals: count, parts, i
270 count = split(line, parts);
271 if (count < 1) return -1;
272 formats[parts[1]] = line;
273
274 parts[count + 1] = "none";
275 for (i = 1; i <= count; i++) {
276 nextFormat[parts[i]] = parts[i + 1];
277 }
278
279 return 0;
280}
281
282# Produce the nextOpcode and isFirst arrays. The former indicates, for
283# each opcode, which one should be tried next when doing instruction
284# fitting. The latter indicates which opcodes are at the head of an
285# instruction fitting chain.
286function deriveOpcodeChains(i, op) {
287 # locals: i, op
288
289 for (i = 0; i <= MAX_OPCODE; i++) {
290 if (isUnused(i)) continue;
291 isFirst[i] = "true";
292 }
293
294 for (i = 0; i <= MAX_OPCODE; i++) {
295 if (isUnused(i)) continue;
296 op = findNextOpcode(i);
297 nextOpcode[i] = op;
298 if (op != -1) {
299 isFirst[op] = "false";
300 }
301 }
302}
303
304# Given an opcode by index, find the next opcode in the same family
305# (that is, with the same base name) to try when matching instructions
306# to opcodes. This simply walks the nextFormat chain looking for a
307# match. This returns the index of the matching opcode or -1 if there
308# is none.
309function findNextOpcode(idx, fam, fmt, result) {
310 # locals: fam, fmt, result
311 fam = family[idx];
312 fmt = format[idx];
313
314 # Not every opcode has a version with every possible format, so
315 # we have to iterate down the chain until we find one or run out of
316 # formats to try.
317 for (fmt = nextFormat[format[idx]]; fmt != "none"; fmt = nextFormat[fmt]) {
318 result = familyFormat[fam,fmt];
319 if (result != "") {
320 return result;
321 }
322 }
323
324 return -1;
325}
326
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800327# Construct the tables of info indexed by packed opcode. The packed opcode
328# values are in the range 0-0x1ff, whereas the unpacked opcodes sparsely
329# span the range 0-0xffff.
330function createPackedTables(i, op) {
331 # locals: i, op
332 for (i = 0; i <= MAX_PACKED_OPCODE; i++) {
333 op = unpackOpcode(i);
Elliott Hughesab35b502012-01-04 15:38:58 -0800334 if (isUnused(op)) {
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800335 packedName[i] = unusedName(op);
336 packedConstName[i] = unusedConstName(op);
337 packedFormat[i] = "00x";
338 packedFlags[i] = 0;
339 packedWidth[i] = 0;
340 packedIndexType[i] = "unknown";
341 } else {
342 packedName[i] = name[op];
343 packedConstName[i] = constName[op];
344 packedFormat[i] = format[op];
345 packedFlags[i] = flags[op];
346 packedWidth[i] = width[op];
347 packedIndexType[i] = indexType[op];
348 }
349 }
350}
351
352# Given a packed opcode, returns the raw (unpacked) opcode value.
353function unpackOpcode(idx) {
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800354 if (idx <= 255) {
355 return idx;
356 } else {
Dan Bornstein21f322d2010-12-03 13:16:08 -0800357 idx -= 256;
Dan Bornstein3c4dc3b2010-12-02 16:05:51 -0800358 return (idx * 256) + 255;
359 }
360}
361
362# Returns the "unused" name of the given opcode (by index).
363# That is, this is the human-oriented name to use for an opcode
364# definition in cases
365# where the opcode isn't used.
366function unusedName(idx) {
367 if (idx <= 255) {
368 return sprintf("unused-%02x", idx);
369 } else {
370 return sprintf("unused-%04x", idx);
371 }
372}
373
374# Returns the "unused" constant name of the given opcode (by index).
375# That is, this is the name to use for a constant definition in cases
376# where the opcode isn't used.
377function unusedConstName(idx) {
378 if (idx <= 255) {
379 return toupper(sprintf("UNUSED_%02x", idx));
380 } else {
381 return toupper(sprintf("UNUSED_%04x", idx));
382 }
383}
384
Dan Bornsteind12de172010-12-02 15:21:59 -0800385# Convert a hex value to an int.
386function parseHex(hex, result, chars, count, c, i) {
387 # locals: result, chars, count, c, i
388 hex = tolower(hex);
389 count = split(hex, chars, "");
390 result = 0;
391 for (i = 1; i <= count; i++) {
392 c = index("0123456789abcdef", chars[i]);
393 if (c == 0) {
Dan Bornstein973171b2010-12-03 13:01:06 -0800394 printf("bogus hex value: %s\n", hex) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800395 return -1;
396 }
397 result = (result * 16) + c - 1;
398 }
399 return result;
400}
401
402# Initialize the indexTypes data.
403function initIndexTypes() {
404 indexTypeValues["unknown"] = "kIndexUnknown";
405 indexTypeValues["none"] = "kIndexNone";
406 indexTypeValues["varies"] = "kIndexVaries";
407 indexTypeValues["type-ref"] = "kIndexTypeRef";
408 indexTypeValues["string-ref"] = "kIndexStringRef";
409 indexTypeValues["method-ref"] = "kIndexMethodRef";
410 indexTypeValues["field-ref"] = "kIndexFieldRef";
411 indexTypeValues["inline-method"] = "kIndexInlineMethod";
412 indexTypeValues["vtable-offset"] = "kIndexVtableOffset";
413 indexTypeValues["field-offset"] = "kIndexFieldOffset";
414}
415
416# Initialize the flags data.
417function initFlags() {
418 flagValues["branch"] = "kInstrCanBranch";
419 flagValues["continue"] = "kInstrCanContinue";
420 flagValues["switch"] = "kInstrCanSwitch";
421 flagValues["throw"] = "kInstrCanThrow";
422 flagValues["return"] = "kInstrCanReturn";
423 flagValues["invoke"] = "kInstrInvoke";
424 flagValues["optimized"] = "0"; # Not represented in C output
425 flagValues["0"] = "0";
426}
427
428# Translate the given flags into the equivalent C expression. Returns
429# "" on error.
430function flagsToC(f, parts, result, i) {
431 # locals: parts, result, i
432 count = split(f, parts, /\|/); # Split input at pipe characters.
433 result = "0";
434
435 for (i = 1; i <= count; i++) {
436 f = flagValues[parts[i]];
437 if (f == "") {
Dan Bornstein973171b2010-12-03 13:01:06 -0800438 printf("bogus flag: %s\n", f) >"/dev/stderr";
Dan Bornsteind12de172010-12-02 15:21:59 -0800439 return ""; # Bogus flag name.
440 } else if (f == "0") {
441 # Nothing to append for this case.
442 } else if (result == "0") {
443 result = f;
444 } else {
445 result = result "|" f;
446 }
447 }
448
449 return result;
450}
451
Dan Bornsteind12de172010-12-02 15:21:59 -0800452# Returns true if the given opcode (by index) is an "optimized" opcode.
453function isOptimized(idx, parts, f) {
454 # locals: parts, f
455 split(flags[idx], parts, /\|/); # Split flags[idx] at pipes.
456 for (f in parts) {
457 if (parts[f] == "optimized") return 1;
458 }
459 return 0;
460}
461
462# Returns true if there is no definition for the given opcode (by index).
463function isUnused(idx) {
464 return (name[idx] == "");
465}