Пример #1
0
/**
 * Create new draw module context with gallivm state for LLVM JIT.
 */
struct draw_context *
draw_create_gallivm(struct pipe_context *pipe, struct gallivm_state *gallivm)
{
   struct draw_context *draw = CALLOC_STRUCT( draw_context );
   if (draw == NULL)
      goto fail;

#if HAVE_LLVM
   if (draw_get_option_use_llvm()) {
      if (!gallivm) {
         gallivm = gallivm_create();
         draw->own_gallivm = gallivm;
      }

      if (gallivm)
         draw->llvm = draw_llvm_create(draw, gallivm);
   }
#endif

   if (!draw_init(draw))
      goto fail;

   draw->pipe = pipe;

   return draw;

fail:
   draw_destroy( draw );
   return NULL;
}
Пример #2
0
PIPE_ALIGN_STACK
static boolean
test_printf(unsigned verbose, FILE *fp,
            const struct printf_test_case *testcase)
{
   struct gallivm_state *gallivm;
   LLVMValueRef test;
   test_printf_t test_printf_func;
   boolean success = TRUE;

   gallivm = gallivm_create("test_module", LLVMGetGlobalContext());

   test = add_printf_test(gallivm);

   gallivm_compile_module(gallivm);

   test_printf_func = (test_printf_t) gallivm_jit_function(gallivm, test);

   gallivm_free_ir(gallivm);

   test_printf_func(0);

   gallivm_destroy(gallivm);

   return success;
}
Пример #3
0
int main(int argc, char **argv)
{
   unsigned verbose = 0;
   FILE *fp = NULL;
   unsigned long n = 1000;
   unsigned i;
   boolean success;
   boolean single = FALSE;
   struct gallivm_state *gallivm;

   for(i = 1; i < argc; ++i) {
      if(strcmp(argv[i], "-v") == 0)
         ++verbose;
      else if(strcmp(argv[i], "-s") == 0)
         single = TRUE;
      else if(strcmp(argv[i], "-o") == 0)
         fp = fopen(argv[++i], "wt");
      else
         n = atoi(argv[i]);
   }

   lp_build_init();

   gallivm = gallivm_create();

   util_cpu_detect();

   if(fp) {
      /* Warm up the caches */
      test_some(gallivm, 0, NULL, 100);

      write_tsv_header(fp);
   }
      
   if (single)
      success = test_single(gallivm, verbose, fp);
   else if (n)
      success = test_some(gallivm, verbose, fp, n);
   else
      success = test_all(gallivm, verbose, fp);

   if(fp)
      fclose(fp);

   return success ? 0 : 1;
}
PIPE_ALIGN_STACK
static boolean
test_one(unsigned verbose,
         FILE *fp,
         struct lp_type src_type,
         struct lp_type dst_type)
{
   struct gallivm_state *gallivm;
   LLVMValueRef func = NULL;
   conv_test_ptr_t conv_test_ptr;
   boolean success;
   const unsigned n = LP_TEST_NUM_SAMPLES;
   int64_t cycles[LP_TEST_NUM_SAMPLES];
   double cycles_avg = 0.0;
   unsigned num_srcs;
   unsigned num_dsts;
   double eps;
   unsigned i, j;

   if ((src_type.width >= dst_type.width && src_type.length > dst_type.length) ||
       (src_type.width <= dst_type.width && src_type.length < dst_type.length)) {
      return TRUE;
   }

   /* Known failures
    * - fixed point 32 -> float 32
    * - float 32 -> signed normalised integer 32
    */
   if ((src_type.floating && !dst_type.floating && dst_type.sign && dst_type.norm && src_type.width == dst_type.width) ||
       (!src_type.floating && dst_type.floating && src_type.fixed && src_type.width == dst_type.width)) {
      return TRUE;
   }

   /* Known failures
    * - fixed point 32 -> float 32
    * - float 32 -> signed normalised integer 32
    */
   if ((src_type.floating && !dst_type.floating && dst_type.sign && dst_type.norm && src_type.width == dst_type.width) ||
       (!src_type.floating && dst_type.floating && src_type.fixed && src_type.width == dst_type.width)) {
      return TRUE;
   }

   if(verbose >= 1)
      dump_conv_types(stderr, src_type, dst_type);

   if (src_type.length > dst_type.length) {
      num_srcs = 1;
      num_dsts = src_type.length/dst_type.length;
   }
   else if (src_type.length < dst_type.length) {
      num_dsts = 1;
      num_srcs = dst_type.length/src_type.length;
   }
   else  {
      num_dsts = 1;
      num_srcs = 1;
   }

   /* We must not loose or gain channels. Only precision */
   assert(src_type.length * num_srcs == dst_type.length * num_dsts);

   eps = MAX2(lp_const_eps(src_type), lp_const_eps(dst_type));

   gallivm = gallivm_create();

   func = add_conv_test(gallivm, src_type, num_srcs, dst_type, num_dsts);

   gallivm_compile_module(gallivm);

   conv_test_ptr = (conv_test_ptr_t)gallivm_jit_function(gallivm, func);

   success = TRUE;
   for(i = 0; i < n && success; ++i) {
      unsigned src_stride = src_type.length*src_type.width/8;
      unsigned dst_stride = dst_type.length*dst_type.width/8;
      PIPE_ALIGN_VAR(LP_MIN_VECTOR_ALIGN) uint8_t src[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
      PIPE_ALIGN_VAR(LP_MIN_VECTOR_ALIGN) uint8_t dst[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
      double fref[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
      uint8_t ref[LP_MAX_VECTOR_LENGTH*LP_MAX_VECTOR_LENGTH];
      int64_t start_counter = 0;
      int64_t end_counter = 0;

      for(j = 0; j < num_srcs; ++j) {
         random_vec(src_type, src + j*src_stride);
         read_vec(src_type, src + j*src_stride, fref + j*src_type.length);
      }

      for(j = 0; j < num_dsts; ++j) {
         write_vec(dst_type, ref + j*dst_stride, fref + j*dst_type.length);
      }

      start_counter = rdtsc();
      conv_test_ptr(src, dst);
      end_counter = rdtsc();

      cycles[i] = end_counter - start_counter;

      for(j = 0; j < num_dsts; ++j) {
         if(!compare_vec_with_eps(dst_type, dst + j*dst_stride, ref + j*dst_stride, eps))
            success = FALSE;
      }

      if (!success || verbose >= 3) {
         if(verbose < 1)
            dump_conv_types(stderr, src_type, dst_type);
         if (success) {
            fprintf(stderr, "PASS\n");
         }
         else {
            fprintf(stderr, "MISMATCH\n");
         }

         for(j = 0; j < num_srcs; ++j) {
            fprintf(stderr, "  Src%u: ", j);
            dump_vec(stderr, src_type, src + j*src_stride);
            fprintf(stderr, "\n");
         }

#if 1
         fprintf(stderr, "  Ref: ");
         for(j = 0; j < src_type.length*num_srcs; ++j)
            fprintf(stderr, " %f", fref[j]);
         fprintf(stderr, "\n");
#endif

         for(j = 0; j < num_dsts; ++j) {
            fprintf(stderr, "  Dst%u: ", j);
            dump_vec(stderr, dst_type, dst + j*dst_stride);
            fprintf(stderr, "\n");

            fprintf(stderr, "  Ref%u: ", j);
            dump_vec(stderr, dst_type, ref + j*dst_stride);
            fprintf(stderr, "\n");
         }
      }
   }

   /*
    * Unfortunately the output of cycle counter is not very reliable as it comes
    * -- sometimes we get outliers (due IRQs perhaps?) which are
    * better removed to avoid random or biased data.
    */
   {
      double sum = 0.0, sum2 = 0.0;
      double avg, std;
      unsigned m;

      for(i = 0; i < n; ++i) {
         sum += cycles[i];
         sum2 += cycles[i]*cycles[i];
      }

      avg = sum/n;
      std = sqrtf((sum2 - n*avg*avg)/n);

      m = 0;
      sum = 0.0;
      for(i = 0; i < n; ++i) {
         if(fabs(cycles[i] - avg) <= 4.0*std) {
            sum += cycles[i];
            ++m;
         }
      }

      cycles_avg = sum/m;

   }

   if(fp)
      write_tsv_row(fp, src_type, dst_type, cycles_avg, success);

   gallivm_free_function(gallivm, func, conv_test_ptr);

   gallivm_destroy(gallivm);

   return success;
}
Пример #5
0
PIPE_ALIGN_STACK
static boolean
test_one(unsigned verbose,
         FILE *fp,
         const struct pipe_blend_state *blend,
         struct lp_type type)
{
    struct gallivm_state *gallivm;
    LLVMValueRef func = NULL;
    blend_test_ptr_t blend_test_ptr;
    boolean success;
    const unsigned n = LP_TEST_NUM_SAMPLES;
    int64_t cycles[LP_TEST_NUM_SAMPLES];
    double cycles_avg = 0.0;
    unsigned i, j;
    const unsigned stride = lp_type_width(type)/8;

    if(verbose >= 1)
        dump_blend_type(stdout, blend, type);

    gallivm = gallivm_create();

    func = add_blend_test(gallivm, blend, type);

    gallivm_compile_module(gallivm);

    blend_test_ptr = (blend_test_ptr_t)gallivm_jit_function(gallivm, func);

    success = TRUE;

    {
        uint8_t *src, *dst, *con, *res, *ref;
        src = align_malloc(stride, stride);
        dst = align_malloc(stride, stride);
        con = align_malloc(stride, stride);
        res = align_malloc(stride, stride);
        ref = align_malloc(stride, stride);

        for(i = 0; i < n && success; ++i) {
            int64_t start_counter = 0;
            int64_t end_counter = 0;

            random_vec(type, src);
            random_vec(type, dst);
            random_vec(type, con);

            {
                double fsrc[LP_MAX_VECTOR_LENGTH];
                double fdst[LP_MAX_VECTOR_LENGTH];
                double fcon[LP_MAX_VECTOR_LENGTH];
                double fref[LP_MAX_VECTOR_LENGTH];

                read_vec(type, src, fsrc);
                read_vec(type, dst, fdst);
                read_vec(type, con, fcon);

                for(j = 0; j < type.length; j += 4)
                    compute_blend_ref(blend, fsrc + j, fdst + j, fcon + j, fref + j);

                write_vec(type, ref, fref);
            }

            start_counter = rdtsc();
            blend_test_ptr(src, dst, con, res);
            end_counter = rdtsc();

            cycles[i] = end_counter - start_counter;

            if(!compare_vec(type, res, ref)) {
                success = FALSE;

                if(verbose < 1)
                    dump_blend_type(stderr, blend, type);
                fprintf(stderr, "MISMATCH\n");

                fprintf(stderr, "  Src: ");
                dump_vec(stderr, type, src);
                fprintf(stderr, "\n");

                fprintf(stderr, "  Dst: ");
                dump_vec(stderr, type, dst);
                fprintf(stderr, "\n");

                fprintf(stderr, "  Con: ");
                dump_vec(stderr, type, con);
                fprintf(stderr, "\n");

                fprintf(stderr, "  Res: ");
                dump_vec(stderr, type, res);
                fprintf(stderr, "\n");

                fprintf(stderr, "  Ref: ");
                dump_vec(stderr, type, ref);
                fprintf(stderr, "\n");
            }
        }
        align_free(src);
        align_free(dst);
        align_free(con);
        align_free(res);
        align_free(ref);
    }

    /*
     * Unfortunately the output of cycle counter is not very reliable as it comes
     * -- sometimes we get outliers (due IRQs perhaps?) which are
     * better removed to avoid random or biased data.
     */
    {
        double sum = 0.0, sum2 = 0.0;
        double avg, std;
        unsigned m;

        for(i = 0; i < n; ++i) {
            sum += cycles[i];
            sum2 += cycles[i]*cycles[i];
        }

        avg = sum/n;
        std = sqrtf((sum2 - n*avg*avg)/n);

        m = 0;
        sum = 0.0;
        for(i = 0; i < n; ++i) {
            if(fabs(cycles[i] - avg) <= 4.0*std) {
                sum += cycles[i];
                ++m;
            }
        }

        cycles_avg = sum/m;

    }

    if(fp)
        write_tsv_row(fp, blend, type, cycles_avg, success);

    gallivm_free_function(gallivm, func, blend_test_ptr);

    gallivm_destroy(gallivm);

    return success;
}
/*
 * Test one LLVM unary arithmetic builder function.
 */
static boolean
test_unary(unsigned verbose, FILE *fp, const struct unary_test_t *test)
{
   struct gallivm_state *gallivm;
   LLVMValueRef test_func;
   unary_func_t test_func_jit;
   boolean success = TRUE;
   int i, j;
   int length = lp_native_vector_width / 32;
   float *in, *out;

   in = align_malloc(length * 4, length * 4);
   out = align_malloc(length * 4, length * 4);

   /* random NaNs or 0s could wreak havoc */
   for (i = 0; i < length; i++) {
      in[i] = 1.0;
   }

   gallivm = gallivm_create();

   test_func = build_unary_test_func(gallivm, test);

   gallivm_compile_module(gallivm);

   test_func_jit = (unary_func_t) gallivm_jit_function(gallivm, test_func);

   for (j = 0; j < (test->num_values + length - 1) / length; j++) {
      int num_vals = ((j + 1) * length <= test->num_values) ? length :
                                                              test->num_values % length;

      for (i = 0; i < num_vals; ++i) {
         in[i] = test->values[i+j*length];
      }

      test_func_jit(out, in);
      for (i = 0; i < num_vals; ++i) {
         float ref = test->ref(in[i]);
         double error, precision;
         bool pass;

         if (util_inf_sign(ref) && util_inf_sign(out[i]) == util_inf_sign(ref)) {
            error = 0;
         } else {
            error = fabs(out[i] - ref);
         }
         precision = error ? -log2(error/fabs(ref)) : FLT_MANT_DIG;

         pass = precision >= test->precision;

         if (isnan(ref)) {
            continue;
         }

         if (!pass || verbose) {
            printf("%s(%.9g): ref = %.9g, out = %.9g, precision = %f bits, %s\n",
                  test->name, in[i], ref, out[i], precision,
                  pass ? "PASS" : "FAIL");
         }

         if (!pass) {
            success = FALSE;
         }
      }
   }

   gallivm_free_function(gallivm, test_func, test_func_jit);

   gallivm_destroy(gallivm);

   align_free(in);
   align_free(out);

   return success;
}