/* Copyright 2002 - 2009 David A. Schleef Copyright 2012 MIPS Technologies, Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef _MSC_VER #define snprintf _snprintf #endif void _orc_profile_init(void); OrcRandomContext rand_context; void orc_test_init (void) { orc_init (); setvbuf (stdout, NULL, _IONBF, 0); orc_random_init (&rand_context, 0x12345678); _orc_profile_init (); #ifdef __aarch64__ // set the FPCR.FZ bit // denormalized single-precision and double-precision inputs to, and // outputs from, floating-point instructions are flushed to zero. // Otherwise, outputs from neon float ops do not match emulated code. int64_t fpcr_value = 0x1000000; #if defined(__GNUC__) || defined(__clang__) __asm__("msr FPCR, %0" : : "r" (fpcr_value)); #elif _MSC_VER __asm msr FPCR, fpcr_value #else #error unsupported compiler for inline assembly #endif #endif } OrcTestResult orc_test_gcc_compile (OrcProgram *p) { char cmd[300]; char *base; char source_filename[100]; char obj_filename[100]; char dis_filename[100]; char dump_filename[100]; char dump_dis_filename[100]; int ret; FILE *file; OrcCompileResult result; OrcTarget *target; unsigned int flags; int n; base = "temp-orc-test"; n = snprintf(source_filename, sizeof(source_filename), "%s-source.s", base); ORC_ASSERT(n < sizeof(source_filename)); n = snprintf(obj_filename, sizeof(obj_filename), "%s.o", base); ORC_ASSERT(n < sizeof(obj_filename)); n = snprintf(dis_filename, sizeof(dis_filename), "%s-source.dis", base); ORC_ASSERT(n < sizeof(dis_filename)); n = snprintf(dump_filename, sizeof(dump_filename), "%s-dump.bin", base); ORC_ASSERT(n < sizeof(dump_filename)); n = snprintf(dump_dis_filename, sizeof(dump_dis_filename), "%s-dump.dis", base); ORC_ASSERT(n < sizeof(dump_dis_filename)); target = orc_target_get_default (); flags = orc_target_get_default_flags (target); flags |= ORC_TARGET_CLEAN_COMPILE; if (strcmp (orc_target_get_name (target), "sse") == 0) { flags |= ORC_TARGET_SSE_SHORT_JUMPS; } if (strcmp (orc_target_get_name (target), "mmx") == 0) { flags |= ORC_TARGET_MMX_SHORT_JUMPS; } result = orc_program_compile_full (p, target, flags); if (ORC_COMPILE_RESULT_IS_FATAL(result)) { printf (" error: %s\n", orc_program_get_error (p)); return ORC_TEST_FAILED; } if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) { /* printf (" no code generated: %s\n", orc_program_get_error (p)); */ return ORC_TEST_INDETERMINATE; } fflush (stdout); file = fopen (source_filename, "w"); fprintf(file, "%s", orc_program_get_asm_code (p)); fclose (file); file = fopen (dump_filename, "w"); ret = fwrite(p->orccode->code, p->orccode->code_size, 1, file); fclose (file); #if defined(HAVE_POWERPC) n = snprintf (cmd, sizeof(cmd), "gcc -Wa,-mregnames -Wall -c %s -o %s", source_filename, obj_filename); #else n = snprintf (cmd, sizeof(cmd), "gcc -Wall -c %s -o %s", source_filename, obj_filename); #endif ORC_ASSERT(n < sizeof(cmd)); ret = system (cmd); if (ret != 0) { ORC_ERROR ("gcc failed"); printf("%s\n", orc_program_get_asm_code (p)); return ORC_TEST_FAILED; } #if 1 n = snprintf (cmd, sizeof(cmd), "objdump -dr %s | sed 's/^[ 0-9a-f]*:/XXX:/' >%s", obj_filename, dis_filename); #else n = snprintf (cmd, sizeof(cmd), "objdump -dr %s >%s", obj_filename, dis_filename); #endif ORC_ASSERT(n < sizeof(cmd)); ret = system (cmd); if (ret != 0) { ORC_ERROR ("objdump failed"); return ORC_TEST_FAILED; } n = snprintf (cmd, sizeof(cmd), "objcopy -I binary " #ifdef HAVE_I386 "-O elf32-i386 -B i386 " #elif defined(HAVE_AMD64) "-O elf64-x86-64 -B i386 " #elif defined(HAVE_POWERPC) "-O elf32-powerpc -B powerpc " #else /* FIXME */ #endif "--rename-section .data=.text " "--redefine-sym _binary_temp_orc_test_dump_bin_start=%s " "%s %s", p->name, dump_filename, obj_filename); ORC_ASSERT(n < sizeof(cmd)); ret = system (cmd); if (ret != 0) { printf("objcopy failed\n"); return ORC_TEST_FAILED; } #if 1 n = snprintf (cmd, sizeof(cmd), "objdump -Dr %s | sed 's/^[ 0-9a-f]*:/XXX:/' >%s", obj_filename, dump_dis_filename); #else n = snprintf (cmd, sizeof(cmd), "objdump -Dr %s >%s", obj_filename, dump_dis_filename); #endif ORC_ASSERT(n < sizeof(cmd)); ret = system (cmd); if (ret != 0) { printf("objdump failed\n"); return ORC_TEST_FAILED; } n = snprintf (cmd, sizeof(cmd), "diff -u %s %s", dis_filename, dump_dis_filename); ORC_ASSERT(n < sizeof(cmd)); ret = system (cmd); if (ret != 0) { printf("diff failed\n"); return ORC_TEST_FAILED; } remove (source_filename); remove (obj_filename); remove (dis_filename); remove (dump_filename); remove (dump_dis_filename); return ORC_TEST_OK; } #define PREFIX "/opt/arm-2008q3/bin/arm-none-linux-gnueabi-" OrcTestResult orc_test_gcc_compile_neon (OrcProgram *p) { char cmd[400]; char *base; char source_filename[100]; char obj_filename[100]; char dis_filename[100]; char dump_filename[100]; char dump_dis_filename[100]; int ret; FILE *file; OrcCompileResult result; OrcTarget *target; unsigned int flags; base = "temp-orc-test"; sprintf(source_filename, "%s-source.s", base); sprintf(obj_filename, "%s.o", base); sprintf(dis_filename, "%s-source.dis", base); sprintf(dump_filename, "%s-dump.bin", base); sprintf(dump_dis_filename, "%s-dump.dis", base); target = orc_target_get_by_name ("neon"); flags = orc_target_get_default_flags (target); flags |= ORC_TARGET_CLEAN_COMPILE; result = orc_program_compile_full (p, target, flags); if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) { /* printf (" no code generated: %s\n", orc_program_get_error (p)); */ return ORC_TEST_INDETERMINATE; } fflush (stdout); file = fopen (source_filename, "w"); fprintf(file, "%s", orc_program_get_asm_code (p)); fclose (file); file = fopen (dump_filename, "w"); ret = fwrite(p->orccode->code, p->orccode->code_size, 1, file); fclose (file); sprintf (cmd, PREFIX "gcc -march=armv6t2 -mcpu=cortex-a8 -mfpu=neon -Wall " "-c %s -o %s", source_filename, obj_filename); ret = system (cmd); if (ret != 0) { ORC_ERROR ("arm gcc failed"); return ORC_TEST_INDETERMINATE; } sprintf (cmd, PREFIX "objdump -dr %s >%s", obj_filename, dis_filename); ret = system (cmd); if (ret != 0) { ORC_ERROR ("objdump failed"); return ORC_TEST_INDETERMINATE; } sprintf (cmd, PREFIX "objcopy -I binary " "-O elf32-littlearm -B arm " "--rename-section .data=.text " "--redefine-sym _binary_temp_orc_test_dump_bin_start=%s " "%s %s", p->name, dump_filename, obj_filename); ret = system (cmd); if (ret != 0) { printf("objcopy failed\n"); return ORC_TEST_INDETERMINATE; } sprintf (cmd, PREFIX "objdump -Dr %s >%s", obj_filename, dump_dis_filename); ret = system (cmd); if (ret != 0) { printf("objdump failed\n"); return ORC_TEST_INDETERMINATE; } sprintf (cmd, "diff -u %s %s", dis_filename, dump_dis_filename); ret = system (cmd); if (ret != 0) { printf("diff failed\n"); return ORC_TEST_FAILED; } remove (source_filename); remove (obj_filename); remove (dis_filename); remove (dump_filename); remove (dump_dis_filename); return ORC_TEST_OK; } #define C64X_PREFIX "/opt/TI/TI_CGT_C6000_6.1.12/bin/" OrcTestResult orc_test_gcc_compile_c64x (OrcProgram *p) { char cmd[300]; char *base; char source_filename[100]; char obj_filename[100]; char dis_filename[100]; char dump_filename[100]; char dump_dis_filename[100]; int ret; FILE *file; OrcCompileResult result; OrcTarget *target; unsigned int flags; base = "temp-orc-test"; sprintf(source_filename, "%s-source.c", base); sprintf(obj_filename, "%s-source.obj", base); sprintf(dis_filename, "%s-source.dis", base); sprintf(dump_filename, "%s-dump.bin", base); sprintf(dump_dis_filename, "%s-dump.dis", base); target = orc_target_get_by_name ("c64x-c"); flags = orc_target_get_default_flags (target); result = orc_program_compile_full (p, target, flags); if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) { /* printf (" no code generated: %s\n", orc_program_get_error (p)); */ return ORC_TEST_INDETERMINATE; } fflush (stdout); file = fopen (source_filename, "w"); fprintf(file, "%s", orc_target_get_preamble (target)); fprintf(file, "%s", orc_program_get_asm_code (p)); fclose (file); file = fopen (dump_filename, "w"); ret = fwrite(p->orccode->code, p->orccode->code_size, 1, file); fclose (file); sprintf (cmd, C64X_PREFIX "cl6x -mv=6400+ " "-c %s", source_filename); ret = system (cmd); if (ret != 0) { ORC_ERROR ("compiler failed"); /* printf("%s\n", orc_program_get_asm_code (p)); */ return ORC_TEST_INDETERMINATE; } sprintf (cmd, C64X_PREFIX "dis6x %s >%s", obj_filename, dis_filename); ret = system (cmd); if (ret != 0) { ORC_ERROR ("objdump failed"); return ORC_TEST_INDETERMINATE; } #if 0 sprintf (cmd, C64X_PREFIX "objcopy -I binary " "-O elf32-littlearm -B arm " "--rename-section .data=.text " "--redefine-sym _binary_temp_orc_test_dump_bin_start=%s " "%s %s", p->name, dump_filename, obj_filename); ret = system (cmd); if (ret != 0) { printf("objcopy failed\n"); return ORC_TEST_FAILED; } #endif #if 0 sprintf (cmd, C64X_PREFIX "dis6x %s >%s", dump_filename, dump_dis_filename); ret = system (cmd); if (ret != 0) { printf("objdump failed\n"); return ORC_TEST_FAILED; } sprintf (cmd, "diff -u %s %s", dis_filename, dump_dis_filename); ret = system (cmd); if (ret != 0) { printf("diff failed\n"); return ORC_TEST_FAILED; } #endif remove (source_filename); remove (obj_filename); remove (dis_filename); remove (dump_filename); remove (dump_dis_filename); return ORC_TEST_OK; } void orc_test_random_bits (void *data, int n_bytes) { #if 1 orc_uint8 *d = data; int i; for(i=0;isize) { case 1: printf (" %5" PRId8 " [%4" PRIu8 "]", (orc_int8)(var->value.x4[0] & 0xFF), (orc_uint8)(var->value.x4[0] & 0xFF)); return var->value.x4[0] & 0xFF; case 2: printf (" %6" PRId16 " [%5" PRIu16 "]", var->value.x4[0], (orc_uint16)var->value.x4[0]); return var->value.x4[0]; case 4: printf (" %11" PRId32 " [%10" PRIu32 "]", var->value.x2[0], (orc_uint32)var->value.x2[0]); return var->value.x2[0]; case 8: printf (" %20" PRId64 " [%20" PRIu64 "]", var->value.i, (orc_uint64)var->value.i); return var->value.i; default: printf (" ERROR!"); return -1; } } static orc_uint64 print_array_val_signed (OrcArray *array, int i, int j) { void *ptr = ORC_PTR_OFFSET (array->data, i*array->element_size + j*array->stride); switch (array->element_size) { case 1: printf (" %5" PRId8 " [%4" PRIu8 "]", *(orc_int8 *)ptr, *(orc_uint8 *)ptr); return *(orc_int8 *)ptr; case 2: printf (" %6" PRId16 " [%5" PRIu16 "]", *(orc_int16 *)ptr, *(orc_uint16 *)ptr); return *(orc_int16 *)ptr; case 4: printf (" %11" PRId32 " [%10" PRIu32 "]", *(orc_int32 *)ptr, *(orc_uint32 *)ptr); return *(orc_int32 *)ptr; case 8: printf (" %20" PRId64 " [%20" PRIu64 "]", *(orc_int64 *)ptr, *(orc_uint64 *)ptr); return *(orc_int64 *)ptr; default: printf (" ERROR!"); return -1; } } static void print_param_val_signed (const int *const var, const int *const var2, const int size) { switch (size) { case 1: printf (" %5" PRId8 " [%4" PRIu8 "]", *(orc_int8 *)var, *(orc_uint8 *)var); break; case 2: printf (" %6" PRId16 " [%5" PRIu16 "]", *(orc_int16 *)var, *(orc_uint16 *)var); break; case 4: printf (" %11" PRId32 " [%10" PRIu32 "]", *(orc_int32 *)var, *(orc_uint32 *)var); break; case 8: { const orc_uint64 v = ((orc_uint64)*var) << 32 | *(orc_uint32 *)var2; printf (" %20" PRId64 " [%20" PRIu64 "]", (orc_int64)v, v); } break; default: printf (" ERROR!"); break; } } #ifdef unused static orc_uint64 print_array_val_unsigned (OrcArray *array, int i, int j) { void *ptr = ORC_PTR_OFFSET (array->data, i*array->element_size + j*array->stride); switch (array->element_size) { case 1: printf(" %4u", *(orc_uint8 *)ptr); return *(orc_int8 *)ptr; case 2: printf(" %5u", *(orc_uint16 *)ptr); return *(orc_int16 *)ptr; case 4: printf(" %10u", *(orc_uint32 *)ptr); return *(orc_int32 *)ptr; case 8: printf(" 0x%08x%08x", (orc_uint32)((*(orc_uint64 *)ptr)>>32), (orc_uint32)((*(orc_uint64 *)ptr))); return *(orc_int64 *)ptr; default: return -1; } } #endif static orc_uint64 print_array_val_hex (OrcArray *array, int i, int j) { void *ptr = ORC_PTR_OFFSET (array->data, i*array->element_size + j*array->stride); switch (array->element_size) { case 1: printf(" %02" PRIx8, *(orc_uint8 *)ptr); return *(orc_int8 *)ptr; case 2: printf(" %04" PRIx16, *(orc_uint16 *)ptr); return *(orc_int16 *)ptr; case 4: printf(" %08" PRIx32, *(orc_uint32 *)ptr); return *(orc_int32 *)ptr; case 8: printf (" %20" PRId64 " [%20" PRIu64 "]", *(orc_int64 *)ptr, *(orc_uint64 *)ptr); return *(orc_int64 *)ptr; default: return -1; } } static void print_array_val_float (OrcArray *array, int i, int j) { void *ptr = ORC_PTR_OFFSET (array->data, i*array->element_size + j*array->stride); switch (array->element_size) { case 4: if (isnan(*(float *)ptr)) { printf(" nan %08" PRIx32, *(orc_uint32 *)ptr); } else { printf(" %12.5g", *(float *)ptr); } break; case 8: printf(" %12.5g", *(double *)ptr); break; default: printf(" ERROR"); } } static void print_const_val_float (const OrcVariable *const var) { switch (var->size) { case 4: if (isnan (var->value.x2f[0])) { printf (" nan %08" PRIx32, var->value.x2[0]); } else { printf (" %12.5g", var->value.x2f[0]); } break; case 8: printf (" %12.5g", var->value.f); break; default: printf (" ERROR"); } } static void print_param_val_float (const int *const var, const int *const var2, const int size) { switch (size) { case 4: if (isnan (*(float *)var)) { printf (" nan %08" PRIx32, *var); } else { printf (" %12.5g", *(float *)var); } break; case 8: { const orc_uint64 tmp = ((orc_uint64)*var2 << 32) | (orc_uint64)*var; printf (" %12.5g", (double)tmp); } break; default: printf (" ERROR"); } } int float_compare (OrcArray *array1, OrcArray *array2, int i, int j) { void *ptr1 = ORC_PTR_OFFSET (array1->data, i*array1->element_size + j*array1->stride); void *ptr2 = ORC_PTR_OFFSET (array2->data, i*array2->element_size + j*array2->stride); switch (array1->element_size) { case 4: if (isnan(*(float *)ptr1) && isnan(*(float *)ptr2)) return TRUE; if (*(float *)ptr1 == *(float *)ptr2) return TRUE; if ((*(float *)ptr1 < 0.0) == (*(float *)ptr2 < 0.0) && abs((orc_int32)(*(orc_uint32 *)ptr1 - *(orc_uint32 *)ptr2)) <= 2) return TRUE; return FALSE; case 8: if (isnan(*(double *)ptr1) && isnan(*(double *)ptr2)) return TRUE; if (*(double *)ptr1 == *(double *)ptr2) return TRUE; if ((*(double *)ptr1 < 0.0) == (*(double *)ptr2 < 0.0) && llabs((orc_int64)(*(orc_uint64 *)ptr1 - *(orc_uint64 *)ptr2)) <= 2) return TRUE; return FALSE; } return FALSE; } OrcTestResult orc_test_compare_output (OrcProgram *program) { return orc_test_compare_output_full_for_target (program, 0, NULL); } OrcTestResult orc_test_compare_output_backup (OrcProgram *program) { return orc_test_compare_output_full (program, ORC_TEST_FLAGS_BACKUP); } OrcTestResult orc_test_compare_output_full (OrcProgram *program, int flags) { return orc_test_compare_output_full_for_target (program, flags, NULL); } static void dump_program (const OrcProgram *const program, const OrcTarget *const target) { char fname[256] = { 0 }; snprintf (fname, 256, "%s-%s.S", program->name, target->name); FILE *f = fopen (fname, "w"); ORC_ASSERT (f); fprintf (f, "%s\n", program->asm_code); fclose (f); snprintf (fname, 256, "%s-%s.bin", program->name, target->name); f = fopen (fname, "wb"); ORC_ASSERT (f); fwrite (program->orccode->code, 1, program->orccode->code_size, f); fclose (f); } OrcTestResult orc_test_compare_output_full_for_target (OrcProgram *program, int flags, const char *target_name) { OrcExecutor *ex; int n; int m; OrcArray *dest_exec[4] = { NULL, NULL, NULL, NULL }; OrcArray *dest_emul[4] = { NULL, NULL, NULL, NULL }; OrcArray *src[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int i; int j; int k; int have_dest ORC_GNUC_UNUSED = FALSE; OrcCompileResult result; int have_acc = FALSE; int acc_exec = 0, acc_emul = 0; int ret = ORC_TEST_OK; int bad = 0; int misalignment; ORC_DEBUG ("got here"); { OrcTarget *target; unsigned int flags; target = orc_target_get_by_name (target_name); flags = orc_target_get_default_flags (target); result = orc_program_compile_full (program, target, flags); if (ORC_COMPILE_RESULT_IS_FATAL(result)) { ret = ORC_TEST_FAILED; goto out; } if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) { /* printf (" no code generated: %s\n", orc_program_get_error (program)); */ ret = ORC_TEST_INDETERMINATE; goto out; } dump_program(program, target); } if (program->constant_n > 0) { n = program->constant_n; } else { n = 64 + (orc_random(&rand_context)&0xf); } ex = orc_executor_new (program); orc_executor_set_n (ex, n); if (program->is_2d) { if (program->constant_m > 0) { m = program->constant_m; } else { m = 8 + (orc_random(&rand_context)&0xf); } } else { m = 1; } orc_executor_set_m (ex, m); ORC_DEBUG("size %d %d", ex->n, ex->params[ORC_VAR_A1]); misalignment = 0; for(i=0;ivars[i].name == NULL) continue; if (program->vars[i].vartype == ORC_VAR_TYPE_SRC) { src[i-ORC_VAR_S1] = orc_array_new (n, m, program->vars[i].size, misalignment, program->vars[i].alignment); orc_array_set_random (src[i-ORC_VAR_S1], &rand_context); misalignment++; } else if (program->vars[i].vartype == ORC_VAR_TYPE_DEST) { dest_exec[i-ORC_VAR_D1] = orc_array_new (n, m, program->vars[i].size, misalignment, program->vars[i].alignment); orc_array_set_pattern (dest_exec[i], ORC_OOB_VALUE); dest_emul[i-ORC_VAR_D1] = orc_array_new (n, m, program->vars[i].size, misalignment, program->vars[i].alignment); orc_array_set_pattern (dest_emul[i], ORC_OOB_VALUE); misalignment++; } else if (program->vars[i].vartype == ORC_VAR_TYPE_PARAM) { switch (program->vars[i].param_type) { case ORC_PARAM_TYPE_INT: orc_executor_set_param (ex, i, 2); break; case ORC_PARAM_TYPE_FLOAT: orc_executor_set_param_float (ex, i, 2.0); break; case ORC_PARAM_TYPE_INT64: orc_executor_set_param_int64 (ex, i, 2); break; case ORC_PARAM_TYPE_DOUBLE: orc_executor_set_param_double (ex, i, 2.0); break; } } } for(i=0;ivars[i].vartype == ORC_VAR_TYPE_DEST) { orc_executor_set_array (ex, i, dest_exec[i-ORC_VAR_D1]->data); orc_executor_set_stride (ex, i, dest_exec[i-ORC_VAR_D1]->stride); have_dest = TRUE; } if (program->vars[i].vartype == ORC_VAR_TYPE_SRC) { orc_executor_set_array (ex, i, src[i-ORC_VAR_S1]->data); orc_executor_set_stride (ex, i, src[i-ORC_VAR_S1]->stride); } } ORC_DEBUG ("running %s\n", program->name); if (flags & ORC_TEST_FLAGS_BACKUP) { orc_executor_run_backup (ex); } else { orc_executor_run (ex); } ORC_DEBUG ("done running"); for(i=0;ivars[i].vartype == ORC_VAR_TYPE_ACCUMULATOR) { acc_exec = ex->accumulators[0]; have_acc = TRUE; } } for(i=0;ivars[i].vartype == ORC_VAR_TYPE_DEST) { orc_executor_set_array (ex, i, dest_emul[i]->data); orc_executor_set_stride (ex, i, dest_emul[i]->stride); } if (program->vars[i].vartype == ORC_VAR_TYPE_SRC) { ORC_DEBUG("setting array %p", src[i-ORC_VAR_S1]->data); orc_executor_set_array (ex, i, src[i-ORC_VAR_S1]->data); orc_executor_set_stride (ex, i, src[i-ORC_VAR_S1]->stride); } } orc_executor_emulate (ex); for(i=0;ivars[i].vartype == ORC_VAR_TYPE_ACCUMULATOR) { acc_emul = ex->accumulators[0]; } } for(k=ORC_VAR_D1;kvars[k].size > 0) { if (!orc_array_compare (dest_exec[k-ORC_VAR_D1], dest_emul[k-ORC_VAR_D1], flags)) { printf("dest array %d bad\n", k); bad = TRUE; } if (!orc_array_check_out_of_bounds (dest_exec[k-ORC_VAR_D1])) { printf("out of bounds failure\n"); ret = ORC_TEST_FAILED; } } } if (bad) { int n_lines_bad = 0; for(j=0;jvars[l].vartype) { case ORC_VAR_TYPE_SRC: if (flags & ORC_TEST_FLAGS_FLOAT) { print_array_val_float (src[l - ORC_VAR_S1], i, j); } else { print_array_val_signed (src[l - ORC_VAR_S1], i, j); } break; case ORC_VAR_TYPE_CONST: if (flags & ORC_TEST_FLAGS_FLOAT) { print_const_val_float (program->vars + l); } else { print_const_val_signed (program->vars + l); } break; case ORC_VAR_TYPE_PARAM: if (flags & ORC_TEST_FLAGS_FLOAT) { print_param_val_float (ex->params + l, ex->params + l + (ORC_VAR_T1-ORC_VAR_P1), program->vars[l].size); } else { print_param_val_signed (ex->params + l, ex->params + l + (ORC_VAR_T1-ORC_VAR_P1), program->vars[l].size); } case ORC_VAR_TYPE_DEST: case ORC_VAR_TYPE_TEMP: case ORC_VAR_TYPE_ACCUMULATOR: break; } } printf(" ->"); for(l=ORC_VAR_D1;lvars[l].size > 0) { if (flags & ORC_TEST_FLAGS_FLOAT) { print_array_val_float (dest_emul[l-ORC_VAR_D1], i, j); print_array_val_float (dest_exec[l-ORC_VAR_D1], i, j); if (!float_compare (dest_emul[l-ORC_VAR_D1], dest_exec[l-ORC_VAR_D1], i, j)) { line_bad = TRUE; n_lines_bad++; } } else { a = print_array_val_hex (dest_emul[l-ORC_VAR_D1], i, j); b = print_array_val_hex (dest_exec[l-ORC_VAR_D1], i, j); if (a != b) { line_bad = TRUE; n_lines_bad++; } } } } if (line_bad) { printf(" *"); } printf("\n"); } } if (n_lines_bad) ret = ORC_TEST_FAILED; } if (have_acc) { if (acc_emul != acc_exec) { for(j=0;jvars[k].vartype) { case ORC_VAR_TYPE_SRC: if (flags & ORC_TEST_FLAGS_FLOAT) { print_array_val_float (src[k - ORC_VAR_S1], i, j); } else { print_array_val_signed (src[k - ORC_VAR_S1], i, j); } break; case ORC_VAR_TYPE_CONST: if (flags & ORC_TEST_FLAGS_FLOAT) { print_const_val_float (program->vars + k); } else { print_const_val_signed (program->vars + k); } break; case ORC_VAR_TYPE_PARAM: if (flags & ORC_TEST_FLAGS_FLOAT) { print_param_val_float (ex->params + k, ex->params + k + (ORC_VAR_T1-ORC_VAR_P1), program->vars[k].size); } else { print_param_val_signed (ex->params + k, ex->params + k + (ORC_VAR_T1-ORC_VAR_P1), program->vars[k].size); } case ORC_VAR_TYPE_DEST: case ORC_VAR_TYPE_TEMP: case ORC_VAR_TYPE_ACCUMULATOR: break; } } printf(" -> acc\n"); } } printf("acc %d %d\n", acc_emul, acc_exec); ret = ORC_TEST_FAILED; } } for(i=0;i<4;i++){ if (dest_exec[i]) orc_array_free (dest_exec[i]); if (dest_emul[i]) orc_array_free (dest_emul[i]); } for(i=0;i<8;i++){ if (src[i]) orc_array_free (src[i]); } orc_executor_free (ex); out: if (!(flags & ORC_TEST_SKIP_RESET)) orc_program_reset (program); return ret; } OrcProgram * orc_test_get_program_for_opcode (OrcStaticOpcode *opcode) { OrcProgram *p; char s[40]; int flags ORC_GNUC_UNUSED = 0; int args[5] = { -1, -1, -1, -1, -1 }; int n_args = 0; p = orc_program_new (); if (opcode->flags & ORC_STATIC_OPCODE_ACCUMULATOR) { args[n_args++] = orc_program_add_accumulator (p, opcode->dest_size[0], "d1"); } else { args[n_args++] = orc_program_add_destination (p, opcode->dest_size[0], "d1"); } if (opcode->dest_size[1] != 0) { args[n_args++] = orc_program_add_destination (p, opcode->dest_size[1], "d2"); } if (opcode->flags & ORC_STATIC_OPCODE_SCALAR) { if (opcode->src_size[1] == 0) { args[n_args++] = orc_program_add_constant (p, opcode->src_size[0], 1, "c1"); } else { args[n_args++] = orc_program_add_source (p, opcode->src_size[0], "s1"); args[n_args++] = orc_program_add_constant (p, opcode->src_size[1], 1, "c1"); if (opcode->src_size[2] != 0) { args[n_args++] = orc_program_add_constant (p, opcode->src_size[1], 1, "c1"); } } } else { args[n_args++] = orc_program_add_source (p, opcode->src_size[0], "s1"); args[n_args++] = orc_program_add_source (p, opcode->src_size[1], "s2"); } if ((opcode->flags & ORC_STATIC_OPCODE_FLOAT_SRC) || (opcode->flags & ORC_STATIC_OPCODE_FLOAT_DEST)) { flags = ORC_TEST_FLAGS_FLOAT; } sprintf(s, "test_%s", opcode->name); orc_program_set_name (p, s); orc_program_append_2 (p, opcode->name, 0, args[0], args[1], args[2], args[3]); return p; } OrcProgram * orc_test_get_program_for_opcode_const (OrcStaticOpcode *opcode) { OrcProgram *p; char s[40]; int args[5] = { -1, -1, -1, -1, -1 }; int flags ORC_GNUC_UNUSED; int n_args = 0; p = orc_program_new (); if (opcode->flags & ORC_STATIC_OPCODE_ACCUMULATOR) { args[n_args++] = orc_program_add_accumulator (p, opcode->dest_size[0], "d1"); } else { args[n_args++] = orc_program_add_destination (p, opcode->dest_size[0], "d1"); } if (opcode->dest_size[1] != 0) { args[n_args++] = orc_program_add_destination (p, opcode->dest_size[1], "d2"); } if (opcode->src_size[1] == 0) { args[n_args++] = orc_program_add_constant (p, opcode->src_size[0], 1, "c1"); } else { args[n_args++] = orc_program_add_source (p, opcode->src_size[0], "s1"); args[n_args++] = orc_program_add_constant (p, opcode->src_size[1], 1, "c1"); if (opcode->src_size[2]) { args[n_args++] = orc_program_add_constant (p, opcode->src_size[2], 1, "c2"); } } if ((opcode->flags & ORC_STATIC_OPCODE_FLOAT_SRC) || (opcode->flags & ORC_STATIC_OPCODE_FLOAT_DEST)) { flags = ORC_TEST_FLAGS_FLOAT; } sprintf(s, "test_const_%s", opcode->name); orc_program_set_name (p, s); orc_program_append_2 (p, opcode->name, 0, args[0], args[1], args[2], args[3]); return p; } OrcProgram * orc_test_get_program_for_opcode_param (OrcStaticOpcode *opcode) { OrcProgram *p; char s[40]; int args[5] = { -1, -1, -1, -1, -1 }; int flags ORC_GNUC_UNUSED; int n_args = 0; if (opcode->src_size[1] == 0) { return NULL; } p = orc_program_new (); if (opcode->flags & ORC_STATIC_OPCODE_ACCUMULATOR) { args[n_args++] = orc_program_add_accumulator (p, opcode->dest_size[0], "d1"); } else { args[n_args++] = orc_program_add_destination (p, opcode->dest_size[0], "d1"); } if (opcode->dest_size[1] != 0) { args[n_args++] = orc_program_add_destination (p, opcode->dest_size[1], "d2"); } args[n_args++] = orc_program_add_source (p, opcode->src_size[0], "s1"); args[n_args++] = orc_program_add_parameter (p, opcode->src_size[1], "p1"); if (opcode->src_size[2]) { args[n_args++] = orc_program_add_parameter (p, opcode->src_size[2], "p2"); } if ((opcode->flags & ORC_STATIC_OPCODE_FLOAT_SRC) || (opcode->flags & ORC_STATIC_OPCODE_FLOAT_DEST)) { flags = ORC_TEST_FLAGS_FLOAT; } sprintf(s, "test_p_%s", opcode->name); orc_program_set_name (p, s); orc_program_append_2 (p, opcode->name, 0, args[0], args[1], args[2], args[3]); return p; } void orc_test_performance (OrcProgram *program, int flags) { orc_test_performance_full (program, flags, NULL); } double orc_test_performance_full (OrcProgram *program, int flags, const char *target_name) { OrcExecutor *ex; int n; int m; OrcArray *dest_exec[4] = { NULL, NULL, NULL, NULL }; OrcArray *dest_emul[4] = { NULL, NULL, NULL, NULL }; OrcArray *src[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int i, j; OrcCompileResult result; OrcProfile prof; double ave, std; OrcTarget *target; int misalignment; ORC_DEBUG ("got here"); target = orc_target_get_by_name (target_name); if (!(flags & ORC_TEST_FLAGS_BACKUP)) { unsigned int flags; flags = orc_target_get_default_flags (target); result = orc_program_compile_full (program, target, flags); if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) { /* printf("compile failed\n"); */ orc_program_reset (program); return 0; } dump_program(program, target); } if (program->constant_n > 0) { n = program->constant_n; } else { /* n = 64 + (orc_random(&rand_context)&0xf); */ n = 1000; } ex = orc_executor_new (program); orc_executor_set_n (ex, n); if (program->is_2d) { if (program->constant_m > 0) { m = program->constant_m; } else { m = 8 + (orc_random(&rand_context)&0xf); } } else { m = 1; } orc_executor_set_m (ex, m); ORC_DEBUG("size %d %d", ex->n, ex->params[ORC_VAR_A1]); misalignment = 0; for(i=0;ivars[i].name == NULL) continue; if (program->vars[i].vartype == ORC_VAR_TYPE_SRC) { src[i-ORC_VAR_S1] = orc_array_new (n, m, program->vars[i].size, misalignment, program->vars[i].alignment); orc_array_set_random (src[i-ORC_VAR_S1], &rand_context); misalignment++; } else if (program->vars[i].vartype == ORC_VAR_TYPE_DEST) { dest_exec[i-ORC_VAR_D1] = orc_array_new (n, m, program->vars[i].size, misalignment, program->vars[i].alignment); orc_array_set_pattern (dest_exec[i], ORC_OOB_VALUE); dest_emul[i-ORC_VAR_D1] = orc_array_new (n, m, program->vars[i].size, misalignment, program->vars[i].alignment); orc_array_set_pattern (dest_emul[i], ORC_OOB_VALUE); misalignment++; } else if (program->vars[i].vartype == ORC_VAR_TYPE_PARAM) { orc_executor_set_param (ex, i, 2); } } ORC_DEBUG ("running %s\n", program->name); orc_profile_init (&prof); for(i=0;i<10;i++){ orc_executor_set_n (ex, n); orc_executor_set_m (ex, m); for(j=0;jvars[j].vartype == ORC_VAR_TYPE_DEST) { orc_executor_set_array (ex, j, dest_exec[j-ORC_VAR_D1]->data); orc_executor_set_stride (ex, j, dest_exec[j-ORC_VAR_D1]->stride); } if (program->vars[j].vartype == ORC_VAR_TYPE_SRC) { orc_executor_set_array (ex, j, src[j-ORC_VAR_S1]->data); orc_executor_set_stride (ex, j, src[j-ORC_VAR_S1]->stride); } } if (flags & ORC_TEST_FLAGS_BACKUP) { orc_profile_start (&prof); orc_executor_run_backup (ex); orc_profile_stop (&prof); } else if (flags & ORC_TEST_FLAGS_EMULATE) { orc_profile_start (&prof); orc_executor_emulate (ex); orc_profile_stop (&prof); } else { orc_profile_start (&prof); orc_executor_run (ex); orc_profile_stop (&prof); } } ORC_DEBUG ("done running"); orc_profile_get_ave_std (&prof, &ave, &std); for(i=0;i<4;i++){ if (dest_exec[i]) orc_array_free (dest_exec[i]); if (dest_emul[i]) orc_array_free (dest_emul[i]); } for(i=0;i<8;i++){ if (src[i]) orc_array_free (src[i]); } orc_executor_free (ex); orc_program_reset (program); return ave/(n*m); } #define MIPS_PREFIX "mipsel-linux-gnu-" OrcTestResult orc_test_gcc_compile_mips (OrcProgram *p) { char cmd[400]; char *base; char source_filename[100]; char obj_filename[100]; char dis_filename[100]; char dump_filename[100]; char dump_dis_filename[100]; int ret; FILE *file; OrcCompileResult result; OrcTarget *target; unsigned int flags; base = "temp-orc-test"; sprintf(source_filename, "%s-source.s", base); sprintf(obj_filename, "%s.o", base); sprintf(dis_filename, "%s-source.dis", base); sprintf(dump_filename, "%s-dump.bin", base); sprintf(dump_dis_filename, "%s-dump.dis", base); target = orc_target_get_by_name ("mips"); flags = orc_target_get_default_flags (target); flags |= ORC_TARGET_CLEAN_COMPILE; result = orc_program_compile_full (p, target, flags); if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) { /* printf (" no code generated: %s\n", orc_program_get_error (p)); */ return ORC_TEST_INDETERMINATE; } fflush (stdout); file = fopen (source_filename, "w"); fprintf(file, "%s", orc_target_get_preamble (target)); fprintf(file, "%s", orc_program_get_asm_code (p)); fclose (file); file = fopen (dump_filename, "w"); ret = fwrite(p->orccode->code, p->orccode->code_size, 1, file); fclose (file); sprintf (cmd, MIPS_PREFIX "gcc -mips32r2 -mdspr2 -Wall " "-c %s -o %s", source_filename, obj_filename); ret = system (cmd); if (ret != 0) { ORC_ERROR ("mips gcc failed"); return ORC_TEST_INDETERMINATE; } sprintf (cmd, MIPS_PREFIX "objdump -Dr -j .text %s >%s", obj_filename, dis_filename); ret = system (cmd); if (ret != 0) { ORC_ERROR ("objdump failed"); return ORC_TEST_INDETERMINATE; } sprintf (cmd, MIPS_PREFIX "objcopy -I binary " "-O elf32-tradlittlemips -B mips:isa32r2 " "--rename-section .data=.text " "--redefine-sym _binary_temp_orc_test_dump_bin_start=%s " "%s %s", p->name, dump_filename, obj_filename); ret = system (cmd); if (ret != 0) { printf("objcopy failed\n"); return ORC_TEST_INDETERMINATE; } sprintf (cmd, MIPS_PREFIX "objdump -Dr %s >%s", obj_filename, dump_dis_filename); ret = system (cmd); if (ret != 0) { printf("objdump failed\n"); return ORC_TEST_INDETERMINATE; } sprintf (cmd, "diff -u %s %s", dis_filename, dump_dis_filename); ret = system (cmd); if (ret != 0) { printf("diff failed\n"); return ORC_TEST_FAILED; } remove (source_filename); remove (obj_filename); remove (dis_filename); remove (dump_filename); remove (dump_dis_filename); return ORC_TEST_OK; }