Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 37 additions & 16 deletions .github/workflows/basic-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,30 @@ env:

jobs:
format-check:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-18 main" | sudo tee /etc/apt/sources.list.d/llvm-18.list

- name: Update apt
run: sudo apt-get update

- name: Install clang-format
run: |
sudo apt-get remove clang-format-*
sudo apt-get install -t llvm-toolchain-noble-18 clang-format-18

- name: Format source code
run: |
find demo lib test \
-type f \
-a \( -name "*.c" -o -name "*.cpp" -o -name "*.h" \) \
-print0 \
| xargs -0 clang-format-14 -i
| xargs -0 clang-format-18 -i

- name: Format check
run: |
Expand All @@ -33,28 +45,31 @@ jobs:
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4
- uses: codespell-project/actions-codespell@v2
- uses: actions/checkout@v5
- uses: codespell-project/actions-codespell@v2.2

build-project:
strategy:
fail-fast: false
matrix:
include:
- llvm-version: 12
os: ubuntu-20.04
preset: develop
- llvm-version: 14
os: ubuntu-22.04
preset: develop
- llvm-version: 18
- llvm-version: 22
os: ubuntu-24.04
preset: develop

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: LLVM apt
if: ${{ matrix.llvm-version >= 19 }}
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-${{ matrix.llvm-version }} main" | sudo tee /etc/apt/sources.list.d/llvm-${{ matrix.llvm-version }}.list

- name: Update apt
run: sudo apt-get update
Expand All @@ -73,12 +88,18 @@ jobs:
echo "CLANG_CMAKE_DIR=/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/clang" >> $GITHUB_ENV
echo "EXTERNAL_LIT=/usr/lib/llvm-${{ matrix.llvm-version }}/build/utils/lit/lit.py" >> $GITHUB_ENV

- name: Build IRPrinter
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DLLVM_DIR=${LLVM_CMAKE_DIR} -DClang_DIR=${CLANG_CMAKE_DIR}
cmake --build build --parallel

- name: Build IRPrinter release
run: |
cmake -B build_rel -DCMAKE_BUILD_TYPE=Release -DLLVM_DIR=${LLVM_CMAKE_DIR} -DClang_DIR=${CLANG_CMAKE_DIR}
cmake --preset release -DLLVM_DIR=${LLVM_CMAKE_DIR} -DClang_DIR=${CLANG_CMAKE_DIR} -DLLVM_EXTERNAL_LIT=${EXTERNAL_LIT}
cmake --build build_rel --parallel --target install

- name: Test and Coverage
run: |
cmake --preset coverage -DLLVM_DIR=${LLVM_CMAKE_DIR} -DClang_DIR=${CLANG_CMAKE_DIR} -DLLVM_EXTERNAL_LIT=${EXTERNAL_LIT}
cmake --build build_cov --target coverage-irprinter

- name: Upload coverage
uses: actions/upload-artifact@v6
with:
name: coverage-report-llvm${{ matrix.llvm-version }}
path: build_cov/coverage_report/
9 changes: 6 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
CMAKE_MINIMUM_REQUIRED(VERSION 3.21)
PROJECT(irprinter
VERSION 0.3
VERSION 0.4
)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
Expand All @@ -17,10 +17,13 @@ list(APPEND CMAKE_MODULE_PATH
include(ToolchainOptions)
include(CMakePackageConfigHelpers)

add_format_target(format-sources
irprinter_add_format_target(format-sources
"Formats project source files"
TARGETS src/*.cpp
include/*.h
)

add_subdirectory(src)
if(PROJECT_IS_TOP_LEVEL)
add_subdirectory(test)
endif()
73 changes: 73 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"version": 2,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "clang-toolchain",
"hidden": true,
"generator": "Unix Makefiles",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
}
},
{
"name": "develop",
"displayName": "Develop (Debug)",
"description": "Default develop build options for Clang",
"binaryDir": "${sourceDir}/build",
"inherits": [
"clang-toolchain"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release",
"displayName": "Release",
"description": "Default release build options for Clang",
"binaryDir": "${sourceDir}/build_rel",
"inherits": [
"clang-toolchain"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "coverage",
"displayName": "Coverage (LLVM)",
"description": "Default coverage build options for Clang (LLVM-based)",
"binaryDir": "${sourceDir}/build_cov",
"inherits": [
"clang-toolchain"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"IRPRINTER_ENABLE_COVERAGE": "ON",
"CMAKE_C_FLAGS": "-fprofile-instr-generate -fcoverage-mapping",
"CMAKE_CXX_FLAGS": "-fprofile-instr-generate -fcoverage-mapping",
"CMAKE_EXE_LINKER_FLAGS": "-fprofile-instr-generate -fcoverage-mapping"
}
}
],
"buildPresets": [
{
"name": "develop",
"configurePreset": "develop"
},
{
"name": "release",
"configurePreset": "release"
},
{
"name": "coverage",
"configurePreset": "coverage"
}
]
}
132 changes: 75 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,86 +1,104 @@
# irprinter · ![License](https://img.shields.io/github/license/ahueck/irprinter)

*irprinter* is a command-line tool for exploring LLVM Intermediate Representation (IR) code.
It allows users to print IR code for specific functions, which is particularly useful when dumping the entire translation unit would result in excessive output.

*irprinter* is a command-line tool for exploring LLVM Intermediate Representation (IR).
It allows you to print IR for specific functions, which is especially useful when dumping an entire translation unit would produce excessive output.

## Features
* Print LLVM IR code for a translation unit (C/C++) to the console.
* Modify and add compiler flags (e.g., replace -g with -O2) and regenerate the (modified) IR.
* Regex matching of (demangled) function names, with options to print:
* Print LLVM IR for a translation unit (C/C++) to the console.
* Modify or add compiler flags (e.g., replacing `-g` with `-O2`) and regenerate the IR.
* Match (demangled) function names using regular expressions, with options to print:
1. Function signatures only.
2. Functions including their bodies.
* Dump the entire IR code of the translation unit.
2. Full function bodies.
* Dump the entire IR of a translation unit.
* Print statements within a specific line number range (based on debug information).
* Printing backward dependencies for location queries is toggleable via `deps`.
* Line-number prefixes are toggleable via `lines`.
* Prefixes use `+` for dependency-discovered instructions.
* A prefix like `+0 | ...` means the instruction has no debug line metadata in IR.

## Usage
See [main.cpp](src/main.cpp) for all possible command-line arguments.

### Example of using *irprinter*
Assume *test.c* contains the code:

```c
int foo () {
return 2;
}
int main() {
int val;
val = foo();
return 0;
}
```
Refer to [main.cpp](src/main.cpp) for a full list of command-line arguments.

### Example
Assume [test.c](test/codes/test.c) contains the following code:

```c
int foo() {
return 2;
}
int main() {
int val;
val = foo();
return 0;
}
```

#### Using irprinter on test.c
In this example we
1) load `test.c` with standard Clang flags,
2) list all functions in `test.c`,
3) print the body of main,
4) optimize the code with `-O3`, and finally,
5) print the body of main again.
In this example, we:
1. Load `test.c` with standard Clang and debug flags.
2. List all functions in `test.c`.
3. Print the body of `main`.
4. Print statements within the line range [6, 7].
5. Optimize the code with `-O3`.
6. Print the body of `main` again to see the result of the optimization.

The regression test input for this flow lives at `test/codes/test.c`.

```console
ahueck@sys:~/irprint/install$ ./bin/irprinter ../test.c --
$ ./bin/irprinter test/codes/test.c -- -g
ir-printer> l
Match 1 [foo]:
Match 1 [foo()]:
; Function Attrs: noinline nounwind optnone uwtable
define i32 @foo() #0
define dso_local i32 @foo() #0 !dbg !10

Match 2 [main]:
; Function Attrs: noinline nounwind optnone uwtable
define i32 @main() #0
define dso_local i32 @main() #0 !dbg !10

ir-printer> p main
Match 1 [main]:
; Function Attrs: noinline nounwind optnone uwtable
define i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 0, i32* %1, align 4
%3 = call i32 @foo()
store i32 %3, i32* %2, align 4
ret i32 0
Match 1 [main]:; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 !dbg !10 {
entry:
%retval = alloca i32, align 4
%val = alloca i32, align 4
store i32 0, ptr %retval, align 4
#dbg_declare(ptr %val, !16, !DIExpression(), !17)
%call = call i32 @foo(), !dbg !18
store i32 %call, ptr %val, align 4, !dbg !19
ret i32 0, !dbg !20
}

ir-printer> 6 7
main:
entry:
+0 | %val = alloca i32, align 4
6 | %call = call i32 @foo(), !dbg !18
6 | store i32 %call, ptr %val, align 4, !dbg !19
7 | ret i32 0, !dbg !20

ir-printer> f -O3
Set flag to -O3. Re-generating module...
ir-printer> p main
Match 1 [main]:
; Function Attrs: norecurse nounwind readnone uwtable
define i32 @main() local_unnamed_addr #1 {
Match 1 [main]:; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable
define dso_local noundef i32 @main() local_unnamed_addr #0 {
entry:
ret i32 0
}

```

## How to build
###### Requirements
Note: this output was captured with LLVM 20.1.8. Exact IR attributes and mangling can vary between LLVM versions.

## How to Build

### Requirements
- CMake >= 3.20
- Clang/LLVM 12, 14, 18 (CMake needs to find the installation, see
the [LLVM CMake documentation](https://llvm.org/docs/CMake.html) or the [CI workflow](.github/workflows/basic-ci.yml))
- C++17 compiler
- Clang/LLVM 12, 14, or 18-22 (CMake must be able to find the installation; see the [LLVM CMake documentation](https://llvm.org/docs/CMake.html) or the [CI workflow](.github/workflows/basic-ci.yml))
- A C++17 compatible compiler

###### Build steps
In the root project folder, execute the following commands (see also [CI workflow](.github/workflows/basic-ci.yml))
### Build Steps
From the root project folder, execute the following commands:

```
cmake -B build -DCMAKE_INSTALL_PREFIX=*your path*
cmake --build build --target install --parallel
```
```bash
cmake -B build -DCMAKE_INSTALL_PREFIX=/path/to/install
cmake --build build --target install --parallel
```
25 changes: 23 additions & 2 deletions cmake/ToolchainOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,36 @@ message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")

list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")

find_package(Clang REQUIRED HINTS "${Clang_DIR}")
find_package(Clang QUIET HINTS "${Clang_DIR}")

if(NOT Clang_FOUND)
# Optional: only needed for CIR-enabled Clang packages:
find_package(MLIR CONFIG QUIET HINTS "${MLIR_DIR}")
find_package(Clang REQUIRED HINTS "${Clang_DIR}")
endif()

include(AddLLVM)
include(clang-tidy)
include(clang-format)
include(log-util)
include(target-util)

set(LOG_LEVEL 0 CACHE STRING "Granularity of the logger. 3 is most verbose, 0 is least.")
set(IRPRINTER_LOG_LEVEL 0 CACHE STRING "Granularity of the logger. 3 is most verbose, 0 is least.")

option(IRPRINTER_AUTO_RESOURCE_DIR "Try to automatically set the Clang resource directory" OFF)
option(IRPRINTER_ENABLE_COVERAGE "Enable LLVM-based coverage" OFF)

if(IRPRINTER_AUTO_RESOURCE_DIR AND NOT IRPRINTER_CLANG_RESOURCE_DIR)
find_program(CLANG_EXECUTABLE NAMES clang-${LLVM_VERSION_MAJOR} clang)
if(CLANG_EXECUTABLE)
execute_process(
COMMAND ${CLANG_EXECUTABLE} -print-resource-dir
OUTPUT_VARIABLE CLANG_RESOURCE_DIR_VAR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(IRPRINTER_CLANG_RESOURCE_DIR ${CLANG_RESOURCE_DIR_VAR} CACHE STRING "Clang resource directory")
endif()
endif()

if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
Expand Down
Loading