#!/bin/sh # APPLE LOCAL file AltiVec # ops-to-gp -gcc vec.ops builtin.ops # Creates vec.h used by rs6000.c arg0=`basename $0` err() { echo "$arg0: $*" 1>&2 exit 2 } if [ $# -eq 0 ] ; then echo "Usage: $arg0 [ -mcc | -gcc ] builtin-ops ..." 1>&2 exit 1 fi MCC=1 GCC=0 suffix="gp" if [ "$1" = "-mcc" ] ; then shift; elif [ "$1" = "-gcc" ] ; then GCC=1 MCC=0 suffix="h" shift; fi output=`basename $1 .ops` gperf="gperf -G -a -o -k1-15 -p -t -D -T -N Is_Builtin_Function $output.gp"; # Lines in the ops file have the form # @ @ betype betype-code type-spelling # @ fetype betype [code] # @ @ @ instruction type # generic op1 op2 ... opn = result specific when configure [addressible # [instruction [const_ptr_ok [volatile_ptr_ok [transform [predicate]]]]]] # Sort the ops file to put it in a canonical order. sort -u $* | \ # Add specific function uid's, make generic functions from specific # functions, validate the types used, compute default parameters, and # compute parts of the default transform and predicate functions. awk 'BEGIN { i = 0 EQ = i++ RESULT = i++ SPECIFIC = i++ WHEN = i++ CONFIGURED = i++ ADDRESSIBLE = i++ INSTRUCTION = i++ CONST_PTR_OK = i++ VOLATILE_PTR_OK = i++ TRANSFORM = i++ PREDICATE = i++ n_lines = 1; tree[3] = "Make_Folded_4tree"; tree[2] = "Make_Folded_3tree"; tree[1] = "Make_Folded_Btree"; tree[0] = "Make_Utree"; optimize["vec_sub"] = 1; optimize["vec_subs"] = 1; optimize["vec_xor"] = 1; optimize["vec_andc"] = 1; optimize["vec_avg"] = 2; optimize["vec_or"] = 2; optimize["vec_and"] = 2; optimize["vec_max"] = 2; optimize["vec_min"] = 2; optimize["vec_sld"] = 3; optimize["vec_splat_s8"] = 4; optimize["vec_splat_s16"] = 5; optimize["vec_splat_s32"] = 6; optimize["vec_splat_u8"] = 4; optimize["vec_splat_u16"] = 5; optimize["vec_splat_u32"] = 6; optimize["vec_cmpeq"] = 7; optimize["vec_lvsl"] = 8; optimize["vec_lvsr"] = 9; # These operations need additional transformation. Key off the # optimize attribute to identify them. optimize["vec_cmplt"] = 10; optimize["vec_cmple"] = 10; optimize["vec_abs"] = 11; optimize["vec_abss"] = 11; } function no_type(t) { printf "%% Error: type %s not declared.\n", t; status = 1; exit; } # Record the type. $1 == "@" { if ($2 == "@") { if ($3 == "@") { # Definition of an instruction. insn_type[$4] = $5; # type } else { # Definition of a betype. becode[$3] = $4; # betype-code bespell[$3] = $5; # type-spelling gsub(/\=/, " ", bespell[$3]); } } else { # Definition of a fetype. print $0; if (!becode[$3]) no_type($3); # Must have defined the betype. betype[$2] = $3; # betype; if (NF == 3) code[$2] = ""; else code[$2] = $4; # code } } function no_equal(i,l) { printf "%% Syntax error %d: %s\n", i, l; status = 1; exit; } function error(f,a) { printf( ("%% error: " f), a); status = 1; exit; } # Ignore comment lines. $1 != "#" && $1 != "@" { # Generate the signature of the specific function, the predicate, # the transform, the arguments to the transform function, the # arguments to the predicate function, and the spelling of the # function type. signature = ""; predicate = ""; transform = ""; insn_code = ""; transform_args = ""; predicate_args = ""; function_type = ""; # First, consider the parameter types. for (i = 2; $i != "=" && i < NF; i++) { if ($i != "...") { if (!betype[$i]) no_type($i); signature = (signature " " $i); predicate = (predicate "_" betype[$i]); transform = (transform code[$i]); transform_args = (transform_args ", ND_kid(t," i-1 ")"); predicate_args = (predicate_args " " becode[betype[$i]]); if (function_type) function_type = (function_type ", " bespell[betype[$i]]); else function_type = bespell[betype[$i]]; } } constraints = (transform "@"); # Check the syntax of the ops file. if ($i != "=" || NF > i+PREDICATE || NF < i+CONFIGURE) no_equal(i,$0); if (!betype[$(i+RESULT)]) no_type($(i+RESULT)); # Incorporate the result type. if (i == 2) { predicate = "_void"; function_type = "void"; } signature = ($(i+SPECIFIC) signature); predicate = sprintf("is_%s_func%s", betype[$(i+RESULT)], predicate); predicate_args = (becode[betype[$(i+RESULT)]] predicate_args); function_type = sprintf("(%s (*)(%s))", bespell[betype[$(i+RESULT)]], \ function_type); if (substr(code[$(i+RESULT)], 1, 1) == "j") { # Handle a jump asm. The code is expedted to be # j={cc-bit-num}={cc-bit-value}[={r|d}]. The operation must have # one operand if the code d is used and two operands otherwise. # The transform function can implement the r code by reversing the # two operands. In all cases, the first operand is a computed # constant encoding both the bit number and the test. n = split(code[$(i+RESULT)], jmp, "="); if (jmp[n] == "d" && i != 3) error("%d operands", i-2); if (jmp[n] != "d" && i != 4) error("%d operands", i-2); if (jmp[n] == "r") transform_args = ", ND_kid(t,2), ND_kid(t,1)"; transform_args = sprintf("%s(OP_VCMP%s%s", tree[i-2], \ toupper(jmp[3]), transform_args); if (jmp[n] == "r") transform = ("r" transform); insn_code = sprintf("CODE_FOR_j_%d_%s_f%s", jmp[2], jmp[3], \ transform); transform = sprintf("transform_j_%d_%s_f%s", jmp[2], jmp[3], \ transform); } else { transform_args = sprintf("%s(OP_%sASM%s%s", tree[i-2], \ toupper(code[$(i+RESULT)]), \ toupper(transform), transform_args); insn_code = sprintf("CODE_FOR_%sf%s", code[$(i+RESULT)], transform); transform = sprintf("transform_%sf%s", code[$(i+RESULT)], transform); } # Give a unique id to the signature if (count[signature] == 0) count[signature] = ++uid[$(i+SPECIFIC)]; # Compute the default instruction name nf = split($(i+SPECIFIC), part, "_"); instruction = ("MOP_" part[nf]); # Compute the insn_code, but use the instruction override if given. if (NF >= i+INSTRUCTION) instruction = $(i+INSTRUCTION); if (insn_type[instruction]) insn_code = (insn_code "_" insn_type[instruction]); # Allow the user to override the addressibility, instruction, # const_ptr_ok, volatile_ptr_ok, transform, and predicate. if (NF >= i+ADDRESSIBLE) addressible = ""; else addressible = "FALSE"; if (NF >= i+INSTRUCTION) instruction = ""; else if (substr($1, 1, 4) == "vec_") print "@ @3", instruction; if (NF >= i+CONST_PTR_OK) const_ptr_ok = ""; else const_ptr_ok = "FALSE"; if (NF >= i+VOLATILE_PTR_OK) volatile_ptr_ok = ""; else volatile_ptr_ok = "FALSE"; if (NF >= i+TRANSFORM) transform = ""; else print "@ @1", transform, transform_args; if (NF >= i+PREDICATE) predicate = ""; else print "@ @2", i-2, predicate, predicate_args, function_type; if (optimize[$1]) optimize_method = optimize[$1]; else optimize_method = "0"; # Record the line, addressibility, instruction, transform, # predicate, and unique id. line[n_lines++] = ($0 " " addressible " " instruction " " \ const_ptr_ok " " volatile_ptr_ok " " transform " " \ predicate " " insn_code " " constraints " " \ optimize_method " " count[signature]); } END { if (status) exit; # generic op1 op2 ... opn = result specific when configured # addressable instruction const_ptr_ok volatile_ptr_ok # transform predicate insn_code constraints optimize uid SPECIFIC = 12 for (i = 1; i < n_lines; i++) { nf = split(line[i], part); specific = part[nf-SPECIFIC]; # Print the generic form. printf "%s", part[1]; for (j = 2; j <= nf-SPECIFIC; j++) printf " %s", part[j]; if (uid[specific] > 1) printf ":%d", part[nf]; while (j < nf) printf " %s", part[j++]; printf "\n"; # Print the specific form. printf "%s", specific; for (j = 2; j <= nf-SPECIFIC; j++) printf " %s", part[j]; if (uid[specific] > 1) printf ":%d", part[nf]; while (j < nf) printf " %s", part[j++]; printf "\n"; } }' | \ # Strip out load and store qualifiers. sed -e 's/_load_op//g' -e 's/_store_op//g' | \ # Sort the processed file and eliminate duplicates. sort -u | \ # Append the count of each generic function to each line. awk 'function push() { if (num) for (i = 0; i < num; i++) print line[i], num; num = 0; } $1 == "@" { print $0; } $1 != "@" { if (last != $1) push(); last = $1; line[num++] = $0; } END { push(); }' | \ # Now compute the gperf input file. # Lines now have a fixed format # generic op1 ... opn = result specific instruction when configured # addressible const_ptr_ok volatile_ptr_ok transform predicate # insn_code constraints optimize count awk 'BEGIN { MCC = '$MCC' GCC = '$GCC' i = 0; COUNT = i++ OPTIMIZE = i++ CONSTRAINTS = i++ INSN_CODE = i++ PREDICATE = i++ TRANSFORM = i++ VOLATILE_PTR_OK = i++ CONST_PTR_OK = i++ INSTRUCTION = i++ ADDRESSIBLE = i++ CONFIGURED = i++ WHEN = i++ SPECIFIC = i++ RESULT = i++ EQ = i++ OPN = i++ NARGS = i++ if (MCC) { print "%{"; print "/* Command-line: '"$gperf"' */"; MAXARGS = 5 } if (GCC) MAXARGS = 3 } function write_test(tree, type, num) { if (type == "PTR") { printf "\n && TY_kind(%s) == KIND_POINTER", tree; } else if (type == "I5") { printf "\n && is_integer_type(%s)", tree; printf "\n && Is_Const(ND_kid0(ND_kid(t,%d)), &tc)", num; printf "\n && ((UINT32)Targ_To_Host(tc) + 16) < 32"; } else if (type == "U5") { printf "\n && is_integer_type(%s)", tree; printf "\n && Is_Const(ND_kid0(ND_kid(t,%d)), &tc)", num; printf "\n && (UINT32)Targ_To_Host(tc) < 32"; } else if (type == "U4") { printf "\n && is_integer_type(%s)", tree; printf "\n && Is_Const(ND_kid0(ND_kid(t,%d)), &tc)", num; printf "\n && (UINT32)Targ_To_Host(tc) < 16"; } else if (type == "U2") { printf "\n && is_integer_type(%s)", tree; printf "\n && Is_Const(ND_kid0(ND_kid(t,%d)), &tc)", num; printf "\n && (UINT32)Targ_To_Host(tc) < 4"; } else if (type == "BETYPE_U4" || type == "BETYPE_I4") { printf "\n && is_integer_type(%s)", tree; } else { printf "\n && Similar_Types(%s,", tree; printf "\n\t\t Be_Type_Tbl(%s), IGNORE_QUALIFIERS)", type; } } $1 == "@" { if (MCC) { if ($2 == "@1") { # Write the predicate function from the given parameters. # The format is: # @ @1 transform_ifii Make_3tree(OP_IASMII, ND_kid(t,1), ND_kid(t,2) print ""; print "/*ARGSUSED*/"; print "static void"; print $3 "(ND *func, ND *parent, ND *t, struct builtin *self)"; print "{"; printf " *t = *%s", $4; for (i = 5; i <= NF; i++) printf " %s", $i; print ","; if (split($3,jmp,"_") == 5 && jmp[2] == "j") printf "\t\t MK_I4CONST_ND((self->data << 5) + %d));\n", \ jmp[3]; else print "\t\t MK_I4CONST_ND(self->data));"; print " Is_True(self->data > 0, (\"No implementation for %s\", self->name));"; print "}"; } else if ($2 == "@2") { # Write the transform function from the given parameters. # The format is: # @ @2 2 is_int_func_int_int BETYPE_I4 BETYPE_I4 BETYPE_I4 # (int (*)(int, int)) print ""; print "/*ARGSUSED*/"; print "static BOOL"; print $4 "(ND *func, ND *parent, ND *t, struct builtin *self)"; print "{"; print " TCON tc;"; printf " if (ND_nkids(t) == %d", $3+1; write_test("ST_type(ND_dec(func))", $5, ""); for (i = 1; i <= $3; i++) { printf "\n && ND_name(ND_kid(t,%d)) == TO_VAL", i; write_test(sprintf("The_Tree_Type(ND_kid(t,%d))", i), $(i+5), i); } print ")"; print " return TRUE;"; print " Error_Prt_Line (ND_linenum(t), ec_builtin_function_type, self->name,"; i = $3+6; printf "\t\t \"%s", $i; while (++i <= NF) printf " %s", $i; print "\");"; print " return FALSE;"; print "}"; } else if ($2 == "@3") { if (once++ == 0) printf "\n#ifndef HAVE_ALTIVEC\n"; printf "#define %s -1\n", $3; } else { if (once && twice++ == 0) printf "#endif /* HAVE_ALTIVEC */\n\n"; printf "extern struct a_type *T_%s;\n", $2; } } next; } $1 == "%" { print $0; status = 1; exit; } { # Compute the signature of the generic function. signature=$1; for (i = 2; i <= NF-OPN; i++) { if ($i != "...") signature=(signature " " $i); } # Ensure that the signature is unique. if (signature_line[signature]) { print "Ambiguous signatures:"; print $0; print line[signature_line[signature]]; } signature_line[signature] = n_lines; # Require that overloaded functions have the same attributes: # number of arguments, when, configured, and addressible. if (same_arg_count[$1] && same_arg_count[$1] != NF) printf "%% number of arguments for %s varies: %d and %d\n", \ $1, NF-NARGS, same_arg_count[$1]-NARGS; same_arg_count[$1] = NF; if (same_when[$1] && same_when[$1] != $(NF-WHEN)) printf "%% when for %s varies: %s and %s\n", \ $1, $(NF-WHEN), same_when[$1]; same_when[$1] = $(NF-WHEN); if (same_configured[$1] && same_configured[$1] != $(NF-CONFIGURED)) printf "%% configured for %s varies: %s and %s\n", \ $1, $(NF-CONFIGURED), same_configured[$1]; same_configured[$1] = $(NF-CONFIGURED); if (same_addressible[$1] && same_addressible[$1] != $(NF-ADDRESSIBLE)) printf "%% addressible for %s varies: %s and %s\n", \ $1, $(NF-ADDRESSIBLE), same_addressible[$1]; else if (same_addressible[$1] && same_addressible[$1] != "FALSE") printf "%% Overloaded function %s is addressible\n", $1 same_addressible[$1] = $(NF-ADDRESSIBLE); # Record the line. line[n_lines++] = $0; } function push(fcn, n) { if (last) printf "};\n"; # Gcc3: declare as arrays of const pointers if (fcn) printf "static const struct builtin *const O_%s[%d] = {\n", fcn, n; last = fcn; } function mangle(name) { if (split(name, names, ":") == 1) return ("B_" names[1]); return ("B" names[2] "_" names[1]); } END { if (status) exit; # Gcc3: Mark file as Apple local printf "/* APPLE LOCAL file AltiVec */\n"; printf "/* This file is generated by ops-to-gp. Do not edit. */\n\n"; printf "/* To regenerate execute:\n"; printf " ops-to-gp -gcc vec.ops builtin.ops\n"; printf " with the current directory being gcc/config/rs6000. */\n\n"; # Output the description of each specific function. uid = 0; if (MCC) print ""; for (i = 0; i < n_lines; i++) { nf = split(line[i], part); fcn = part[nf-SPECIFIC]; if (!done[fcn]) { printf "static const struct builtin %s = {", mangle(fcn); if (GCC) printf " {"; ellipsis = 1; for (j = 2; j <= nf-OPN; j++) if (part[j] != "...") { printf " &T_%s,", part[j]; } else { ellipsis = -1; printf " NULL,"; } while (j++ <= MAXARGS+1) printf " NULL,"; instruction = part[nf-INSTRUCTION]; if (substr(instruction, 1, 4) == "MOP_") instruction = substr(instruction, 5); if (substr(instruction, length(instruction)) == "D") instruction = (substr(instruction, 1, length(instruction) - 1) "."); # Gcc3: Prefix each specific instruction with a "*" if (match (instruction, "^[a-zA-Z]") > 0) instruction = "*" instruction; if (GCC) printf " },"; if (GCC) printf " \"%s\",", substr(part[nf-CONSTRAINTS], 1, length(part[nf-CONSTRAINTS]) - 1); printf " &T_%s,", part[nf-RESULT]; if (MCC) printf " \"%s\",", part[nf-SPECIFIC]; printf " %d,", ellipsis * (nf - NARGS); if (MCC) { printf " %s,", part[nf-WHEN]; printf " %s,", part[nf-ADDRESSIBLE]; printf " %s,", part[nf-CONST_PTR_OK]; printf " %s,", part[nf-VOLATILE_PTR_OK]; printf " %s,", part[nf-CONFIGURED]; printf " %s,", part[nf-INSTRUCTION]; printf " %s,", part[nf-TRANSFORM]; printf " %s", part[nf-PREDICATE]; } else if (GCC) { printf " %s,", part[nf-CONST_PTR_OK]; printf " %s,", part[nf-VOLATILE_PTR_OK]; printf " %s,", part[nf-OPTIMIZE]; printf " \"%s\",", part[nf-SPECIFIC]; printf " \"%s\",", instruction; printf " %s,", part[nf-INSN_CODE]; printf " B_UID(%d)", uid++; } printf " };\n"; } done[fcn] = 1; } if (GCC) printf "#define LAST_B_UID B_UID(%d)\n", uid; if (GCC) { # Output the description of each specific function. print ""; uid = 0; for (i in done) done[i] = ""; print "const struct builtin * const Builtin[] = {" for (i = 0; i < n_lines; i++) { nf = split(line[i], part); fcn = part[nf-SPECIFIC]; if (!done[fcn]) { printf " &%s,\n", mangle(fcn); } done[fcn] = 1; } print "};" } # Output the overload tables for each generic function. print ""; for (i = 0; i < n_lines; i++) { nf = split(line[i], part); fcn = part[1]; if (last != fcn) push(fcn, part[nf]); printf " &%s,\n", mangle(part[nf-SPECIFIC]); } push("", 0); # Output the builtin function structure. print ""; if (MCC) { print "%}"; print "struct overloadx {"; print " char *name;"; print " int fcns;"; print " int args;"; print " struct builtin **functions;"; print "};"; print "%%"; } else if (GCC) { print "const struct overloadx Overload[] = {"; } # Output the builtin function list and data. uid = 0; for (i = 0; i < n_lines; i++) { nf = split(line[i], part); fcn = part[1]; args = nf - NARGS; if (part[nf-OPN] == "...") args = -args; if (last != fcn) { if (MCC) printf "%s, %d, %d, O_%s\n", fcn, part[nf], args, fcn; if (GCC) printf " { \"%s\", %d, %d, O_%s, O_UID(%d) },\n", \ fcn, part[nf], args, fcn, uid++; } last = fcn; } if (GCC) { print " { NULL, 0, 0, NULL, 0 }" print "};"; printf "#define LAST_O_UID O_UID(%d)\n", uid; } }' > $output.$suffix if [ "$MCC" = "1" ] ; then $gperf > $output.h fi