#include "config.h"
#define ORC_ENABLE_UNSTABLE_API
#include <orc/orc.h>
#include <orc/orcparse.h>
#include <orc/orcbytecode.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static char * read_file (const char *filename);
void output_code (OrcProgram *p, FILE *output);
void output_code_header (OrcProgram *p, FILE *output);
void output_code_test (OrcProgram *p, FILE *output);
void output_code_backup (OrcProgram *p, FILE *output);
void output_code_no_orc (OrcProgram *p, FILE *output);
void output_code_assembly (OrcProgram *p, FILE *output);
void output_code_execute (OrcProgram *p, FILE *output, int is_inline);
void output_program_generation (OrcProgram *p, FILE *output, int is_inline);
void output_init_function (FILE *output);
static char * get_barrier (const char *s);
static const char * my_basename (const char *s);
int verbose = 0;
int error = 0;
int compat;
int n_programs;
OrcProgram **programs;
int use_inline = FALSE;
int use_code = FALSE;
int use_lazy_init = FALSE;
int use_backup = TRUE;
int use_internal = FALSE;
const char *init_function = NULL;
char *target = "sse";
#define ORC_VERSION(a,b,c,d) ((a)*1000000 + (b)*10000 + (c)*100 + (d))
#define REQUIRE(a,b,c,d) do { \
if (ORC_VERSION((a),(b),(c),(d)) > compat) { \
fprintf(stderr, "Feature used that is incompatible with --compat in program %s\n", p->name); \
exit (1); \
} \
} while (0)
typedef enum {
MODE_IMPL,
MODE_HEADER,
MODE_TEST,
MODE_ASSEMBLY
} OrcMode;
OrcMode mode = MODE_IMPL;
void help (void)
{
printf("Usage:\n");
printf(" orcc [OPTION...] INPUT_FILE\n");
printf("\n");
printf("Help Options:\n");
printf(" -h, --help Show help options\n");
printf("\n");
printf("Application Options:\n");
printf(" -v, --verbose Output more information\n");
printf(" -o, --output FILE Write output to FILE\n");
printf(" --implementation Produce C code implementing functions\n");
printf(" --header Produce C header for functions\n");
printf(" --test Produce test code for functions\n");
printf(" --assembly Produce assembly code for functions\n");
printf(" --include FILE Add #include <FILE> to code\n");
printf(" --target TARGET Generate assembly for TARGET\n");
printf(" --compat VERSION Generate code compatible with Orc version VERSION\n");
printf(" --inline Generate inline functions in header\n");
printf(" --no-inline Do not generate inline functions in header\n");
printf(" --internal Mark functions in header for internal visibility\n");
printf(" --no-internal Do not mark functions in header for internal visibility\n");
printf(" --init-function FUNCTION Generate initialization function\n");
printf(" --lazy-init Do Orc compile at function execution\n");
printf(" --no-backup Do not generate backup functions\n");
printf("\n");
exit (0);
}
int
main (int argc, char *argv[])
{
const char *orc_version;
char *code;
int n;
int i;
char *output_file = NULL;
char *input_file = NULL;
char *include_file = NULL;
char *compat_version = VERSION;
FILE *output;
char *log = NULL;
orc_init ();
orc_version = orc_version_string ();
if (strcmp (orc_version, VERSION) != 0) {
fprintf (stderr, "WARNING: unexpected liborc library version %s is being "
"picked up by %s, which is version %s. This might be because orc was "
"installed from source and is also installed via packages, and liborc "
"from the wrong prefix is used. Check your system setup.\n",
orc_version, argv[0], VERSION);
exit(1);
}
for(i=1;i<argc;i++) {
if (strcmp(argv[i], "--header") == 0) {
mode = MODE_HEADER;
} else if (strcmp(argv[i], "--implementation") == 0) {
mode = MODE_IMPL;
} else if (strcmp(argv[i], "--test") == 0) {
mode = MODE_TEST;
} else if (strcmp(argv[i], "--assembly") == 0) {
mode = MODE_ASSEMBLY;
} else if (strcmp(argv[i], "--include") == 0) {
if (i+1 < argc) {
include_file = argv[i+1];
i++;
} else {
help();
}
} else if (strcmp (argv[i], "--output") == 0 ||
strcmp(argv[i], "-o") == 0) {
if (i+1 < argc) {
output_file = argv[i+1];
i++;
} else {
help();
}
} else if (strcmp(argv[i], "--target") == 0 ||
strcmp(argv[i], "-t") == 0) {
if (i+1 < argc) {
target = argv[i+1];
i++;
} else {
help();
}
} else if (strcmp(argv[i], "--inline") == 0) {
use_inline = TRUE;
} else if (strcmp(argv[i], "--no-inline") == 0) {
use_inline = FALSE;
} else if (strcmp(argv[i], "--internal") == 0) {
use_internal = TRUE;
} else if (strcmp(argv[i], "--no-internal") == 0) {
use_internal = FALSE;
} else if (strcmp(argv[i], "--init-function") == 0) {
if (i+1 < argc) {
init_function = argv[i+1];
i++;
} else {
help();
}
} else if (strcmp(argv[i], "--help") == 0 ||
strcmp(argv[i], "-h") == 0) {
help ();
} else if (strcmp(argv[i], "--verbose") == 0 ||
strcmp(argv[i], "-v") == 0) {
verbose = 1;
} else if (strcmp(argv[i], "--version") == 0) {
printf("Orc Compiler " PACKAGE_VERSION "\n");
exit (0);
} else if (strcmp(argv[i], "--compat") == 0) {
if (i+1 < argc) {
compat_version = argv[i+1];
i++;
} else {
help();
}
} else if (strcmp(argv[i], "--lazy-init") == 0) {
use_lazy_init = TRUE;
} else if (strcmp(argv[i], "--no-backup") == 0) {
use_backup = FALSE;
} else if (strncmp(argv[i], "-", 1) == 0) {
printf("Unknown option: %s\n", argv[i]);
exit (1);
} else {
if (input_file == NULL) {
input_file = argv[i];
} else {
printf("More than one input file specified: %s\n", argv[i]);
exit (1);
}
}
}
if (input_file == NULL) {
printf("No input file specified\n");
exit (1);
}
if (mode == MODE_ASSEMBLY && orc_target_get_by_name (target) == NULL) {
printf("Unknown target \"%s\"\n", target);
exit (1);
}
if (compat_version) {
int major, minor, micro, nano = 0;
int n;
n = sscanf (compat_version, "%d.%d.%d.%d", &major, &minor, µ, &nano);
if (n < 3) {
printf("Unknown version \"%s\"\n", compat_version);
exit (1);
}
compat = ORC_VERSION(major,minor,micro,nano);
if (compat < ORC_VERSION(0,4,5,0)) {
printf("Compatibility version \"%s\" not supported. Minimum 0.4.5\n",
compat_version);
exit (1);
}
}
if (compat >= ORC_VERSION(0,4,11,1)) {
use_code = TRUE;
}
if (output_file == NULL) {
switch (mode) {
case MODE_IMPL:
output_file = "out.c";
break;
case MODE_HEADER:
output_file = "out.h";
break;
case MODE_TEST:
output_file = "out_test.c";
break;
case MODE_ASSEMBLY:
output_file = "out.s";
break;
}
}
code = read_file (input_file);
if (!code) {
printf("Could not read input file: %s\n", input_file);
exit(1);
}
n = orc_parse_full (code, &programs, &log);
free(code);
n_programs = n;
printf("%s", log);
free(log);
if (programs == NULL) {
printf("no programs\n");
exit(1);
}
if (init_function == NULL) {
init_function = orc_parse_get_init_function (programs[0]);
}
if (init_function == NULL) {
use_lazy_init = TRUE;
}
output = fopen (output_file, "w");
if (!output) {
printf("Could not write output file: %s\n", output_file);
exit(1);
}
fprintf(output, "\n");
fprintf(output, "/* autogenerated from %s */\n", my_basename(input_file));
fprintf(output, "\n");
if (mode == MODE_IMPL) {
fprintf(output, "#ifdef HAVE_CONFIG_H\n");
fprintf(output, "#include \"config.h\"\n");
fprintf(output, "#endif\n");
if (include_file) {
fprintf(output, "#include <%s>\n", include_file);
}
fprintf(output, "\n");
fprintf(output, "%s", orc_target_c_get_typedefs ());
fprintf(output, "\n");
fprintf(output, "#ifndef DISABLE_ORC\n");
fprintf(output, "#include <orc/orc.h>\n");
fprintf(output, "#endif\n");
for(i=0;i<n;i++){
output_code_header (programs[i], output);
}
if (init_function) {
fprintf(output, "\n");
fprintf(output, "void %s (void);\n", init_function);
}
fprintf(output, "\n");
fprintf(output, "%s", orc_target_get_asm_preamble ("c"));
fprintf(output, "\n");
for(i=0;i<n;i++){
output_code (programs[i], output);
}
fprintf(output, "\n");
if (init_function) {
output_init_function (output);
fprintf(output, "\n");
}
} else if (mode == MODE_HEADER) {
char *barrier = get_barrier (output_file);
fprintf(output, "#ifndef _%s_\n", barrier);
fprintf(output, "#define _%s_\n", barrier);
free (barrier);
fprintf(output, "\n");
if (include_file) {
fprintf(output, "#include <%s>\n", include_file);
}
fprintf(output, "\n");
fprintf(output, "#ifdef __cplusplus\n");
fprintf(output, "extern \"C\" {\n");
fprintf(output, "#endif\n");
fprintf(output, "\n");
if (init_function) {
fprintf(output, "void %s (void);\n", init_function);
fprintf(output, "\n");
}
fprintf(output, "\n");
if (!use_inline) {
fprintf(output, "\n");
fprintf(output, "%s", orc_target_c_get_typedefs ());
for(i=0;i<n;i++){
output_code_header (programs[i], output);
}
} else {
fprintf(output, "\n");
fprintf(output, "#include <orc/orc.h>\n");
fprintf(output, "\n");
for(i=0;i<n;i++){
output_code_execute (programs[i], output, TRUE);
}
}
fprintf(output, "\n");
fprintf(output, "#ifdef __cplusplus\n");
fprintf(output, "}\n");
fprintf(output, "#endif\n");
fprintf(output, "\n");
fprintf(output, "#endif\n");
fprintf(output, "\n");
} else if (mode == MODE_TEST) {
fprintf(output, "#include <stdio.h>\n");
fprintf(output, "#include <string.h>\n");
fprintf(output, "#include <stdlib.h>\n");
fprintf(output, "#include <math.h>\n");
if (include_file) {
fprintf(output, "#include <%s>\n", include_file);
}
fprintf(output, "\n");
fprintf(output, "%s", orc_target_c_get_typedefs ());
fprintf(output, "#include <orc/orc.h>\n");
fprintf(output, "#include <orc-test/orctest.h>\n");
fprintf(output, "%s", orc_target_get_asm_preamble ("c"));
fprintf(output, "\n");
if (use_backup) {
for(i=0;i<n;i++){
fprintf(output, "/* %s */\n", programs[i]->name);
output_code_backup (programs[i], output);
}
}
fprintf(output, "\n");
fprintf(output, "static int quiet = 0;\n");
fprintf(output, "static int benchmark = 0;\n");
fprintf(output, "\n");
fprintf(output, "static void help (const char *argv0)\n");
fprintf(output, "{\n");
fprintf(output, " printf(\"Usage:\\n\");\n");
fprintf(output, " printf(\" %%s [OPTION]\\n\", argv0);\n");
fprintf(output, " printf(\"Help Options:\\n\");\n");
fprintf(output, " printf(\" -h, --help Show help options\\n\");\n");
fprintf(output, " printf(\"Application Options:\\n\");\n");
fprintf(output, " printf(\" -b, --benchmark Run benchmark and show results\\n\");\n");
fprintf(output, " printf(\" -q, --quiet Don't output anything except on failures\\n\");\n");
fprintf(output, "\n");
fprintf(output, " exit(0);\n");
fprintf(output, "}\n");
fprintf(output, "\n");
fprintf(output, "int\n");
fprintf(output, "main (int argc, char *argv[])\n");
fprintf(output, "{\n");
fprintf(output, " int error = FALSE;\n");
fprintf(output, " int i;\n");
fprintf(output, "\n");
fprintf(output, " orc_test_init ();\n");
fprintf(output, "\n");
fprintf(output, " for(i=1;i<argc;i++) {\n");
fprintf(output, " if (strcmp(argv[i], \"--help\") == 0 ||\n");
fprintf(output, " strcmp(argv[i], \"-h\") == 0) {\n");
fprintf(output, " help(argv[0]);\n");
fprintf(output, " } else if (strcmp(argv[i], \"--quiet\") == 0 ||\n");
fprintf(output, " strcmp(argv[i], \"-q\") == 0) {\n");
fprintf(output, " quiet = 1;\n");
fprintf(output, " benchmark = 0;\n");
fprintf(output, " } else if (strcmp(argv[i], \"--benchmark\") == 0 ||\n");
fprintf(output, " strcmp(argv[i], \"-b\") == 0) {\n");
fprintf(output, " benchmark = 1;\n");
fprintf(output, " quiet = 0;\n");
fprintf(output, " }\n");
fprintf(output, " }\n");
fprintf(output, "\n");
for(i=0;i<n;i++){
output_code_test (programs[i], output);
}
fprintf(output, "\n");
fprintf(output, " if (error) {\n");
fprintf(output, " return 1;\n");
fprintf(output, " };\n");
fprintf(output, " return 0;\n");
fprintf(output, "}\n");
} else if (mode == MODE_ASSEMBLY) {
fprintf(output, "%s", orc_target_get_asm_preamble (target));
for(i=0;i<n;i++){
output_code_assembly (programs[i], output);
}
}
for(i=0;i<n;i++){
orc_program_free(programs[i]);
}
free(programs);
fclose (output);
if (error) {
remove (output_file);
exit(1);
}
return 0;
}
static char *
get_barrier (const char *s)
{
char *barrier;
int n;
int i;
n = strlen(s);
barrier = malloc (n + 1);
for(i=0;i<n;i++) {
if (isalnum (s[i])) {
barrier[i] = toupper(s[i]);
} else {
barrier[i] = '_';
}
}
barrier[n] = 0;
return barrier;
}
static char *
read_file (const char *filename)
{
FILE *file = NULL;
char *contents = NULL;
long size;
int ret;
file = fopen (filename, "rb");
if (file == NULL) return NULL;
ret = fseek (file, 0, SEEK_END);
if (ret < 0) goto bail;
size = ftell (file);
if (size < 0) goto bail;
ret = fseek (file, 0, SEEK_SET);
if (ret < 0) goto bail;
contents = malloc (size + 1);
if (contents == NULL) goto bail;
ret = fread (contents, size, 1, file);
if (ret < 0) goto bail;
contents[size] = 0;
fclose (file);
return contents;
bail:
/* something failed */
if (file) fclose (file);
if (contents) free (contents);
return NULL;
}
const char *varnames[] = {
"d1", "d2", "d3", "d4",
"s1", "s2", "s3", "s4",
"s5", "s6", "s7", "s8",
"a1", "a2", "a3", "d4",
"c1", "c2", "c3", "c4",
"c5", "c6", "c7", "c8",
"p1", "p2", "p3", "p4",
"p5", "p6", "p7", "p8",
"t1", "t2", "t3", "t4",
"t5", "t6", "t7", "t8",
"t9", "t10", "t11", "t12",
"t13", "t14", "t15", "t16"
};
const char *enumnames[] = {
"ORC_VAR_D1", "ORC_VAR_D2", "ORC_VAR_D3", "ORC_VAR_D4",
"ORC_VAR_S1", "ORC_VAR_S2", "ORC_VAR_S3", "ORC_VAR_S4",
"ORC_VAR_S5", "ORC_VAR_S6", "ORC_VAR_S7", "ORC_VAR_S8",
"ORC_VAR_A1", "ORC_VAR_A2", "ORC_VAR_A3", "ORC_VAR_A4",
"ORC_VAR_C1", "ORC_VAR_C2", "ORC_VAR_C3", "ORC_VAR_C4",
"ORC_VAR_C5", "ORC_VAR_C6", "ORC_VAR_C7", "ORC_VAR_C8",
"ORC_VAR_P1", "ORC_VAR_P2", "ORC_VAR_P3", "ORC_VAR_P4",
"ORC_VAR_P5", "ORC_VAR_P6", "ORC_VAR_P7", "ORC_VAR_P8",
"ORC_VAR_T1", "ORC_VAR_T2", "ORC_VAR_T3", "ORC_VAR_T4",
"ORC_VAR_T5", "ORC_VAR_T6", "ORC_VAR_T7", "ORC_VAR_T8",
"ORC_VAR_T9", "ORC_VAR_T10", "ORC_VAR_T11", "ORC_VAR_T12",
"ORC_VAR_T13", "ORC_VAR_T14", "ORC_VAR_T15",
/* ORC_VAR_T16 is a special case because it didn't exist in
the API until 0.4.8 */
"47"
};
static const char *orcify_typename (const char *s)
{
if (strcmp (s, "int8_t") == 0) return "orc_int8";
if (strcmp (s, "int16_t") == 0) return "orc_int16";
if (strcmp (s, "int32_t") == 0) return "orc_int32";
if (strcmp (s, "int64_t") == 0) return "orc_int64";
if (strcmp (s, "uint8_t") == 0) return "orc_uint8";
if (strcmp (s, "uint16_t") == 0) return "orc_uint16";
if (strcmp (s, "uint32_t") == 0) return "orc_uint32";
if (strcmp (s, "uint64_t") == 0) return "orc_uint64";
return s;
}
void
output_prototype (OrcProgram *p, FILE *output, int backup)
{
OrcVariable *var;
int i;
int need_comma;
fprintf(output, "%s (", backup ? p->backup_name : p->name);
need_comma = FALSE;
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_D1 + i];
if (var->size) {
if (need_comma) fprintf(output, ", ");
if (var->type_name) {
fprintf(output, "%s * ORC_RESTRICT %s", orcify_typename(var->type_name),
varnames[ORC_VAR_D1 + i]);
} else {
fprintf(output, "orc_uint%d * ORC_RESTRICT %s", var->size*8,
varnames[ORC_VAR_D1 + i]);
}
if (p->is_2d) {
fprintf(output, ", int %s_stride", varnames[ORC_VAR_D1 + i]);
}
need_comma = TRUE;
}
}
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_A1 + i];
if (var->size) {
if (need_comma) fprintf(output, ", ");
if (var->type_name) {
fprintf(output, "%s * ORC_RESTRICT %s", orcify_typename(var->type_name),
varnames[ORC_VAR_A1 + i]);
} else {
fprintf(output, "orc_uint%d * ORC_RESTRICT %s", var->size*8,
varnames[ORC_VAR_A1 + i]);
}
need_comma = TRUE;
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_S1 + i];
if (var->size) {
if (need_comma) fprintf(output, ", ");
if (var->type_name) {
fprintf(output, "const %s * ORC_RESTRICT %s",
orcify_typename(var->type_name),
varnames[ORC_VAR_S1 + i]);
} else {
fprintf(output, "const orc_uint%d * ORC_RESTRICT %s", var->size*8,
varnames[ORC_VAR_S1 + i]);
}
if (p->is_2d) {
fprintf(output, ", int %s_stride", varnames[ORC_VAR_S1 + i]);
}
need_comma = TRUE;
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_P1 + i];
if (var->size) {
if (need_comma) fprintf(output, ", ");
switch (var->param_type) {
case ORC_PARAM_TYPE_INT:
fprintf(output, "int %s", varnames[ORC_VAR_P1 + i]);
break;
case ORC_PARAM_TYPE_FLOAT:
REQUIRE(0,4,5,1);
fprintf(output, "float %s", varnames[ORC_VAR_P1 + i]);
break;
case ORC_PARAM_TYPE_INT64:
REQUIRE(0,4,7,1);
fprintf(output, "orc_int64 %s", varnames[ORC_VAR_P1 + i]);
break;
case ORC_PARAM_TYPE_DOUBLE:
REQUIRE(0,4,7,1);
fprintf(output, "double %s", varnames[ORC_VAR_P1 + i]);
break;
default:
ORC_ASSERT(0);
}
need_comma = TRUE;
}
}
if (p->constant_n == 0) {
if (need_comma) fprintf(output, ", ");
fprintf(output, "int n");
need_comma = TRUE;
}
if (p->is_2d && p->constant_m == 0) {
if (need_comma) fprintf(output, ", ");
fprintf(output, "int m");
}
fprintf(output, ")");
}
void
output_executor_backup_call (OrcProgram *p, FILE *output)
{
OrcVariable *var;
int i;
fprintf(output, " %s (", p->backup_name);
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_D1 + i];
if (var->size) {
fprintf(output, "ex->arrays[%s], ", enumnames[ORC_VAR_D1 + i]);
if (p->is_2d) {
fprintf(output, "ex->params[%s], ", enumnames[ORC_VAR_D1 + i]);
}
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_S1 + i];
if (var->size) {
fprintf(output, "ex->arrays[%s], ", enumnames[ORC_VAR_S1 + i]);
if (p->is_2d) {
fprintf(output, " ex->params[%s], ", enumnames[ORC_VAR_S1 + i]);
}
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_P1 + i];
if (var->size) {
switch (var->param_type) {
case ORC_PARAM_TYPE_INT:
fprintf(output, "ex->params[%s],", enumnames[ORC_VAR_P1 + i]);
break;
case ORC_PARAM_TYPE_FLOAT:
fprintf(output, "((orc_union32 * )&ex->params[%s])->f, ",
enumnames[ORC_VAR_P1 + i]);
break;
case ORC_PARAM_TYPE_INT64:
fprintf(output, "(ex->params[%s] & 0xffffffff) | ((orc_uint64)(ex->params[%s]) << 32), ", enumnames[ORC_VAR_P1 + i], enumnames[ORC_VAR_T1 + i]);
break;
case ORC_PARAM_TYPE_DOUBLE:
/* FIXME */
break;
default:
ORC_ASSERT(0);
}
}
}
if (p->constant_n) {
fprintf(output, "%d", p->constant_n);
} else {
fprintf(output, "ex->n");
}
if (p->is_2d) {
if (p->constant_m) {
fprintf(output, ", %d", p->constant_m);
} else {
fprintf(output, ", ORC_EXECUTOR_M(ex)");
}
}
fprintf(output, ");\n");
}
void
output_backup_call (OrcProgram *p, FILE *output)
{
OrcVariable *var;
int i;
fprintf(output, " %s (", p->backup_name);
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_D1 + i];
if (var->size) {
fprintf(output, "%s, ", varnames[ORC_VAR_D1 + i]);
if (p->is_2d) {
fprintf(output, "%s_stride, ", varnames[ORC_VAR_D1 + i]);
}
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_S1 + i];
if (var->size) {
fprintf(output, "%s, ", varnames[ORC_VAR_S1 + i]);
if (p->is_2d) {
fprintf(output, "%s_stride, ", varnames[ORC_VAR_S1 + i]);
}
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_P1 + i];
if (var->size) {
fprintf(output, "%s, ", varnames[ORC_VAR_P1 + i]);
}
}
if (p->constant_n) {
fprintf(output, "%d", p->constant_n);
} else {
fprintf(output, "n");
}
if (p->is_2d) {
if (p->constant_m) {
fprintf(output, ", %d", p->constant_m);
} else {
fprintf(output, ", m");
}
}
fprintf(output, ");\n");
}
void
output_code_header (OrcProgram *p, FILE *output)
{
if(use_internal) {
fprintf(output, "ORC_INTERNAL void ");
} else {
fprintf(output, "void ");
}
output_prototype (p, output, 0);
fprintf(output, ";\n");
if (p->backup_name && mode != MODE_TEST) {
fprintf(output, "void ");
output_prototype (p, output, 1);
fprintf(output, ";\n");
}
}
void
output_code_backup (OrcProgram *p, FILE *output)
{
fprintf(output, "static void\n");
if (compat < ORC_VERSION(0,4,7,1)) {
fprintf(output, "_backup_%s (OrcExecutor * ex)\n", p->name);
} else {
fprintf(output, "_backup_%s (OrcExecutor * ORC_RESTRICT ex)\n", p->name);
}
fprintf(output, "{\n");
if (p->backup_name && mode != MODE_TEST) {
output_executor_backup_call (p, output);
} else {
OrcCompileResult result;
result = orc_program_compile_full (p, orc_target_get_by_name("c"),
ORC_TARGET_C_BARE);
if (ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) {
fprintf(output, "%s\n", orc_program_get_asm_code (p));
} else {
printf("Failed to compile backup code for '%s'\n", p->name);
error = TRUE;
}
}
fprintf(output, "}\n");
fprintf(output, "\n");
}
void
output_code_no_orc (OrcProgram *p, FILE *output)
{
fprintf(output, "void\n");
output_prototype (p, output, 0);
fprintf(output, "{\n");
if (p->backup_name && mode != MODE_TEST) {
output_backup_call (p, output);
} else {
OrcCompileResult result;
result = orc_program_compile_full (p, orc_target_get_by_name("c"),
ORC_TARGET_C_BARE | ORC_TARGET_C_NOEXEC);
if (ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) {
fprintf(output, "%s\n", orc_program_get_asm_code (p));
} else {
printf("Failed to compile no orc for '%s'\n", p->name);
error = TRUE;
}
}
fprintf(output, "}\n");
fprintf(output, "\n");
}
void
output_code (OrcProgram *p, FILE *output)
{
fprintf(output, "\n");
fprintf(output, "/* %s */\n", p->name);
fprintf(output, "#ifdef DISABLE_ORC\n");
output_code_no_orc (p, output);
fprintf(output, "#else\n");
if (use_backup) {
output_code_backup (p, output);
}
output_code_execute (p, output, FALSE);
fprintf(output, "#endif\n");
fprintf(output, "\n");
}
void
output_code_execute (OrcProgram *p, FILE *output, int is_inline)
{
OrcVariable *var;
int i;
if (!use_lazy_init) {
const char *storage;
if (is_inline) {
storage = "extern ";
} else {
if (use_inline) {
storage = "";
} else {
storage = "static ";
}
}
if (use_code) {
fprintf(output, "%sOrcCode *_orc_code_%s;\n", storage, p->name);
} else {
fprintf(output, "%sOrcProgram *_orc_program_%s;\n", storage, p->name);
}
}
if (is_inline) {
fprintf(output, "static inline void\n");
} else {
fprintf(output, "void\n");
}
output_prototype (p, output, 0);
fprintf(output, "\n");
fprintf(output, "{\n");
fprintf(output, " OrcExecutor _ex, *ex = &_ex;\n");
if (!use_lazy_init) {
if (use_code) {
fprintf(output, " OrcCode *c = _orc_code_%s;\n", p->name);
} else {
fprintf(output, " OrcProgram *p = _orc_program_%s;\n", p->name);
}
} else {
fprintf(output, " static volatile int p_inited = 0;\n");
if (use_code) {
fprintf(output, " static OrcCode *c = 0;\n");
} else {
fprintf(output, " static OrcProgram *p = 0;\n");
}
}
fprintf(output, " void (*func) (OrcExecutor *);\n");
fprintf(output, "\n");
if (use_lazy_init) {
fprintf(output, " if (!p_inited) {\n");
fprintf(output, " orc_once_mutex_lock ();\n");
fprintf(output, " if (!p_inited) {\n");
if (use_code) {
fprintf(output, " OrcProgram *p;\n");
}
fprintf(output, "\n");
output_program_generation (p, output, is_inline);
fprintf(output, "\n");
fprintf(output, " orc_program_compile (p);\n");
if (use_code) {
fprintf(output, " c = orc_program_take_code (p);\n");
fprintf(output, " orc_program_free (p);\n");
}
fprintf(output, " }\n");
fprintf(output, " p_inited = TRUE;\n");
fprintf(output, " orc_once_mutex_unlock ();\n");
fprintf(output, " }\n");
}
if (use_code) {
fprintf(output, " ex->arrays[ORC_VAR_A2] = c;\n");
fprintf(output, " ex->program = 0;\n");
} else {
fprintf(output, " ex->program = p;\n");
}
fprintf(output, "\n");
if (p->constant_n) {
fprintf(output, " ex->n = %d;\n", p->constant_n);
} else {
fprintf(output, " ex->n = n;\n");
}
if (p->is_2d) {
if (p->constant_m) {
fprintf(output, " ORC_EXECUTOR_M(ex) = %d;\n", p->constant_m);
} else {
fprintf(output, " ORC_EXECUTOR_M(ex) = m;\n");
}
}
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_D1 + i];
if (var->size) {
fprintf(output, " ex->arrays[%s] = %s;\n",
enumnames[ORC_VAR_D1 + i], varnames[ORC_VAR_D1 + i]);
if (p->is_2d) {
fprintf(output, " ex->params[%s] = %s_stride;\n",
enumnames[ORC_VAR_D1 + i], varnames[ORC_VAR_D1 + i]);
}
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_S1 + i];
if (var->size) {
fprintf(output, " ex->arrays[%s] = (void *)%s;\n",
enumnames[ORC_VAR_S1 + i], varnames[ORC_VAR_S1 + i]);
if (p->is_2d) {
fprintf(output, " ex->params[%s] = %s_stride;\n",
enumnames[ORC_VAR_S1 + i], varnames[ORC_VAR_S1 + i]);
}
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_P1 + i];
if (var->size) {
switch (var->param_type) {
case ORC_PARAM_TYPE_INT:
fprintf(output, " ex->params[%s] = %s;\n",
enumnames[ORC_VAR_P1 + i], varnames[ORC_VAR_P1 + i]);
break;
case ORC_PARAM_TYPE_FLOAT:
REQUIRE(0,4,5,1);
fprintf(output, " {\n");
fprintf(output, " orc_union32 tmp;\n");
fprintf(output, " tmp.f = %s;\n", varnames[ORC_VAR_P1 + i]);
fprintf(output, " ex->params[%s] = tmp.i;\n",
enumnames[ORC_VAR_P1 + i]);
fprintf(output, " }\n");
break;
case ORC_PARAM_TYPE_INT64:
REQUIRE(0,4,7,1);
fprintf(output, " {\n");
fprintf(output, " orc_union64 tmp;\n");
fprintf(output, " tmp.i = %s;\n", varnames[ORC_VAR_P1 + i]);
fprintf(output, " ex->params[%s] = ((orc_uint64) tmp.i) & 0xffffffff;\n",
enumnames[ORC_VAR_P1 + i]);
fprintf(output, " ex->params[%s] = ((orc_uint64) tmp.i) >> 32;\n",
enumnames[ORC_VAR_T1 + i]);
fprintf(output, " }\n");
break;
case ORC_PARAM_TYPE_DOUBLE:
REQUIRE(0,4,5,1);
fprintf(output, " {\n");
fprintf(output, " orc_union64 tmp;\n");
fprintf(output, " tmp.f = %s;\n", varnames[ORC_VAR_P1 + i]);
fprintf(output, " ex->params[%s] = ((orc_uint64) tmp.i) & 0xffffffff;\n",
enumnames[ORC_VAR_P1 + i]);
fprintf(output, " ex->params[%s] = ((orc_uint64) tmp.i) >> 32;\n",
enumnames[ORC_VAR_T1 + i]);
fprintf(output, " }\n");
break;
default:
ORC_ASSERT(0);
}
}
}
fprintf(output, "\n");
if (use_code) {
fprintf(output, " func = c->exec;\n");
} else {
fprintf(output, " func = p->code_exec;\n");
}
fprintf(output, " func (ex);\n");
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_A1 + i];
if (var->size) {
fprintf(output, " *%s = orc_executor_get_accumulator (ex, %s);\n",
varnames[ORC_VAR_A1 + i], enumnames[ORC_VAR_A1 + i]);
}
}
fprintf(output, "}\n");
}
void
output_program_generation (OrcProgram *p, FILE *output, int is_inline)
{
OrcVariable *var;
int i;
if (ORC_VERSION(0,4,16,1) <= compat) {
OrcBytecode *bytecode;
int i;
bytecode = orc_bytecode_from_program (p);
fprintf(output, "#if 1\n");
/* fprintf(output, "#ifdef bytecode\n"); */
fprintf(output, " static const orc_uint8 bc[] = {\n");
for(i=0;i<bytecode->length;i++) {
if ((i&0xf) == 0) {
fprintf(output, " ");
}
fprintf(output, "%d, ", bytecode->bytecode[i]);
if ((i&0xf) == 15) {
fprintf(output, "\n");
}
}
if ((i&0xf) != 15) {
fprintf(output, "\n");
}
fprintf(output, " };\n");
fprintf(output, " p = orc_program_new_from_static_bytecode (bc);\n");
/* fprintf(output, " orc_program_set_name (p, \"%s\");\n", p->name); */
if (use_backup && !is_inline) {
fprintf(output, " orc_program_set_backup_function (p, _backup_%s);\n",
p->name);
}
#if 0
/* CHECK */
{
OrcProgram *p2 = orc_program_new_from_static_bytecode (bytecode->bytecode);
OrcBytecode *bytecode2 = bytecode2 = orc_bytecode_from_program (p2);
fprintf(output, "#ifdef badbytecode\n");
fprintf(output, " static const orc_uint8 bc[] = {\n");
for(i=0;i<bytecode2->length;i++) {
if ((i&0xf) == 0) {
fprintf(output, " ");
}
fprintf(output, "%s%d, ",
(bytecode->bytecode[i] == bytecode2->bytecode[i]) ? "" : "/* */",
bytecode2->bytecode[i]);
if ((i&0xf) == 15) {
fprintf(output, "\n");
}
}
if ((i&0xf) != 15) {
fprintf(output, "\n");
}
fprintf(output, " };\n");
fprintf(output, "#endif\n");
}
#endif
orc_bytecode_free (bytecode);
fprintf(output, "#else\n");
}
fprintf(output, " p = orc_program_new ();\n");
if (p->constant_n != 0) {
fprintf(output, " orc_program_set_constant_n (p, %d);\n",
p->constant_n);
}
if (p->n_multiple != 0) {
REQUIRE(0,4,14,1);
fprintf(output, " orc_program_set_n_multiple (p, %d);\n",
p->n_multiple);
}
if (p->n_minimum != 0) {
REQUIRE(0,4,14,1);
fprintf(output, " orc_program_set_n_minimum (p, %d);\n",
p->n_minimum);
}
if (p->n_maximum != 0) {
REQUIRE(0,4,14,1);
fprintf(output, " orc_program_set_n_maximum (p, %d);\n",
p->n_maximum);
}
if (p->is_2d) {
fprintf(output, " orc_program_set_2d (p);\n");
if (p->constant_m != 0) {
fprintf(output, " orc_program_set_constant_m (p, %d);\n",
p->constant_m);
}
}
fprintf(output, " orc_program_set_name (p, \"%s\");\n", p->name);
if (use_backup && !is_inline) {
fprintf(output, " orc_program_set_backup_function (p, _backup_%s);\n",
p->name);
}
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_D1 + i];
if (var->size) {
if (var->alignment != var->size) {
REQUIRE(0,4,14,1);
fprintf(output, " orc_program_add_destination_full (p, %d, \"%s\", 0, %d);\n",
var->size, varnames[ORC_VAR_D1 + i], var->alignment);
} else {
fprintf(output, " orc_program_add_destination (p, %d, \"%s\");\n",
var->size, varnames[ORC_VAR_D1 + i]);
}
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_S1 + i];
if (var->size) {
if (var->alignment != var->size) {
REQUIRE(0,4,14,1);
fprintf(output, " orc_program_add_source_full (p, %d, \"%s\", 0, %d);\n",
var->size, varnames[ORC_VAR_S1 + i],
var->alignment);
} else {
fprintf(output, " orc_program_add_source (p, %d, \"%s\");\n",
var->size, varnames[ORC_VAR_S1 + i]);
}
}
}
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_A1 + i];
if (var->size) {
fprintf(output, " orc_program_add_accumulator (p, %d, \"%s\");\n",
var->size, varnames[ORC_VAR_A1 + i]);
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_C1 + i];
if (var->size == 0) continue;
if (var->size <= 4) {
fprintf(output, " orc_program_add_constant (p, %d, 0x%08x, \"%s\");\n",
var->size, (int)var->value.i, varnames[ORC_VAR_C1 + i]);
} else if (var->size > 4) {
REQUIRE(0,4,8,1);
fprintf(output, " orc_program_add_constant_int64 (p, %d, 0x%08x%08xULL, \"%s\");\n",
var->size, (orc_uint32)(((orc_uint64)var->value.i)>>32),
(orc_uint32)(var->value.i), varnames[ORC_VAR_C1 + i]);
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_P1 + i];
if (var->size) {
const char *suffix = NULL;
switch (var->param_type) {
case ORC_PARAM_TYPE_INT:
suffix="";
break;
case ORC_PARAM_TYPE_FLOAT:
REQUIRE(0,4,5,1);
suffix="_float";
break;
case ORC_PARAM_TYPE_INT64:
REQUIRE(0,4,7,1);
suffix="_int64";
break;
case ORC_PARAM_TYPE_DOUBLE:
REQUIRE(0,4,7,1);
suffix="_double";
break;
default:
ORC_ASSERT(0);
}
fprintf(output, " orc_program_add_parameter%s (p, %d, \"%s\");\n",
suffix, var->size, varnames[ORC_VAR_P1 + i]);
}
}
for(i=0;i<16;i++){
var = &p->vars[ORC_VAR_T1 + i];
if (var->size) {
fprintf(output, " orc_program_add_temporary (p, %d, \"%s\");\n",
var->size, varnames[ORC_VAR_T1 + i]);
}
}
fprintf(output, "\n");
for(i=0;i<p->n_insns;i++){
OrcInstruction *insn = p->insns + i;
if (compat < ORC_VERSION(0,4,6,1)) {
if (insn->flags) {
REQUIRE(0,4,6,1);
}
if (p->vars[insn->src_args[1]].size != 0) {
fprintf(output, " orc_program_append (p, \"%s\", %s, %s, %s);\n",
insn->opcode->name, enumnames[insn->dest_args[0]],
enumnames[insn->src_args[0]], enumnames[insn->src_args[1]]);
} else {
fprintf(output, " orc_program_append_ds (p, \"%s\", %s, %s);\n",
insn->opcode->name, enumnames[insn->dest_args[0]],
enumnames[insn->src_args[0]]);
}
} else {
int args[4] = { 0, 0, 0, 0 };
int n_args = 0;
if (insn->opcode->dest_size[0] != 0) {
args[n_args++] = insn->dest_args[0];
}
if (insn->opcode->dest_size[1] != 0) {
args[n_args++] = insn->dest_args[1];
}
if (insn->opcode->src_size[0] != 0) {
args[n_args++] = insn->src_args[0];
}
if (insn->opcode->src_size[1] != 0) {
args[n_args++] = insn->src_args[1];
}
if (insn->opcode->src_size[2] != 0) {
args[n_args++] = insn->src_args[2];
}
fprintf(output, " orc_program_append_2 (p, \"%s\", %d, %s, %s, %s, %s);\n",
insn->opcode->name, insn->flags, enumnames[args[0]],
enumnames[args[1]], enumnames[args[2]],
enumnames[args[3]]);
}
}
if (ORC_VERSION(0,4,16,1) <= compat) {
fprintf(output, "#endif\n");
}
}
void
output_init_function (FILE *output)
{
int i;
fprintf(output, "void\n");
fprintf(output, "%s (void)\n", init_function);
fprintf(output, "{\n");
if (!use_lazy_init) {
fprintf(output, "#ifndef DISABLE_ORC\n");
for(i=0;i<n_programs;i++){
fprintf(output, " {\n");
fprintf(output, " /* %s */\n", programs[i]->name);
fprintf(output, " OrcProgram *p;\n");
fprintf(output, "\n");
output_program_generation (programs[i], output, FALSE);
fprintf(output, "\n");
fprintf(output, " orc_program_compile (p);\n");
fprintf(output, "\n");
if (use_code) {
fprintf(output, " _orc_code_%s = orc_program_take_code (p);\n",
programs[i]->name);
fprintf(output, " orc_program_free (p);\n");
} else {
fprintf(output, " _orc_program_%s = p;\n", programs[i]->name);
}
fprintf(output, " }\n");
}
fprintf(output, "#endif\n");
}
fprintf(output, "}\n");
fprintf(output, "\n");
}
void
output_code_test (OrcProgram *p, FILE *output)
{
OrcVariable *var;
int i;
fprintf(output, " /* %s */\n", p->name);
fprintf(output, " {\n");
fprintf(output, " OrcProgram *p = NULL;\n");
fprintf(output, " int ret;\n");
fprintf(output, "\n");
fprintf(output, " if (!quiet)");
fprintf(output, " printf (\"%s:\\n\");\n", p->name);
fprintf(output, " p = orc_program_new ();\n");
if (p->constant_n != 0) {
fprintf(output, " orc_program_set_constant_n (p, %d);\n",
p->constant_n);
}
if (p->is_2d) {
fprintf(output, " orc_program_set_2d (p);\n");
if (p->constant_m != 0) {
fprintf(output, " orc_program_set_constant_m (p, %d);\n",
p->constant_m);
}
}
fprintf(output, " orc_program_set_name (p, \"%s\");\n", p->name);
if (use_backup) {
fprintf(output, " orc_program_set_backup_function (p, _backup_%s);\n",
p->name);
}
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_D1 + i];
if (var->size) {
fprintf(output, " orc_program_add_destination (p, %d, \"%s\");\n",
var->size, varnames[ORC_VAR_D1 + i]);
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_S1 + i];
if (var->size) {
fprintf(output, " orc_program_add_source (p, %d, \"%s\");\n",
var->size, varnames[ORC_VAR_S1 + i]);
}
}
for(i=0;i<4;i++){
var = &p->vars[ORC_VAR_A1 + i];
if (var->size) {
fprintf(output, " orc_program_add_accumulator (p, %d, \"%s\");\n",
var->size, varnames[ORC_VAR_A1 + i]);
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_C1 + i];
if (var->size) {
if (var->size < 8) {
fprintf(output, " orc_program_add_constant (p, %d, 0x%08x, \"%s\");\n",
var->size, (int)var->value.i, varnames[ORC_VAR_C1 + i]);
} else {
fprintf(output, " orc_program_add_constant_int64 (p, %d, "
"0x%08x%08xULL, \"%s\");\n",
var->size, (orc_uint32)(((orc_uint64)var->value.i)>>32),
(orc_uint32)(var->value.i), varnames[ORC_VAR_C1 + i]);
}
}
}
for(i=0;i<8;i++){
var = &p->vars[ORC_VAR_P1 + i];
if (var->size) {
const char *suffix = NULL;
switch (var->param_type) {
case ORC_PARAM_TYPE_INT:
suffix="";
break;
case ORC_PARAM_TYPE_FLOAT:
REQUIRE(0,4,5,1);
suffix="_float";
break;
case ORC_PARAM_TYPE_INT64:
REQUIRE(0,4,7,1);
suffix="_int64";
break;
case ORC_PARAM_TYPE_DOUBLE:
REQUIRE(0,4,7,1);
suffix="_double";
break;
default:
ORC_ASSERT(0);
}
fprintf(output, " orc_program_add_parameter%s (p, %d, \"%s\");\n",
suffix, var->size, varnames[ORC_VAR_P1 + i]);
}
}
for(i=0;i<16;i++){
var = &p->vars[ORC_VAR_T1 + i];
if (var->size) {
fprintf(output, " orc_program_add_temporary (p, %d, \"%s\");\n",
var->size, varnames[ORC_VAR_T1 + i]);
}
}
fprintf(output, "\n");
for(i=0;i<p->n_insns;i++){
OrcInstruction *insn = p->insns + i;
if (compat < ORC_VERSION(0,4,6,1)) {
if (insn->flags) {
REQUIRE(0,4,6,1);
}
if (p->vars[insn->src_args[1]].size != 0) {
fprintf(output, " orc_program_append (p, \"%s\", %s, %s, %s);\n",
insn->opcode->name, enumnames[insn->dest_args[0]],
enumnames[insn->src_args[0]], enumnames[insn->src_args[1]]);
} else {
fprintf(output, " orc_program_append_ds (p, \"%s\", %s, %s);\n",
insn->opcode->name, enumnames[insn->dest_args[0]],
enumnames[insn->src_args[0]]);
}
} else {
int args[4] = { 0, 0, 0, 0 };
int n_args = 0;
if (insn->opcode->dest_size[0] != 0) {
args[n_args++] = insn->dest_args[0];
}
if (insn->opcode->dest_size[1] != 0) {
args[n_args++] = insn->dest_args[1];
}
if (insn->opcode->src_size[0] != 0) {
args[n_args++] = insn->src_args[0];
}
if (insn->opcode->src_size[1] != 0) {
args[n_args++] = insn->src_args[1];
}
if (insn->opcode->src_size[2] != 0) {
args[n_args++] = insn->src_args[2];
}
fprintf(output, " orc_program_append_2 (p, \"%s\", %d, %s, %s, %s, %s);\n",
insn->opcode->name, insn->flags, enumnames[args[0]],
enumnames[args[1]], enumnames[args[2]],
enumnames[args[3]]);
}
}
fprintf(output, "\n");
if (compat >= ORC_VERSION(0,4,7,1)) {
fprintf(output, " if (benchmark) {\n");
fprintf(output, " printf (\" cycles (emulate) : %%g\\n\",\n");
fprintf(output, " orc_test_performance_full (p, ORC_TEST_FLAGS_EMULATE, NULL));\n");
fprintf(output, " }\n");
fprintf(output, "\n");
}
if (use_backup) {
fprintf(output, " ret = orc_test_compare_output_backup (p);\n");
fprintf(output, " if (!ret) {\n");
fprintf(output, " error = TRUE;\n");
fprintf(output, " } else if (!quiet) {\n");
fprintf(output, " printf (\" backup function : PASSED\\n\");\n");
fprintf(output, " }\n");
fprintf(output, "\n");
if (compat >= ORC_VERSION(0,4,7,1)) {
fprintf(output, " if (benchmark) {\n");
fprintf(output, " printf (\" cycles (backup) : %%g\\n\",\n");
fprintf(output, " orc_test_performance_full (p, ORC_TEST_FLAGS_BACKUP, NULL));\n");
fprintf(output, " }\n");
fprintf(output, "\n");
}
}
fprintf(output, " ret = orc_test_compare_output (p);\n");
fprintf(output, " if (ret == ORC_TEST_INDETERMINATE && !quiet) {\n");
fprintf(output, " printf (\" compiled function: COMPILE FAILED\\n\");\n");
fprintf(output, " } else if (!ret) {\n");
fprintf(output, " error = TRUE;\n");
fprintf(output, " } else if (!quiet) {\n");
fprintf(output, " printf (\" compiled function: PASSED\\n\");\n");
fprintf(output, " }\n");
fprintf(output, "\n");
if (compat >= ORC_VERSION(0,4,7,1)) {
fprintf(output, " if (benchmark) {\n");
fprintf(output, " printf (\" cycles (compiled): %%g\\n\",\n");
fprintf(output, " orc_test_performance_full (p, 0, NULL));\n");
fprintf(output, " }\n");
}
fprintf(output, "\n");
fprintf(output, " orc_program_free (p);\n");
fprintf(output, " }\n");
fprintf(output, "\n");
}
void
output_code_assembly (OrcProgram *p, FILE *output)
{
fprintf(output, "/* %s */\n", p->name);
/* output_prototype (p, output); */
{
OrcCompileResult result;
OrcTarget *t = orc_target_get_by_name(target);
result = orc_program_compile_full (p, t,
orc_target_get_default_flags (t));
if (ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) {
fprintf(output, "%s\n", orc_program_get_asm_code (p));
} else {
printf("Failed to compile assembly for '%s'\n", p->name);
error = TRUE;
}
}
fprintf(output, "\n");
}
static const char *
my_basename (const char *s)
{
const char *ret = s;
const char *t;
t = s;
while (t[0] != 0) {
if (t[0] == '/') ret = t+1;
t++;
}
return ret;
}