Repository files navigation

LoopChainIR

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Quickstart

Prerequisites

LoopChainIR depends on the following libraries:

Configure, Make, Test, and install

You must first configure the project before building using the configuration script:

./configure

See the configuration options available using ./configure --help.

After a successful configuration, the makefile will be generated. Run make all to compile the LoopChainIR library object. To ensure the project is in working order run make test to run the unit and integration tests.

To install, run make install. To choose a non-default installation location, use the --prefix option of the configuration script. To uninstall run make uninstall. installed.txt lists the full path of each file and directory that was installed.

Project Directory Structure

  • bin/ : Where all executables (including intermediate *.o and *.a files) are compiled to. Known as $(BIN).

  • src/ : Where all the sources for the binary files live. Known as $(SRC).

  • test/ : Subdirectory for testing. Known as $(TEST)

    • integration-tests : Subdirectory for integration-test files. Known as $(REG_TEST_DIR)

    • unit-tests : Subdirectory for unit-test files. Known as $(UNIT_TEST_DIR)

      • bin/ : Where all executables (including intermediate *.o and *.a files) only relating to the unit tests are compiled to. Known as $(UNIT_TEST_BIN)

      • src/ : Where all the source for the unit tests live. Known as $(UNIT_TEST_SRC)

  • util/ : Where utility resources (such as scripts) live. Known as $(UTIL)

  • documentation/: Where doxygen outputs its files. Known as $(DOC_PATH)

  • third-party/ : Subdirectory for third-party materials, their source, their build directories, and their install directories. Known as $(THIRD_PARTY)

    • source/ : The original source distributions of third-party materials. Known as $(THIRD_PARTY_SRC)

    • build/: Where third-party materials are extracted to and built. Created after make genesis. Known as $(THIRD_PARTY_BUILD)

    • install/ : Where third-party materials are installed to. Created after make genesis. Known as $(THIRD_PARTY_INSTALL)

      • lib/ : Third-party libraries. Known as $(LIB)

      • include/ : Third-party headers. Known as $(INC)

Make commands

  • initialize (or init): This is the first command that should be run when getting started with the project. It builds and places all the third-party tools into good organized places.

  • all: Builds the LoopChainIR.a library (after first performing initialize if necessary)

  • test: Performs unit-tests and integration-tests

  • unit-tests: Runs all unit tests specified by $(UNIT-TESTS)

  • integration-tests: Runs all integration tests specified by $(REG_TESTS)

  • documentation (or doc): Runs doxygen, uses the local Doxyfile

  • neat: Removes all *.o files from $(BIN).

  • clean-third-party: Removes (recursive, forced) $(THIRD_PARTY_INSTALL) and $(THIRD_PARTY_BUILD).

  • clean-test: Removes (recursive) all files from $(UNIT_TEST_BIN), and *.dir and *.log files from $(REG_TEST_DIR)

  • clean-doc: Removes (recursive) the $(DOC_PATH) directory

  • clean: Performs clean-test and removes (recursively) all files under $(BIN).

  • clean-all: Performs clean, clean-third-party, and clean-doc. Mimics a restored project state.

  • install: Copies the library and header files to the location described by $(prefix). Installed files are listed in the install log (install.txt)

  • uninstall: Removes (recursive, forced) the files listed in the install log (install.txt)

Documentation

The LoopChainIR API is documented using Doxygen.

To generate the HTML documentation, run

make documentation

or

make doc

The output can be found at $(DOC)

Testing

A complete run of all tests (both integration and unit) is run with

make test

Unit Testing

Testing is conducted through the Google Test unit test framework.

Preferably, each project source file gets its own unit test file (i.e. RectangularDomain.cpp and RectangularDomain_test.cpp).

Tests are run with

make unit-tests

Or individually using the name of the test, for example:

make RectangularDomain_test

Integration Testing

Integration testing is conducted by an in-house script (see $(UTIL)/integration-util.py).

Test files are placed in $(REG_TEST_DIR).

Tests are run with

make integration-tests

Or individually using the name of the test.

If a test fails, it's log file is dropped next to the test file suffixed with '.log'. This can be useful to determine what failed, how to fix it, and in the case of a software error is useful to us.

Itegration Test Files

A integration test has several sections:

  • test name : Name of the test. Prefers no white-space.

  • loop chain : An ordered list of each loop nest, where each loop nest is expressed as a terse domain.

    Example:

    loop chain:
    (i){0..9}
    (i){0..9}
    (i,j){0..M-1,0..N-1}
    :end
    

    The iterators (symbols in the parentheses) are comma separated and can be any valid C variable symbol. The bounds (expressions in the brackets) as comma separated list of ranges. Each range is expressed lower_bound .. upper_bound, and bounds can contain simple expressions (using + - * / % operators and parentheses, no function calls) The iterators and bounds are matched up by their index (i.e. the first iterator is bounded by the first range, and the second iterator by the second, and so on.)

  • schedule : There are three schedule {things}

    • Original: default sequential schedule for a loop chain. code: original
      regex: original

    • Fusion schedule: Fuse a series of loops.
      code: fuse {loop index} {loop index} [{loop index} ...]
      regex: "fuse\s+(?P<list>(?:\d+\s*){2,})
      Example: fuse 0, 1 fuses loops 0 and 1 (the first and second loops).

    • Shift: shift the domain of a loop by some extent(s). Extents can be constant integers, symbols, and valid C expressions using only arithmetic operators. There must be the same number of extents as dimensions of the domain of the loop.
      code: shift {loop index} ({extent} [,{extent} ...])
      regex: shift\s+(?P<loopid>\d+)\s+\(\s*(?P<extents>.+)\s*\)
      Example: shift 0 (1,K,n+3) shifts the first loop in the chain, which is 3D,by 1, K, and n+3.

    Multiple schedules can be composed, and are applied in the order specified.

  • dependencies : The dependencies that must be satisfied for any transformation on the loop. These are used to ensure that a transformation produced a loop satisfying the dependencies of the original loop. This is expressed in traditional ISCC syntax. However, unlike in ISCC, each iteration must be expressed in full-form syntax [loop nest, iterator, (loop nest, iterator,)* statement]. Further, they must be padded so that all iterations are the same length For example, the statement 'inside' the first loop is expressed in full-form as [0,i,0], since its the 0'th loop, has iteration i, and is the 0'th statement. With padding it becomes [0,i,0,0,0]

    Code Example, continuing with loop chain example:

    dependencies:
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The first line indicates that iteration i comes before iteration i+1 in the first loop.
    The second line indicates that iteration i comes before iteration i+1 in the second loop.
    The third line indicates that iteration j comes before iteration j+1 in the third loop.
    The fourth line indicates that iteration i comes before iteration i+1 in the second loop.
    The fifth line indicates that all iterations in the first loop come before any iterations in the second loop.

    Please note that each dependency is treated by the framework as a separate entity, and is split by newlines. This means that a dependency expression currently cannot span multiple lines.

  • new ordering : The dependencies that must be satisfied for the particular transformation. This is written in the same way as the dependencies section. If the transformation being tested is the original schedule, then the text will probably be identical. Code Example, continuing with loop chain example, performing a loop fusion on the first two loops:

    new ordering:
    { [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The only change from the dependency code is the first line, which indicates that iteration i in the second loop comes before iteration i+1 in the first loop.

  • exemplar : (Optional) (Currently InOp) Actual original C/C++ code that should be tested by the source-to-source transformation tool (which doesn't exist yet). Code Example:

    exemplar:
    for( int i = 0; i < 10; i += 1 ){
    A[i] = Static[i];
    }
    for( int i = 0; i <= 9; i++ ){
    B[i] = f( A[i] );
    }
    for( int i = 0; i < M; ++i ){
    for( int j = 0; j <= N-1; j = j + 1 ){
    C[i,j] = A[i%10] / B[i%10];
    }
    }
    :end
    

The full test (using all the examples) would look something like this:

test name: example_3N_1D_1D_2D
loop chain:
(i){0..9}
(i){0..9}
(i,j){0..M-1,0..N-1}
:end
dependencies:
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
schedule:
fuse 0, 1, 2
:end
new ordering:
{ [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
exemplar:
for( int i = 0; i < 10; i += 1 ){
A[i] = Static[i];
}
for( int i = 0; i <= 9; i++ ){
B[i] = f( A[i] );
}
for( int i = 0; i < M; ++i ){
for( int j = 0; j <= N-1; j = j + 1 ){
C[i,j] = A[i%10] / B[i%10];
}
}
:end

integration-util.py

The integration-util.py script lives in $(UTIL) and is the driver behind the integration testing framework.

To run a test (or list of tests) by hand, simply calls

python $(UTIL)/integration-util.py path/to/file.test path/to/file2.test

There are options for the script:

  • --save_env (or -se): Save the testing environment after a test completes. By default, test environments are erased when test completes, regardless of failure state.

  • --save_env_on_fail (or -sf): Save the testing environment after a test fails. By default, test environments are erased when test completes, regardless of failure state.

  • --save_log (or -sl): Save the log file, even if test is successful. By default, logs are only saved to file if a test fails.

  • --resources_path PATH (or -r): Give the script a path to $(UTIL)/resources. By default, the script assumes that it lives in the same directory as the resources folder and will construct the path from its call.

  • --project_path PATH (or -p): Give the script a path to the LoopChainIR project directory. By default, the script assumes that it will be called from the LoopChainIr project root directory, and thus the path would be equivalent to ".".

Third-Party materials

Included with this project are several third-party materials under the $(THIRD_PARTY_SRC) directory.

  1. Google Test

All third-party materials are provided as they were downloaded, and include their copyright and license information.

About

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Resources

Stars

0 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

LoopChainIR

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Quickstart

Prerequisites

LoopChainIR depends on the following libraries:

Configure, Make, Test, and install

You must first configure the project before building using the configuration script:

./configure

See the configuration options available using ./configure --help.

After a successful configuration, the makefile will be generated. Run make all to compile the LoopChainIR library object. To ensure the project is in working order run make test to run the unit and integration tests.

To install, run make install. To choose a non-default installation location, use the --prefix option of the configuration script. To uninstall run make uninstall. installed.txt lists the full path of each file and directory that was installed.

Project Directory Structure

  • bin/ : Where all executables (including intermediate *.o and *.a files) are compiled to. Known as $(BIN).

  • src/ : Where all the sources for the binary files live. Known as $(SRC).

  • test/ : Subdirectory for testing. Known as $(TEST)

    • integration-tests : Subdirectory for integration-test files. Known as $(REG_TEST_DIR)

    • unit-tests : Subdirectory for unit-test files. Known as $(UNIT_TEST_DIR)

      • bin/ : Where all executables (including intermediate *.o and *.a files) only relating to the unit tests are compiled to. Known as $(UNIT_TEST_BIN)

      • src/ : Where all the source for the unit tests live. Known as $(UNIT_TEST_SRC)

  • util/ : Where utility resources (such as scripts) live. Known as $(UTIL)

  • documentation/: Where doxygen outputs its files. Known as $(DOC_PATH)

  • third-party/ : Subdirectory for third-party materials, their source, their build directories, and their install directories. Known as $(THIRD_PARTY)

    • source/ : The original source distributions of third-party materials. Known as $(THIRD_PARTY_SRC)

    • build/: Where third-party materials are extracted to and built. Created after make genesis. Known as $(THIRD_PARTY_BUILD)

    • install/ : Where third-party materials are installed to. Created after make genesis. Known as $(THIRD_PARTY_INSTALL)

      • lib/ : Third-party libraries. Known as $(LIB)

      • include/ : Third-party headers. Known as $(INC)

Make commands

  • initialize (or init): This is the first command that should be run when getting started with the project. It builds and places all the third-party tools into good organized places.

  • all: Builds the LoopChainIR.a library (after first performing initialize if necessary)

  • test: Performs unit-tests and integration-tests

  • unit-tests: Runs all unit tests specified by $(UNIT-TESTS)

  • integration-tests: Runs all integration tests specified by $(REG_TESTS)

  • documentation (or doc): Runs doxygen, uses the local Doxyfile

  • neat: Removes all *.o files from $(BIN).

  • clean-third-party: Removes (recursive, forced) $(THIRD_PARTY_INSTALL) and $(THIRD_PARTY_BUILD).

  • clean-test: Removes (recursive) all files from $(UNIT_TEST_BIN), and *.dir and *.log files from $(REG_TEST_DIR)

  • clean-doc: Removes (recursive) the $(DOC_PATH) directory

  • clean: Performs clean-test and removes (recursively) all files under $(BIN).

  • clean-all: Performs clean, clean-third-party, and clean-doc. Mimics a restored project state.

  • install: Copies the library and header files to the location described by $(prefix). Installed files are listed in the install log (install.txt)

  • uninstall: Removes (recursive, forced) the files listed in the install log (install.txt)

Documentation

The LoopChainIR API is documented using Doxygen.

To generate the HTML documentation, run

make documentation

or

make doc

The output can be found at $(DOC)

Testing

A complete run of all tests (both integration and unit) is run with

make test

Unit Testing

Testing is conducted through the Google Test unit test framework.

Preferably, each project source file gets its own unit test file (i.e. RectangularDomain.cpp and RectangularDomain_test.cpp).

Tests are run with

make unit-tests

Or individually using the name of the test, for example:

make RectangularDomain_test

Integration Testing

Integration testing is conducted by an in-house script (see $(UTIL)/integration-util.py).

Test files are placed in $(REG_TEST_DIR).

Tests are run with

make integration-tests

Or individually using the name of the test.

If a test fails, it's log file is dropped next to the test file suffixed with '.log'. This can be useful to determine what failed, how to fix it, and in the case of a software error is useful to us.

Itegration Test Files

A integration test has several sections:

  • test name : Name of the test. Prefers no white-space.

  • loop chain : An ordered list of each loop nest, where each loop nest is expressed as a terse domain.

    Example:

    loop chain:
    (i){0..9}
    (i){0..9}
    (i,j){0..M-1,0..N-1}
    :end
    

    The iterators (symbols in the parentheses) are comma separated and can be any valid C variable symbol. The bounds (expressions in the brackets) as comma separated list of ranges. Each range is expressed lower_bound .. upper_bound, and bounds can contain simple expressions (using + - * / % operators and parentheses, no function calls) The iterators and bounds are matched up by their index (i.e. the first iterator is bounded by the first range, and the second iterator by the second, and so on.)

  • schedule : There are three schedule {things}

    • Original: default sequential schedule for a loop chain. code: original
      regex: original

    • Fusion schedule: Fuse a series of loops.
      code: fuse {loop index} {loop index} [{loop index} ...]
      regex: "fuse\s+(?P<list>(?:\d+\s*){2,})
      Example: fuse 0, 1 fuses loops 0 and 1 (the first and second loops).

    • Shift: shift the domain of a loop by some extent(s). Extents can be constant integers, symbols, and valid C expressions using only arithmetic operators. There must be the same number of extents as dimensions of the domain of the loop.
      code: shift {loop index} ({extent} [,{extent} ...])
      regex: shift\s+(?P<loopid>\d+)\s+\(\s*(?P<extents>.+)\s*\)
      Example: shift 0 (1,K,n+3) shifts the first loop in the chain, which is 3D,by 1, K, and n+3.

    Multiple schedules can be composed, and are applied in the order specified.

  • dependencies : The dependencies that must be satisfied for any transformation on the loop. These are used to ensure that a transformation produced a loop satisfying the dependencies of the original loop. This is expressed in traditional ISCC syntax. However, unlike in ISCC, each iteration must be expressed in full-form syntax [loop nest, iterator, (loop nest, iterator,)* statement]. Further, they must be padded so that all iterations are the same length For example, the statement 'inside' the first loop is expressed in full-form as [0,i,0], since its the 0'th loop, has iteration i, and is the 0'th statement. With padding it becomes [0,i,0,0,0]

    Code Example, continuing with loop chain example:

    dependencies:
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The first line indicates that iteration i comes before iteration i+1 in the first loop.
    The second line indicates that iteration i comes before iteration i+1 in the second loop.
    The third line indicates that iteration j comes before iteration j+1 in the third loop.
    The fourth line indicates that iteration i comes before iteration i+1 in the second loop.
    The fifth line indicates that all iterations in the first loop come before any iterations in the second loop.

    Please note that each dependency is treated by the framework as a separate entity, and is split by newlines. This means that a dependency expression currently cannot span multiple lines.

  • new ordering : The dependencies that must be satisfied for the particular transformation. This is written in the same way as the dependencies section. If the transformation being tested is the original schedule, then the text will probably be identical. Code Example, continuing with loop chain example, performing a loop fusion on the first two loops:

    new ordering:
    { [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The only change from the dependency code is the first line, which indicates that iteration i in the second loop comes before iteration i+1 in the first loop.

  • exemplar : (Optional) (Currently InOp) Actual original C/C++ code that should be tested by the source-to-source transformation tool (which doesn't exist yet). Code Example:

    exemplar:
    for( int i = 0; i < 10; i += 1 ){
    A[i] = Static[i];
    }
    for( int i = 0; i <= 9; i++ ){
    B[i] = f( A[i] );
    }
    for( int i = 0; i < M; ++i ){
    for( int j = 0; j <= N-1; j = j + 1 ){
    C[i,j] = A[i%10] / B[i%10];
    }
    }
    :end
    

The full test (using all the examples) would look something like this:

test name: example_3N_1D_1D_2D
loop chain:
(i){0..9}
(i){0..9}
(i,j){0..M-1,0..N-1}
:end
dependencies:
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
schedule:
fuse 0, 1, 2
:end
new ordering:
{ [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
exemplar:
for( int i = 0; i < 10; i += 1 ){
A[i] = Static[i];
}
for( int i = 0; i <= 9; i++ ){
B[i] = f( A[i] );
}
for( int i = 0; i < M; ++i ){
for( int j = 0; j <= N-1; j = j + 1 ){
C[i,j] = A[i%10] / B[i%10];
}
}
:end

integration-util.py

The integration-util.py script lives in $(UTIL) and is the driver behind the integration testing framework.

To run a test (or list of tests) by hand, simply calls

python $(UTIL)/integration-util.py path/to/file.test path/to/file2.test

There are options for the script:

  • --save_env (or -se): Save the testing environment after a test completes. By default, test environments are erased when test completes, regardless of failure state.

  • --save_env_on_fail (or -sf): Save the testing environment after a test fails. By default, test environments are erased when test completes, regardless of failure state.

  • --save_log (or -sl): Save the log file, even if test is successful. By default, logs are only saved to file if a test fails.

  • --resources_path PATH (or -r): Give the script a path to $(UTIL)/resources. By default, the script assumes that it lives in the same directory as the resources folder and will construct the path from its call.

  • --project_path PATH (or -p): Give the script a path to the LoopChainIR project directory. By default, the script assumes that it will be called from the LoopChainIr project root directory, and thus the path would be equivalent to ".".

Third-Party materials

Included with this project are several third-party materials under the $(THIRD_PARTY_SRC) directory.

  1. Google Test

All third-party materials are provided as they were downloaded, and include their copyright and license information.

About

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Resources

Stars

0 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

LoopChainIR

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Quickstart

Prerequisites

LoopChainIR depends on the following libraries:

Configure, Make, Test, and install

You must first configure the project before building using the configuration script:

./configure

See the configuration options available using ./configure --help.

After a successful configuration, the makefile will be generated. Run make all to compile the LoopChainIR library object. To ensure the project is in working order run make test to run the unit and integration tests.

To install, run make install. To choose a non-default installation location, use the --prefix option of the configuration script. To uninstall run make uninstall. installed.txt lists the full path of each file and directory that was installed.

Project Directory Structure

  • bin/ : Where all executables (including intermediate *.o and *.a files) are compiled to. Known as $(BIN).

  • src/ : Where all the sources for the binary files live. Known as $(SRC).

  • test/ : Subdirectory for testing. Known as $(TEST)

    • integration-tests : Subdirectory for integration-test files. Known as $(REG_TEST_DIR)

    • unit-tests : Subdirectory for unit-test files. Known as $(UNIT_TEST_DIR)

      • bin/ : Where all executables (including intermediate *.o and *.a files) only relating to the unit tests are compiled to. Known as $(UNIT_TEST_BIN)

      • src/ : Where all the source for the unit tests live. Known as $(UNIT_TEST_SRC)

  • util/ : Where utility resources (such as scripts) live. Known as $(UTIL)

  • documentation/: Where doxygen outputs its files. Known as $(DOC_PATH)

  • third-party/ : Subdirectory for third-party materials, their source, their build directories, and their install directories. Known as $(THIRD_PARTY)

    • source/ : The original source distributions of third-party materials. Known as $(THIRD_PARTY_SRC)

    • build/: Where third-party materials are extracted to and built. Created after make genesis. Known as $(THIRD_PARTY_BUILD)

    • install/ : Where third-party materials are installed to. Created after make genesis. Known as $(THIRD_PARTY_INSTALL)

      • lib/ : Third-party libraries. Known as $(LIB)

      • include/ : Third-party headers. Known as $(INC)

Make commands

  • initialize (or init): This is the first command that should be run when getting started with the project. It builds and places all the third-party tools into good organized places.

  • all: Builds the LoopChainIR.a library (after first performing initialize if necessary)

  • test: Performs unit-tests and integration-tests

  • unit-tests: Runs all unit tests specified by $(UNIT-TESTS)

  • integration-tests: Runs all integration tests specified by $(REG_TESTS)

  • documentation (or doc): Runs doxygen, uses the local Doxyfile

  • neat: Removes all *.o files from $(BIN).

  • clean-third-party: Removes (recursive, forced) $(THIRD_PARTY_INSTALL) and $(THIRD_PARTY_BUILD).

  • clean-test: Removes (recursive) all files from $(UNIT_TEST_BIN), and *.dir and *.log files from $(REG_TEST_DIR)

  • clean-doc: Removes (recursive) the $(DOC_PATH) directory

  • clean: Performs clean-test and removes (recursively) all files under $(BIN).

  • clean-all: Performs clean, clean-third-party, and clean-doc. Mimics a restored project state.

  • install: Copies the library and header files to the location described by $(prefix). Installed files are listed in the install log (install.txt)

  • uninstall: Removes (recursive, forced) the files listed in the install log (install.txt)

Documentation

The LoopChainIR API is documented using Doxygen.

To generate the HTML documentation, run

make documentation

or

make doc

The output can be found at $(DOC)

Testing

A complete run of all tests (both integration and unit) is run with

make test

Unit Testing

Testing is conducted through the Google Test unit test framework.

Preferably, each project source file gets its own unit test file (i.e. RectangularDomain.cpp and RectangularDomain_test.cpp).

Tests are run with

make unit-tests

Or individually using the name of the test, for example:

make RectangularDomain_test

Integration Testing

Integration testing is conducted by an in-house script (see $(UTIL)/integration-util.py).

Test files are placed in $(REG_TEST_DIR).

Tests are run with

make integration-tests

Or individually using the name of the test.

If a test fails, it's log file is dropped next to the test file suffixed with '.log'. This can be useful to determine what failed, how to fix it, and in the case of a software error is useful to us.

Itegration Test Files

A integration test has several sections:

  • test name : Name of the test. Prefers no white-space.

  • loop chain : An ordered list of each loop nest, where each loop nest is expressed as a terse domain.

    Example:

    loop chain:
    (i){0..9}
    (i){0..9}
    (i,j){0..M-1,0..N-1}
    :end
    

    The iterators (symbols in the parentheses) are comma separated and can be any valid C variable symbol. The bounds (expressions in the brackets) as comma separated list of ranges. Each range is expressed lower_bound .. upper_bound, and bounds can contain simple expressions (using + - * / % operators and parentheses, no function calls) The iterators and bounds are matched up by their index (i.e. the first iterator is bounded by the first range, and the second iterator by the second, and so on.)

  • schedule : There are three schedule {things}

    • Original: default sequential schedule for a loop chain. code: original
      regex: original

    • Fusion schedule: Fuse a series of loops.
      code: fuse {loop index} {loop index} [{loop index} ...]
      regex: "fuse\s+(?P<list>(?:\d+\s*){2,})
      Example: fuse 0, 1 fuses loops 0 and 1 (the first and second loops).

    • Shift: shift the domain of a loop by some extent(s). Extents can be constant integers, symbols, and valid C expressions using only arithmetic operators. There must be the same number of extents as dimensions of the domain of the loop.
      code: shift {loop index} ({extent} [,{extent} ...])
      regex: shift\s+(?P<loopid>\d+)\s+\(\s*(?P<extents>.+)\s*\)
      Example: shift 0 (1,K,n+3) shifts the first loop in the chain, which is 3D,by 1, K, and n+3.

    Multiple schedules can be composed, and are applied in the order specified.

  • dependencies : The dependencies that must be satisfied for any transformation on the loop. These are used to ensure that a transformation produced a loop satisfying the dependencies of the original loop. This is expressed in traditional ISCC syntax. However, unlike in ISCC, each iteration must be expressed in full-form syntax [loop nest, iterator, (loop nest, iterator,)* statement]. Further, they must be padded so that all iterations are the same length For example, the statement 'inside' the first loop is expressed in full-form as [0,i,0], since its the 0'th loop, has iteration i, and is the 0'th statement. With padding it becomes [0,i,0,0,0]

    Code Example, continuing with loop chain example:

    dependencies:
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The first line indicates that iteration i comes before iteration i+1 in the first loop.
    The second line indicates that iteration i comes before iteration i+1 in the second loop.
    The third line indicates that iteration j comes before iteration j+1 in the third loop.
    The fourth line indicates that iteration i comes before iteration i+1 in the second loop.
    The fifth line indicates that all iterations in the first loop come before any iterations in the second loop.

    Please note that each dependency is treated by the framework as a separate entity, and is split by newlines. This means that a dependency expression currently cannot span multiple lines.

  • new ordering : The dependencies that must be satisfied for the particular transformation. This is written in the same way as the dependencies section. If the transformation being tested is the original schedule, then the text will probably be identical. Code Example, continuing with loop chain example, performing a loop fusion on the first two loops:

    new ordering:
    { [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The only change from the dependency code is the first line, which indicates that iteration i in the second loop comes before iteration i+1 in the first loop.

  • exemplar : (Optional) (Currently InOp) Actual original C/C++ code that should be tested by the source-to-source transformation tool (which doesn't exist yet). Code Example:

    exemplar:
    for( int i = 0; i < 10; i += 1 ){
    A[i] = Static[i];
    }
    for( int i = 0; i <= 9; i++ ){
    B[i] = f( A[i] );
    }
    for( int i = 0; i < M; ++i ){
    for( int j = 0; j <= N-1; j = j + 1 ){
    C[i,j] = A[i%10] / B[i%10];
    }
    }
    :end
    

The full test (using all the examples) would look something like this:

test name: example_3N_1D_1D_2D
loop chain:
(i){0..9}
(i){0..9}
(i,j){0..M-1,0..N-1}
:end
dependencies:
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
schedule:
fuse 0, 1, 2
:end
new ordering:
{ [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
exemplar:
for( int i = 0; i < 10; i += 1 ){
A[i] = Static[i];
}
for( int i = 0; i <= 9; i++ ){
B[i] = f( A[i] );
}
for( int i = 0; i < M; ++i ){
for( int j = 0; j <= N-1; j = j + 1 ){
C[i,j] = A[i%10] / B[i%10];
}
}
:end

integration-util.py

The integration-util.py script lives in $(UTIL) and is the driver behind the integration testing framework.

To run a test (or list of tests) by hand, simply calls

python $(UTIL)/integration-util.py path/to/file.test path/to/file2.test

There are options for the script:

  • --save_env (or -se): Save the testing environment after a test completes. By default, test environments are erased when test completes, regardless of failure state.

  • --save_env_on_fail (or -sf): Save the testing environment after a test fails. By default, test environments are erased when test completes, regardless of failure state.

  • --save_log (or -sl): Save the log file, even if test is successful. By default, logs are only saved to file if a test fails.

  • --resources_path PATH (or -r): Give the script a path to $(UTIL)/resources. By default, the script assumes that it lives in the same directory as the resources folder and will construct the path from its call.

  • --project_path PATH (or -p): Give the script a path to the LoopChainIR project directory. By default, the script assumes that it will be called from the LoopChainIr project root directory, and thus the path would be equivalent to ".".

Third-Party materials

Included with this project are several third-party materials under the $(THIRD_PARTY_SRC) directory.

  1. Google Test

All third-party materials are provided as they were downloaded, and include their copyright and license information.

About

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Resources

Stars

0 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

LoopChainIR

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Quickstart

Prerequisites

LoopChainIR depends on the following libraries:

Configure, Make, Test, and install

You must first configure the project before building using the configuration script:

./configure

See the configuration options available using ./configure --help.

After a successful configuration, the makefile will be generated. Run make all to compile the LoopChainIR library object. To ensure the project is in working order run make test to run the unit and integration tests.

To install, run make install. To choose a non-default installation location, use the --prefix option of the configuration script. To uninstall run make uninstall. installed.txt lists the full path of each file and directory that was installed.

Project Directory Structure

  • bin/ : Where all executables (including intermediate *.o and *.a files) are compiled to. Known as $(BIN).

  • src/ : Where all the sources for the binary files live. Known as $(SRC).

  • test/ : Subdirectory for testing. Known as $(TEST)

    • integration-tests : Subdirectory for integration-test files. Known as $(REG_TEST_DIR)

    • unit-tests : Subdirectory for unit-test files. Known as $(UNIT_TEST_DIR)

      • bin/ : Where all executables (including intermediate *.o and *.a files) only relating to the unit tests are compiled to. Known as $(UNIT_TEST_BIN)

      • src/ : Where all the source for the unit tests live. Known as $(UNIT_TEST_SRC)

  • util/ : Where utility resources (such as scripts) live. Known as $(UTIL)

  • documentation/: Where doxygen outputs its files. Known as $(DOC_PATH)

  • third-party/ : Subdirectory for third-party materials, their source, their build directories, and their install directories. Known as $(THIRD_PARTY)

    • source/ : The original source distributions of third-party materials. Known as $(THIRD_PARTY_SRC)

    • build/: Where third-party materials are extracted to and built. Created after make genesis. Known as $(THIRD_PARTY_BUILD)

    • install/ : Where third-party materials are installed to. Created after make genesis. Known as $(THIRD_PARTY_INSTALL)

      • lib/ : Third-party libraries. Known as $(LIB)

      • include/ : Third-party headers. Known as $(INC)

Make commands

  • initialize (or init): This is the first command that should be run when getting started with the project. It builds and places all the third-party tools into good organized places.

  • all: Builds the LoopChainIR.a library (after first performing initialize if necessary)

  • test: Performs unit-tests and integration-tests

  • unit-tests: Runs all unit tests specified by $(UNIT-TESTS)

  • integration-tests: Runs all integration tests specified by $(REG_TESTS)

  • documentation (or doc): Runs doxygen, uses the local Doxyfile

  • neat: Removes all *.o files from $(BIN).

  • clean-third-party: Removes (recursive, forced) $(THIRD_PARTY_INSTALL) and $(THIRD_PARTY_BUILD).

  • clean-test: Removes (recursive) all files from $(UNIT_TEST_BIN), and *.dir and *.log files from $(REG_TEST_DIR)

  • clean-doc: Removes (recursive) the $(DOC_PATH) directory

  • clean: Performs clean-test and removes (recursively) all files under $(BIN).

  • clean-all: Performs clean, clean-third-party, and clean-doc. Mimics a restored project state.

  • install: Copies the library and header files to the location described by $(prefix). Installed files are listed in the install log (install.txt)

  • uninstall: Removes (recursive, forced) the files listed in the install log (install.txt)

Documentation

The LoopChainIR API is documented using Doxygen.

To generate the HTML documentation, run

make documentation

or

make doc

The output can be found at $(DOC)

Testing

A complete run of all tests (both integration and unit) is run with

make test

Unit Testing

Testing is conducted through the Google Test unit test framework.

Preferably, each project source file gets its own unit test file (i.e. RectangularDomain.cpp and RectangularDomain_test.cpp).

Tests are run with

make unit-tests

Or individually using the name of the test, for example:

make RectangularDomain_test

Integration Testing

Integration testing is conducted by an in-house script (see $(UTIL)/integration-util.py).

Test files are placed in $(REG_TEST_DIR).

Tests are run with

make integration-tests

Or individually using the name of the test.

If a test fails, it's log file is dropped next to the test file suffixed with '.log'. This can be useful to determine what failed, how to fix it, and in the case of a software error is useful to us.

Itegration Test Files

A integration test has several sections:

  • test name : Name of the test. Prefers no white-space.

  • loop chain : An ordered list of each loop nest, where each loop nest is expressed as a terse domain.

    Example:

    loop chain:
    (i){0..9}
    (i){0..9}
    (i,j){0..M-1,0..N-1}
    :end
    

    The iterators (symbols in the parentheses) are comma separated and can be any valid C variable symbol. The bounds (expressions in the brackets) as comma separated list of ranges. Each range is expressed lower_bound .. upper_bound, and bounds can contain simple expressions (using + - * / % operators and parentheses, no function calls) The iterators and bounds are matched up by their index (i.e. the first iterator is bounded by the first range, and the second iterator by the second, and so on.)

  • schedule : There are three schedule {things}

    • Original: default sequential schedule for a loop chain. code: original
      regex: original

    • Fusion schedule: Fuse a series of loops.
      code: fuse {loop index} {loop index} [{loop index} ...]
      regex: "fuse\s+(?P<list>(?:\d+\s*){2,})
      Example: fuse 0, 1 fuses loops 0 and 1 (the first and second loops).

    • Shift: shift the domain of a loop by some extent(s). Extents can be constant integers, symbols, and valid C expressions using only arithmetic operators. There must be the same number of extents as dimensions of the domain of the loop.
      code: shift {loop index} ({extent} [,{extent} ...])
      regex: shift\s+(?P<loopid>\d+)\s+\(\s*(?P<extents>.+)\s*\)
      Example: shift 0 (1,K,n+3) shifts the first loop in the chain, which is 3D,by 1, K, and n+3.

    Multiple schedules can be composed, and are applied in the order specified.

  • dependencies : The dependencies that must be satisfied for any transformation on the loop. These are used to ensure that a transformation produced a loop satisfying the dependencies of the original loop. This is expressed in traditional ISCC syntax. However, unlike in ISCC, each iteration must be expressed in full-form syntax [loop nest, iterator, (loop nest, iterator,)* statement]. Further, they must be padded so that all iterations are the same length For example, the statement 'inside' the first loop is expressed in full-form as [0,i,0], since its the 0'th loop, has iteration i, and is the 0'th statement. With padding it becomes [0,i,0,0,0]

    Code Example, continuing with loop chain example:

    dependencies:
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The first line indicates that iteration i comes before iteration i+1 in the first loop.
    The second line indicates that iteration i comes before iteration i+1 in the second loop.
    The third line indicates that iteration j comes before iteration j+1 in the third loop.
    The fourth line indicates that iteration i comes before iteration i+1 in the second loop.
    The fifth line indicates that all iterations in the first loop come before any iterations in the second loop.

    Please note that each dependency is treated by the framework as a separate entity, and is split by newlines. This means that a dependency expression currently cannot span multiple lines.

  • new ordering : The dependencies that must be satisfied for the particular transformation. This is written in the same way as the dependencies section. If the transformation being tested is the original schedule, then the text will probably be identical. Code Example, continuing with loop chain example, performing a loop fusion on the first two loops:

    new ordering:
    { [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The only change from the dependency code is the first line, which indicates that iteration i in the second loop comes before iteration i+1 in the first loop.

  • exemplar : (Optional) (Currently InOp) Actual original C/C++ code that should be tested by the source-to-source transformation tool (which doesn't exist yet). Code Example:

    exemplar:
    for( int i = 0; i < 10; i += 1 ){
    A[i] = Static[i];
    }
    for( int i = 0; i <= 9; i++ ){
    B[i] = f( A[i] );
    }
    for( int i = 0; i < M; ++i ){
    for( int j = 0; j <= N-1; j = j + 1 ){
    C[i,j] = A[i%10] / B[i%10];
    }
    }
    :end
    

The full test (using all the examples) would look something like this:

test name: example_3N_1D_1D_2D
loop chain:
(i){0..9}
(i){0..9}
(i,j){0..M-1,0..N-1}
:end
dependencies:
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
schedule:
fuse 0, 1, 2
:end
new ordering:
{ [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
exemplar:
for( int i = 0; i < 10; i += 1 ){
A[i] = Static[i];
}
for( int i = 0; i <= 9; i++ ){
B[i] = f( A[i] );
}
for( int i = 0; i < M; ++i ){
for( int j = 0; j <= N-1; j = j + 1 ){
C[i,j] = A[i%10] / B[i%10];
}
}
:end

integration-util.py

The integration-util.py script lives in $(UTIL) and is the driver behind the integration testing framework.

To run a test (or list of tests) by hand, simply calls

python $(UTIL)/integration-util.py path/to/file.test path/to/file2.test

There are options for the script:

  • --save_env (or -se): Save the testing environment after a test completes. By default, test environments are erased when test completes, regardless of failure state.

  • --save_env_on_fail (or -sf): Save the testing environment after a test fails. By default, test environments are erased when test completes, regardless of failure state.

  • --save_log (or -sl): Save the log file, even if test is successful. By default, logs are only saved to file if a test fails.

  • --resources_path PATH (or -r): Give the script a path to $(UTIL)/resources. By default, the script assumes that it lives in the same directory as the resources folder and will construct the path from its call.

  • --project_path PATH (or -p): Give the script a path to the LoopChainIR project directory. By default, the script assumes that it will be called from the LoopChainIr project root directory, and thus the path would be equivalent to ".".

Third-Party materials

Included with this project are several third-party materials under the $(THIRD_PARTY_SRC) directory.

  1. Google Test

All third-party materials are provided as they were downloaded, and include their copyright and license information.

About

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Resources

Stars

0 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

LoopChainIR

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Quickstart

Prerequisites

LoopChainIR depends on the following libraries:

Configure, Make, Test, and install

You must first configure the project before building using the configuration script:

./configure

See the configuration options available using ./configure --help.

After a successful configuration, the makefile will be generated. Run make all to compile the LoopChainIR library object. To ensure the project is in working order run make test to run the unit and integration tests.

To install, run make install. To choose a non-default installation location, use the --prefix option of the configuration script. To uninstall run make uninstall. installed.txt lists the full path of each file and directory that was installed.

Project Directory Structure

  • bin/ : Where all executables (including intermediate *.o and *.a files) are compiled to. Known as $(BIN).

  • src/ : Where all the sources for the binary files live. Known as $(SRC).

  • test/ : Subdirectory for testing. Known as $(TEST)

    • integration-tests : Subdirectory for integration-test files. Known as $(REG_TEST_DIR)

    • unit-tests : Subdirectory for unit-test files. Known as $(UNIT_TEST_DIR)

      • bin/ : Where all executables (including intermediate *.o and *.a files) only relating to the unit tests are compiled to. Known as $(UNIT_TEST_BIN)

      • src/ : Where all the source for the unit tests live. Known as $(UNIT_TEST_SRC)

  • util/ : Where utility resources (such as scripts) live. Known as $(UTIL)

  • documentation/: Where doxygen outputs its files. Known as $(DOC_PATH)

  • third-party/ : Subdirectory for third-party materials, their source, their build directories, and their install directories. Known as $(THIRD_PARTY)

    • source/ : The original source distributions of third-party materials. Known as $(THIRD_PARTY_SRC)

    • build/: Where third-party materials are extracted to and built. Created after make genesis. Known as $(THIRD_PARTY_BUILD)

    • install/ : Where third-party materials are installed to. Created after make genesis. Known as $(THIRD_PARTY_INSTALL)

      • lib/ : Third-party libraries. Known as $(LIB)

      • include/ : Third-party headers. Known as $(INC)

Make commands

  • initialize (or init): This is the first command that should be run when getting started with the project. It builds and places all the third-party tools into good organized places.

  • all: Builds the LoopChainIR.a library (after first performing initialize if necessary)

  • test: Performs unit-tests and integration-tests

  • unit-tests: Runs all unit tests specified by $(UNIT-TESTS)

  • integration-tests: Runs all integration tests specified by $(REG_TESTS)

  • documentation (or doc): Runs doxygen, uses the local Doxyfile

  • neat: Removes all *.o files from $(BIN).

  • clean-third-party: Removes (recursive, forced) $(THIRD_PARTY_INSTALL) and $(THIRD_PARTY_BUILD).

  • clean-test: Removes (recursive) all files from $(UNIT_TEST_BIN), and *.dir and *.log files from $(REG_TEST_DIR)

  • clean-doc: Removes (recursive) the $(DOC_PATH) directory

  • clean: Performs clean-test and removes (recursively) all files under $(BIN).

  • clean-all: Performs clean, clean-third-party, and clean-doc. Mimics a restored project state.

  • install: Copies the library and header files to the location described by $(prefix). Installed files are listed in the install log (install.txt)

  • uninstall: Removes (recursive, forced) the files listed in the install log (install.txt)

Documentation

The LoopChainIR API is documented using Doxygen.

To generate the HTML documentation, run

make documentation

or

make doc

The output can be found at $(DOC)

Testing

A complete run of all tests (both integration and unit) is run with

make test

Unit Testing

Testing is conducted through the Google Test unit test framework.

Preferably, each project source file gets its own unit test file (i.e. RectangularDomain.cpp and RectangularDomain_test.cpp).

Tests are run with

make unit-tests

Or individually using the name of the test, for example:

make RectangularDomain_test

Integration Testing

Integration testing is conducted by an in-house script (see $(UTIL)/integration-util.py).

Test files are placed in $(REG_TEST_DIR).

Tests are run with

make integration-tests

Or individually using the name of the test.

If a test fails, it's log file is dropped next to the test file suffixed with '.log'. This can be useful to determine what failed, how to fix it, and in the case of a software error is useful to us.

Itegration Test Files

A integration test has several sections:

  • test name : Name of the test. Prefers no white-space.

  • loop chain : An ordered list of each loop nest, where each loop nest is expressed as a terse domain.

    Example:

    loop chain:
    (i){0..9}
    (i){0..9}
    (i,j){0..M-1,0..N-1}
    :end
    

    The iterators (symbols in the parentheses) are comma separated and can be any valid C variable symbol. The bounds (expressions in the brackets) as comma separated list of ranges. Each range is expressed lower_bound .. upper_bound, and bounds can contain simple expressions (using + - * / % operators and parentheses, no function calls) The iterators and bounds are matched up by their index (i.e. the first iterator is bounded by the first range, and the second iterator by the second, and so on.)

  • schedule : There are three schedule {things}

    • Original: default sequential schedule for a loop chain. code: original
      regex: original

    • Fusion schedule: Fuse a series of loops.
      code: fuse {loop index} {loop index} [{loop index} ...]
      regex: "fuse\s+(?P<list>(?:\d+\s*){2,})
      Example: fuse 0, 1 fuses loops 0 and 1 (the first and second loops).

    • Shift: shift the domain of a loop by some extent(s). Extents can be constant integers, symbols, and valid C expressions using only arithmetic operators. There must be the same number of extents as dimensions of the domain of the loop.
      code: shift {loop index} ({extent} [,{extent} ...])
      regex: shift\s+(?P<loopid>\d+)\s+\(\s*(?P<extents>.+)\s*\)
      Example: shift 0 (1,K,n+3) shifts the first loop in the chain, which is 3D,by 1, K, and n+3.

    Multiple schedules can be composed, and are applied in the order specified.

  • dependencies : The dependencies that must be satisfied for any transformation on the loop. These are used to ensure that a transformation produced a loop satisfying the dependencies of the original loop. This is expressed in traditional ISCC syntax. However, unlike in ISCC, each iteration must be expressed in full-form syntax [loop nest, iterator, (loop nest, iterator,)* statement]. Further, they must be padded so that all iterations are the same length For example, the statement 'inside' the first loop is expressed in full-form as [0,i,0], since its the 0'th loop, has iteration i, and is the 0'th statement. With padding it becomes [0,i,0,0,0]

    Code Example, continuing with loop chain example:

    dependencies:
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The first line indicates that iteration i comes before iteration i+1 in the first loop.
    The second line indicates that iteration i comes before iteration i+1 in the second loop.
    The third line indicates that iteration j comes before iteration j+1 in the third loop.
    The fourth line indicates that iteration i comes before iteration i+1 in the second loop.
    The fifth line indicates that all iterations in the first loop come before any iterations in the second loop.

    Please note that each dependency is treated by the framework as a separate entity, and is split by newlines. This means that a dependency expression currently cannot span multiple lines.

  • new ordering : The dependencies that must be satisfied for the particular transformation. This is written in the same way as the dependencies section. If the transformation being tested is the original schedule, then the text will probably be identical. Code Example, continuing with loop chain example, performing a loop fusion on the first two loops:

    new ordering:
    { [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The only change from the dependency code is the first line, which indicates that iteration i in the second loop comes before iteration i+1 in the first loop.

  • exemplar : (Optional) (Currently InOp) Actual original C/C++ code that should be tested by the source-to-source transformation tool (which doesn't exist yet). Code Example:

    exemplar:
    for( int i = 0; i < 10; i += 1 ){
    A[i] = Static[i];
    }
    for( int i = 0; i <= 9; i++ ){
    B[i] = f( A[i] );
    }
    for( int i = 0; i < M; ++i ){
    for( int j = 0; j <= N-1; j = j + 1 ){
    C[i,j] = A[i%10] / B[i%10];
    }
    }
    :end
    

The full test (using all the examples) would look something like this:

test name: example_3N_1D_1D_2D
loop chain:
(i){0..9}
(i){0..9}
(i,j){0..M-1,0..N-1}
:end
dependencies:
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
schedule:
fuse 0, 1, 2
:end
new ordering:
{ [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
exemplar:
for( int i = 0; i < 10; i += 1 ){
A[i] = Static[i];
}
for( int i = 0; i <= 9; i++ ){
B[i] = f( A[i] );
}
for( int i = 0; i < M; ++i ){
for( int j = 0; j <= N-1; j = j + 1 ){
C[i,j] = A[i%10] / B[i%10];
}
}
:end

integration-util.py

The integration-util.py script lives in $(UTIL) and is the driver behind the integration testing framework.

To run a test (or list of tests) by hand, simply calls

python $(UTIL)/integration-util.py path/to/file.test path/to/file2.test

There are options for the script:

  • --save_env (or -se): Save the testing environment after a test completes. By default, test environments are erased when test completes, regardless of failure state.

  • --save_env_on_fail (or -sf): Save the testing environment after a test fails. By default, test environments are erased when test completes, regardless of failure state.

  • --save_log (or -sl): Save the log file, even if test is successful. By default, logs are only saved to file if a test fails.

  • --resources_path PATH (or -r): Give the script a path to $(UTIL)/resources. By default, the script assumes that it lives in the same directory as the resources folder and will construct the path from its call.

  • --project_path PATH (or -p): Give the script a path to the LoopChainIR project directory. By default, the script assumes that it will be called from the LoopChainIr project root directory, and thus the path would be equivalent to ".".

Third-Party materials

Included with this project are several third-party materials under the $(THIRD_PARTY_SRC) directory.

  1. Google Test

All third-party materials are provided as they were downloaded, and include their copyright and license information.

About

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Resources

Stars

0 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

LoopChainIR

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Quickstart

Prerequisites

LoopChainIR depends on the following libraries:

Configure, Make, Test, and install

You must first configure the project before building using the configuration script:

./configure

See the configuration options available using ./configure --help.

After a successful configuration, the makefile will be generated. Run make all to compile the LoopChainIR library object. To ensure the project is in working order run make test to run the unit and integration tests.

To install, run make install. To choose a non-default installation location, use the --prefix option of the configuration script. To uninstall run make uninstall. installed.txt lists the full path of each file and directory that was installed.

Project Directory Structure

  • bin/ : Where all executables (including intermediate *.o and *.a files) are compiled to. Known as $(BIN).

  • src/ : Where all the sources for the binary files live. Known as $(SRC).

  • test/ : Subdirectory for testing. Known as $(TEST)

    • integration-tests : Subdirectory for integration-test files. Known as $(REG_TEST_DIR)

    • unit-tests : Subdirectory for unit-test files. Known as $(UNIT_TEST_DIR)

      • bin/ : Where all executables (including intermediate *.o and *.a files) only relating to the unit tests are compiled to. Known as $(UNIT_TEST_BIN)

      • src/ : Where all the source for the unit tests live. Known as $(UNIT_TEST_SRC)

  • util/ : Where utility resources (such as scripts) live. Known as $(UTIL)

  • documentation/: Where doxygen outputs its files. Known as $(DOC_PATH)

  • third-party/ : Subdirectory for third-party materials, their source, their build directories, and their install directories. Known as $(THIRD_PARTY)

    • source/ : The original source distributions of third-party materials. Known as $(THIRD_PARTY_SRC)

    • build/: Where third-party materials are extracted to and built. Created after make genesis. Known as $(THIRD_PARTY_BUILD)

    • install/ : Where third-party materials are installed to. Created after make genesis. Known as $(THIRD_PARTY_INSTALL)

      • lib/ : Third-party libraries. Known as $(LIB)

      • include/ : Third-party headers. Known as $(INC)

Make commands

  • initialize (or init): This is the first command that should be run when getting started with the project. It builds and places all the third-party tools into good organized places.

  • all: Builds the LoopChainIR.a library (after first performing initialize if necessary)

  • test: Performs unit-tests and integration-tests

  • unit-tests: Runs all unit tests specified by $(UNIT-TESTS)

  • integration-tests: Runs all integration tests specified by $(REG_TESTS)

  • documentation (or doc): Runs doxygen, uses the local Doxyfile

  • neat: Removes all *.o files from $(BIN).

  • clean-third-party: Removes (recursive, forced) $(THIRD_PARTY_INSTALL) and $(THIRD_PARTY_BUILD).

  • clean-test: Removes (recursive) all files from $(UNIT_TEST_BIN), and *.dir and *.log files from $(REG_TEST_DIR)

  • clean-doc: Removes (recursive) the $(DOC_PATH) directory

  • clean: Performs clean-test and removes (recursively) all files under $(BIN).

  • clean-all: Performs clean, clean-third-party, and clean-doc. Mimics a restored project state.

  • install: Copies the library and header files to the location described by $(prefix). Installed files are listed in the install log (install.txt)

  • uninstall: Removes (recursive, forced) the files listed in the install log (install.txt)

Documentation

The LoopChainIR API is documented using Doxygen.

To generate the HTML documentation, run

make documentation

or

make doc

The output can be found at $(DOC)

Testing

A complete run of all tests (both integration and unit) is run with

make test

Unit Testing

Testing is conducted through the Google Test unit test framework.

Preferably, each project source file gets its own unit test file (i.e. RectangularDomain.cpp and RectangularDomain_test.cpp).

Tests are run with

make unit-tests

Or individually using the name of the test, for example:

make RectangularDomain_test

Integration Testing

Integration testing is conducted by an in-house script (see $(UTIL)/integration-util.py).

Test files are placed in $(REG_TEST_DIR).

Tests are run with

make integration-tests

Or individually using the name of the test.

If a test fails, it's log file is dropped next to the test file suffixed with '.log'. This can be useful to determine what failed, how to fix it, and in the case of a software error is useful to us.

Itegration Test Files

A integration test has several sections:

  • test name : Name of the test. Prefers no white-space.

  • loop chain : An ordered list of each loop nest, where each loop nest is expressed as a terse domain.

    Example:

    loop chain:
    (i){0..9}
    (i){0..9}
    (i,j){0..M-1,0..N-1}
    :end
    

    The iterators (symbols in the parentheses) are comma separated and can be any valid C variable symbol. The bounds (expressions in the brackets) as comma separated list of ranges. Each range is expressed lower_bound .. upper_bound, and bounds can contain simple expressions (using + - * / % operators and parentheses, no function calls) The iterators and bounds are matched up by their index (i.e. the first iterator is bounded by the first range, and the second iterator by the second, and so on.)

  • schedule : There are three schedule {things}

    • Original: default sequential schedule for a loop chain. code: original
      regex: original

    • Fusion schedule: Fuse a series of loops.
      code: fuse {loop index} {loop index} [{loop index} ...]
      regex: "fuse\s+(?P<list>(?:\d+\s*){2,})
      Example: fuse 0, 1 fuses loops 0 and 1 (the first and second loops).

    • Shift: shift the domain of a loop by some extent(s). Extents can be constant integers, symbols, and valid C expressions using only arithmetic operators. There must be the same number of extents as dimensions of the domain of the loop.
      code: shift {loop index} ({extent} [,{extent} ...])
      regex: shift\s+(?P<loopid>\d+)\s+\(\s*(?P<extents>.+)\s*\)
      Example: shift 0 (1,K,n+3) shifts the first loop in the chain, which is 3D,by 1, K, and n+3.

    Multiple schedules can be composed, and are applied in the order specified.

  • dependencies : The dependencies that must be satisfied for any transformation on the loop. These are used to ensure that a transformation produced a loop satisfying the dependencies of the original loop. This is expressed in traditional ISCC syntax. However, unlike in ISCC, each iteration must be expressed in full-form syntax [loop nest, iterator, (loop nest, iterator,)* statement]. Further, they must be padded so that all iterations are the same length For example, the statement 'inside' the first loop is expressed in full-form as [0,i,0], since its the 0'th loop, has iteration i, and is the 0'th statement. With padding it becomes [0,i,0,0,0]

    Code Example, continuing with loop chain example:

    dependencies:
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The first line indicates that iteration i comes before iteration i+1 in the first loop.
    The second line indicates that iteration i comes before iteration i+1 in the second loop.
    The third line indicates that iteration j comes before iteration j+1 in the third loop.
    The fourth line indicates that iteration i comes before iteration i+1 in the second loop.
    The fifth line indicates that all iterations in the first loop come before any iterations in the second loop.

    Please note that each dependency is treated by the framework as a separate entity, and is split by newlines. This means that a dependency expression currently cannot span multiple lines.

  • new ordering : The dependencies that must be satisfied for the particular transformation. This is written in the same way as the dependencies section. If the transformation being tested is the original schedule, then the text will probably be identical. Code Example, continuing with loop chain example, performing a loop fusion on the first two loops:

    new ordering:
    { [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The only change from the dependency code is the first line, which indicates that iteration i in the second loop comes before iteration i+1 in the first loop.

  • exemplar : (Optional) (Currently InOp) Actual original C/C++ code that should be tested by the source-to-source transformation tool (which doesn't exist yet). Code Example:

    exemplar:
    for( int i = 0; i < 10; i += 1 ){
    A[i] = Static[i];
    }
    for( int i = 0; i <= 9; i++ ){
    B[i] = f( A[i] );
    }
    for( int i = 0; i < M; ++i ){
    for( int j = 0; j <= N-1; j = j + 1 ){
    C[i,j] = A[i%10] / B[i%10];
    }
    }
    :end
    

The full test (using all the examples) would look something like this:

test name: example_3N_1D_1D_2D
loop chain:
(i){0..9}
(i){0..9}
(i,j){0..M-1,0..N-1}
:end
dependencies:
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
schedule:
fuse 0, 1, 2
:end
new ordering:
{ [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
exemplar:
for( int i = 0; i < 10; i += 1 ){
A[i] = Static[i];
}
for( int i = 0; i <= 9; i++ ){
B[i] = f( A[i] );
}
for( int i = 0; i < M; ++i ){
for( int j = 0; j <= N-1; j = j + 1 ){
C[i,j] = A[i%10] / B[i%10];
}
}
:end

integration-util.py

The integration-util.py script lives in $(UTIL) and is the driver behind the integration testing framework.

To run a test (or list of tests) by hand, simply calls

python $(UTIL)/integration-util.py path/to/file.test path/to/file2.test

There are options for the script:

  • --save_env (or -se): Save the testing environment after a test completes. By default, test environments are erased when test completes, regardless of failure state.

  • --save_env_on_fail (or -sf): Save the testing environment after a test fails. By default, test environments are erased when test completes, regardless of failure state.

  • --save_log (or -sl): Save the log file, even if test is successful. By default, logs are only saved to file if a test fails.

  • --resources_path PATH (or -r): Give the script a path to $(UTIL)/resources. By default, the script assumes that it lives in the same directory as the resources folder and will construct the path from its call.

  • --project_path PATH (or -p): Give the script a path to the LoopChainIR project directory. By default, the script assumes that it will be called from the LoopChainIr project root directory, and thus the path would be equivalent to ".".

Third-Party materials

Included with this project are several third-party materials under the $(THIRD_PARTY_SRC) directory.

  1. Google Test

All third-party materials are provided as they were downloaded, and include their copyright and license information.

About

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Resources

Stars

0 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

LoopChainIR

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Quickstart

Prerequisites

LoopChainIR depends on the following libraries:

Configure, Make, Test, and install

You must first configure the project before building using the configuration script:

./configure

See the configuration options available using ./configure --help.

After a successful configuration, the makefile will be generated. Run make all to compile the LoopChainIR library object. To ensure the project is in working order run make test to run the unit and integration tests.

To install, run make install. To choose a non-default installation location, use the --prefix option of the configuration script. To uninstall run make uninstall. installed.txt lists the full path of each file and directory that was installed.

Project Directory Structure

  • bin/ : Where all executables (including intermediate *.o and *.a files) are compiled to. Known as $(BIN).

  • src/ : Where all the sources for the binary files live. Known as $(SRC).

  • test/ : Subdirectory for testing. Known as $(TEST)

    • integration-tests : Subdirectory for integration-test files. Known as $(REG_TEST_DIR)

    • unit-tests : Subdirectory for unit-test files. Known as $(UNIT_TEST_DIR)

      • bin/ : Where all executables (including intermediate *.o and *.a files) only relating to the unit tests are compiled to. Known as $(UNIT_TEST_BIN)

      • src/ : Where all the source for the unit tests live. Known as $(UNIT_TEST_SRC)

  • util/ : Where utility resources (such as scripts) live. Known as $(UTIL)

  • documentation/: Where doxygen outputs its files. Known as $(DOC_PATH)

  • third-party/ : Subdirectory for third-party materials, their source, their build directories, and their install directories. Known as $(THIRD_PARTY)

    • source/ : The original source distributions of third-party materials. Known as $(THIRD_PARTY_SRC)

    • build/: Where third-party materials are extracted to and built. Created after make genesis. Known as $(THIRD_PARTY_BUILD)

    • install/ : Where third-party materials are installed to. Created after make genesis. Known as $(THIRD_PARTY_INSTALL)

      • lib/ : Third-party libraries. Known as $(LIB)

      • include/ : Third-party headers. Known as $(INC)

Make commands

  • initialize (or init): This is the first command that should be run when getting started with the project. It builds and places all the third-party tools into good organized places.

  • all: Builds the LoopChainIR.a library (after first performing initialize if necessary)

  • test: Performs unit-tests and integration-tests

  • unit-tests: Runs all unit tests specified by $(UNIT-TESTS)

  • integration-tests: Runs all integration tests specified by $(REG_TESTS)

  • documentation (or doc): Runs doxygen, uses the local Doxyfile

  • neat: Removes all *.o files from $(BIN).

  • clean-third-party: Removes (recursive, forced) $(THIRD_PARTY_INSTALL) and $(THIRD_PARTY_BUILD).

  • clean-test: Removes (recursive) all files from $(UNIT_TEST_BIN), and *.dir and *.log files from $(REG_TEST_DIR)

  • clean-doc: Removes (recursive) the $(DOC_PATH) directory

  • clean: Performs clean-test and removes (recursively) all files under $(BIN).

  • clean-all: Performs clean, clean-third-party, and clean-doc. Mimics a restored project state.

  • install: Copies the library and header files to the location described by $(prefix). Installed files are listed in the install log (install.txt)

  • uninstall: Removes (recursive, forced) the files listed in the install log (install.txt)

Documentation

The LoopChainIR API is documented using Doxygen.

To generate the HTML documentation, run

make documentation

or

make doc

The output can be found at $(DOC)

Testing

A complete run of all tests (both integration and unit) is run with

make test

Unit Testing

Testing is conducted through the Google Test unit test framework.

Preferably, each project source file gets its own unit test file (i.e. RectangularDomain.cpp and RectangularDomain_test.cpp).

Tests are run with

make unit-tests

Or individually using the name of the test, for example:

make RectangularDomain_test

Integration Testing

Integration testing is conducted by an in-house script (see $(UTIL)/integration-util.py).

Test files are placed in $(REG_TEST_DIR).

Tests are run with

make integration-tests

Or individually using the name of the test.

If a test fails, it's log file is dropped next to the test file suffixed with '.log'. This can be useful to determine what failed, how to fix it, and in the case of a software error is useful to us.

Itegration Test Files

A integration test has several sections:

  • test name : Name of the test. Prefers no white-space.

  • loop chain : An ordered list of each loop nest, where each loop nest is expressed as a terse domain.

    Example:

    loop chain:
    (i){0..9}
    (i){0..9}
    (i,j){0..M-1,0..N-1}
    :end
    

    The iterators (symbols in the parentheses) are comma separated and can be any valid C variable symbol. The bounds (expressions in the brackets) as comma separated list of ranges. Each range is expressed lower_bound .. upper_bound, and bounds can contain simple expressions (using + - * / % operators and parentheses, no function calls) The iterators and bounds are matched up by their index (i.e. the first iterator is bounded by the first range, and the second iterator by the second, and so on.)

  • schedule : There are three schedule {things}

    • Original: default sequential schedule for a loop chain. code: original
      regex: original

    • Fusion schedule: Fuse a series of loops.
      code: fuse {loop index} {loop index} [{loop index} ...]
      regex: "fuse\s+(?P<list>(?:\d+\s*){2,})
      Example: fuse 0, 1 fuses loops 0 and 1 (the first and second loops).

    • Shift: shift the domain of a loop by some extent(s). Extents can be constant integers, symbols, and valid C expressions using only arithmetic operators. There must be the same number of extents as dimensions of the domain of the loop.
      code: shift {loop index} ({extent} [,{extent} ...])
      regex: shift\s+(?P<loopid>\d+)\s+\(\s*(?P<extents>.+)\s*\)
      Example: shift 0 (1,K,n+3) shifts the first loop in the chain, which is 3D,by 1, K, and n+3.

    Multiple schedules can be composed, and are applied in the order specified.

  • dependencies : The dependencies that must be satisfied for any transformation on the loop. These are used to ensure that a transformation produced a loop satisfying the dependencies of the original loop. This is expressed in traditional ISCC syntax. However, unlike in ISCC, each iteration must be expressed in full-form syntax [loop nest, iterator, (loop nest, iterator,)* statement]. Further, they must be padded so that all iterations are the same length For example, the statement 'inside' the first loop is expressed in full-form as [0,i,0], since its the 0'th loop, has iteration i, and is the 0'th statement. With padding it becomes [0,i,0,0,0]

    Code Example, continuing with loop chain example:

    dependencies:
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The first line indicates that iteration i comes before iteration i+1 in the first loop.
    The second line indicates that iteration i comes before iteration i+1 in the second loop.
    The third line indicates that iteration j comes before iteration j+1 in the third loop.
    The fourth line indicates that iteration i comes before iteration i+1 in the second loop.
    The fifth line indicates that all iterations in the first loop come before any iterations in the second loop.

    Please note that each dependency is treated by the framework as a separate entity, and is split by newlines. This means that a dependency expression currently cannot span multiple lines.

  • new ordering : The dependencies that must be satisfied for the particular transformation. This is written in the same way as the dependencies section. If the transformation being tested is the original schedule, then the text will probably be identical. Code Example, continuing with loop chain example, performing a loop fusion on the first two loops:

    new ordering:
    { [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The only change from the dependency code is the first line, which indicates that iteration i in the second loop comes before iteration i+1 in the first loop.

  • exemplar : (Optional) (Currently InOp) Actual original C/C++ code that should be tested by the source-to-source transformation tool (which doesn't exist yet). Code Example:

    exemplar:
    for( int i = 0; i < 10; i += 1 ){
    A[i] = Static[i];
    }
    for( int i = 0; i <= 9; i++ ){
    B[i] = f( A[i] );
    }
    for( int i = 0; i < M; ++i ){
    for( int j = 0; j <= N-1; j = j + 1 ){
    C[i,j] = A[i%10] / B[i%10];
    }
    }
    :end
    

The full test (using all the examples) would look something like this:

test name: example_3N_1D_1D_2D
loop chain:
(i){0..9}
(i){0..9}
(i,j){0..M-1,0..N-1}
:end
dependencies:
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
schedule:
fuse 0, 1, 2
:end
new ordering:
{ [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
exemplar:
for( int i = 0; i < 10; i += 1 ){
A[i] = Static[i];
}
for( int i = 0; i <= 9; i++ ){
B[i] = f( A[i] );
}
for( int i = 0; i < M; ++i ){
for( int j = 0; j <= N-1; j = j + 1 ){
C[i,j] = A[i%10] / B[i%10];
}
}
:end

integration-util.py

The integration-util.py script lives in $(UTIL) and is the driver behind the integration testing framework.

To run a test (or list of tests) by hand, simply calls

python $(UTIL)/integration-util.py path/to/file.test path/to/file2.test

There are options for the script:

  • --save_env (or -se): Save the testing environment after a test completes. By default, test environments are erased when test completes, regardless of failure state.

  • --save_env_on_fail (or -sf): Save the testing environment after a test fails. By default, test environments are erased when test completes, regardless of failure state.

  • --save_log (or -sl): Save the log file, even if test is successful. By default, logs are only saved to file if a test fails.

  • --resources_path PATH (or -r): Give the script a path to $(UTIL)/resources. By default, the script assumes that it lives in the same directory as the resources folder and will construct the path from its call.

  • --project_path PATH (or -p): Give the script a path to the LoopChainIR project directory. By default, the script assumes that it will be called from the LoopChainIr project root directory, and thus the path would be equivalent to ".".

Third-Party materials

Included with this project are several third-party materials under the $(THIRD_PARTY_SRC) directory.

  1. Google Test

All third-party materials are provided as they were downloaded, and include their copyright and license information.

About

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Resources

Stars

0 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

LoopChainIR

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Quickstart

Prerequisites

LoopChainIR depends on the following libraries:

Configure, Make, Test, and install

You must first configure the project before building using the configuration script:

./configure

See the configuration options available using ./configure --help.

After a successful configuration, the makefile will be generated. Run make all to compile the LoopChainIR library object. To ensure the project is in working order run make test to run the unit and integration tests.

To install, run make install. To choose a non-default installation location, use the --prefix option of the configuration script. To uninstall run make uninstall. installed.txt lists the full path of each file and directory that was installed.

Project Directory Structure

  • bin/ : Where all executables (including intermediate *.o and *.a files) are compiled to. Known as $(BIN).

  • src/ : Where all the sources for the binary files live. Known as $(SRC).

  • test/ : Subdirectory for testing. Known as $(TEST)

    • integration-tests : Subdirectory for integration-test files. Known as $(REG_TEST_DIR)

    • unit-tests : Subdirectory for unit-test files. Known as $(UNIT_TEST_DIR)

      • bin/ : Where all executables (including intermediate *.o and *.a files) only relating to the unit tests are compiled to. Known as $(UNIT_TEST_BIN)

      • src/ : Where all the source for the unit tests live. Known as $(UNIT_TEST_SRC)

  • util/ : Where utility resources (such as scripts) live. Known as $(UTIL)

  • documentation/: Where doxygen outputs its files. Known as $(DOC_PATH)

  • third-party/ : Subdirectory for third-party materials, their source, their build directories, and their install directories. Known as $(THIRD_PARTY)

    • source/ : The original source distributions of third-party materials. Known as $(THIRD_PARTY_SRC)

    • build/: Where third-party materials are extracted to and built. Created after make genesis. Known as $(THIRD_PARTY_BUILD)

    • install/ : Where third-party materials are installed to. Created after make genesis. Known as $(THIRD_PARTY_INSTALL)

      • lib/ : Third-party libraries. Known as $(LIB)

      • include/ : Third-party headers. Known as $(INC)

Make commands

  • initialize (or init): This is the first command that should be run when getting started with the project. It builds and places all the third-party tools into good organized places.

  • all: Builds the LoopChainIR.a library (after first performing initialize if necessary)

  • test: Performs unit-tests and integration-tests

  • unit-tests: Runs all unit tests specified by $(UNIT-TESTS)

  • integration-tests: Runs all integration tests specified by $(REG_TESTS)

  • documentation (or doc): Runs doxygen, uses the local Doxyfile

  • neat: Removes all *.o files from $(BIN).

  • clean-third-party: Removes (recursive, forced) $(THIRD_PARTY_INSTALL) and $(THIRD_PARTY_BUILD).

  • clean-test: Removes (recursive) all files from $(UNIT_TEST_BIN), and *.dir and *.log files from $(REG_TEST_DIR)

  • clean-doc: Removes (recursive) the $(DOC_PATH) directory

  • clean: Performs clean-test and removes (recursively) all files under $(BIN).

  • clean-all: Performs clean, clean-third-party, and clean-doc. Mimics a restored project state.

  • install: Copies the library and header files to the location described by $(prefix). Installed files are listed in the install log (install.txt)

  • uninstall: Removes (recursive, forced) the files listed in the install log (install.txt)

Documentation

The LoopChainIR API is documented using Doxygen.

To generate the HTML documentation, run

make documentation

or

make doc

The output can be found at $(DOC)

Testing

A complete run of all tests (both integration and unit) is run with

make test

Unit Testing

Testing is conducted through the Google Test unit test framework.

Preferably, each project source file gets its own unit test file (i.e. RectangularDomain.cpp and RectangularDomain_test.cpp).

Tests are run with

make unit-tests

Or individually using the name of the test, for example:

make RectangularDomain_test

Integration Testing

Integration testing is conducted by an in-house script (see $(UTIL)/integration-util.py).

Test files are placed in $(REG_TEST_DIR).

Tests are run with

make integration-tests

Or individually using the name of the test.

If a test fails, it's log file is dropped next to the test file suffixed with '.log'. This can be useful to determine what failed, how to fix it, and in the case of a software error is useful to us.

Itegration Test Files

A integration test has several sections:

  • test name : Name of the test. Prefers no white-space.

  • loop chain : An ordered list of each loop nest, where each loop nest is expressed as a terse domain.

    Example:

    loop chain:
    (i){0..9}
    (i){0..9}
    (i,j){0..M-1,0..N-1}
    :end
    

    The iterators (symbols in the parentheses) are comma separated and can be any valid C variable symbol. The bounds (expressions in the brackets) as comma separated list of ranges. Each range is expressed lower_bound .. upper_bound, and bounds can contain simple expressions (using + - * / % operators and parentheses, no function calls) The iterators and bounds are matched up by their index (i.e. the first iterator is bounded by the first range, and the second iterator by the second, and so on.)

  • schedule : There are three schedule {things}

    • Original: default sequential schedule for a loop chain. code: original
      regex: original

    • Fusion schedule: Fuse a series of loops.
      code: fuse {loop index} {loop index} [{loop index} ...]
      regex: "fuse\s+(?P<list>(?:\d+\s*){2,})
      Example: fuse 0, 1 fuses loops 0 and 1 (the first and second loops).

    • Shift: shift the domain of a loop by some extent(s). Extents can be constant integers, symbols, and valid C expressions using only arithmetic operators. There must be the same number of extents as dimensions of the domain of the loop.
      code: shift {loop index} ({extent} [,{extent} ...])
      regex: shift\s+(?P<loopid>\d+)\s+\(\s*(?P<extents>.+)\s*\)
      Example: shift 0 (1,K,n+3) shifts the first loop in the chain, which is 3D,by 1, K, and n+3.

    Multiple schedules can be composed, and are applied in the order specified.

  • dependencies : The dependencies that must be satisfied for any transformation on the loop. These are used to ensure that a transformation produced a loop satisfying the dependencies of the original loop. This is expressed in traditional ISCC syntax. However, unlike in ISCC, each iteration must be expressed in full-form syntax [loop nest, iterator, (loop nest, iterator,)* statement]. Further, they must be padded so that all iterations are the same length For example, the statement 'inside' the first loop is expressed in full-form as [0,i,0], since its the 0'th loop, has iteration i, and is the 0'th statement. With padding it becomes [0,i,0,0,0]

    Code Example, continuing with loop chain example:

    dependencies:
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The first line indicates that iteration i comes before iteration i+1 in the first loop.
    The second line indicates that iteration i comes before iteration i+1 in the second loop.
    The third line indicates that iteration j comes before iteration j+1 in the third loop.
    The fourth line indicates that iteration i comes before iteration i+1 in the second loop.
    The fifth line indicates that all iterations in the first loop come before any iterations in the second loop.

    Please note that each dependency is treated by the framework as a separate entity, and is split by newlines. This means that a dependency expression currently cannot span multiple lines.

  • new ordering : The dependencies that must be satisfied for the particular transformation. This is written in the same way as the dependencies section. If the transformation being tested is the original schedule, then the text will probably be identical. Code Example, continuing with loop chain example, performing a loop fusion on the first two loops:

    new ordering:
    { [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
    { [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
    { [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
    [N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
    [N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
    :end
    

    The only change from the dependency code is the first line, which indicates that iteration i in the second loop comes before iteration i+1 in the first loop.

  • exemplar : (Optional) (Currently InOp) Actual original C/C++ code that should be tested by the source-to-source transformation tool (which doesn't exist yet). Code Example:

    exemplar:
    for( int i = 0; i < 10; i += 1 ){
    A[i] = Static[i];
    }
    for( int i = 0; i <= 9; i++ ){
    B[i] = f( A[i] );
    }
    for( int i = 0; i < M; ++i ){
    for( int j = 0; j <= N-1; j = j + 1 ){
    C[i,j] = A[i%10] / B[i%10];
    }
    }
    :end
    

The full test (using all the examples) would look something like this:

test name: example_3N_1D_1D_2D
loop chain:
(i){0..9}
(i){0..9}
(i,j){0..M-1,0..N-1}
:end
dependencies:
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [2,i,0,j,0] -> [2,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [2,i,0,j,0] -> [2,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [2,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
schedule:
fuse 0, 1, 2
:end
new ordering:
{ [1,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10}
{ [0,i,0,0,0] -> [0,i+1,0,0,0] : 0 <= i < 10 }
{ [1,i,0,0,0] -> [1,i+1,0,0,0] : 0 <= i < 10 }
[N,M] -> { [1,i,0,j,0] -> [1,i,0,j+1,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [1,i,0,j,0] -> [1,i+1,0,j,0] : 0 <= i < M and 0 <= j < N }
[N,M] -> { [0,i,0,0,0] -> [1,i',0,j,0] : 0 <= i < 10 and 0 <= i < M and 0 <= j < N }
:end
exemplar:
for( int i = 0; i < 10; i += 1 ){
A[i] = Static[i];
}
for( int i = 0; i <= 9; i++ ){
B[i] = f( A[i] );
}
for( int i = 0; i < M; ++i ){
for( int j = 0; j <= N-1; j = j + 1 ){
C[i,j] = A[i%10] / B[i%10];
}
}
:end

integration-util.py

The integration-util.py script lives in $(UTIL) and is the driver behind the integration testing framework.

To run a test (or list of tests) by hand, simply calls

python $(UTIL)/integration-util.py path/to/file.test path/to/file2.test

There are options for the script:

  • --save_env (or -se): Save the testing environment after a test completes. By default, test environments are erased when test completes, regardless of failure state.

  • --save_env_on_fail (or -sf): Save the testing environment after a test fails. By default, test environments are erased when test completes, regardless of failure state.

  • --save_log (or -sl): Save the log file, even if test is successful. By default, logs are only saved to file if a test fails.

  • --resources_path PATH (or -r): Give the script a path to $(UTIL)/resources. By default, the script assumes that it lives in the same directory as the resources folder and will construct the path from its call.

  • --project_path PATH (or -p): Give the script a path to the LoopChainIR project directory. By default, the script assumes that it will be called from the LoopChainIr project root directory, and thus the path would be equivalent to ".".

Third-Party materials

Included with this project are several third-party materials under the $(THIRD_PARTY_SRC) directory.

  1. Google Test

All third-party materials are provided as they were downloaded, and include their copyright and license information.

About

The code repository for the internal representation data structure that holds a loop chain execution schedule.

Resources

Stars

0 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages