static void init_module(compile_t* c, ast_t* program, pass_opt_t* opt) { c->opt = opt; // Get the first package and the builtin package. ast_t* package = ast_child(program); ast_t* builtin = ast_sibling(package); // If we have only one package, we are compiling builtin itself. if(builtin == NULL) builtin = package; c->reach = reach_new(); // The name of the first package is the name of the program. c->filename = package_filename(package); // LLVM context and machine settings. if(c->opt->library || target_is_ilp32(opt->triple)) c->callconv = LLVMCCallConv; else c->callconv = LLVMFastCallConv; if(!c->opt->release || c->opt->library || c->opt->extfun) c->linkage = LLVMExternalLinkage; else c->linkage = LLVMPrivateLinkage; c->context = LLVMContextCreate(); c->machine = make_machine(opt); c->target_data = LLVMGetTargetMachineData(c->machine); // Create a module. c->module = LLVMModuleCreateWithNameInContext(c->filename, c->context); // Set the target triple. LLVMSetTarget(c->module, opt->triple); // Set the data layout. char* layout = LLVMCopyStringRepOfTargetData(c->target_data); LLVMSetDataLayout(c->module, layout); LLVMDisposeMessage(layout); // IR builder. c->builder = LLVMCreateBuilderInContext(c->context); c->di = LLVMNewDIBuilder(c->module); // TODO: what LANG id should be used? c->di_unit = LLVMDIBuilderCreateCompileUnit(c->di, 0x0004, package_filename(package), package_path(package), "ponyc-" PONY_VERSION, c->opt->release); // Empty frame stack. c->frame = NULL; }
LLVMModuleRef radeon_llvm_parse_bitcode(const unsigned char * bitcode, unsigned bitcode_len) { LLVMMemoryBufferRef buf; LLVMContextRef ctx = LLVMContextCreate(); LLVMModuleRef module; buf = LLVMCreateMemoryBufferWithMemoryRangeCopy((const char*)bitcode, bitcode_len, "radeon"); LLVMParseBitcodeInContext(ctx, buf, &module, NULL); LLVMDisposeMemoryBuffer(buf); return module; }
void *evergreen_create_compute_state( struct pipe_context *ctx_, const const struct pipe_compute_state *cso) { struct r600_context *ctx = (struct r600_context *)ctx_; struct r600_pipe_compute *shader = CALLOC_STRUCT(r600_pipe_compute); #ifdef HAVE_OPENCL const struct pipe_llvm_program_header * header; const char *code; void *p; boolean use_kill; COMPUTE_DBG(ctx->screen, "*** evergreen_create_compute_state\n"); header = cso->prog; code = cso->prog + sizeof(struct pipe_llvm_program_header); #if HAVE_LLVM < 0x0306 (void)use_kill; (void)p; shader->llvm_ctx = LLVMContextCreate(); shader->num_kernels = radeon_llvm_get_num_kernels(shader->llvm_ctx, code, header->num_bytes); shader->kernels = CALLOC(sizeof(struct r600_kernel), shader->num_kernels); { unsigned i; for (i = 0; i < shader->num_kernels; i++) { struct r600_kernel *kernel = &shader->kernels[i]; kernel->llvm_module = radeon_llvm_get_kernel_module( shader->llvm_ctx, i, code, header->num_bytes); } } #else radeon_shader_binary_init(&shader->binary); radeon_elf_read(code, header->num_bytes, &shader->binary); r600_create_shader(&shader->bc, &shader->binary, &use_kill); shader->code_bo = r600_compute_buffer_alloc_vram(ctx->screen, shader->bc.ndw * 4); p = r600_buffer_map_sync_with_rings(&ctx->b, shader->code_bo, PIPE_TRANSFER_WRITE); memcpy(p, shader->bc.bytecode, shader->bc.ndw * 4); ctx->b.ws->buffer_unmap(shader->code_bo->buf); #endif #endif shader->ctx = ctx; shader->local_size = cso->req_local_mem; shader->private_size = cso->req_private_mem; shader->input_size = cso->req_input_mem; return shader; }
int main(int argc, char **argv) { int n = argc > 1 ? atol(argv[1]) : 24; LLVMInitializeNativeTarget(); LLVMLinkInInterpreter(); LLVMContextRef Context = LLVMContextCreate(); // Create some module to put our function into it. LLVMModuleRef M = LLVMModuleCreateWithNameInContext("test", Context); // We are about to create the "fib" function: LLVMValueRef FibF = CreateFibFunction(M, Context); // Now we going to create JIT LLVMExecutionEngineRef EE; char * outError; if (LLVMCreateInterpreterForModule(&EE, M, &outError) != 0) { printf("%s\n", outError); return 1; } printf("verifying...\n"); if (LLVMVerifyModule(M, LLVMReturnStatusAction, &outError) != 0) { printf("%s\n", outError); return 1; } printf("OK\n"); printf("We just constructed this LLVM module:\n\n---------\n"); printf("%s\n", LLVMPrintModuleToString(M)); LLVMGenericValueRef Args = LLVMCreateGenericValueOfInt(LLVMInt32TypeInContext(Context), n, 0); LLVMGenericValueRef Result = LLVMRunFunction(EE, FibF, 1, &Args); printf("Result: %llu\n", LLVMGenericValueToInt(Result, 0)); return 0; }
static void init_module(compile_t* c, ast_t* program, pass_opt_t* opt) { c->opt = opt; // Get the first package and the builtin package. ast_t* package = ast_child(program); ast_t* builtin = ast_sibling(package); // If we have only one package, we are compiling builtin itself. if(builtin == NULL) builtin = package; c->reachable = reach_new(); reach_primitives(c->reachable, opt, builtin); // The name of the first package is the name of the program. c->filename = package_filename(package); // LLVM context and machine settings. c->context = LLVMContextCreate(); c->machine = make_machine(opt); c->target_data = LLVMGetTargetMachineData(c->machine); // Create a module. c->module = LLVMModuleCreateWithNameInContext(c->filename, c->context); // Set the target triple. LLVMSetTarget(c->module, opt->triple); // Set the data layout. char* layout = LLVMCopyStringRepOfTargetData(c->target_data); LLVMSetDataLayout(c->module, layout); LLVMDisposeMessage(layout); // IR builder. c->builder = LLVMCreateBuilderInContext(c->context); // Empty frame stack. c->frame = NULL; }
void *evergreen_create_compute_state( struct pipe_context *ctx_, const const struct pipe_compute_state *cso) { struct r600_context *ctx = (struct r600_context *)ctx_; struct r600_pipe_compute *shader = CALLOC_STRUCT(r600_pipe_compute); #ifdef HAVE_OPENCL const struct pipe_llvm_program_header * header; const unsigned char * code; unsigned i; shader->llvm_ctx = LLVMContextCreate(); COMPUTE_DBG(ctx->screen, "*** evergreen_create_compute_state\n"); header = cso->prog; code = cso->prog + sizeof(struct pipe_llvm_program_header); #endif shader->ctx = (struct r600_context*)ctx; shader->local_size = cso->req_local_mem; shader->private_size = cso->req_private_mem; shader->input_size = cso->req_input_mem; #ifdef HAVE_OPENCL shader->num_kernels = radeon_llvm_get_num_kernels(shader->llvm_ctx, code, header->num_bytes); shader->kernels = CALLOC(sizeof(struct r600_kernel), shader->num_kernels); for (i = 0; i < shader->num_kernels; i++) { struct r600_kernel *kernel = &shader->kernels[i]; kernel->llvm_module = radeon_llvm_get_kernel_module(shader->llvm_ctx, i, code, header->num_bytes); } #endif return shader; }
/** * Allocate gallivm LLVM objects. * \return TRUE for success, FALSE for failure */ static boolean init_gallivm_state(struct gallivm_state *gallivm) { assert(!gallivm->context); assert(!gallivm->module); assert(!gallivm->provider); lp_build_init(); gallivm->context = LLVMContextCreate(); if (!gallivm->context) goto fail; gallivm->module = LLVMModuleCreateWithNameInContext("gallivm", gallivm->context); if (!gallivm->module) goto fail; gallivm->provider = LLVMCreateModuleProviderForExistingModule(gallivm->module); if (!gallivm->provider) goto fail; if (!GlobalEngine) { /* We can only create one LLVMExecutionEngine (w/ LLVM 2.6 anyway) */ enum LLVM_CodeGenOpt_Level optlevel; char *error = NULL; if (gallivm_debug & GALLIVM_DEBUG_NO_OPT) { optlevel = None; } else { optlevel = Default; } if (LLVMCreateJITCompiler(&GlobalEngine, gallivm->provider, (unsigned) optlevel, &error)) { _debug_printf("%s\n", error); LLVMDisposeMessage(error); goto fail; } #if defined(DEBUG) || defined(PROFILE) lp_register_oprofile_jit_event_listener(GlobalEngine); #endif } gallivm->engine = GlobalEngine; LLVMAddModuleProvider(gallivm->engine, gallivm->provider);//new gallivm->target = LLVMGetExecutionEngineTargetData(gallivm->engine); if (!gallivm->target) goto fail; if (!create_pass_manager(gallivm)) goto fail; gallivm->builder = LLVMCreateBuilderInContext(gallivm->context); if (!gallivm->builder) goto fail; return TRUE; fail: free_gallivm_state(gallivm); return FALSE; }
PIPE_ALIGN_STACK static boolean test_one(unsigned verbose, FILE *fp, struct lp_type src_type, struct lp_type dst_type) { LLVMContextRef context; 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)); if (dst_type.norm && dst_type.sign && src_type.sign && !src_type.floating) { /* * This is quite inaccurate due to shift being used. * I don't think it's possible to hit such conversions with * llvmpipe though. */ eps *= 2; } context = LLVMContextCreate(); gallivm = gallivm_create("test_module", context); 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); gallivm_free_ir(gallivm); 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_destroy(gallivm); LLVMContextDispose(context); return success; }
/** * Allocate gallivm LLVM objects. * \return TRUE for success, FALSE for failure */ static boolean init_gallivm_state(struct gallivm_state *gallivm) { assert(!gallivm->context); assert(!gallivm->module); assert(!gallivm->provider); lp_build_init(); if (!gallivm_context) { gallivm_context = LLVMContextCreate(); } gallivm->context = gallivm_context; if (!gallivm->context) goto fail; gallivm->module = LLVMModuleCreateWithNameInContext("gallivm", gallivm->context); if (!gallivm->module) goto fail; gallivm->provider = LLVMCreateModuleProviderForExistingModule(gallivm->module); if (!gallivm->provider) goto fail; gallivm->builder = LLVMCreateBuilderInContext(gallivm->context); if (!gallivm->builder) goto fail; /* FIXME: MC-JIT only allows compiling one module at a time, and it must be * complete when MC-JIT is created. So defer the MC-JIT engine creation for * now. */ #if !USE_MCJIT if (!init_gallivm_engine(gallivm)) { goto fail; } #else /* * MC-JIT engine compiles the module immediately on creation, so we can't * obtain the target data from it. Instead we create a target data layout * from a string. * * The produced layout strings are not precisely the same, but should make * no difference for the kind of optimization passes we run. * * For reference this is the layout string on x64: * * e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64 * * See also: * - http://llvm.org/docs/LangRef.html#datalayout */ { const unsigned pointer_size = 8 * sizeof(void *); char layout[512]; util_snprintf(layout, sizeof layout, "%c-p:%u:%u:%u-i64:64:64-a0:0:%u-s0:%u:%u", #ifdef PIPE_ARCH_LITTLE_ENDIAN 'e', // little endian #else 'E', // big endian #endif pointer_size, pointer_size, pointer_size, // pointer size, abi alignment, preferred alignment pointer_size, // aggregate preferred alignment pointer_size, pointer_size); // stack objects abi alignment, preferred alignment gallivm->target = LLVMCreateTargetData(layout); if (!gallivm->target) { return FALSE; } } #endif if (!create_pass_manager(gallivm)) goto fail; return TRUE; fail: free_gallivm_state(gallivm); return FALSE; }
/* * machine_init * * Initializes the machine context. */ machinedef_t * machine_init (const char *mspec) { machine_ctx_t m; machinedef_t *mach; char *err; LLVMTargetRef target; char *machspec = (char *) mspec; unsigned long allosize; if (machspec == 0) { machspec = LLVM_DEFAULT_TARGET_TRIPLE; } allosize = (sizeof(struct machine_ctx_s) + sizeof(struct machinedef_s) + strlen(machspec) + 1); m = malloc(allosize); if (m == 0) return 0; memset(m, 0, allosize); m->triple = ((char *) m) + (sizeof(struct machine_ctx_s) + sizeof(struct machinedef_s)); memcpy(m->triple, machspec, strlen(machspec)); LLVM_NATIVE_TARGETINFO(); LLVM_NATIVE_TARGET(); LLVM_NATIVE_TARGETMC(); LLVM_NATIVE_ASMPRINTER(); LLVM_NATIVE_ASMPARSER(); err = 0; target = HelperLookupTarget(machspec, &err); if (target == 0) { if (err != 0) free(err); free(m); return 0; } m->target_machine = LLVMCreateTargetMachine(target, (char *)machspec, "", "", LLVMCodeGenLevelDefault, LLVMRelocPIC, LLVMCodeModelDefault); if (m->target_machine == 0) { free(m); return 0; } HelperSetAsmVerbosity(m->target_machine, 1); m->llvmctx = LLVMContextCreate(); if (m->llvmctx == 0) { LLVMDisposeTargetMachine(m->target_machine); free(m); return 0; } m->is_macho = (strstr(machspec, "darwin") != 0); // XXX mach = (machinedef_t *)(m + 1); mach->machctx = m; mach->bpaddr = sizeof(int *) * 8; mach->bpval = sizeof(long) * 8; mach->bpunit = 8; mach->charsize_count = 1; mach->charsizes[0] = 8; mach->flags = MACH_M_SIGNEXT | MACH_M_LTC_INIT; mach->max_align = 4; mach->reg_count = 16; return mach; } /* machine_init */
int main(int c, char **v) { LLVMContextRef *contexts; LLVMModuleRef *modules; char *error; const char *mode = "opt"; const char **filenames; unsigned numFiles; unsigned i; bool moreOptions; static int verboseFlag = 0; static int timingFlag = 0; static int disassembleFlag = 0; bool manyContexts = true; double beforeAll; if (c == 1) usage(); moreOptions = true; while (moreOptions) { static struct option longOptions[] = { {"verbose", no_argument, &verboseFlag, 1}, {"timing", no_argument, &timingFlag, 1}, {"disassemble", no_argument, &disassembleFlag, 1}, {"mode", required_argument, 0, 0}, {"contexts", required_argument, 0, 0}, {"help", no_argument, 0, 0} }; int optionIndex; int optionValue; optionValue = getopt_long(c, v, "", longOptions, &optionIndex); switch (optionValue) { case -1: moreOptions = false; break; case 0: { const char* thisOption = longOptions[optionIndex].name; if (!strcmp(thisOption, "help")) usage(); if (!strcmp(thisOption, "contexts")) { if (!strcasecmp(optarg, "one")) manyContexts = false; else if (!strcasecmp(optarg, "many")) manyContexts = true; else { fprintf(stderr, "Invalid argument for --contexts.\n"); exit(1); } break; } if (!strcmp(thisOption, "mode")) { mode = strdup(optarg); break; } break; } case '?': exit(0); break; default: printf("optionValue = %d\n", optionValue); abort(); break; } } LLVMLinkInMCJIT(); LLVMInitializeNativeTarget(); LLVMInitializeX86AsmPrinter(); LLVMInitializeX86Disassembler(); filenames = (const char **)(v + optind); numFiles = c - optind; contexts = malloc(sizeof(LLVMContextRef) * numFiles); modules = malloc(sizeof(LLVMModuleRef) * numFiles); if (manyContexts) { for (i = 0; i < numFiles; ++i) contexts[i] = LLVMContextCreate(); } else { LLVMContextRef context = LLVMContextCreate(); for (i = 0; i < numFiles; ++i) contexts[i] = context; } for (i = 0; i < numFiles; ++i) { LLVMMemoryBufferRef buffer; const char* filename = filenames[i]; if (LLVMCreateMemoryBufferWithContentsOfFile(filename, &buffer, &error)) { fprintf(stderr, "Error reading file %s: %s\n", filename, error); exit(1); } if (LLVMParseBitcodeInContext(contexts[i], buffer, modules + i, &error)) { fprintf(stderr, "Error parsing file %s: %s\n", filename, error); exit(1); } LLVMDisposeMemoryBuffer(buffer); if (verboseFlag) { printf("Module #%u (%s) after parsing:\n", i, filename); LLVMDumpModule(modules[i]); } } if (verboseFlag) printf("Generating code for modules...\n"); if (timingFlag) beforeAll = currentTime(); for (i = 0; i < numFiles; ++i) { LLVMModuleRef module; LLVMExecutionEngineRef engine; struct LLVMMCJITCompilerOptions options; LLVMValueRef value; LLVMPassManagerRef functionPasses = 0; LLVMPassManagerRef modulePasses = 0; double before; if (timingFlag) before = currentTime(); module = modules[i]; LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); options.OptLevel = 2; options.EnableFastISel = 0; options.MCJMM = LLVMCreateSimpleMCJITMemoryManager( 0, mmAllocateCodeSection, mmAllocateDataSection, mmApplyPermissions, mmDestroy); if (LLVMCreateMCJITCompilerForModule(&engine, module, &options, sizeof(options), &error)) { fprintf(stderr, "Error building MCJIT: %s\n", error); exit(1); } if (!strcasecmp(mode, "simple")) { modulePasses = LLVMCreatePassManager(); LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), modulePasses); LLVMAddConstantPropagationPass(modulePasses); LLVMAddInstructionCombiningPass(modulePasses); LLVMAddPromoteMemoryToRegisterPass(modulePasses); LLVMAddBasicAliasAnalysisPass(modulePasses); LLVMAddTypeBasedAliasAnalysisPass(modulePasses); LLVMAddGVNPass(modulePasses); LLVMAddCFGSimplificationPass(modulePasses); LLVMRunPassManager(modulePasses, module); } else if (!strcasecmp(mode, "opt")) { LLVMPassManagerBuilderRef passBuilder; passBuilder = LLVMPassManagerBuilderCreate(); LLVMPassManagerBuilderSetOptLevel(passBuilder, 2); LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0); functionPasses = LLVMCreateFunctionPassManagerForModule(module); modulePasses = LLVMCreatePassManager(); LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), modulePasses); LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder, functionPasses); LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses); LLVMPassManagerBuilderDispose(passBuilder); LLVMInitializeFunctionPassManager(functionPasses); for (value = LLVMGetFirstFunction(module); value; value = LLVMGetNextFunction(value)) LLVMRunFunctionPassManager(functionPasses, value); LLVMFinalizeFunctionPassManager(functionPasses); LLVMRunPassManager(modulePasses, module); } else { fprintf(stderr, "Bad optimization mode: %s.\n", mode); fprintf(stderr, "Valid modes are: \"simple\" or \"opt\".\n"); exit(1); } if (verboseFlag) { printf("Module #%d (%s) after optimization:\n", i, filenames[i]); LLVMDumpModule(module); } for (value = LLVMGetFirstFunction(module); value; value = LLVMGetNextFunction(value)) { if (LLVMIsDeclaration(value)) continue; LLVMGetPointerToGlobal(engine, value); } if (functionPasses) LLVMDisposePassManager(functionPasses); if (modulePasses) LLVMDisposePassManager(modulePasses); LLVMDisposeExecutionEngine(engine); if (timingFlag) { double after = currentTime(); printf("Module #%d (%s) took %lf ms.\n", i, filenames[i], (after - before) * 1000); } } if (timingFlag) { double after = currentTime(); printf("Compilation took a total of %lf ms.\n", (after - beforeAll) * 1000); } if (disassembleFlag) { LLVMDisasmContextRef disassembler; struct MemorySection *section; disassembler = LLVMCreateDisasm("x86_64-apple-darwin", 0, 0, 0, symbolLookupCallback); if (!disassembler) { fprintf(stderr, "Error building disassembler.\n"); exit(1); } for (section = sectionHead; section; section = section->next) { printf("Disassembly for section %p:\n", section); char pcString[20]; char instructionString[1000]; uint8_t *pc; uint8_t *end; pc = section->start; end = pc + section->size; while (pc < end) { snprintf( pcString, sizeof(pcString), "0x%lx", (unsigned long)(uintptr_t)pc); size_t instructionSize = LLVMDisasmInstruction( disassembler, pc, end - pc, (uintptr_t)pc, instructionString, sizeof(instructionString)); if (!instructionSize) snprintf(instructionString, sizeof(instructionString), ".byte 0x%02x", *pc++); else pc += instructionSize; printf(" %16s: %s\n", pcString, instructionString); } } } return 0; }
PIPE_ALIGN_STACK static boolean test_one(unsigned verbose, FILE *fp, const struct pipe_blend_state *blend, struct lp_type type) { LLVMContextRef context; 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); context = LLVMContextCreate(); gallivm = gallivm_create("test_module", context); func = add_blend_test(gallivm, blend, type); gallivm_compile_module(gallivm); blend_test_ptr = (blend_test_ptr_t)gallivm_jit_function(gallivm, func); gallivm_free_ir(gallivm); success = TRUE; { uint8_t *src, *src1, *dst, *con, *res, *ref; src = align_malloc(stride, stride); src1 = 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, src1); random_vec(type, dst); random_vec(type, con); { double fsrc[LP_MAX_VECTOR_LENGTH]; double fsrc1[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, src1, fsrc1); read_vec(type, dst, fdst); read_vec(type, con, fcon); for(j = 0; j < type.length; j += 4) compute_blend_ref(blend, fsrc + j, fsrc1 + j, fdst + j, fcon + j, fref + j); write_vec(type, ref, fref); } start_counter = rdtsc(); blend_test_ptr(src, src1, 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, " Src1: "); dump_vec(stderr, type, src1); 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(src1); 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_destroy(gallivm); LLVMContextDispose(context); return success; }