LLVMValueRef lp_build_array_get(struct gallivm_state *gallivm, LLVMValueRef ptr, LLVMValueRef index) { LLVMValueRef element_ptr; LLVMValueRef res; assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(ptr))) == LLVMArrayTypeKind); element_ptr = lp_build_array_get_ptr(gallivm, ptr, index); res = LLVMBuildLoad(gallivm->builder, element_ptr, ""); #ifdef DEBUG lp_build_name(res, "%s[%s]", LLVMGetValueName(ptr), LLVMGetValueName(index)); #endif return res; }
LLVMValueRef lp_build_pointer_get_unaligned(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef index, unsigned alignment) { LLVMValueRef element_ptr; LLVMValueRef res; assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind); element_ptr = LLVMBuildGEP(builder, ptr, &index, 1, ""); res = LLVMBuildLoad(builder, element_ptr, ""); lp_set_load_alignment(res, alignment); #ifdef DEBUG lp_build_name(res, "%s[%s]", LLVMGetValueName(ptr), LLVMGetValueName(index)); #endif return res; }
LLVMValueRef lp_build_array_get_ptr(struct gallivm_state *gallivm, LLVMValueRef ptr, LLVMValueRef index) { LLVMValueRef indices[2]; LLVMValueRef element_ptr; assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(ptr))) == LLVMArrayTypeKind); indices[0] = lp_build_const_int32(gallivm, 0); indices[1] = index; element_ptr = LLVMBuildGEP(gallivm->builder, ptr, indices, Elements(indices), ""); #ifdef DEBUG lp_build_name(element_ptr, "&%s[%s]", LLVMGetValueName(ptr), LLVMGetValueName(index)); #endif return element_ptr; }
int module_list_functions(void) { LLVMModuleRef M = load_module(false, false); LLVMValueRef f; f = LLVMGetFirstFunction(M); while (f) { if (LLVMIsDeclaration(f)) { printf("FunctionDeclaration: %s\n", LLVMGetValueName(f)); } else { LLVMBasicBlockRef bb; LLVMValueRef isn; unsigned nisn = 0; unsigned nbb = 0; printf("FunctionDefinition: %s [#bb=%u]\n", LLVMGetValueName(f), LLVMCountBasicBlocks(f)); for (bb = LLVMGetFirstBasicBlock(f); bb; bb = LLVMGetNextBasicBlock(bb)) { nbb++; for (isn = LLVMGetFirstInstruction(bb); isn; isn = LLVMGetNextInstruction(isn)) { nisn++; if (LLVMIsACallInst(isn)) { LLVMValueRef callee = LLVMGetOperand(isn, LLVMGetNumOperands(isn) - 1); printf(" calls: %s\n", LLVMGetValueName(callee)); } } } printf(" #isn: %u\n", nisn); printf(" #bb: %u\n\n", nbb); } f = LLVMGetNextFunction(f); } LLVMDisposeModule(M); return 0; }
LLVMValueRef lp_build_struct_get(struct gallivm_state *gallivm, LLVMValueRef ptr, unsigned member, const char *name) { LLVMValueRef member_ptr; LLVMValueRef res; assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(ptr))) == LLVMStructTypeKind); member_ptr = lp_build_struct_get_ptr(gallivm, ptr, member, name); res = LLVMBuildLoad(gallivm->builder, member_ptr, ""); lp_build_name(res, "%s.%s", LLVMGetValueName(ptr), name); return res; }
LLVMValueRef lp_build_struct_get_ptr(struct gallivm_state *gallivm, LLVMValueRef ptr, unsigned member, const char *name) { LLVMValueRef indices[2]; LLVMValueRef member_ptr; assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(ptr))) == LLVMStructTypeKind); indices[0] = lp_build_const_int32(gallivm, 0); indices[1] = lp_build_const_int32(gallivm, member); member_ptr = LLVMBuildGEP(gallivm->builder, ptr, indices, Elements(indices), ""); lp_build_name(member_ptr, "%s.%s_ptr", LLVMGetValueName(ptr), name); return member_ptr; }
/** * Validate and optimze a function. */ static void gallivm_optimize_function(struct gallivm_state *gallivm, LLVMValueRef func) { if (0) { debug_printf("optimizing %s...\n", LLVMGetValueName(func)); } assert(gallivm->passmgr); /* Apply optimizations to LLVM IR */ LLVMRunFunctionPassManager(gallivm->passmgr, func); if (0) { if (gallivm_debug & GALLIVM_DEBUG_IR) { /* Print the LLVM IR to stderr */ lp_debug_dump_value(func); debug_printf("\n"); } } }
int module_list_globals(void) { LLVMModuleRef M = load_module(false, false); LLVMValueRef g; g = LLVMGetFirstGlobal(M); while (g) { LLVMTypeRef T = LLVMTypeOf(g); char *s = LLVMPrintTypeToString(T); printf("Global%s: %s %s\n", LLVMIsDeclaration(g) ? "Declaration" : "Definition", LLVMGetValueName(g), s); LLVMDisposeMessage(s); g = LLVMGetNextGlobal(g); } LLVMDisposeModule(M); return 0; }
/* * Linux perf profiler integration. * * See also: * - http://penberg.blogspot.co.uk/2009/06/jato-has-profiler.html * - https://github.com/penberg/jato/commit/73ad86847329d99d51b386f5aba692580d1f8fdc * - http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=80d496be89ed7dede5abee5c057634e80a31c82d */ extern "C" void lp_profile(LLVMValueRef func, const void *code) { #if defined(__linux__) && defined(PROFILE) static boolean first_time = TRUE; static FILE *perf_map_file = NULL; static int perf_asm_fd = -1; if (first_time) { /* * We rely on the disassembler for determining a function's size, but * the disassembly is a leaky and slow operation, so avoid running * this except when running inside linux perf, which can be inferred * by the PERF_BUILDID_DIR environment variable. */ if (getenv("PERF_BUILDID_DIR")) { pid_t pid = getpid(); char filename[256]; util_snprintf(filename, sizeof filename, "/tmp/perf-%llu.map", (unsigned long long)pid); perf_map_file = fopen(filename, "wt"); util_snprintf(filename, sizeof filename, "/tmp/perf-%llu.map.asm", (unsigned long long)pid); mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; perf_asm_fd = open(filename, O_WRONLY | O_CREAT, mode); } first_time = FALSE; } if (perf_map_file) { const char *symbol = LLVMGetValueName(func); unsigned long addr = (uintptr_t)code; llvm::raw_fd_ostream Out(perf_asm_fd, false); Out << symbol << ":\n"; unsigned long size = disassemble(code, Out); fprintf(perf_map_file, "%lx %lx %s\n", addr, size, symbol); fflush(perf_map_file); } #else (void)func; (void)code; #endif }
extern "C" void lp_disassemble(LLVMValueRef func, const void *code) { raw_debug_ostream Out; Out << LLVMGetValueName(func) << ":\n"; disassemble(code, Out); }
extern "C" void lp_disassemble(LLVMValueRef func, const void *code) { _debug_printf("%s:\n", LLVMGetValueName(func)); disassemble(code); }
void ac_optimize_vs_outputs(struct ac_llvm_context *ctx, LLVMValueRef main_fn, uint8_t *vs_output_param_offset, uint32_t num_outputs, uint8_t *num_param_exports) { LLVMBasicBlockRef bb; bool removed_any = false; struct ac_vs_exports exports; exports.num = 0; /* Process all LLVM instructions. */ bb = LLVMGetFirstBasicBlock(main_fn); while (bb) { LLVMValueRef inst = LLVMGetFirstInstruction(bb); while (inst) { LLVMValueRef cur = inst; inst = LLVMGetNextInstruction(inst); struct ac_vs_exp_inst exp; if (LLVMGetInstructionOpcode(cur) != LLVMCall) continue; LLVMValueRef callee = ac_llvm_get_called_value(cur); if (!ac_llvm_is_function(callee)) continue; const char *name = LLVMGetValueName(callee); unsigned num_args = LLVMCountParams(callee); /* Check if this is an export instruction. */ if ((num_args != 9 && num_args != 8) || (strcmp(name, "llvm.SI.export") && strcmp(name, "llvm.amdgcn.exp.f32"))) continue; LLVMValueRef arg = LLVMGetOperand(cur, AC_EXP_TARGET); unsigned target = LLVMConstIntGetZExtValue(arg); if (target < V_008DFC_SQ_EXP_PARAM) continue; target -= V_008DFC_SQ_EXP_PARAM; /* Parse the instruction. */ memset(&exp, 0, sizeof(exp)); exp.offset = target; exp.inst = cur; for (unsigned i = 0; i < 4; i++) { LLVMValueRef v = LLVMGetOperand(cur, AC_EXP_OUT0 + i); exp.chan[i].value = v; if (LLVMIsUndef(v)) { exp.chan[i].type = AC_IR_UNDEF; } else if (LLVMIsAConstantFP(v)) { LLVMBool loses_info; exp.chan[i].type = AC_IR_CONST; exp.chan[i].const_float = LLVMConstRealGetDouble(v, &loses_info); } else { exp.chan[i].type = AC_IR_VALUE; } } /* Eliminate constant and duplicated PARAM exports. */ if (ac_eliminate_const_output(vs_output_param_offset, num_outputs, &exp) || ac_eliminate_duplicated_output(vs_output_param_offset, num_outputs, &exports, &exp)) { removed_any = true; } else { exports.exp[exports.num++] = exp; } } bb = LLVMGetNextBasicBlock(bb); } /* Remove holes in export memory due to removed PARAM exports. * This is done by renumbering all PARAM exports. */ if (removed_any) { uint8_t old_offset[VARYING_SLOT_MAX]; unsigned out, i; /* Make a copy of the offsets. We need the old version while * we are modifying some of them. */ memcpy(old_offset, vs_output_param_offset, sizeof(old_offset)); for (i = 0; i < exports.num; i++) { unsigned offset = exports.exp[i].offset; /* Update vs_output_param_offset. Multiple outputs can * have the same offset. */ for (out = 0; out < num_outputs; out++) { if (old_offset[out] == offset) vs_output_param_offset[out] = i; } /* Change the PARAM offset in the instruction. */ LLVMSetOperand(exports.exp[i].inst, AC_EXP_TARGET, LLVMConstInt(ctx->i32, V_008DFC_SQ_EXP_PARAM + i, 0)); } *num_param_exports = exports.num; } }