From e13337f3ddcb74842be4d4e2ecb060cc34bf9032 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 12 Dec 2023 15:55:06 +0000 Subject: [PATCH] fix alignment of emit_unbox_store copy The dest alignment might be determined to be greater than the source. For example, observed with: code_llvm(dump_module=true, optimize=false, (Int,)) do x Pair(ntuple(i -> 0x00, 8), x) end Where the alignment of the first field of the Pair is at least 4, but the alignment of the ntuple data is 1. --- doc/src/devdocs/debuggingtips.md | 7 ++++- src/aotcompile.cpp | 52 ++++++++++++++++++++++++++++++++ src/cgutils.cpp | 3 +- src/intrinsics.cpp | 2 +- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/doc/src/devdocs/debuggingtips.md b/doc/src/devdocs/debuggingtips.md index 7639e8be2ef96..a7740b1780b06 100644 --- a/doc/src/devdocs/debuggingtips.md +++ b/doc/src/devdocs/debuggingtips.md @@ -41,11 +41,16 @@ useful. ## Useful Julia functions for Inspecting those variables - * `jl_gdblookup($rip)` :: For looking up the current function and line. (use `$eip` on i686 platforms) + * `jl_print_task_backtraces(0)` :: Similar to gdb's `thread apply all bt` or lldb's `thread backtrace + all`. Runs all threads while printing backtraces for all existing tasks. + * `jl_gdblookup($pc)` :: For looking up the current function and line. + * `jl_gdblookupinfo($pc)` :: For looking up the current method instance object. + * `jl_gdbdumpcode(mi)` :: For dumping all of `code_typed/code_llvm/code_asm` when the REPL is not working right. * `jlbacktrace()` :: For dumping the current Julia backtrace stack to stderr. Only usable after `record_backtrace()` has been called. * `jl_dump_llvm_value(Value*)` :: For invoking `Value->dump()` in gdb, where it doesn't work natively. For example, `f->linfo->functionObject`, `f->linfo->specFunctionObject`, and `to_function(f->linfo)`. + * `jl_dump_llvm_module(Module*)` :: For invoking `Module->dump()` in gdb, where it doesn't work natively. * `Type->dump()` :: only works in lldb. Note: add something like `;1` to prevent lldb from printing its prompt over the output * `jl_eval_string("expr")` :: for invoking side-effects to modify the current state or to lookup diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 64ce3b3f6350c..be70016e45f21 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -1820,6 +1820,58 @@ void addTargetPasses(legacy::PassManagerBase *PM, const Triple &triple, TargetIR PM->add(createTargetTransformInfoWrapperPass(std::move(analysis))); } +// sometimes in GDB you want to find out what code was created from a mi +extern "C" JL_DLLEXPORT_CODEGEN jl_code_info_t *jl_gdbdumpcode(jl_method_instance_t *mi) +{ + jl_llvmf_dump_t llvmf_dump; + size_t world = jl_current_task->world_age; + JL_STREAM *stream = (JL_STREAM*)STDERR_FILENO; + + jl_printf(stream, "---- dumping IR for ----\n"); + jl_static_show(stream, (jl_value_t*)mi); + jl_printf(stream, "\n----\n"); + + jl_printf(stream, "\n---- unoptimized IR ----"); + jl_get_llvmf_defn(&llvmf_dump, mi, world, 0, false, jl_default_cgparams); + if (llvmf_dump.F) { + jl_value_t *ir = jl_dump_function_ir(&llvmf_dump, 0, 1, "source"); + jl_static_show(stream, ir); + } + jl_printf(stream, "----\n"); + + jl_printf(stream, "\n---- optimized IR ----"); + jl_get_llvmf_defn(&llvmf_dump, mi, world, 0, true, jl_default_cgparams); + if (llvmf_dump.F) { + jl_value_t *ir = jl_dump_function_ir(&llvmf_dump, 0, 1, "source"); + jl_static_show(stream, ir); + } + jl_printf(stream, "----\n"); + + jl_printf(stream, "\n---- assembly ----"); + jl_get_llvmf_defn(&llvmf_dump, mi, world, 0, true, jl_default_cgparams); + if (llvmf_dump.F) { + jl_value_t *ir = jl_dump_function_asm(&llvmf_dump, 0, "", "source", 0, true); + jl_static_show(stream, ir); + } + jl_printf(stream, "----\n"); + + jl_code_info_t *src = NULL; + jl_value_t *ci = jl_default_cgparams.lookup(mi, world, world); + if (ci != jl_nothing) { + jl_code_instance_t *codeinst = (jl_code_instance_t*)ci; + src = (jl_code_info_t*)jl_atomic_load_relaxed(&codeinst->inferred); + if ((jl_value_t*)src != jl_nothing && !jl_is_code_info(src) && jl_is_method(mi->def.method)) { + JL_GC_PUSH2(&codeinst, &src); + src = jl_uncompress_ir(mi->def.method, codeinst, (jl_value_t*)src); + JL_GC_POP(); + } + } + if (!src || (jl_value_t*)src == jl_nothing) { + src = jl_type_infer(mi, world, 0); + } + return src; +} + // --- native code info, and dump function to IR and ASM --- // Get pointer to llvm::Function instance, compiling if necessary // for use in reflection from Julia. diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 9f74fee1fb6ae..8c6880d7245cd 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -2911,7 +2911,8 @@ static void init_bits_cgval(jl_codectx_t &ctx, Value *newv, const jl_cgval_t& v, { // newv should already be tagged if (v.ispointer()) { - emit_memcpy(ctx, newv, jl_aliasinfo_t::fromTBAA(ctx, tbaa), v, jl_datatype_size(v.typ), sizeof(void*), julia_alignment(v.typ)); + unsigned align = std::max(julia_alignment(v.typ), (unsigned)sizeof(void*)); + emit_memcpy(ctx, newv, jl_aliasinfo_t::fromTBAA(ctx, tbaa), v, jl_datatype_size(v.typ), align, julia_alignment(v.typ)); } else { init_bits_value(ctx, newv, v.V, tbaa); diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 81fc9ec1af831..c784727c4f598 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -520,7 +520,7 @@ static void emit_unbox_store(jl_codectx_t &ctx, const jl_cgval_t &x, Value *dest } Value *src = data_pointer(ctx, x); - emit_memcpy(ctx, dest, jl_aliasinfo_t::fromTBAA(ctx, tbaa_dest), src, jl_aliasinfo_t::fromTBAA(ctx, x.tbaa), jl_datatype_size(x.typ), alignment, alignment, isVolatile); + emit_memcpy(ctx, dest, jl_aliasinfo_t::fromTBAA(ctx, tbaa_dest), src, jl_aliasinfo_t::fromTBAA(ctx, x.tbaa), jl_datatype_size(x.typ), alignment, julia_alignment(x.typ), isVolatile); } static jl_datatype_t *staticeval_bitstype(const jl_cgval_t &targ)