program-markers inserts markers (as function calls) in C or C++ source code to enable differential testing for missed optimizations:
- Instrument a program.
- Compile it with two or more compilers (or compiler versions, or optimization levels, etc).
- For each output: the markers whose corresponding calls are still present in the generated assembly are alive, the remaining are dead.
- Differential testing: compare the sets of alive and dead markers across outputs.
There are two kinds of markers supported:
- DCE (Dead Code Elimination) Markers
- VR (Value Range) Markers
A DCEMarker tests if a compiler dead code eliminates a piece of code (basic block). For example,
if (Cond){
DCEMarker0_();
STMT0;
STMT1;
//...
}
If call DCEMarker0_(); is not present in the generated assembly code then the
compiler determined that Cond must always be false and therefore the body of
this if statement is dead.
A VRMarker tests if a compiler can determine subsets of the value ranges of variables, for example:
if (!(LB <= a and a <= UB))
VRMarker0_();
If call VRMarker0_(); is not present in the generated assembly code then the
compiler determined that a's value is always LB <= a <= UB. Currently only
integer variables are instrumented.
To build just the clang tool
Prerequisites: cmake, make, clang/llvm 13/14.
mkdir build
cd build
cmake ..
cmake --build . [--parallel]
cmake --install . --prefix=/where/to/install/
Usage
cat test.c
int foo(int a) {
if (a == 0)
return 1;
else {
a = 5;
}
return a;
}
dead-instrument test.c --
cat test.c | clang-format
#if defined DisableDCEMarker0_
#define DCEMARKERMACRO0_ ;
#elif defined UnreachableDCEMarker0_
#define DCEMARKERMACRO0_ __builtin_unreachable();
#else
#define DCEMARKERMACRO0_ DCEMarker0_();
void DCEMarker0_(void);
#endif
#if defined DisableDCEMarker1_
#define DCEMARKERMACRO1_ ;
#elif defined UnreachableDCEMarker1_
#define DCEMARKERMACRO1_ __builtin_unreachable();
#else
#define DCEMARKERMACRO1_ DCEMarker1_();
void DCEMarker1_(void);
#endif
int foo(int a) {
if (a == 0)
{
DCEMARKERMACRO1_
return 1;
}
else {
DCEMARKERMACRO0_
a = 5;
}
return a;
}
Individual markers can be disabled or turned into unreachables (useful for helping the compiler optimize parts known to be dead):
gcc -E -P -DDisableDCEMarker0_ -DUnreachableDCEMarker1_ test.c | clang-format
int foo(int a) {
if (a == 0) {
__builtin_unreachable();
return 1;
} else {
;
a = 5;
}
return a;
}
Passing --ignore-functions-with-macros to program-markers will cause it to ignore any functions that contain macro expansions.
Value range markers can be emitted instead by using --mode=vr:
cat test.c
int foo(int a) {
if (a == 0)
return 1;
return 0;
}
program-markers --mode=vr test.c --
cat test.c | clang-format
#if defined DisableVRMarker0_
#define VRMARKERMACRO0_(VAR, TYPE)
#elif defined UnreachableVRMarker0_
#define VRMARKERMACRO0_(VAR, TYPE) \
if (!(VRMarkerLowerBound0_ <= (VAR) && (VAR) <= VRMarkerUpperBound0_)) \
__builtin_unreachable();
#else
#define VRMARKERMACRO0_(VAR, TYPE) \
if (!(VRMarkerLowerBound0_ <= (VAR) && (VAR) <= VRMarkerUpperBound0_)) \
VRMarker0_();
void VRMarker0_(void);
#endif
#ifndef VRMarkerLowerBound0_
#define VRMarkerLowerBound0_ 0
#endif
#ifndef VRMarkerUpperBound0_
#define VRMarkerUpperBound0_ 0
#endif
int foo(int a) {
VRMARKERMACRO0_(a,"int")
if (a == 0)
return 1;
return 0;
}
The ranges that each marker test can be adjucted via macros:
gcc -E -P -DVRMarkerLowerBound0_=-4 test.c | clang-format
void VRMarker0_(void);
int foo(int a) {
if (!(-4 <= (a) && (a) <= 0))
VRMarker0_();
if (a == 0)
return 1;
return 0;
}
Python wrapper
pip install program-markers
To use the instrumenter in python import from program_markers.instrumenter import instrument_program: instrument_program(program: diopter.SourceProgram, ignore_functions_with_macros: bool) -> InstrumentedProgram.
Building the python wrapper
Local build
./build_python_wheel_local.sh #this will build the current branch
pip install .
Docker based build
docker run --rm -e REVISION=REV -v `pwd`:/io theodort/manylinux-with-llvm:latest /io/build_python_wheel_docker.sh
This will build multiple wheels for REV with multiple python versions.
The output is stored in the wheelhouse directory.
The docker image is based on https://github.com/thetheodor/manylinux-with-llvm.
Metadata
Release files for program-markers 0.5.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| program_markers-0.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.28+ x86-64, Linux glibc 2.17+ x86-64 | Details for program_markers-0.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl |
| program_markers-0.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl | CPython 3.10 | CPython 3.10 | Linux glibc 2.17+ x86-64, Linux glibc 2.28+ x86-64 | Details for program_markers-0.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl |
Total release size: 33.7 MB
Release files / program_markers-0.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
| Download URL | program_markers-0.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 16.8 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
c1ed61a9a59139a9bd8547a4c80a88efedc632610f1ab39b9ed306d26c01ce7a
|
|
BLAKE2b-256 checksum How to use checksums |
4120fd17a90fc164fa87c558c668dbca9713faa5f34e44c1600c826315cd5906
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.2 CPython/3.11.5
|
Release files / program_markers-0.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
| Download URL | program_markers-0.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 16.8 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
01f5f2014b92dd4e96b588bb650ba0a14aa15c0d492e374874765d9e115dabe6
|
|
BLAKE2b-256 checksum How to use checksums |
19c5be50bf1300ce660f48728a354ef865b71246389f25f1a1f555f243b2b807
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.2 CPython/3.11.5
|
Security for program-markers 0.5.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.