Skip to content

Commit

Permalink
Merge pull request #12 from Keluaa/better_pipeline
Browse files Browse the repository at this point in the history
Code structure overhaul
  • Loading branch information
Keluaa authored May 9, 2024
2 parents ad91714 + ca15df4 commit 5119a0a
Show file tree
Hide file tree
Showing 8 changed files with 571 additions and 716 deletions.
43 changes: 27 additions & 16 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ Supports:
- native CPU assembly (output of `@code_native`, highlighted by `InteractiveUtils.print_native`)
- LLVM IR (output of `@code_llvm`, highlighted by `InteractiveUtils.print_llvm`)
- Typed Julia IR (output of `@code_typed`, highlighted through the `Base.show` method of `Core.CodeInfo`)
- Julia AST (an `Expr`), highlighting is done with:
- OhMyREPL.jl's Julia syntax highlighting in Markdown code blocks
- (Julia ≥ v1.11) [JuliaSyntaxHighlighting.jl](https://github.com/JuliaLang/JuliaSyntaxHighlighting.jl)
- Julia AST (an `Expr`), highlighting is done with OhMyREPL.jl's Julia syntax highlighting in Markdown code blocks

The [`@code_diff`](@ref) macro is the main entry point. If possible, the code type will be
detected automatically, otherwise add e.g. `type=:llvm` for LLVM IR comparison:
Expand Down Expand Up @@ -56,29 +54,42 @@ julia> @code_diff type=:llvm debuginfo=:none color=false f1(1) f2(1)
5 } ┃ } 5
```

# Main functions
# Comparison entry points

```@docs
CodeDiff
compare_code_native
compare_code_llvm
compare_code_typed
compare_ast
code_diff(::Any, ::Any)
code_diff(::Val{:ast}, ::Any, ::Any)
@code_diff
code_diff
code_for_diff
CodeDiff
```

# Display functions
# Code fetching

```@docs
optimize_line_changes!
replace_llvm_module_name
side_by_side_diff
code_native
code_llvm
code_typed
code_ast
get_code
```

# Highlighting

```@docs
code_highlighter
```

# Internals
# Cleanup

```@docs
cleanup_code
replace_llvm_module_name
LLVM_MODULE_NAME_REGEX
```

# Diff display

```@docs
optimize_line_changes!
side_by_side_diff
```
5 changes: 4 additions & 1 deletion src/CodeDiffs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ using Markdown
using StringDistances
using WidthLimitedIO

export @code_diff
export @code_diff, code_diff

const ANSI_REGEX = r"(?>\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]))+"
const OhMYREPL_PKG_ID = Base.PkgId(Base.UUID("5fb14364-9ced-5910-84b2-373655c76a03"), "OhMyREPL")
const Revise_PKG_ID = Base.PkgId(Base.UUID("295af30f-e4ad-537b-8983-00126c2a3abe"), "Revise")

include("CodeDiff.jl")
include("get_code.jl")
include("highlighting.jl")
include("cleanup.jl")
include("compare.jl")
include("display.jl")

Expand Down
78 changes: 78 additions & 0 deletions src/cleanup.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

"""
LLVM_MODULE_NAME_REGEX
Should match the LLVM module of any function which does not have any of `'",;-` or spaces
in it.
It is `'get_function_name'`, in `'julia/src/codegen.cpp'` which builds the function name
for the LLVM module used to get the function code. The regex is built to match any output
from that function.
Since the `'globalUniqueGeneratedNames'` counter (the number at the end of the module name)
is incremented at each call to `'get_function_name'`, and since `code_llvm` or `code_native`
forces a compilation, it should be guaranteed that the match with the highest number at
the end is the name of our function in `code`.
"""
const LLVM_MODULE_NAME_REGEX = r"(?>julia|japi3|japi1)_([^\"\s,;\-']*)_(\d+)"


"""
replace_llvm_module_name(code::AbstractString)
Remove in `code` the trailing numbers in the LLVM module names, e.g. `"julia_f_2007" => "f"`.
This allows to remove false differences when comparing raw code, since each call to
`code_native` (or `code_llvm`) triggers a new compilation using an unique LLVM module name,
therefore each consecutive call is different even though the actual code does not
change.
```jldoctest; setup = :(using InteractiveUtils; import CodeDiffs: replace_llvm_module_name)
julia> f() = 1
f (generic function with 1 method)
julia> buf = IOBuffer();
julia> code_native(buf, f, Tuple{}) # Equivalent to `@code_native f()`
julia> code₁ = String(take!(buf));
julia> code_native(buf, f, Tuple{})
julia> code₂ = String(take!(buf));
julia> code₁ == code₂ # Different LLVM module names...
false
julia> replace_llvm_module_name(code₁) == replace_llvm_module_name(code₂) # ...but same code
true
```
"""
replace_llvm_module_name(code::AbstractString) = replace(code, LLVM_MODULE_NAME_REGEX => s"\1")


"""
replace_llvm_module_name(code::AbstractString, function_name)
Replace only LLVM module names for `function_name`.
"""
function replace_llvm_module_name(code::AbstractString, function_name)
function_name = string(function_name)
if Sys.islinux() && startswith(function_name, '@')
# See 'get_function_name' in 'julia/src/codegen.cpp'
function_name = function_name[2:end]
end
func_re = Regex("(?>julia|japi3|japi1)_\\Q$(function_name)\\E_(\\d+)")
return replace(code, func_re => function_name)
end


"""
cleanup_code(::Val{code_type}, code)
Perform minor changes to `code` to improve readability and the quality of the differences.
Currently only [`replace_llvm_module_name`](@ref) is applied to `:native` and `:llvm` code.
"""
cleanup_code(_, c) = c

cleanup_code(::Val{:native}, c) = replace_llvm_module_name(c)
cleanup_code(::Val{:llvm}, c) = replace_llvm_module_name(c)
Loading

0 comments on commit 5119a0a

Please sign in to comment.