diff --git a/.github/workflows/basic-ci.yml b/.github/workflows/basic-ci.yml index 6e5b140b..f8a39fda 100644 --- a/.github/workflows/basic-ci.yml +++ b/.github/workflows/basic-ci.yml @@ -39,12 +39,11 @@ jobs: - uses: codespell-project/actions-codespell@v2 lit-suite: - runs-on: ubuntu-22.04 - strategy: fail-fast: false matrix: - llvm-version: [ 14 ] + os: [ ubuntu-22.04, ubuntu-24.04 ] + llvm-version: [ 14, 18, 19 ] typeart-typegen-legacy: [ 0, 1 ] preset: - name: ci-thread-safe-safeptr @@ -59,10 +58,29 @@ jobs: - name: ci-libcxx libcxx: true skip_test: true + exclude: + - llvm-version: 14 + os: ubuntu-24.04 + - llvm-version: 18 + os: ubuntu-22.04 + - llvm-version: 18 + typeart-typegen-legacy: 1 + - llvm-version: 19 + os: ubuntu-22.04 + - llvm-version: 19 + typeart-typegen-legacy: 1 + + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + - name: LLVM apt + if: ${{ matrix.llvm-version == 19 }} + run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" | sudo tee /etc/apt/sources.list.d/llvm-19.list + - name: Update apt run: sudo apt-get update diff --git a/.github/workflows/ext-ci.yml b/.github/workflows/ext-ci.yml index add22d7e..9d16f848 100644 --- a/.github/workflows/ext-ci.yml +++ b/.github/workflows/ext-ci.yml @@ -11,16 +11,24 @@ env: jobs: run-testbench: - runs-on: ubuntu-22.04 - strategy: fail-fast: false matrix: - llvm-version: [ 14 ] + os: [ ubuntu-22.04, ubuntu-24.04 ] + llvm-version: [ 14, 18, 19 ] preset: - name: release-counter - name: release-safeptr-counter - name: release-unsafe-counter + exclude: + - llvm-version: 14 + os: ubuntu-24.04 + - llvm-version: 18 + os: ubuntu-22.04 + - llvm-version: 19 + os: ubuntu-22.04 + + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -32,6 +40,12 @@ jobs: ssh-key: ${{ secrets.AUTH_SSH_CI_EXT }} path: test-bench + - name: LLVM apt + if: ${{ matrix.llvm-version == 19 }} + run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" | sudo tee /etc/apt/sources.list.d/llvm-19.list + - name: Update apt run: sudo apt-get update @@ -96,15 +110,23 @@ jobs: path: artifact run-AD-testbench: - runs-on: ubuntu-22.04 - strategy: fail-fast: false matrix: - llvm-version: [ 14 ] + os: [ ubuntu-22.04, ubuntu-24.04 ] + llvm-version: [ 14, 18, 19 ] preset: - name: release-counter - name: release-unsafe-counter + exclude: + - llvm-version: 14 + os: ubuntu-24.04 + - llvm-version: 18 + os: ubuntu-22.04 + - llvm-version: 19 + os: ubuntu-22.04 + + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -117,6 +139,12 @@ jobs: ref: feat/ci path: ad-test-bench + - name: LLVM apt + if: ${{ matrix.llvm-version == 19 }} + run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" | sudo tee /etc/apt/sources.list.d/llvm-19.list + - name: Update apt run: sudo apt-get update @@ -165,18 +193,26 @@ jobs: path: artifact run-OMP-testbench: - runs-on: ubuntu-22.04 - env: OMP_NUM_THREAD: 2 strategy: fail-fast: false matrix: - llvm-version: [ 14 ] + os: [ ubuntu-22.04, ubuntu-24.04 ] + llvm-version: [ 14, 18, 19 ] preset: - name: release-counter - name: release-safeptr-counter + exclude: + - llvm-version: 14 + os: ubuntu-24.04 + - llvm-version: 18 + os: ubuntu-22.04 + - llvm-version: 19 + os: ubuntu-22.04 + + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -189,6 +225,12 @@ jobs: ref: ci/omp path: omp-test-bench + - name: LLVM apt + if: ${{ matrix.llvm-version == 19 }} + run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" | sudo tee /etc/apt/sources.list.d/llvm-19.list + - name: Update apt run: sudo apt-get update diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a5e0bf8..dd7476d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.20) project(typeart - VERSION 1.9 + VERSION 2.0 HOMEPAGE_URL https://github.com/tudasc/TypeART DESCRIPTION "LLVM-based type and memory allocation tracking sanitizer" ) diff --git a/README.md b/README.md index 40b8fe27..496d11fd 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Using TypeART involves two phases: ### 1.1 Compiling a target code -TypeART’s LLVM compiler pass plugins instrument allocations and serialize static type layouts into a YAML file (default: `types.yaml`). We provide compiler wrapper scripts (available in the bin folder of the TypeART installation) for Clang and MPI. By default, these wrappers instrument heap, stack, and global allocations, while MPI wrappers filter allocations unrelated to MPI calls (see [Section 1.1.4](#114-filtering-allocations)). +TypeART’s LLVM compiler pass plugins instrument allocations and serialize static type layouts into a YAML file (default: `typeart-types.yaml`). We provide compiler wrapper scripts (available in the bin folder of the TypeART installation) for Clang and MPI. By default, these wrappers instrument heap, stack, and global allocations, while MPI wrappers filter allocations unrelated to MPI calls (see [Section 1.1.4](#114-filtering-allocations)). *Note*: Currently, the compilation must be serialized, e.g., `make -j 1`, to ensure consistent type information across translation units. @@ -92,14 +92,13 @@ $> typeart-clang++ -O2 $(COMPILE_FLAGS) -c code.cpp -o code.o $> typeart-clang++ $(LINK_FLAGS) code.o -o binary ``` -The wrapper performs the following steps: +The wrapper performs the following steps using Clang's `-fpass-plugin`: -1. Compiles the code to LLVM IR and pipes it to the `opt` tool, retaining original compile flags. -2. Applies heap instrumentation with TypeART. +1. Compiles the code to LLVM IR retaining original compile flags. +2. Applies heap instrumentation with TypeART (before optimizations). 3. Optimizes the code using provided -O flag. -4. Applies stack and global instrumentation with TypeART. -5. Converts the LLVM IR to an object file using `llc`. -6. Links the TypeART runtime library with the provided linker flags. +4. Applies stack and global instrumentation with TypeART (after optimizations). +5. Links the TypeART runtime library with the provided linker flags. *Note*: Heap allocations are instrumented before optimizations to prevent loss of type information in some cases. @@ -121,9 +120,7 @@ $> cmake --build build --target install -- -j1 The wrappers `typeart-mpicc` and `typeart-mpic++` are generated for compiling MPI codes with TypeART. Here, we rely on detecting the vendor to generate wrappers with appropriate environment variables to force the use of the Clang/LLVM compiler. -We support detection for OpenMPI, Intel MPI and MPICH based on `mpi.h` symbols, and use the following flags for setting -the Clang -compiler: +We support detection for OpenMPI, Intel MPI and MPICH based on `mpi.h` symbols, and use the following flags for setting the Clang compiler: | Vendor | Symbol | C compiler env. var | C++ compiler env. var | |-----------|---------------|----------------------|------------------------| @@ -132,102 +129,63 @@ compiler: | MPICH | MPICH_NAME | MPICH_CC | MPICH_CXX | -#### 1.1.2 Options for TypeART passes and compiler wrapper +#### 1.1.2 Options for controlling the TypeART pass -The pass behavior can be configured with the command line options listed below. TypeART also supports a configuration -file based on a yaml format. *Note:* For now, the TypeART pass prioritizes (1) commandline arguments and then (2) -environment files (if set) over the file-based configuration option. +The pass behavior can be configured with the environment flags as listed below. The TypeART pass prioritizes environment flags (if set) over the default configuration option. -##### Pass +In particular, `TYPEART_OPTIONS` can be set to globally modify the TypeART pass (stack/heap specific options exist). +The format requires the option names separated by a semicolon, e.g., `TYPEART_OPTIONS="filter-glob=API_*;no-stats"` sets the filter glob target to `API_*` and deactivates stats printing of the TypeART pass. +Prepending `no-` to boolean flags sets them to false. -For modification of the pass behavior, we provide several options. Some options have equivalent environment variables. - - -| Flag | Env. variable | Default | Description | -|----------------------------------------------|:--------------------|:------------:|----------------------------------------------------------------------------------------------------------------------------------------------------| -| `-typeart` | - | - | Invoke TypeART pass through LLVM `opt` | -| `--typeart-config` | `TYPEART_CONFIG` | - | Pass configuration file (defines has all options below) | -| `--typeart-types` | `TYPEART_TYPE_FILE` | `types.yaml` | Serialized type layout information of user-defined types. File location and name can also be controlled with the env variable `TYPEART_TYPE_FILE`. | -| `--typeart-heap` | - | `true` | Instrument heap allocations | -| `--typeart-stack` | - | `false` | Instrument stack and global allocations. Enables instrumentation of global allocations. | -| `--typeart-stack-lifetime` | - | `true` | Instrument stack `llvm.lifetime.start` instead of `alloca` directly -| `--typeart-global` | - | `false` | Instrument global allocations (see --typeart-stack). | -| `--typeart-typegen` | - | `dimeta` | Values: `dimeta`, `ir`. The env variable `TYPEART_TYPEGEN_IR` set to 1 toggles `--typeart-typegen=ir`, i.e., serializing type information based on LLVM IR. See [Section 1.1.3](#113-serialized-type-information). | -| `--typeart-stats` | - | `false` | Show instrumentation statistic counters | -| `--typeart-filter` | - | `false` | Filter stack and global allocations. See also [Section 1.1.4](#114-filtering-allocations) | -| `--typeart-filter-implementation` | - | `std` | Values: `std`, `none`. See also [Section 1.1.4](#114-filtering-allocations) | -| `--typeart-filter-glob` | - | `*MPI_*` | Filter API string target (glob string) | -| `--typeart-analysis-filter-global` | - | `true` | Filter global alloca based on heuristics | -| `--typeart-analysis-filter-heap-alloca` | - | `true` | Filter stack alloca that have a store instruction from a heap allocation | -| `--typeart-analysis-filter-non-array-alloca` | - | `false` | Filter scalar valued allocas | -| `--typeart-analysis-filter-pointer-alloca` | - | `true` | Filter allocas of pointer types | - - +**Note**: Single environment options are prioritized over `TYPEART_OPTIONS`. -##### Compiler wrapper - -For modification of the pass behavior, the wrapper accepts configuration file commandline options. Equivalent -environment variables can be set. -| Flag | Env. variable | Description | -|---------------------------------|---------------------------------|-----------------------------------------------------------------------| -| `--typeart-config=` | `TYPEART_WRAPPER_CONFIG` | Pass yaml file configuration to heap and stack phase of TypeART pass. | -| `--typeart-heap-config=` | `TYPEART_WRAPPER_HEAP_CONFIG` | See above, heap phase only. | -| `--typeart-stack-config=` | `TYPEART_WRAPPER_STACK_CONFIG` | See above, stack/global phase only. | +| Env. variable | Option name | Default value | Description | +| :----------------------------------------- | ---------------------------------- | :------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| `TYPEART_OPTIONS` | | | Set multiple options at once, separated by `;`. | +| `TYPEART_OPTIONS_STACK` | | | Same as above for stack phase only. | +| `TYPEART_OPTIONS_HEAP` | | | Same as above for heap phase only. | +| `TYPEART_TYPES` | `types` | `typeart-types.yaml` | Serialized type layout information of user-defined types. File location and name can also be controlled with the env variable `TYPEART_TYPES`. | +| `TYPEART_HEAP` | `heap` | `true` | Instrument heap allocations | +| `TYPEART_STACK` | `stack` | `false` | Instrument stack and global allocations. Enables instrumentation of global allocations. | +| `TYPEART_STACK_LIFETIME` | `stack-lifetime` | `true` | Instrument stack `llvm.lifetime.start` instead of `alloca` directly | +| `TYPEART_GLOBAL` | `global` | `false` | Instrument global allocations (see stack). | +| `TYPEART_TYPEGEN` | `typegen` | `dimeta` | Values: `dimeta`, `ir`. How serializing of type information is done, see [Section 1.1.3](#113-serialized-type-information). | +| `TYPEART_STATS` | `stats` | `false` | Show instrumentation statistic counters | +| `TYPEART_FILTER` | `filter` | `false` | Filter stack and global allocations. See also [Section 1.1.4](#114-filtering-allocations) | +| `TYPEART_FILTER_IMPLEMENTATION` | `filter-implementation` | `std` | Values: `std`, `none`. See also [Section 1.1.4](#114-filtering-allocations) | +| `TYPEART_FILTER_GLOB` | `filter-glob` | `*MPI_*` | Filter API string target (glob string) | +| `TYPEART_FILTER_GLOB_DEEP` | `filter-glob-deep` | `MPI_*` | Filter values based on specific API: Values passed as ptr are correlated when string matched. | +| `TYPEART_ANALYSIS_FILTER_GLOBAL` | `analysis-filter-global` | `true` | Filter global alloca based on heuristics | +| `TYPEART_ANALYSIS_FILTER_HEAP_ALLOCA` | `analysis-filter-heap-alloca` | `true` | Filter stack alloca that have a store instruction from a heap allocation | +| `TYPEART_ANALYSTS_FILTER_NON_ARRAY_ALLOCA` | `analysis-filter-non-array-alloca` | `false` | Filter scalar valued allocas | +| `TYPEART_ANALYSIS_FILTER_POINTER_ALLOCA` | `analysis-filter-pointer-alloca` | `true` | Filter allocas of pointer types | + +Additionally, there are two debug environment flags for dumping the LLVM IR per phase (pre heap, heap, opt, stack) to a set of files. + +| Env. variable | Description | +| :------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | +| `TYPEART_WRAPPER_EMIT_IR` | If set, the compiler wrapper will create 4 files for each TypeART phase with the file pattern `${source_basename}_heap.ll` etc. | +| `TYPEART_PASS_INTERNAL_EMIT_IR` | Internal pass use only. Toggled by wrapper. | -##### Configuration file - -The default file content of the configuration file is listed below. The option names correlate with the command line -options. Notably, e.g., the option `call-filter: { implementation: false }` correlates -to `--typeart-filter-implementation=false` etc. - -```yaml ---- -types: types.yaml -heap: true -stack: false -global: false -stats: false -stack-lifetime: true -typegen: dimeta -filter: true -call-filter: - implementation: std - glob: '*MPI_*' - glob-deep: 'MPI_*' - cg-file: '' -analysis: - filter-global: true - filter-heap-alloca: false - filter-pointer-alloca: true - filter-non-array-alloca: false -... - -``` - #### 1.1.3 Serialized type information -After instrumentation, the file `types.yaml` (`env TYPEART_TYPE_FILE`) contains the static type information. Each user-defined type layout is +After instrumentation, the file `typeart-types.yaml` (`env TYPEART_TYPES`) contains the static type information. Each user-defined type layout is extracted and an integer `type-id` is attached to it. Built-in types (e.g., float) have pre-defined ids and byte layouts. -To generate these type layouts, TypeART is using either the [LLVM IR type system](https://llvm.org/docs/LangRef.html#type-system) (`--typeart-typegen=ir`), or using the external library [llvm-dimeta](https://github.com/ahueck/llvm-dimeta) (`--typeart-typegen=dimeta`) which extracts type information using [LLVM debug metadata](https://llvm.org/docs/SourceLevelDebugging.html). -The latter is default. +To generate these type layouts, TypeART is using either the [LLVM IR type system](https://llvm.org/docs/LangRef.html#type-system) (`typegen=ir`), or using the external library [llvm-dimeta](https://github.com/ahueck/llvm-dimeta) (`typegen=dimeta`) which extracts type information using [LLVM debug metadata](https://llvm.org/docs/SourceLevelDebugging.html). +The latter is default, the former only works with LLVM 14. The TypeART instrumentation callbacks use the `type-id`. The runtime library correlates the allocation with the respective type (and layout) during execution. Consider the following struct: -After instrumentation, the `types.yaml` file (also controlled via the `TYPEART_TYPE_FILE` environment variable) stores static type information. +After instrumentation, the `typeart-types.yaml` file (also controlled via the `TYPEART_TYPES` environment variable) stores static type information. Each user-defined type layout is assigned a unique integer type-id. Built-in types (e.g., float) use predefined type-ids and byte layouts. -Type layouts are generated using one of the following methods: - -* LLVM IR Type System: Extracts types directly from LLVM IR (`--typeart-typegen=ir`). -* LLVM Debug Metadata (Default): Extracts types using the llvm-dimeta library and LLVM debug metadata (`--typeart-typegen=dimeta`). - -During execution, TypeART’s runtime library uses the type-id from callbacks to associate allocations with their type and layout. For example, consider the following struct: +During execution, TypeART’s runtime library uses the type-id from callbacks to associate allocations with their type and layout. For example, consider the following C struct: ```c struct s1_t { @@ -236,32 +194,30 @@ struct s1_t { } ``` -The TypeART pass may write a `types.yaml` file with the following content: +The TypeART pass may write a `typeart-types.yaml` file with the following content: ```yaml -- id: 256 // struct type-id +- id: 256 // struct type-id name: s1_t - extent: 16 // size in bytes + extent: 16 // size in bytes member_count: 2 - offsets: [ 0, 8 ] // byte offsets from struct start - types: [ 0, 10 ] // member type-ids (0->char, 10->pointer) - sizes: [ 3, 1 ] // member (array) length + offsets: [ 0, 8 ] // byte offsets from struct start + types: [ 5, 1 ] // member type-ids (5->char, 1->pointer) + sizes: [ 3, 1 ] // member (array) length ``` -##### Limitations +##### Limitations of LLVM IR Type System -The type-id system is tailored for LLVM IR types, which imposes certain constraints. For instance, C/C++ types like unsigned integers are currently unsupported (and represented like signed integers). The list of supported built-in type-ids is defined in [TypeInterface.h](lib/typelib/TypeInterface.h) and reflects the types that TypeART can represent. +The list of supported built-in type-ids is defined in [TypeInterface.h](lib/typelib/TypeInterface.h) and reflects the types that TypeART can represent with **LLVM Debug Metadata**. +In contrast, when using **LLVM IR Type System**, certain constraints are imposed. For instance, C/C++ types like unsigned integers are unsupported (and represented like signed integers). #### 1.1.4 Filtering allocations -To improve performance, a translation unit-local (TU) data-flow filter for global and stack variables exist. It follows -the LLVM IR `use-def` chain. If the allocation provably never reaches the target API, it can be filtered. Otherwise, it -is instrumented. Use the option `--typeart-filter` to filter and `--typeart-glob=` (default: `*MPI_*`) -to target the correct API. +To improve performance, a translation unit-local (TU) data-flow filter for global and stack variables exist. It follows the LLVM IR use-def chain. If the allocation provably never reaches the target API, it can be filtered. Otherwise, it is instrumented. Use the option `filter` to filter and `filter-glob=` (default: `*MPI_*`) to target the correct API. Consider the following example. @@ -285,11 +241,11 @@ void foo() { ### 1.2 Executing an instrumented target code To execute the instrumented code, the TypeART runtime library (or a derivative) has to be loaded to accept the -callbacks. The library also requires access to the `types.yaml` file to correlate the `type-id` with the actual type -layouts. To specify its path, you can use the environment variable `TYPEART_TYPE_FILE`, e.g.: +callbacks. The library also requires access to the `typeart-types.yaml` file to correlate the `type-id` with the actual type +layouts. To specify its path, you can use the environment variable `TYPEART_TYPES`, e.g.: ```shell -$> export TYPEART_TYPE_FILE=/path/to/types.yaml +$> export TYPEART_TYPES=/path/to/typeart-types.yaml # If the TypeART runtime is not resolved, LD_LIBRARY_PATH is set: $> env LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(TYPEART_LIBPATH) ./binary ``` @@ -323,7 +279,7 @@ To compile and run the demo targets: ## 2. Building TypeART -TypeART supports LLVM version 14 (lower LLVM version support is deprecated) and CMake version >= 3.20. +TypeART supports LLVM version 14 and 18 and CMake version >= 3.20. ### 2.1 Optional software requirements @@ -355,9 +311,11 @@ $> cmake --build build --target install --parallel -| Option | Default | Description | -|-----------------------|:----------:|-----------------------------------------------------------| -| `TYPEART_MPI_WRAPPER` | `ON` | Install TypeART MPI wrapper (mpic, mpic++). Requires MPI. | +| Option | Default | Description | +| ---------------------------- | :-----: | -------------------------------------------------------------------------------- | +| `TYPEART_MPI_WRAPPER` | `ON` | Install TypeART MPI wrapper (mpic, mpic++). Requires MPI. | +| `TYPEART_USE_LEGACY_WRAPPER` | `OFF` | Use legacy wrapper invoking opt/llc directly instead of Clang's `-fpass-plugin`. | + @@ -420,7 +378,7 @@ Example using CMake [FetchContent](https://cmake.org/cmake/help/latest/module/Fe FetchContent_Declare( typeart GIT_REPOSITORY https://github.com/tudasc/TypeART - GIT_TAG v1.9 + GIT_TAG v1.9.1 GIT_SHALLOW 1 ) FetchContent_MakeAvailable(typeart) diff --git a/cmake/modules/coverage-lcov.cmake b/cmake/modules/coverage-lcov.cmake index ea1cb827..c97a985b 100644 --- a/cmake/modules/coverage-lcov.cmake +++ b/cmake/modules/coverage-lcov.cmake @@ -18,23 +18,24 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # workaround lcov and clang --coverage have a version mismatch set(GCOV_TOOL --gcov-tool ${CMAKE_BINARY_DIR}/scripts/llvm-gcov.sh) # these autogenerated file in build/* causes error when using llvm-cov gcov (should be fine with gcc), - # finally, CallSite.h should not be measured (extracted from LLVM 10 code base) - set(GCOV_WORKAROUND --exclude *mpi_interceptor_rt.c --exclude */Version.cpp --exclude */CallSite.h) -else() - # CallSite is taken from LLVM 10, no need for coverage - set(GCOV_WORKAROUND --exclude */CallSite.h) + set(GCOV_WORKAROUND --rc derive_function_end_line=0) + if(${LLVM_VERSION_MAJOR} GREATER_EQUAL 14) + # LCOV version dependent but suffices for Action CI + set(GCOV_WORKAROUND --exclude */Version.cpp ${GCOV_WORKAROUND}) + endif() endif() add_custom_target( typeart-lcov-make COMMAND ${TYPEART_LCOV_EXEC} ${GCOV_TOOL} ${GCOV_WORKAROUND} --no-external -c -d ${CMAKE_BINARY_DIR} -b ${CMAKE_SOURCE_DIR} -o typeart.coverage - COMMAND ${TYPEART_LCOV_EXEC} --remove typeart.coverage '${CMAKE_BINARY_DIR}/*' -o typeart.coverage + COMMAND ${TYPEART_LCOV_EXEC} --rc derive_function_end_line=0 --remove typeart.coverage '${CMAKE_BINARY_DIR}/*' -o typeart.coverage ) add_custom_target( typeart-lcov-html - COMMAND ${TYPEART_GENHTML_EXEC} -o ${TYPEART_PROFILE_DIR} typeart.coverage + COMMAND ${TYPEART_GENHTML_EXEC} --rc derive_function_end_line=0 + -o ${TYPEART_PROFILE_DIR} typeart.coverage DEPENDS typeart-lcov-make ) diff --git a/cmake/typeartToolchainOptions.cmake b/cmake/typeartToolchainOptions.cmake index acf99383..ef6a9756 100644 --- a/cmake/typeartToolchainOptions.cmake +++ b/cmake/typeartToolchainOptions.cmake @@ -91,6 +91,13 @@ mark_as_advanced(TYPEART_TEST_CONFIGURE_IDE) option(TYPEART_CONFIG_DIR_IS_SHARE "Install to \"share/cmake/\" instead of \"lib/cmake/\"" OFF) mark_as_advanced(TYPEART_CONFIG_DIR_IS_SHARE) +option(TYPEART_USE_LEGACY_WRAPPER "Use the old TypeART compiler wrapper" OFF) +# mark_as_advanced(TYPEART_USE_NEW_PASSMANAGER) + +# if(LLVM_VERSION_MAJOR VERSION_GREATER_EQUAL "18") +# set(TYPEART_USE_NEW_PASSMANAGER ON CACHE BOOL ON FORCE) +# endif() + set(warning_guard "") if(NOT TYPEART_IS_TOP_LEVEL) option( diff --git a/demo/02_broken_struct_example.c b/demo/02_broken_struct_example.c index 7a9d5cd1..bac9124f 100644 --- a/demo/02_broken_struct_example.c +++ b/demo/02_broken_struct_example.c @@ -6,7 +6,7 @@ #define COUNT 5 // Comment out for heap allocation -//#define USE_STACK +// #define USE_STACK struct particle { int id; diff --git a/demo/Makefile b/demo/Makefile index db28c1d7..16dd527b 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -16,18 +16,6 @@ demo_broken: 02_broken_struct_example.c $(MPICC) -O1 -g -c $< -o $@.o $(MPICC) $@.o -o $@ -toy-stack: toy.c - $(MPICC) -O1 -g -c $< -o $@.o - $(MPICC) $@.o -o $@ - -toy: toy.c - $(MPICC) -DNOSTACK -O1 -g -c $< -o $@.o - $(MPICC) $@.o -o $@ - -runtoy: toy toy-stack - ./toy - ./toy-stack - run: run-demo run-demo_broken run-demo: demo libtool.so diff --git a/demo/tool.c b/demo/tool.c index 98a1d814..368a2777 100644 --- a/demo/tool.c +++ b/demo/tool.c @@ -1,3 +1,5 @@ +#include "TypeInterface.h" + #include #include #include @@ -5,17 +7,26 @@ int isCompatible(MPI_Datatype mpi_type, typeart_builtin_type recorded_type) { // This comparison is not exhaustive and is only used for this simple demo switch (recorded_type) { - case TYPEART_INT8: - return mpi_type == MPI_CHAR || mpi_type == MPI_UNSIGNED_CHAR; - case TYPEART_INT16: - return mpi_type == MPI_SHORT || mpi_type == MPI_UNSIGNED_SHORT; - case TYPEART_INT32: - return mpi_type == MPI_INT || mpi_type == MPI_UNSIGNED; - case TYPEART_INT64: - return mpi_type == MPI_LONG || mpi_type == MPI_UNSIGNED_LONG; - case TYPEART_FLOAT: + case TYPEART_CHAR_8: + case TYPEART_INT_8: + return mpi_type == MPI_CHAR; + case TYPEART_UCHAR_8: + return mpi_type == MPI_UNSIGNED_CHAR; + case TYPEART_INT_16: + return mpi_type == MPI_SHORT; + case TYPEART_UINT_16: + return mpi_type == MPI_UNSIGNED_SHORT; + case TYPEART_INT_32: + return mpi_type == MPI_INT; + case TYPEART_UINT_32: + return mpi_type == MPI_UNSIGNED; + case TYPEART_INT_64: + return mpi_type == MPI_LONG; + case TYPEART_UINT_64: + return mpi_type == MPI_UNSIGNED_LONG; + case TYPEART_FLOAT_32: return mpi_type == MPI_FLOAT; - case TYPEART_DOUBLE: + case TYPEART_FLOAT_64: return mpi_type == MPI_DOUBLE; default: break; @@ -40,11 +51,14 @@ void analyseBuffer(const void* buf, int count, MPI_Datatype type) { printf("Basetype(%s, addr=%p, size=%i , count=%i)\n", type_name, buf, size, count); - int type_id; - size_t count_check; - typeart_status status = typeart_get_type(buf, &type_id, &count_check); + typeart_type_info info; + typeart_status status = typeart_get_type(buf, &info); if (status == TYPEART_OK) { + int type_id; + size_t count_check; + type_id = info.type_id; + count_check = info.count; // If the address corresponds to a struct, fetch the type of the first member while (type_id >= TYPEART_NUM_RESERVED_IDS) { typeart_struct_layout struct_layout; diff --git a/demo/toy.c b/demo/toy.c deleted file mode 100644 index d65f0c6d..00000000 --- a/demo/toy.c +++ /dev/null @@ -1,99 +0,0 @@ -#include -#include -#include -#include - -struct test { - int a; - double b; - unsigned int c; - void* d; - int e; - struct test* f; -}; - -int main(int argc, char** argv) { - MPI_Init(&argc, &argv); - -#ifdef NOSTACK - struct test* mystruct = malloc(sizeof(struct test) * 5); -#else - struct test mystruct[5]; -#endif - - int type = 0; - size_t count = 0; - -#ifdef NOSTACK - int* buffer = malloc(sizeof(int) * 50); -#else - int buffer[50]; -#endif - - typeart_status status = typeart_get_type(mystruct, &type, &count); - - if (status == TYPEART_OK) - printf("type (id=%i), count=%lu\n", type, count); - else - printf("[Demo] Toy Error: %i\n", status); - - status = typeart_get_type(&(mystruct[2].e), &type, &count); - - if (status == TYPEART_OK) - printf("(sub) type (id=%i), count=%lu\n", type, count); - else - printf("[Demo] Toy Error: %i\n", status); - - status = typeart_get_type(&(mystruct[2].e), &type, &count); - - if (status == TYPEART_OK) - printf("type (id=%i), count=%lu\n", type, count); - else - printf("[Demo] Toy Error: %i\n", status); - - status = typeart_get_type(&(mystruct[2].c), &type, &count); - - if (status == TYPEART_OK) - printf("(sub) type (id=%i), count=%lu\n", type, count); - else - printf("[Demo] Toy Error: %i\n", status); - - status = typeart_get_type(&(mystruct[2].c), &type, &count); - - if (status == TYPEART_OK) - printf("type (id=%i), count=%lu\n", type, count); - else - printf("[Demo] Toy Error: %i\n", status); - - const void* base_address; - size_t offset; - status = typeart_get_containing_type(&(mystruct[2].c), &type, &count, &base_address, &offset); - - if (status == TYPEART_OK) - printf("containing_type (id=%i), count=%lu, %p, %lu\n", type, count, base_address, offset); - else - printf("[Demo] Toy Error: %i\n", status); - - printf("buffer\n"); - - status = typeart_get_containing_type(&(buffer[20]), &type, &count, &base_address, &offset); - - if (status == TYPEART_OK) - printf("containing_type (id=%i), count=%lu, %p, %lu\n", type, count, base_address, offset); - else - printf("[Demo] Toy Error: %i\n", status); - - MPI_Sendrecv(mystruct, 1, MPI_INT, 0, 0, buffer + 20, 1, MPI_INT, 0, 0, MPI_COMM_SELF, MPI_STATUS_IGNORE); - - MPI_Finalize(); - -#ifdef NOSTACK - free(mystruct); -#else -#endif - -#ifdef NOSTACK - free(buffer); -#else -#endif -} diff --git a/externals/abseil/CMakeLists.txt b/externals/abseil/CMakeLists.txt index 119056b4..cf6c35a8 100644 --- a/externals/abseil/CMakeLists.txt +++ b/externals/abseil/CMakeLists.txt @@ -3,7 +3,7 @@ set(ABSL_PROPAGATE_CXX_STD ON) FetchContent_Declare( cpp-abseil GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git - GIT_TAG 20240722.0 + GIT_TAG 20240722.1 GIT_SHALLOW 1 ) diff --git a/externals/dimeta/CMakeLists.txt b/externals/dimeta/CMakeLists.txt index c03af7e4..d717bbdb 100644 --- a/externals/dimeta/CMakeLists.txt +++ b/externals/dimeta/CMakeLists.txt @@ -1,11 +1,18 @@ FetchContent_Declare( llvm-dimeta GIT_REPOSITORY https://github.com/ahueck/llvm-dimeta - GIT_TAG v0.1.0 + GIT_TAG v0.2.0 GIT_SHALLOW 1 ) -FetchContent_MakeAvailable(llvm-dimeta) +#FetchContent_MakeAvailable(llvm-dimeta) + +# TODO need exclude to not install llvm-dimeta with TypeART +FetchContent_GetProperties(llvm-dimeta) +if(NOT llvm-dimeta_POPULATED) + FetchContent_Populate(llvm-dimeta) + add_subdirectory(${llvm-dimeta_SOURCE_DIR} ${llvm-dimeta_BINARY_DIR} EXCLUDE_FROM_ALL) +endif() mark_as_advanced( DIMETA_USE_HEAPALLOCSITE diff --git a/externals/phmap/CMakeLists.txt b/externals/phmap/CMakeLists.txt index 562549e5..e3c4f169 100644 --- a/externals/phmap/CMakeLists.txt +++ b/externals/phmap/CMakeLists.txt @@ -2,7 +2,7 @@ FetchContent_Declare( phmap_phmap GIT_REPOSITORY https://github.com/greg7mdp/parallel-hashmap.git GIT_SHALLOW 1 - GIT_TAG v1.4.1 + GIT_TAG v2.0.0 ) FetchContent_GetProperties(phmap_phmap) diff --git a/lib/mpi_interceptor/InterceptorFunctions.h b/lib/mpi_interceptor/InterceptorFunctions.h index d3468da7..c782924e 100644 --- a/lib/mpi_interceptor/InterceptorFunctions.h +++ b/lib/mpi_interceptor/InterceptorFunctions.h @@ -98,9 +98,10 @@ int ta_check_buffer(const char* mpi_name, const void* called_from, const void* b ta_print_loc(called_from); return -1; } - int typeId; - size_t count = 0; - typeart_status typeart_status_v = typeart_get_type(buf, &typeId, &count); + // int typeId; + // size_t count = 0; + typeart_type_info info; + typeart_status typeart_status_v = typeart_get_type(buf, &info); if (typeart_status_v != TYPEART_OK) { ++mcounter.error; const char* msg = ta_get_error_message(typeart_status_v); @@ -119,7 +120,7 @@ int ta_check_buffer(const char* mpi_name, const void* called_from, const void* b } void ta_print_loc(const void* call_adr) { - const char* exe = getenv("TA_EXE_TARGET"); + const char* exe = getenv("TYPEART_EXE_TARGET"); if (exe == NULL || exe[0] == '\0') { return; } @@ -133,8 +134,8 @@ void ta_print_loc(const void* call_adr) { while (fgets(read_buf, sizeof(read_buf), fp)) { printf(" %s", read_buf); } + pclose(fp); } - pclose(fp); } void ta_exit() { diff --git a/lib/passes/CMakeLists.txt b/lib/passes/CMakeLists.txt index b9ca81c1..7d8f44af 100644 --- a/lib/passes/CMakeLists.txt +++ b/lib/passes/CMakeLists.txt @@ -1,27 +1,35 @@ add_subdirectory(typegen) add_subdirectory(filter) add_subdirectory(analysis) +add_subdirectory(configuration) set(PASS_SOURCES TypeARTPass.cpp - Commandline.cpp support/TypeUtil.cpp + support/ModuleDumper.cpp instrumentation/InstrumentationHelper.cpp instrumentation/TypeARTFunctions.cpp instrumentation/MemOpArgCollector.cpp instrumentation/MemOpInstrumentation.cpp instrumentation/Instrumentation.cpp - ../support/FileConfiguration.cpp TypeARTConfiguration.cpp + Commandline.cpp ) +if(${LLVM_VERSION_MAJOR} VERSION_LESS_EQUAL "14") + set(TYPE_IR_GEN typeart::TypeGenStatic) +else() + set(TYPE_IR_GEN ) +endif() + typeart_make_llvm_module( ${TYPEART_PREFIX}_TransformPass "${PASS_SOURCES}" LINK_LIBS typeart::MemInstFinder typeart::TypesStatic typeart::TypeGenDimetaStatic + typeart::PassConfiguration dimeta::Types - typeart::TypeGenStatic + ${TYPE_IR_GEN} INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/lib/ ${PROJECT_SOURCE_DIR}/lib/passes/ diff --git a/lib/passes/Commandline.cpp b/lib/passes/Commandline.cpp index ff504a59..204766ef 100644 --- a/lib/passes/Commandline.cpp +++ b/lib/passes/Commandline.cpp @@ -13,20 +13,43 @@ #include "Commandline.h" #include "analysis/MemInstFinder.h" +#include "configuration/Configuration.h" +#include "configuration/EnvironmentConfiguration.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" #include "typegen/TypeGenerator.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" +#include +#include +#include +#include + using namespace llvm; -namespace typeart::config::cl { +namespace typeart::config { + +// namespace util { + +// std::string get_type_file_path() { +// auto flag_value = env::get_env_flag(config::EnvironmentStdArgs::types); +// return flag_value.value_or(ConfigStdArgValues::types); +// } + +// } // namespace util + +namespace cl { struct CommandlineStdArgs final { -#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description) static constexpr char name[] = "typeart-" path; +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ + static constexpr char name[] = "typeart-" path; #include "support/ConfigurationBaseOptions.h" #undef TYPEART_CONFIG_OPTION }; -} // namespace typeart::config::cl +} // namespace cl + +} // namespace typeart::config using typeart::config::ConfigStdArgDescriptions; using typeart::config::ConfigStdArgTypes; @@ -37,6 +60,7 @@ cl::OptionCategory typeart_category("TypeART instrumentation pass", "These contr static cl::opt cl_typeart_type_file(CommandlineStdArgs::types, cl::desc(ConfigStdArgDescriptions::types), + cl::init(ConfigStdArgValues::types), cl::cat(typeart_category)); static cl::opt cl_typeart_stats(CommandlineStdArgs::stats, @@ -57,12 +81,7 @@ static cl::opt cl_typeart_instrument_global(Comman static cl::opt cl_typeart_instrument_stack(CommandlineStdArgs::stack, cl::desc(ConfigStdArgDescriptions::stack), cl::init(ConfigStdArgValues::stack), - cl::cat(typeart_category), - cl::callback([](const bool& opt) { - if (opt) { - ::cl_typeart_instrument_global = true; - } - })); + cl::cat(typeart_category)); static cl::opt cl_typeart_instrument_stack_lifetime( CommandlineStdArgs::stack_lifetime, cl::desc(ConfigStdArgDescriptions::stack_lifetime), @@ -122,19 +141,19 @@ static cl::opt cl_typeart_f namespace typeart::config::cl { -std::string get_type_file_path() { - if (!cl_typeart_type_file.empty()) { - LOG_DEBUG("Using cl::opt for types file " << cl_typeart_type_file.getValue()); - return cl_typeart_type_file.getValue(); - } - const char* type_file = std::getenv("TYPEART_TYPE_FILE"); - if (type_file != nullptr) { - LOG_DEBUG("Using env var for types file " << type_file) - return std::string{type_file}; - } - LOG_DEBUG("Loading default types file types.yaml"); - return "types.yaml"; -} +// std::string get_type_file_path() { +// if (!cl_typeart_type_file.empty()) { +// LOG_DEBUG("Using cl::opt for types file " << cl_typeart_type_file.getValue()); +// return cl_typeart_type_file.getValue(); +// } +// const char* type_file = std::getenv("TYPEART_TYPE_FILE"); +// if (type_file != nullptr) { +// LOG_DEBUG("Using env var for types file " << type_file) +// return std::string{type_file}; +// } +// LOG_DEBUG("Loading default types file types.yaml"); +// return "types.yaml"; +// } namespace detail { template @@ -151,14 +170,12 @@ config::OptionValue make_opt(const ClOpt& cl_opt) { } template -std::pair make_entry(std::string&& key, - ClOpt&& cl_opt) { +std::pair make_entry(std::string&& key, ClOpt&& cl_opt) { return {key, make_opt(std::forward(cl_opt))}; } template -std::pair make_occurr_entry(std::string&& key, - ClOpt&& cl_opt) { +std::pair make_occurr_entry(std::string&& key, ClOpt&& cl_opt) { return {key, (cl_opt.getNumOccurrences() > 0)}; } } // namespace detail @@ -167,8 +184,16 @@ CommandLineOptions::CommandLineOptions() { using namespace config; using namespace typeart::config::cl::detail; + // const auto type_file = [&]() { + // if (!cl_typeart_type_file.empty()) { + // LOG_DEBUG("Using cl::opt for types file " << cl_typeart_type_file.getValue()); + // return cl_typeart_type_file.getValue(); + // } + // return util::get_type_file_path(); + // }(); + mapping_ = { - make_entry(ConfigStdArgs::types, get_type_file_path()), + make_entry(ConfigStdArgs::types, cl_typeart_type_file), make_entry(ConfigStdArgs::stats, cl_typeart_stats), make_entry(ConfigStdArgs::heap, cl_typeart_instrument_heap), make_entry(ConfigStdArgs::global, cl_typeart_instrument_global), @@ -204,14 +229,20 @@ CommandLineOptions::CommandLineOptions() { make_occurr_entry(ConfigStdArgs::analysis_filter_pointer_alloc, cl_typeart_filter_pointer_alloca), make_occurr_entry(ConfigStdArgs::analysis_filter_alloca_non_array, cl_typeart_filter_stack_non_array), }; + + if (!occurence_mapping_.lookup(ConfigStdArgs::global) && occurence_mapping_.lookup(ConfigStdArgs::stack)) { + const auto stack_value = mapping_.lookup(ConfigStdArgs::stack); + mapping_[ConfigStdArgs::global] = OptionValue{static_cast(stack_value)}; + occurence_mapping_[ConfigStdArgs::global] = true; + } } -llvm::Optional CommandLineOptions::getValue(std::string_view opt_path) const { +std::optional CommandLineOptions::getValue(std::string_view opt_path) const { auto key = llvm::StringRef(opt_path.data()); - if (mapping_.count(key) != 0U) { + if (occurence_mapping_.lookup(key)) { return mapping_.lookup(key); } - return llvm::None; + return {}; } [[maybe_unused]] bool CommandLineOptions::valueSpecified(std::string_view opt_path) const { diff --git a/lib/passes/Commandline.h b/lib/passes/Commandline.h index 8be22c74..8b554908 100644 --- a/lib/passes/Commandline.h +++ b/lib/passes/Commandline.h @@ -13,24 +13,18 @@ #ifndef TYPEART_COMMANDLINE_H #define TYPEART_COMMANDLINE_H -#include "support/Configuration.h" - -#include "llvm/ADT/StringMap.h" +#include "configuration/Configuration.h" namespace typeart::config::cl { class CommandLineOptions final : public config::Configuration { - public: - using OptionsMap = llvm::StringMap; - using ClOccurrenceMap = llvm::StringMap; - private: OptionsMap mapping_; - ClOccurrenceMap occurence_mapping_; + OptOccurrenceMap occurence_mapping_; public: CommandLineOptions(); - [[nodiscard]] llvm::Optional getValue(std::string_view opt_path) const override; + [[nodiscard]] std::optional getValue(std::string_view opt_path) const override; [[maybe_unused]] [[nodiscard]] bool valueSpecified(std::string_view opt_path) const; }; diff --git a/lib/passes/TypeARTConfiguration.cpp b/lib/passes/TypeARTConfiguration.cpp index ddff6c7e..93b50ccd 100644 --- a/lib/passes/TypeARTConfiguration.cpp +++ b/lib/passes/TypeARTConfiguration.cpp @@ -13,40 +13,68 @@ #include "TypeARTConfiguration.h" #include "Commandline.h" -#include "support/FileConfiguration.h" +#include "configuration/Configuration.h" +#include "configuration/EnvironmentConfiguration.h" +#include "configuration/FileConfiguration.h" +#include "configuration/TypeARTOptions.h" +#include "support/ConfigurationBase.h" +#include "support/Logger.h" + +#include +#include namespace typeart::config { TypeARTConfiguration::TypeARTConfiguration(std::unique_ptr config_options, - std::unique_ptr commandline_options) - : configuration_options_(std::move(config_options)), commandline_options_(std::move(commandline_options)) { + std::unique_ptr commandline_options, + std::unique_ptr env_options) + : configuration_options_(std::move(config_options)), + commandline_options_(std::move(commandline_options)), + env_options_(std::move(env_options)) { } -llvm::Optional TypeARTConfiguration::getValue(std::string_view opt_path) const { - const bool use_cl = prioritize_commandline && commandline_options_->valueSpecified(opt_path); - if (use_cl) { - LOG_DEBUG("Take CL arg for " << opt_path.data()) - return commandline_options_->getValue(opt_path); +std::optional TypeARTConfiguration::getValue(std::string_view opt_path) const { + if (prioritize_commandline) { + if (auto value = env_options_->getValue(opt_path)) { + // LOG_DEBUG("Take ENV " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } + if (auto value = commandline_options_->getValue(opt_path)) { + // LOG_DEBUG("Take CL " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } } return configuration_options_->getValue(opt_path); } -OptionValue TypeARTConfiguration::getValueOr(std::string_view opt_path, OptionValue alt) const { - const bool use_cl = prioritize_commandline && commandline_options_->valueSpecified(opt_path); - if (use_cl) { - LOG_DEBUG("Take CL arg for " << opt_path.data()) - return commandline_options_->getValueOr(opt_path, alt); +OptionValue TypeARTConfiguration::getValueOr(std::string_view opt_path, const OptionValue& alt) const { + if (prioritize_commandline) { + if (auto value = env_options_->getValue(opt_path)) { + // LOG_DEBUG("Take ENV " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } + if (auto value = commandline_options_->getValue(opt_path)) { + // LOG_DEBUG("Take CL " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } } return configuration_options_->getValueOr(opt_path, alt); } OptionValue TypeARTConfiguration::operator[](std::string_view opt_path) const { - const bool use_cl = prioritize_commandline && commandline_options_->valueSpecified(opt_path); - if (use_cl) { - LOG_DEBUG("Take CL arg for " << opt_path.data()) - return commandline_options_->operator[](opt_path); + if (prioritize_commandline) { + if (auto value = env_options_->getValue(opt_path)) { + // LOG_DEBUG("Take ENV " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } + if (auto value = commandline_options_->getValue(opt_path)) { + // LOG_DEBUG("Take CL " << opt_path << "=" << (std::string(value.value()))); + return value.value(); + } } - return configuration_options_->operator[](opt_path); + auto result = configuration_options_->operator[](opt_path); + // LOG_DEBUG("Take File " << opt_path << "=" << (std::string(result))); + return result; } void TypeARTConfiguration::prioritizeCommandline(bool do_prioritize) { @@ -57,19 +85,43 @@ void TypeARTConfiguration::emitTypeartFileConfiguration(llvm::raw_ostream& out_s out_stream << configuration_options_->getConfigurationAsString(); } -llvm::ErrorOr> make_typeart_configuration(const TypeARTConfigInit& init) { - auto file_opts = init.mode != TypeARTConfigInit::FileConfigurationMode::Empty - ? config::file::make_file_configuration(init.file_path) - : config::file::make_default_file_configuration(); +template +std::pair make_occurr_entry(std::string&& key, ClOpt&& cl_opt) { + return {key, (cl_opt.getNumOccurrences() > 0)}; +} + +TypeARTConfigOptions TypeARTConfiguration::getOptions() const { + return helper::config_to_options(*this); +} + +inline llvm::ErrorOr> make_config( + llvm::ErrorOr> file_opts) { if (file_opts) { - auto cl_opts = std::make_unique(); - auto config = std::make_unique(std::move(file_opts.get()), std::move(cl_opts)); + const bool heap = file_opts->get()->getValue(config::ConfigStdArgs::heap).value_or(OptionValue{false}); + const bool stack = file_opts->get()->getValue(config::ConfigStdArgs::stack).value_or(OptionValue{false}); + auto cl_opts = std::make_unique(); + auto env_opts = std::make_unique(); + env_opts->parsePhaseEnvFlags({heap, stack}); + auto config = std::make_unique(std::move(file_opts.get()), std::move(cl_opts), + std::move(env_opts)); config->prioritizeCommandline(true); return config; } - LOG_FATAL("Could not initialize file configuration: \'" << init.file_path - << "\'. Reason: " << file_opts.getError().message()) + LOG_FATAL("Could not initialize file configuration. Reason: " << file_opts.getError().message()) return file_opts.getError(); } +llvm::ErrorOr> make_typeart_configuration(const TypeARTConfigInit& init) { + auto file_opts = init.mode != TypeARTConfigInit::FileConfigurationMode::Empty + ? config::file::make_file_configuration(init.file_path) + : config::file::make_default_file_configuration(); + return make_config(std::move(file_opts)); +} + +llvm::ErrorOr> make_typeart_configuration_from_opts( + const TypeARTConfigOptions& opts) { + auto file_opts = config::file::make_from_configuration(opts); + return make_config(std::move(file_opts)); +} + } // namespace typeart::config diff --git a/lib/passes/TypeARTConfiguration.h b/lib/passes/TypeARTConfiguration.h index da7a3eeb..2927d5e3 100644 --- a/lib/passes/TypeARTConfiguration.h +++ b/lib/passes/TypeARTConfiguration.h @@ -13,7 +13,8 @@ #ifndef TYPEART_TYPEARTCONFIGURATION_H #define TYPEART_TYPEARTCONFIGURATION_H -#include "support/Configuration.h" +#include "configuration/Configuration.h" +#include "configuration/TypeARTOptions.h" #include "llvm/Support/ErrorOr.h" @@ -27,20 +28,28 @@ namespace cl { class CommandLineOptions; } // namespace cl +namespace env { +class EnvironmentFlagsOptions; +} // namespace env + class TypeARTConfiguration final : public Configuration { private: std::unique_ptr configuration_options_; std::unique_ptr commandline_options_; + std::unique_ptr env_options_; bool prioritize_commandline{true}; public: TypeARTConfiguration(std::unique_ptr config_options, - std::unique_ptr commandline_options); + std::unique_ptr commandline_options, + std::unique_ptr env_options); void prioritizeCommandline(bool do_prioritize); - [[nodiscard]] llvm::Optional getValue(std::string_view opt_path) const override; - [[nodiscard]] OptionValue getValueOr(std::string_view opt_path, OptionValue alt) const override; + [[nodiscard]] std::optional getValue(std::string_view opt_path) const override; + [[nodiscard]] OptionValue getValueOr(std::string_view opt_path, const OptionValue& alt) const override; [[nodiscard]] OptionValue operator[](std::string_view opt_path) const override; void emitTypeartFileConfiguration(llvm::raw_ostream& out_stream); + [[nodiscard]] TypeARTConfigOptions getOptions() const; + ~TypeARTConfiguration() override = default; }; @@ -53,6 +62,9 @@ struct TypeARTConfigInit { [[maybe_unused]] llvm::ErrorOr> make_typeart_configuration( const TypeARTConfigInit& init); +[[maybe_unused]] llvm::ErrorOr> make_typeart_configuration_from_opts( + const TypeARTConfigOptions& opts); + } // namespace typeart::config #endif // TYPEART_TYPEARTCONFIGURATION_H diff --git a/lib/passes/TypeARTPass.cpp b/lib/passes/TypeARTPass.cpp index a7f2f510..23bc5afa 100644 --- a/lib/passes/TypeARTPass.cpp +++ b/lib/passes/TypeARTPass.cpp @@ -10,34 +10,46 @@ // SPDX-License-Identifier: BSD-3-Clause // -#include "TypeARTPass.h" - #include "Commandline.h" #include "TypeARTConfiguration.h" #include "analysis/MemInstFinder.h" +#include "configuration/Configuration.h" +#include "configuration/EnvironmentConfiguration.h" +#include "configuration/FileConfiguration.h" +#include "configuration/PassBuilderUtil.h" +#include "configuration/PassConfiguration.h" +#include "configuration/TypeARTOptions.h" #include "instrumentation/MemOpArgCollector.h" #include "instrumentation/MemOpInstrumentation.h" #include "instrumentation/TypeARTFunctions.h" -#include "support/Configuration.h" -#include "support/FileConfiguration.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" +#include "support/ModuleDumper.h" #include "support/Table.h" +#include "support/Util.h" #include "typegen/TypeGenerator.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" #include #include +#include +#include #include #include #include @@ -48,9 +60,6 @@ class BasicBlock; using namespace llvm; -static llvm::RegisterPass msp("typeart", "TypeArt type instrumentation sanitizer", false, - false); - extern llvm::cl::OptionCategory typeart_category; static cl::opt cl_typeart_configuration_file( @@ -59,10 +68,6 @@ static cl::opt cl_typeart_configuration_file( "Location of the configuration file to configure the TypeART pass. Commandline arguments are prioritized."), cl::cat(typeart_category)); -static cl::opt cl_typeart_configuration_file_dump("typeart-config-dump", cl::init(false), cl::Hidden, - cl::desc("Dump default config file content to std::out."), - cl::cat(typeart_category)); - #define DEBUG_TYPE "typeart" ALWAYS_ENABLED_STATISTIC(NumInstrumentedMallocs, "Number of instrumented mallocs"); @@ -72,7 +77,7 @@ ALWAYS_ENABLED_STATISTIC(NumInstrumentedGlobal, "Number of instrumented globals" namespace typeart::pass { -llvm::Optional get_configuration_file_path() { +std::optional get_configuration_file_path() { if (!cl_typeart_configuration_file.empty()) { LOG_DEBUG("Using cl::opt for config file " << cl_typeart_configuration_file.getValue()); return cl_typeart_configuration_file.getValue(); @@ -83,237 +88,367 @@ llvm::Optional get_configuration_file_path() { return std::string{config_file}; } LOG_INFO("No configuration file set.") - return llvm::None; + return {}; } -// Used by LLVM pass manager to identify passes in memory -char TypeArtPass::ID = 0; +class TypeArtPass : public llvm::PassInfoMixin { + std::optional pass_opts{std::nullopt}; + std::unique_ptr pass_config; -TypeArtPass::TypeArtPass() : llvm::ModulePass(ID) { - EnableStatistics(false); -} + struct TypeArtFunc { + const std::string name; + llvm::Value* f{nullptr}; + }; -void TypeArtPass::getAnalysisUsage(llvm::AnalysisUsage& info) const { -} + TypeArtFunc typeart_alloc{"__typeart_alloc"}; + TypeArtFunc typeart_alloc_global{"__typeart_alloc_global"}; + TypeArtFunc typeart_alloc_stack{"__typeart_alloc_stack"}; + TypeArtFunc typeart_free{"__typeart_free"}; + TypeArtFunc typeart_leave_scope{"__typeart_leave_scope"}; + + TypeArtFunc typeart_alloc_omp = typeart_alloc; + TypeArtFunc typeart_alloc_stacks_omp = typeart_alloc_stack; + TypeArtFunc typeart_free_omp = typeart_free; + TypeArtFunc typeart_leave_scope_omp = typeart_leave_scope; + + std::unique_ptr meminst_finder; + std::unique_ptr typeManager; + InstrumentationHelper instrumentation_helper; + TAFunctions functions; + std::unique_ptr instrumentation_context; + + const config::Configuration& configuration() const { + return *pass_config; + } -bool TypeArtPass::doInitialization(Module& m) { - if (cl_typeart_configuration_file_dump.getValue()) { - auto config = config::make_typeart_configuration({"", config::TypeARTConfigInit::FileConfigurationMode::Empty}); - config->get()->emitTypeartFileConfiguration(llvm::outs()); - LOG_DEBUG("Emitted standard config. Exiting now.") - std::exit(EXIT_SUCCESS); + public: + TypeArtPass() = default; + explicit TypeArtPass(config::TypeARTConfigOptions opts) : pass_opts(opts) { + // LOG_INFO("Created with \n" << opts) } - auto config_file_path = get_configuration_file_path(); + bool doInitialization(Module& m) { + auto config_file_path = get_configuration_file_path(); - if (!config_file_path) { - pass_config = std::make_unique(); - } else { - auto typeart_config = config::make_typeart_configuration({config_file_path.getValue()}); - if (typeart_config) { - { - std::string typeart_conf_str; - llvm::raw_string_ostream conf_out_stream{typeart_conf_str}; - typeart_config->get()->emitTypeartFileConfiguration(conf_out_stream); - LOG_INFO("Emitting TypeART file content\n" << conf_out_stream.str()) + const auto init = config_file_path.has_value() + ? config::TypeARTConfigInit{config_file_path.value()} + : config::TypeARTConfigInit{{}, config::TypeARTConfigInit::FileConfigurationMode::Empty}; + + auto typeart_config = [&](const auto& init_value) { + if (init_value.mode == config::TypeARTConfigInit::FileConfigurationMode::Empty) { + return config::make_typeart_configuration_from_opts(pass_opts.value_or(config::TypeARTConfigOptions{})); } + return config::make_typeart_configuration(init_value); + }(init); + + if (typeart_config) { + LOG_INFO("Emitting TypeART configuration content\n" << typeart_config.get()->getOptions()) pass_config = std::move(*typeart_config); } else { - LOG_FATAL("Could not load TypeARTConfiguration.") + LOG_FATAL("Could not load TypeART configuration.") std::exit(EXIT_FAILURE); } - } - meminst_finder = analysis::create_finder(*pass_config); - const std::string types_file = - pass_config->getValueOr(config::ConfigStdArgs::types, {config::ConfigStdArgValues::types}); + meminst_finder = analysis::create_finder(configuration()); - const TypegenImplementation typesgen_parser = - pass_config->getValueOr(config::ConfigStdArgs::typegen, {config::ConfigStdArgValues::typegen}); - typeManager = make_typegen(types_file, typesgen_parser); + const std::string types_file = + configuration().getValueOr(config::ConfigStdArgs::types, {config::ConfigStdArgValues::types}); - LOG_DEBUG("Propagating type infos."); - const auto [loaded, error] = typeManager->load(); - if (loaded) { - LOG_DEBUG("Existing type configuration successfully loaded from " << types_file); - } else { - LOG_DEBUG("No valid existing type configuration found: " << types_file << ". Reason: " << error.message()); - } + const TypegenImplementation typesgen_parser = + configuration().getValueOr(config::ConfigStdArgs::typegen, {config::ConfigStdArgValues::typegen}); + typeManager = make_typegen(types_file, typesgen_parser); - instrumentation_helper.setModule(m); - ModuleData mdata{&m}; - typeManager->registerModule(mdata); + LOG_DEBUG("Propagating type infos."); + const auto [loaded, error] = typeManager->load(); + if (loaded) { + LOG_DEBUG("Existing type configuration successfully loaded from " << types_file); + } else { + LOG_DEBUG("No valid existing type configuration found: " << types_file << ". Reason: " << error.message()); + } - auto arg_collector = std::make_unique(typeManager.get(), instrumentation_helper); - const bool instrument_stack_lifetime = (*pass_config)[config::ConfigStdArgs::stack_lifetime]; - auto mem_instrument = - std::make_unique(functions, instrumentation_helper, instrument_stack_lifetime); - instrumentation_context = - std::make_unique(std::move(arg_collector), std::move(mem_instrument)); + instrumentation_helper.setModule(m); + ModuleData mdata{&m}; + typeManager->registerModule(mdata); - return true; -} + auto arg_collector = + std::make_unique(configuration(), typeManager.get(), instrumentation_helper); + // const bool instrument_stack_lifetime = configuration()[config::ConfigStdArgs::stack_lifetime]; + auto mem_instrument = std::make_unique(configuration(), functions, instrumentation_helper); + instrumentation_context = + std::make_unique(std::move(arg_collector), std::move(mem_instrument)); -bool TypeArtPass::runOnModule(Module& m) { - meminst_finder->runOnModule(m); - const bool instrument_global = (*pass_config)[config::ConfigStdArgs::global]; - bool instrumented_global{false}; - if (instrument_global) { - declareInstrumentationFunctions(m); - - const auto& globalsList = meminst_finder->getModuleGlobals(); - if (!globalsList.empty()) { - const auto global_count = instrumentation_context->handleGlobal(globalsList); - NumInstrumentedGlobal += global_count; - instrumented_global = global_count > 0; - } + return true; } - const auto instrumented_function = llvm::count_if(m.functions(), [&](auto& f) { return runOnFunc(f); }) > 0; - return instrumented_function || instrumented_global; -} - -bool TypeArtPass::runOnFunc(Function& f) { - using namespace typeart; + bool doFinalization() { + /* + * Persist the accumulated type definition information for this module. + */ + const std::string types_file = configuration()[config::ConfigStdArgs::types]; + LOG_DEBUG("Writing type file to " << types_file); - if (f.isDeclaration() || f.getName().startswith("__typeart")) { - return false; - } + const auto [stored, error] = typeManager->store(); + if (stored) { + LOG_DEBUG("Success!"); + } else { + LOG_FATAL("Failed writing type config to " << types_file << ". Reason: " << error.message()); + } - if (!meminst_finder->hasFunctionData(f)) { - LOG_WARNING("No allocation data could be retrieved for function: " << f.getName()); + const bool print_stats = configuration()[config::ConfigStdArgs::stats]; + if (print_stats) { + auto& out = llvm::errs(); + printStats(out); + } return false; } - LOG_DEBUG("Running on function: " << f.getName()) + void declareInstrumentationFunctions(Module& m) { + // Remove this return if problems come up during compilation + if (typeart_alloc_global.f != nullptr && typeart_alloc_stack.f != nullptr && typeart_alloc.f != nullptr && + typeart_free.f != nullptr && typeart_leave_scope.f != nullptr) { + return; + } - // FIXME this is required when "PassManagerBuilder::EP_OptimizerLast" is used as the function (constant) pointer are - // nullpointer/invalidated - declareInstrumentationFunctions(*f.getParent()); + TAFunctionDeclarator decl(m, instrumentation_helper, functions); - bool mod{false}; - // auto& c = f.getContext(); - DataLayout dl(f.getParent()); + auto alloc_arg_types = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent); + auto free_arg_types = instrumentation_helper.make_parameters(IType::ptr); + auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count); - llvm::SmallDenseMap allocCounts; + typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types); + typeart_alloc_stack.f = decl.make_function(IFunc::stack, typeart_alloc_stack.name, alloc_arg_types); + typeart_alloc_global.f = decl.make_function(IFunc::global, typeart_alloc_global.name, alloc_arg_types); + typeart_free.f = decl.make_function(IFunc::free, typeart_free.name, free_arg_types); + typeart_leave_scope.f = decl.make_function(IFunc::scope, typeart_leave_scope.name, leavescope_arg_types); - const auto& fData = meminst_finder->getFunctionData(f); - const auto& mallocs = fData.mallocs; - const auto& allocas = fData.allocas; - const auto& frees = fData.frees; + typeart_alloc_omp.f = decl.make_function(IFunc::heap_omp, typeart_alloc_omp.name, alloc_arg_types, true); + typeart_alloc_stacks_omp.f = + decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp.name, alloc_arg_types, true); + typeart_free_omp.f = decl.make_function(IFunc::free_omp, typeart_free_omp.name, free_arg_types, true); + typeart_leave_scope_omp.f = + decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types, true); + } - const bool instrument_heap = (*pass_config)[config::ConfigStdArgs::heap]; - const bool instrument_stack = (*pass_config)[config::ConfigStdArgs::stack]; + void printStats(llvm::raw_ostream& out) { + const auto scope_exit_cleanup_counter = llvm::make_scope_exit([&]() { + NumInstrumentedAlloca = 0; + NumInstrumentedFrees = 0; + NumInstrumentedGlobal = 0; + NumInstrumentedMallocs = 0; + }); + meminst_finder->printStats(out); + + const auto get_ta_mode = [&]() { + const bool heap = configuration()[config::ConfigStdArgs::heap]; + const bool stack = configuration()[config::ConfigStdArgs::stack]; + const bool global = configuration()[config::ConfigStdArgs::global]; + + if (heap) { + if (stack) { + return " [Heap & Stack]"; + } + return " [Heap]"; + } - if (instrument_heap) { - // instrument collected calls of bb: - const auto heap_count = instrumentation_context->handleHeap(mallocs); - const auto free_count = instrumentation_context->handleFree(frees); + if (stack) { + return " [Stack]"; + } - NumInstrumentedMallocs += heap_count; - NumInstrumentedFrees += free_count; + if (global) { + return " [Global]"; + } - mod |= heap_count > 0 || free_count > 0; + LOG_ERROR("Did not find heap or stack, or combination thereof!"); + assert((heap || stack || global) && "Needs stack, heap, global or combination thereof"); + return " [Unknown]"; + }; + + Table stats("TypeArtPass"); + stats.wrap_header_ = true; + stats.title_ += get_ta_mode(); + stats.put(Row::make("Malloc", NumInstrumentedMallocs.getValue())); + stats.put(Row::make("Free", NumInstrumentedFrees.getValue())); + stats.put(Row::make("Alloca", NumInstrumentedAlloca.getValue())); + stats.put(Row::make("Global", NumInstrumentedGlobal.getValue())); + + std::ostringstream stream; + stats.print(stream); + out << stream.str(); } - if (instrument_stack) { - const auto stack_count = instrumentation_context->handleStack(allocas); - NumInstrumentedAlloca += stack_count; - mod |= stack_count > 0; + llvm::PreservedAnalyses run(llvm::Module& m, llvm::ModuleAnalysisManager&) { + bool changed{false}; + changed |= doInitialization(m); + const bool heap = configuration()[config::ConfigStdArgs::heap]; // Must happen after doInit + dump_module(m, heap ? util::module::ModulePhase::kBase : util::module::ModulePhase::kOpt); + changed |= runOnModule(m); + dump_module(m, heap ? util::module::ModulePhase::kHeap : util::module::ModulePhase::kStack); + changed |= doFinalization(); + return changed ? llvm::PreservedAnalyses::none() : llvm::PreservedAnalyses::all(); } - return mod; -} // namespace pass - -bool TypeArtPass::doFinalization(Module&) { - /* - * Persist the accumulated type definition information for this module. - */ - const std::string types_file = (*pass_config)[config::ConfigStdArgs::types]; - LOG_DEBUG("Writing type file to " << types_file); - - const auto [stored, error] = typeManager->store(); - if (stored) { - LOG_DEBUG("Success!"); - } else { - LOG_FATAL("Failed writing type config to " << types_file << ". Reason: " << error.message()); - } + bool runOnModule(llvm::Module& m) { + meminst_finder->runOnModule(m); + const bool instrument_global = configuration()[config::ConfigStdArgs::global]; + bool globals_were_instrumented{false}; + if (instrument_global) { + declareInstrumentationFunctions(m); + + const auto& globalsList = meminst_finder->getModuleGlobals(); + if (!globalsList.empty()) { + const auto global_count = instrumentation_context->handleGlobal(globalsList); + NumInstrumentedGlobal += global_count; + globals_were_instrumented = global_count > 0; + } + } - const bool print_stats = (*pass_config)[config::ConfigStdArgs::stats]; - if (print_stats) { - auto& out = llvm::errs(); - printStats(out); + const auto instrumented_function = llvm::count_if(m.functions(), [&](auto& f) { return runOnFunc(f); }) > 0; + return instrumented_function || globals_were_instrumented; } - return false; -} -void TypeArtPass::declareInstrumentationFunctions(Module& m) { - // Remove this return if problems come up during compilation - if (typeart_alloc_global.f != nullptr && typeart_alloc_stack.f != nullptr && typeart_alloc.f != nullptr && - typeart_free.f != nullptr && typeart_leave_scope.f != nullptr) { - return; - } + bool runOnFunc(llvm::Function& f) { + using namespace typeart; - TAFunctionDeclarator decl(m, instrumentation_helper, functions); + if (f.isDeclaration() || util::starts_with_any_of(f.getName(), "__typeart", "typeart")) { + return false; + } - auto alloc_arg_types = instrumentation_helper.make_parameters(IType::ptr, IType::type_id, IType::extent); - auto free_arg_types = instrumentation_helper.make_parameters(IType::ptr); - auto leavescope_arg_types = instrumentation_helper.make_parameters(IType::stack_count); + if (!meminst_finder->hasFunctionData(f)) { + LOG_WARNING("No allocation data could be retrieved for function: " << f.getName()); + return false; + } - typeart_alloc.f = decl.make_function(IFunc::heap, typeart_alloc.name, alloc_arg_types); - typeart_alloc_stack.f = decl.make_function(IFunc::stack, typeart_alloc_stack.name, alloc_arg_types); - typeart_alloc_global.f = decl.make_function(IFunc::global, typeart_alloc_global.name, alloc_arg_types); - typeart_free.f = decl.make_function(IFunc::free, typeart_free.name, free_arg_types); - typeart_leave_scope.f = decl.make_function(IFunc::scope, typeart_leave_scope.name, leavescope_arg_types); + LOG_DEBUG("Running on function: " << f.getName()) - typeart_alloc_omp.f = decl.make_function(IFunc::heap_omp, typeart_alloc_omp.name, alloc_arg_types, true); - typeart_alloc_stacks_omp.f = - decl.make_function(IFunc::stack_omp, typeart_alloc_stacks_omp.name, alloc_arg_types, true); - typeart_free_omp.f = decl.make_function(IFunc::free_omp, typeart_free_omp.name, free_arg_types, true); - typeart_leave_scope_omp.f = - decl.make_function(IFunc::scope_omp, typeart_leave_scope_omp.name, leavescope_arg_types, true); -} + // FIXME this is required when "PassManagerBuilder::EP_OptimizerLast" is used as the function (constant) pointer are + // nullpointer/invalidated + declareInstrumentationFunctions(*f.getParent()); -void TypeArtPass::printStats(llvm::raw_ostream& out) { - meminst_finder->printStats(out); + bool mod{false}; + // auto& c = f.getContext(); + DataLayout dl(f.getParent()); - const auto get_ta_mode = [&]() { - const bool heap = (*pass_config)[config::ConfigStdArgs::heap]; - const bool stack = (*pass_config)[config::ConfigStdArgs::stack]; + const auto& fData = meminst_finder->getFunctionData(f); + const auto& mallocs = fData.mallocs; + const auto& allocas = fData.allocas; + const auto& frees = fData.frees; - if (heap) { - if (stack) { - return " [Heap & Stack]"; - } - return " [Heap]"; + const bool instrument_heap = configuration()[config::ConfigStdArgs::heap]; + const bool instrument_stack = configuration()[config::ConfigStdArgs::stack]; + + if (instrument_heap) { + // instrument collected calls of bb: + const auto heap_count = instrumentation_context->handleHeap(mallocs); + const auto free_count = instrumentation_context->handleFree(frees); + + NumInstrumentedMallocs += heap_count; + NumInstrumentedFrees += free_count; + + mod |= heap_count > 0 || free_count > 0; } - if (stack) { - return " [Stack]"; + if (instrument_stack) { + const auto stack_count = instrumentation_context->handleStack(allocas); + NumInstrumentedAlloca += stack_count; + mod |= stack_count > 0; } - llvm_unreachable("Did not find heap or stack, or combination thereof!"); - }; + return mod; + } +}; + +class LegacyTypeArtPass : public llvm::ModulePass { + private: + TypeArtPass pass_impl_; + + public: + static char ID; // NOLINT + + LegacyTypeArtPass() : ModulePass(ID){}; - Table stats("TypeArtPass"); - stats.wrap_header = true; - stats.title += get_ta_mode(); - stats.put(Row::make("Malloc", NumInstrumentedMallocs.getValue())); - stats.put(Row::make("Free", NumInstrumentedFrees.getValue())); - stats.put(Row::make("Alloca", NumInstrumentedAlloca.getValue())); - stats.put(Row::make("Global", NumInstrumentedGlobal.getValue())); - - std::ostringstream stream; - stats.print(stream); - out << stream.str(); + bool doInitialization(llvm::Module&) override; + + bool runOnModule(llvm::Module& module) override; + + bool doFinalization(llvm::Module&) override; + + ~LegacyTypeArtPass() override = default; +}; + +bool LegacyTypeArtPass::doInitialization(llvm::Module& m) { + return pass_impl_.doInitialization(m); +} + +bool LegacyTypeArtPass::runOnModule(llvm::Module& module) { + bool changed{false}; + changed |= pass_impl_.runOnModule(module); + return changed; +} + +bool LegacyTypeArtPass::doFinalization(llvm::Module&) { + return pass_impl_.doFinalization(); + ; } } // namespace typeart::pass -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" +//..................... +// New PM +//..................... +llvm::PassPluginLibraryInfo getTypeartPassPluginInfo() { + using namespace llvm; + return {LLVM_PLUGIN_API_VERSION, "TypeART", LLVM_VERSION_STRING, [](PassBuilder& pass_builder) { + pass_builder.registerPipelineStartEPCallback([](auto& MPM, OptimizationLevel) { + auto parameters = typeart::util::pass::parsePassParameters(typeart::config::pass::parse_typeart_config, + "typeart", "typeart"); + if (!parameters) { + LOG_FATAL("Error parsing heap params: " << parameters.takeError()) + return; + } + MPM.addPass(typeart::pass::TypeArtPass(typeart::pass::TypeArtPass(parameters.get()))); + }); + pass_builder.registerOptimizerLastEPCallback([](auto& MPM, OptimizationLevel) { + auto parameters = typeart::util::pass::parsePassParameters(typeart::config::pass::parse_typeart_config, + "typeart", "typeart"); + if (!parameters) { + LOG_FATAL("Error parsing stack params: " << parameters.takeError()) + return; + } + MPM.addPass(typeart::pass::TypeArtPass(typeart::pass::TypeArtPass(parameters.get()))); + }); + pass_builder.registerPipelineParsingCallback( + [](StringRef name, ModulePassManager& module_pm, ArrayRef) { + if (typeart::util::pass::checkParametrizedPassName(name, "typeart")) { + auto parameters = typeart::util::pass::parsePassParameters( + typeart::config::pass::parse_typeart_config, name, "typeart"); + if (!parameters) { + LOG_FATAL("Error parsing params: " << parameters.takeError()) + return false; + } + module_pm.addPass(typeart::pass::TypeArtPass(parameters.get())); + return true; + } + LOG_FATAL("Not a valid parametrized pass name: " << name) + return false; + }); + }}; +} + +extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() { + return getTypeartPassPluginInfo(); +} + +//..................... +// Old PM +//..................... +char typeart::pass::LegacyTypeArtPass::ID = 0; // NOLINT + +static RegisterPass x("typeart", "TypeArt Pass"); // NOLINT + +ModulePass* createTypeArtPass() { + return new typeart::pass::LegacyTypeArtPass(); +} -static void registerClangPass(const llvm::PassManagerBuilder&, llvm::legacy::PassManagerBase& PM) { - PM.add(new typeart::pass::TypeArtPass()); +extern "C" void AddTypeArtPass(LLVMPassManagerRef pass_manager) { + unwrap(pass_manager)->add(createTypeArtPass()); } -static RegisterStandardPasses RegisterClangPass(PassManagerBuilder::EP_OptimizerLast, registerClangPass); diff --git a/lib/passes/TypeARTPass.h b/lib/passes/TypeARTPass.h deleted file mode 100644 index a7d997e8..00000000 --- a/lib/passes/TypeARTPass.h +++ /dev/null @@ -1,89 +0,0 @@ -// TypeART library -// -// Copyright (c) 2017-2025 TypeART Authors -// Distributed under the BSD 3-Clause license. -// (See accompanying file LICENSE.txt or copy at -// https://opensource.org/licenses/BSD-3-Clause) -// -// Project home: https://github.com/tudasc/TypeART -// -// SPDX-License-Identifier: BSD-3-Clause -// - -#ifndef _LIB_MUSTSUPPORTPASS_H -#define _LIB_MUSTSUPPORTPASS_H - -#include "instrumentation/Instrumentation.h" -#include "instrumentation/InstrumentationHelper.h" -#include "instrumentation/TypeARTFunctions.h" -#include "support/Configuration.h" - -#include "llvm/Pass.h" - -#include -#include - -namespace llvm { -class Module; -class Function; -class AnalysisUsage; -class Value; -class raw_ostream; -} // namespace llvm - -namespace typeart { -class TypeGenerator; - -namespace analysis { -class MemInstFinder; -} // namespace analysis - -} // namespace typeart - -namespace typeart::pass { - -class TypeArtPass : public llvm::ModulePass { - private: - // const std::string default_types_file{"types.yaml"}; - std::unique_ptr pass_config; - - struct TypeArtFunc { - const std::string name; - llvm::Value* f{nullptr}; - }; - - TypeArtFunc typeart_alloc{"__typeart_alloc"}; - TypeArtFunc typeart_alloc_global{"__typeart_alloc_global"}; - TypeArtFunc typeart_alloc_stack{"__typeart_alloc_stack"}; - TypeArtFunc typeart_free{"__typeart_free"}; - TypeArtFunc typeart_leave_scope{"__typeart_leave_scope"}; - - TypeArtFunc typeart_alloc_omp = typeart_alloc; - TypeArtFunc typeart_alloc_stacks_omp = typeart_alloc_stack; - TypeArtFunc typeart_free_omp = typeart_free; - TypeArtFunc typeart_leave_scope_omp = typeart_leave_scope; - - std::unique_ptr meminst_finder; - std::unique_ptr typeManager; - InstrumentationHelper instrumentation_helper; - TAFunctions functions; - std::unique_ptr instrumentation_context; - - public: - static char ID; // used to identify pass - - TypeArtPass(); - bool doInitialization(llvm::Module&) override; - bool runOnModule(llvm::Module&) override; - bool runOnFunc(llvm::Function&); - bool doFinalization(llvm::Module&) override; - void getAnalysisUsage(llvm::AnalysisUsage&) const override; - - private: - void declareInstrumentationFunctions(llvm::Module&); - void printStats(llvm::raw_ostream&); -}; - -} // namespace typeart::pass - -#endif diff --git a/lib/passes/analysis/MemInstFinder.cpp b/lib/passes/analysis/MemInstFinder.cpp index e2830a88..051fc85b 100644 --- a/lib/passes/analysis/MemInstFinder.cpp +++ b/lib/passes/analysis/MemInstFinder.cpp @@ -13,13 +13,16 @@ #include "MemInstFinder.h" #include "MemOpVisitor.h" +#include "TypeARTConfiguration.h" #include "analysis/MemOpData.h" +#include "configuration/Configuration.h" +#include "configuration/TypeARTOptions.h" #include "filter/CGForwardFilter.h" #include "filter/CGInterface.h" #include "filter/Filter.h" #include "filter/Matcher.h" #include "filter/StdForwardFilter.h" -#include "support/Configuration.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/Table.h" #include "support/TypeUtil.h" @@ -40,7 +43,9 @@ #include #include +#include #include +#include #include using namespace llvm; @@ -59,24 +64,7 @@ ALWAYS_ENABLED_STATISTIC(NumCallFilteredGlobals, "Number of filtered globals"); namespace typeart::analysis { -struct MemInstFinderConfig { - struct Filter { - bool useCallFilter{false}; - FilterImplementation implementation{FilterImplementation::standard}; - std::string callFilterGlob{"*MPI_*"}; - std::string callFilterDeepGlob{"MPI_*"}; - std::string callFilterCgFile{}; - bool filterNonArrayAlloca{false}; - bool filterMallocAllocPair{false}; - bool filterGlobal{true}; - bool filterPointerAlloca{false}; - }; - - bool collect_heap{false}; - bool collect_alloca{false}; - bool collect_global{false}; - Filter filter; -}; +using MemInstFinderConfig = config::Configuration; namespace filter { class CallFilter { @@ -100,25 +88,27 @@ namespace filter { namespace detail { static std::unique_ptr make_filter(const MemInstFinderConfig& config) { using namespace typeart::filter; - const auto filter_id = config.filter.implementation; - const std::string glob = config.filter.callFilterGlob; + const bool filter = config[config::ConfigStdArgs::filter]; + const FilterImplementation filter_id = config[config::ConfigStdArgs::filter_impl]; + const std::string glob = config[config::ConfigStdArgs::filter_glob]; - if (filter_id == FilterImplementation::none || !config.filter.useCallFilter) { + if (filter_id == FilterImplementation::none || !filter) { LOG_DEBUG("Return no-op filter") return std::make_unique(); } else if (filter_id == FilterImplementation::cg) { - if (config.filter.callFilterCgFile.empty()) { + const std::string cg_file = config[config::ConfigStdArgs::filter_cg_file]; + if (cg_file.empty()) { LOG_FATAL("CG File not set!"); std::exit(1); } - LOG_DEBUG("Return CG filter with CG file @ " << config.filter.callFilterCgFile) - auto json_cg = JSONCG::getJSON(config.filter.callFilterCgFile); + LOG_DEBUG("Return CG filter with CG file @ " << cg_file) + auto json_cg = JSONCG::getJSON(cg_file); auto matcher = std::make_unique(util::glob2regex(glob)); return std::make_unique(glob, std::move(json_cg), std::move(matcher)); } else { LOG_DEBUG("Return default filter") auto matcher = std::make_unique(util::glob2regex(glob)); - const auto deep_glob = config.filter.callFilterDeepGlob; + const auto deep_glob = config[config::ConfigStdArgs::filter_glob_deep]; auto deep_matcher = std::make_unique(util::glob2regex(deep_glob)); return std::make_unique(std::move(matcher), std::move(deep_matcher)); } @@ -128,28 +118,28 @@ static std::unique_ptr make_filter(const MemInstFinderC CallFilter::CallFilter(const MemInstFinderConfig& config) : fImpl{detail::make_filter(config)} { } -bool CallFilter::operator()(AllocaInst* in) { - LOG_DEBUG("Analyzing value: " << util::dump(*in)); +bool CallFilter::operator()(AllocaInst* allocation) { + LOG_DEBUG("Analyzing value: " << util::dump(*allocation)); fImpl->setMode(/*search mallocs = */ false); - fImpl->setStartingFunction(in->getParent()->getParent()); - const auto filter_ = fImpl->filter(in); + fImpl->setStartingFunction(allocation->getParent()->getParent()); + const auto filter_ = fImpl->filter(allocation); if (filter_) { - LOG_DEBUG("Filtering value: " << util::dump(*in) << "\n"); + LOG_DEBUG("Filtering value: " << util::dump(*allocation) << "\n"); } else { - LOG_DEBUG("Keeping value: " << util::dump(*in) << "\n"); + LOG_DEBUG("Keeping value: " << util::dump(*allocation) << "\n"); } return filter_; } -bool CallFilter::operator()(GlobalValue* g) { - LOG_DEBUG("Analyzing value: " << util::dump(*g)); +bool CallFilter::operator()(GlobalValue* global_value) { + LOG_DEBUG("Analyzing value: " << util::dump(*global_value)); fImpl->setMode(/*search mallocs = */ false); fImpl->setStartingFunction(nullptr); - const auto filter_ = fImpl->filter(g); + const auto filter_ = fImpl->filter(global_value); if (filter_) { - LOG_DEBUG("Filtering value: " << util::dump(*g) << "\n"); + LOG_DEBUG("Filtering value: " << util::dump(*global_value) << "\n"); } else { - LOG_DEBUG("Keeping value: " << util::dump(*g) << "\n"); + LOG_DEBUG("Keeping value: " << util::dump(*global_value) << "\n"); } return filter_; } @@ -165,7 +155,7 @@ class MemInstFinderPass : public MemInstFinder { MemOpVisitor mOpsCollector; filter::CallFilter filter; llvm::DenseMap functionMap; - MemInstFinderConfig config; + const MemInstFinderConfig& config; public: explicit MemInstFinderPass(const MemInstFinderConfig&); @@ -175,21 +165,21 @@ class MemInstFinderPass : public MemInstFinder { const GlobalDataList& getModuleGlobals() const override; void printStats(llvm::raw_ostream&) const override; // void configure(MemInstFinderConfig&) override; - ~MemInstFinderPass() = default; + ~MemInstFinderPass() override = default; private: bool runOnFunction(llvm::Function&); }; -MemInstFinderPass::MemInstFinderPass(const MemInstFinderConfig& config) - : mOpsCollector(config.collect_alloca, config.collect_heap), filter(config), config(config) { +MemInstFinderPass::MemInstFinderPass(const MemInstFinderConfig& conf_) + : mOpsCollector(conf_), filter(conf_), config(conf_) { } bool MemInstFinderPass::runOnModule(Module& module) { mOpsCollector.collectGlobals(module); auto& globals = mOpsCollector.globals; NumDetectedGlobals += globals.size(); - if (config.filter.filterGlobal) { + if (config[config::ConfigStdArgs::analysis_filter_global]) { globals.erase(llvm::remove_if( globals, [&](const auto gdata) { // NOLINT @@ -202,15 +192,9 @@ bool MemInstFinderPass::runOnModule(Module& module) { return true; } - if (name.startswith("llvm.") || name.startswith("__llvm_gcov") || - name.startswith("__llvm_gcda") || name.startswith("__profn")) { - // 2nd and 3rd check: Check if the global is private gcov data (--coverage). - LOG_DEBUG("LLVM startswith \"llvm\"") - return true; - } - - if (name.startswith("___asan") || name.startswith("__msan") || name.startswith("__tsan")) { - LOG_DEBUG("LLVM startswith \"sanitizer\"") + if (util::starts_with_any_of(name, "llvm.", "__llvm_gcov", "__llvm_gcda", "__profn", "___asan", + "__msan", "__tsan")) { + LOG_DEBUG("Prefixed matched on " << name) return true; } @@ -278,7 +262,7 @@ bool MemInstFinderPass::runOnModule(Module& module) { } // namespace typeart bool MemInstFinderPass::runOnFunction(llvm::Function& function) { - if (function.isDeclaration() || function.getName().startswith("__typeart")) { + if (function.isDeclaration() || util::starts_with_any_of(function.getName(), "__typeart")) { return false; } @@ -286,6 +270,7 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { mOpsCollector.collect(function); +#if LLVM_VERSION_MAJOR < 15 const auto checkAmbigiousMalloc = [&function](const MallocData& mallocData) { using namespace typeart::util::type; auto primaryBitcast = mallocData.primary; @@ -305,10 +290,11 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { }); } }; +#endif NumDetectedAllocs += mOpsCollector.allocas.size(); - if (config.filter.filterNonArrayAlloca) { + if (config[config::ConfigStdArgs::analysis_filter_alloca_non_array]) { auto& allocs = mOpsCollector.allocas; allocs.erase(llvm::remove_if(allocs, [&](const auto& data) { @@ -321,7 +307,7 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { allocs.end()); } - if (config.filter.filterMallocAllocPair) { + if (config[config::ConfigStdArgs::analysis_filter_heap_alloc]) { auto& allocs = mOpsCollector.allocas; auto& mallocs = mOpsCollector.mallocs; @@ -357,7 +343,7 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { allocs.end()); } - if (config.filter.filterPointerAlloca) { + if (config[config::ConfigStdArgs::analysis_filter_pointer_alloc]) { auto& allocs = mOpsCollector.allocas; allocs.erase(llvm::remove_if(allocs, [&](const auto& data) { @@ -371,7 +357,8 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { allocs.end()); } - if (config.filter.useCallFilter) { + // if (config.filter.useCallFilter) { + if (config[config::ConfigStdArgs::filter]) { auto& allocs = mOpsCollector.allocas; allocs.erase(llvm::remove_if(allocs, [&](const auto& data) { @@ -388,9 +375,11 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { auto& mallocs = mOpsCollector.mallocs; NumDetectedHeap += mallocs.size(); +#if LLVM_VERSION_MAJOR < 15 for (const auto& mallocData : mallocs) { checkAmbigiousMalloc(mallocData); } +#endif FunctionData data{mOpsCollector.mallocs, mOpsCollector.frees, mOpsCollector.allocas}; functionMap[&function] = data; @@ -401,11 +390,21 @@ bool MemInstFinderPass::runOnFunction(llvm::Function& function) { } // namespace typeart void MemInstFinderPass::printStats(llvm::raw_ostream& out) const { - auto all_stack = double(NumDetectedAllocs); - auto nonarray_stack = double(NumFilteredNonArrayAllocs); - auto malloc_alloc_stack = double(NumFilteredMallocAllocs); - auto call_filter_stack = double(NumCallFilteredAllocs); - auto filter_pointer_stack = double(NumFilteredPointerAllocs); + const auto scope_exit_cleanup_counter = llvm::make_scope_exit([&]() { + NumDetectedAllocs = 0; + NumFilteredNonArrayAllocs = 0; + NumFilteredMallocAllocs = 0; + NumCallFilteredAllocs = 0; + NumFilteredPointerAllocs = 0; + NumDetectedHeap = 0; + NumFilteredGlobals = 0; + NumDetectedGlobals = 0; + }); + auto all_stack = double(NumDetectedAllocs); + auto nonarray_stack = double(NumFilteredNonArrayAllocs); + auto malloc_alloc_stack = double(NumFilteredMallocAllocs); + auto call_filter_stack = double(NumCallFilteredAllocs); + auto filter_pointer_stack = double(NumFilteredPointerAllocs); const auto call_filter_stack_p = (call_filter_stack / @@ -422,9 +421,10 @@ void MemInstFinderPass::printStats(llvm::raw_ostream& out) const { (double(NumFilteredGlobals) / std::max(1.0, double(NumDetectedGlobals))) * 100.0; Table stats("MemInstFinderPass"); - stats.wrap_header = true; - stats.wrap_length = true; - stats.put(Row::make("Filter string", config.filter.callFilterGlob)); + stats.wrap_header_ = true; + stats.wrap_length_ = true; + std::string glob = config[config::ConfigStdArgs::filter_glob]; + stats.put(Row::make("Filter string", glob)); stats.put(Row::make_row("> Heap Memory")); stats.put(Row::make("Heap alloc", NumDetectedHeap.getValue())); stats.put(Row::make("Heap call filtered %", call_filter_heap_p)); @@ -458,23 +458,9 @@ const GlobalDataList& MemInstFinderPass::getModuleGlobals() const { } std::unique_ptr create_finder(const config::Configuration& config) { - using typeart::config::ConfigStdArgs; - const auto meminst_config = [&config]() { - return analysis::MemInstFinderConfig{ - config[ConfigStdArgs::heap], // - config[ConfigStdArgs::stack], // - config[ConfigStdArgs::global], // - analysis::MemInstFinderConfig::Filter{config[ConfigStdArgs::filter], // - config[ConfigStdArgs::filter_impl], // - config[ConfigStdArgs::filter_glob], // - config[ConfigStdArgs::filter_glob_deep], // - config[ConfigStdArgs::filter_cg_file], // - config[ConfigStdArgs::analysis_filter_alloca_non_array], // - config[ConfigStdArgs::analysis_filter_heap_alloc], // - config[ConfigStdArgs::analysis_filter_global], // - config[ConfigStdArgs::analysis_filter_pointer_alloc]}}; // - }(); - return std::make_unique(meminst_config); + LOG_DEBUG("Constructing MemInstFinder") + // const auto meminst_conf = config::helper::config_to_options(config); + return std::make_unique(config); } } // namespace typeart::analysis diff --git a/lib/passes/analysis/MemOpData.h b/lib/passes/analysis/MemOpData.h index b5bd27b4..8750b07d 100644 --- a/lib/passes/analysis/MemOpData.h +++ b/lib/passes/analysis/MemOpData.h @@ -13,11 +13,12 @@ #ifndef TYPEART_MEMOPDATA_H #define TYPEART_MEMOPDATA_H -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include + namespace llvm { class CallBase; class BitCastInst; @@ -45,28 +46,28 @@ enum class MemOpKind : uint8_t { }; struct MemOps { - inline llvm::Optional kind(llvm::StringRef function) const { + inline std::optional kind(llvm::StringRef function) const { if (auto alloc = allocKind(function)) { return alloc; } if (auto dealloc = deallocKind(function)) { return dealloc; } - return llvm::None; + return {}; } - inline llvm::Optional allocKind(llvm::StringRef function) const { + inline std::optional allocKind(llvm::StringRef function) const { if (auto it = alloc_map.find(function); it != std::end(alloc_map)) { return {(*it).second}; } - return llvm::None; + return {}; } - inline llvm::Optional deallocKind(llvm::StringRef function) const { + inline std::optional deallocKind(llvm::StringRef function) const { if (auto it = dealloc_map.find(function); it != std::end(dealloc_map)) { return {(*it).second}; } - return llvm::None; + return {}; } const llvm::StringMap& allocs() const { @@ -129,7 +130,7 @@ struct ArrayCookieData { struct MallocData { llvm::CallBase* call{nullptr}; - llvm::Optional array_cookie{llvm::None}; + std::optional array_cookie{}; llvm::BitCastInst* primary{nullptr}; // Non-null if non (void*) cast exists llvm::SmallPtrSet bitcasts; MemOpKind kind; @@ -138,7 +139,7 @@ struct MallocData { struct FreeData { llvm::CallBase* call{nullptr}; - llvm::Optional array_cookie_gep{llvm::None}; + std::optional array_cookie_gep{}; MemOpKind kind; bool is_invoke{false}; }; diff --git a/lib/passes/analysis/MemOpVisitor.cpp b/lib/passes/analysis/MemOpVisitor.cpp index 3725637a..3abc4f97 100644 --- a/lib/passes/analysis/MemOpVisitor.cpp +++ b/lib/passes/analysis/MemOpVisitor.cpp @@ -14,15 +14,21 @@ #include "analysis/MemOpData.h" #include "compat/CallSite.h" +#include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" #include "support/Error.h" #include "support/Logger.h" #include "support/TypeUtil.h" +#include "support/Util.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringRef.h" + +#include +#include +#include + #if LLVM_VERSION_MAJOR >= 12 #include "llvm/Analysis/ValueTracking.h" // llvm::findAllocaForValue #else @@ -38,6 +44,7 @@ #include "llvm/Support/raw_ostream.h" #include +#include namespace typeart::analysis { @@ -46,16 +53,18 @@ using namespace llvm; MemOpVisitor::MemOpVisitor() : MemOpVisitor(true, true) { } -MemOpVisitor::MemOpVisitor(bool collect_allocas, bool collect_heap) - : collect_allocas(collect_allocas), collect_heap(collect_heap) { +MemOpVisitor::MemOpVisitor(const config::Configuration& config) + : MemOpVisitor(config[config::ConfigStdArgs::stack], config[config::ConfigStdArgs::heap]) { +} +MemOpVisitor::MemOpVisitor(bool stack, bool heap) : collect_allocas(stack), collect_heap(heap) { } void MemOpVisitor::collect(llvm::Function& function) { visit(function); for (auto& [lifetime, alloc] : lifetime_starts) { - auto* data = - llvm::find_if(allocas, [alloc = std::ref(alloc)](const AllocaData& data) { return data.alloca == alloc; }); + auto* data = llvm::find_if( + allocas, [alloc_ = std::ref(alloc)](const AllocaData& alloca_data) { return alloca_data.alloca == alloc_; }); if (data != std::end(allocas)) { data->lifetime_start.insert(lifetime); } @@ -82,12 +91,12 @@ void MemOpVisitor::visitCallBase(llvm::CallBase& cb) { if (!collect_heap) { return; } - const auto isInSet = [&](const auto& fMap) -> llvm::Optional { + const auto isInSet = [&](const auto& fMap) -> std::optional { const auto* f = cb.getCalledFunction(); if (!f) { // TODO handle calls through, e.g., function pointers? - seems infeasible // LOG_INFO("Encountered indirect call, skipping."); - return None; + return {}; } const auto name = f->getName().str(); @@ -95,41 +104,64 @@ void MemOpVisitor::visitCallBase(llvm::CallBase& cb) { if (res != fMap.end()) { return {(*res).second}; } - return None; + return {}; }; if (auto alloc_val = isInSet(mem_operations.allocs())) { - visitMallocLike(cb, alloc_val.getValue()); + visitMallocLike(cb, alloc_val.value()); } else if (auto dealloc_val = isInSet(mem_operations.deallocs())) { - visitFreeLike(cb, dealloc_val.getValue()); + visitFreeLike(cb, dealloc_val.value()); } } -template -llvm::Expected getSingleUserAs(llvm::Value* value) { - auto users = value->users(); - const auto num_users = value->getNumUses(); - RETURN_ERROR_IF(num_users == 0, "Expected a single user on value \"{}\" that has no users!", *value); +template +std::optional getSingleUserAs(llvm::Instruction* value) { + auto users = value->users(); + const auto num_stores = llvm::count_if(users, [](llvm::User* use) { return llvm::isa(*use); }); + RETURN_NONE_IF((num_stores == 0), "Expected a single store on call \"{0}\". It has no users!", *value); - // Check for calls: In case of ASAN, the array cookie is passed to its API. - // TODO: this may need to be extended to include other such calls - const auto num_asan_calls = llvm::count_if(users, [](llvm::User* user) { + const auto num_asan_call = llvm::count_if(users, [](llvm::User* user) { CallSite csite(user); if (!(csite.isCall() || csite.isInvoke()) || csite.getCalledFunction() == nullptr) { return false; } const auto name = csite.getCalledFunction()->getName(); - return name.startswith("__asan"); + return util::starts_with_any_of(name, "__asan"); }); - RETURN_ERROR_IF(num_asan_calls != (num_users - 1), - "Expected a single user on value \"{}\" but found multiple potential candidates!", *value); - // This should return the type T we need: - auto user = llvm::find_if(users, [](auto user) { return isa(*user); }); - RETURN_ERROR_IF(user == std::end(users), - "Expected a single user on value \"{}\" but didn't find a user of the desired type!", *value); + RETURN_NONE_IF(num_asan_call > 1, "Expected one ASAN call for array cookie."); + + auto* target_instruction = + dyn_cast(*llvm::find_if(users, [](llvm::User* use) { return llvm::isa(*use); })); + + if constexpr (std::is_same_v) { + // if (llvm::isa(value)) { + RETURN_NONE_IF((target_instruction->getValueOperand() == value), + "Did not expect malloc-like \"{0}\" as store value operand.", *value); + // } + } - return {dyn_cast(*user)}; + if (num_asan_call != 0) { + const auto* asan_call = dyn_cast(*llvm::find_if(users, [](llvm::User* user) { + CallSite csite(user); + if (!(csite.isCall() || csite.isInvoke()) || csite.getCalledFunction() == nullptr) { + return false; + } + const auto name = csite.getCalledFunction()->getName(); + return util::starts_with_any_of(name, "__asan"); + })); + if constexpr (std::is_same_v) { + RETURN_NONE_IF(target_instruction->getPointerOperand() != asan_call->getArgOperand(0), + "Expected a single user on value \"{0}\" but found multiple potential candidates!", *value); + } else { + if constexpr (std::is_same_v) { + RETURN_NONE_IF(target_instruction != asan_call->getArgOperand(0), + "Expected a single user on value \"{0}\" but found multiple potential candidates!", *value); + } + } + } + + return {target_instruction}; } using MallocGeps = SmallPtrSet; @@ -165,80 +197,95 @@ std::pair collectRelevantMallocUsers(llvm::CallBase& c return {geps, bcasts}; } -llvm::Expected handleUnpaddedArrayCookie(const MallocGeps& geps, MallocBcasts& bcasts, - BitCastInst*& primary_cast) { +std::optional handleUnpaddedArrayCookie(llvm::CallBase& ci, const MallocGeps& geps, + MallocBcasts& bcasts, BitCastInst*& primary_cast) { using namespace util::type; +#if LLVM_VERSION_MAJOR < 15 // We expect only the bitcast to size_t for the array cookie store. - RETURN_ERROR_IF(bcasts.size() != 1, "Couldn't identify bitcast instruction of an unpadded array cookie!"); - + RETURN_NONE_IF(bcasts.size() != 1, "Couldn't identify bitcast instruction of an unpadded array cookie!"); auto cookie_bcast = *bcasts.begin(); - RETURN_ERROR_IF(!isi64Ptr(cookie_bcast->getDestTy()), "Found non-i64Ptr bitcast instruction for an array cookie!"); + RETURN_NONE_IF(!isi64Ptr(cookie_bcast->getDestTy()), "Found non-i64Ptr bitcast instruction for an array cookie!"); auto cookie_store = getSingleUserAs(cookie_bcast); - RETURN_ON_ERROR(cookie_store); + RETURN_ON_NONE(cookie_store); auto array_gep = *geps.begin(); - RETURN_ERROR_IF(array_gep->getNumIndices() != 1, "Found multidimensional array cookie gep!"); + RETURN_NONE_IF(array_gep->getNumIndices() != 1, "Found multidimensional array cookie gep!"); auto array_bcast = getSingleUserAs(array_gep); - RETURN_ON_ERROR(array_bcast); + RETURN_ON_NONE(array_bcast); bcasts.insert(*array_bcast); primary_cast = *array_bcast; - +#else + auto cookie_store = getSingleUserAs(&ci); + RETURN_ON_NONE(cookie_store); + // RETURN_NONE_IF(cookie_store.get()->getValueOperand() == &ci, "Cookie store has CallBase as value operand.") + auto array_gep = *geps.begin(); + RETURN_NONE_IF(array_gep->getNumIndices() != 1, "Found multidimensional array cookie gep!"); +#endif return {ArrayCookieData{*cookie_store, array_gep}}; } -llvm::Expected handlePaddedArrayCookie(const MallocGeps& geps, MallocBcasts& bcasts, - BitCastInst*& primary_cast) { +std::optional handlePaddedArrayCookie(llvm::CallBase& ci, const MallocGeps& geps, MallocBcasts& bcasts, + BitCastInst*& primary_cast) { using namespace util::type; +#if LLVM_VERSION_MAJOR < 15 // We expect bitcasts only after the GEP instructions in this case. - RETURN_ERROR_IF(!bcasts.empty(), "Found unrelated bitcast instructions on a padded array cookie!"); + RETURN_NONE_IF(!bcasts.empty(), "Found unrelated bitcast instructions on a padded array cookie!"); auto gep_it = geps.begin(); auto array_gep = *gep_it++; auto cookie_gep = *gep_it++; auto cookie_bcast = getSingleUserAs(cookie_gep); - RETURN_ON_ERROR(cookie_bcast); - RETURN_ERROR_IF(!isi64Ptr((*cookie_bcast)->getDestTy()), "Found non-i64Ptr bitcast instruction for an array cookie!"); + RETURN_ON_NONE(cookie_bcast); + RETURN_NONE_IF(!isi64Ptr((*cookie_bcast)->getDestTy()), "Found non-i64Ptr bitcast instruction for an array cookie!"); auto cookie_store = getSingleUserAs(*cookie_bcast); - RETURN_ON_ERROR(cookie_store); - RETURN_ERROR_IF(array_gep->getNumIndices() != 1, "Found multidimensional array cookie gep!"); + RETURN_ON_NONE(cookie_store); + RETURN_NONE_IF(array_gep->getNumIndices() != 1, "Found multidimensional array cookie gep!"); auto array_bcast = getSingleUserAs(array_gep); - RETURN_ON_ERROR(array_bcast); + RETURN_ON_NONE(array_bcast); bcasts.insert(*array_bcast); primary_cast = *array_bcast; - +#else + auto gep_it = geps.begin(); + auto array_gep = *gep_it++; + auto cookie_gep = *gep_it++; + auto cookie_store = getSingleUserAs(cookie_gep); + RETURN_ON_NONE(cookie_store); + RETURN_NONE_IF(array_gep->getNumIndices() != 1, "Found multidimensional array cookie gep!"); +#endif return {ArrayCookieData{*cookie_store, array_gep}}; } -llvm::Optional handleArrayCookie(const MallocGeps& geps, MallocBcasts& bcasts, - BitCastInst*& primary_cast) { - auto exit_on_error = llvm::ExitOnError{"Array Cookie Detection failed!"}; +std::optional handleArrayCookie(llvm::CallBase& ci, const MallocGeps& geps, MallocBcasts& bcasts, + BitCastInst*& primary_cast) { if (geps.size() == 1) { - return exit_on_error(handleUnpaddedArrayCookie(geps, bcasts, primary_cast)); + return handleUnpaddedArrayCookie(ci, geps, bcasts, primary_cast); } else if (geps.size() == 2) { - return exit_on_error(handlePaddedArrayCookie(geps, bcasts, primary_cast)); + return handlePaddedArrayCookie(ci, geps, bcasts, primary_cast); } else if (geps.size() > 2) { // Found a case where the address of an allocation is used more than two // times as an argument to a GEP instruction. This is unexpected as at most // two GEPs, for calculating the offsets of an array cookie itself and the // array pointer, are expected. - auto err = "Expected at most two GEP instructions!"; + auto exit_on_error = llvm::ExitOnError{"Array Cookie Detection failed!"}; + auto err = "Expected at most two GEP instructions!"; LOG_FATAL(err); exit_on_error({error::make_string_error(err)}); + return {}; } - return llvm::None; + return {}; } void MemOpVisitor::visitMallocLike(llvm::CallBase& ci, MemOpKind k) { auto [geps, bcasts] = collectRelevantMallocUsers(ci); auto primary_cast = bcasts.empty() ? nullptr : *bcasts.begin(); - auto array_cookie = handleArrayCookie(geps, bcasts, primary_cast); + auto array_cookie = handleArrayCookie(ci, geps, bcasts, primary_cast); if (primary_cast == nullptr) { LOG_DEBUG("Primary bitcast null: " << ci) } @@ -253,12 +300,12 @@ void MemOpVisitor::visitFreeLike(llvm::CallBase& ci, MemOpKind k) { if (auto f = ci.getCalledFunction()) { auto dkind = mem_operations.deallocKind(f->getName()); if (dkind) { - kind = dkind.getValue(); + kind = dkind.value(); } } auto gep = dyn_cast(ci.getArgOperand(0)); - auto array_cookie_gep = gep != nullptr ? llvm::Optional{gep} : llvm::None; + auto array_cookie_gep = gep != nullptr ? std::optional{gep} : std::nullopt; frees.emplace_back(FreeData{&ci, array_cookie_gep, kind, isa(ci)}); } diff --git a/lib/passes/analysis/MemOpVisitor.h b/lib/passes/analysis/MemOpVisitor.h index bfcd71e4..3117e41a 100644 --- a/lib/passes/analysis/MemOpVisitor.h +++ b/lib/passes/analysis/MemOpVisitor.h @@ -14,6 +14,7 @@ #define LIB_MEMOPVISITOR_H_ #include "MemOpData.h" +#include "configuration/Configuration.h" #include "llvm/IR/InstVisitor.h" @@ -41,7 +42,8 @@ struct MemOpVisitor : public llvm::InstVisitor { public: MemOpVisitor(); - MemOpVisitor(bool collect_allocas, bool collect_heap); + explicit MemOpVisitor(const config::Configuration& config); + MemOpVisitor(bool stack, bool heap); void collect(llvm::Function& function); void collectGlobals(llvm::Module& module); void clear(); diff --git a/lib/passes/compat/CallSite.h b/lib/passes/compat/CallSite.h index 0666d8e4..9a4f821a 100644 --- a/lib/passes/compat/CallSite.h +++ b/lib/passes/compat/CallSite.h @@ -10,760 +10,80 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Compatibility for Clang v10 and higher. -// In Clang 11 the CallSite.h was removed, therefore we copied the Clang v10 version of the header into the TypeART -// project, see https://github.com/llvm/llvm-project +// In Clang 11 CallSite.h was removed, this is a small wrapper reimplementation #ifndef COMPAT_LLVM_IR_CALLSITE_H #define COMPAT_LLVM_IR_CALLSITE_H -#ifndef LLVM_VERSION_MAJOR -#define LLVM_VERSION_MAJOR 10 -#endif - -#if LLVM_VERSION_MAJOR < 11 -#include "llvm/IR/CallSite.h" -#else -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" -//===- CallSite.h - Abstract Call & Invoke instrs ---------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/IR/Attributes.h" -#include "llvm/IR/CallingConv.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Use.h" -#include "llvm/IR/User.h" -#include "llvm/IR/Value.h" -#include "llvm/Support/Casting.h" -#include -#include -#include +#include +#include +#include +#include namespace llvm { - -namespace Intrinsic { -typedef unsigned ID; -} - -template -class CallSiteBase { - protected: - PointerIntPair I; - - CallSiteBase() = default; - CallSiteBase(CallTy* CI) : I(CI, 1) { - assert(CI); - } - CallSiteBase(InvokeTy* II) : I(II, 0) { - assert(II); - } - CallSiteBase(CallBrTy* CBI) : I(CBI, 2) { - assert(CBI); - } - explicit CallSiteBase(ValTy* II) { - *this = get(II); - } - +class CallSite { private: - /// This static method is like a constructor. It will create an appropriate - /// call site for a Call, Invoke or CallBr instruction, but it can also create - /// a null initialized CallSiteBase object for something which is NOT a call - /// site. - static CallSiteBase get(ValTy* V) { - if (InstrTy* II = dyn_cast(V)) { - if (II->getOpcode() == Instruction::Call) - return CallSiteBase(static_cast(II)); - if (II->getOpcode() == Instruction::Invoke) - return CallSiteBase(static_cast(II)); - if (II->getOpcode() == Instruction::CallBr) - return CallSiteBase(static_cast(II)); - } - return CallSiteBase(); - } + llvm::Instruction* instruction_{nullptr}; public: - /// Return true if a CallInst is enclosed. - bool isCall() const { - return I.getInt() == 1; + explicit CallSite(llvm::Instruction* instruction) : instruction_{instruction} { } - /// Return true if a InvokeInst is enclosed. !I.getInt() may also signify a - /// NULL instruction pointer, so check that. - bool isInvoke() const { - return getInstruction() && I.getInt() == 0; + explicit CallSite(llvm::Value* instruction) : instruction_{dyn_cast(instruction)} { } - /// Return true if a CallBrInst is enclosed. - bool isCallBr() const { - return I.getInt() == 2; + [[nodiscard]] bool isCall() const { + return instruction_ != nullptr && llvm::isa(instruction_); } - InstrTy* getInstruction() const { - return I.getPointer(); - } - InstrTy* operator->() const { - return I.getPointer(); - } - explicit operator bool() const { - return I.getPointer(); - } - - /// Get the basic block containing the call site. - BBTy* getParent() const { - return getInstruction()->getParent(); - } - - /// Return the pointer to function that is being called. - ValTy* getCalledValue() const { - assert(getInstruction() && "Not a call, invoke or callbr instruction!"); - return *getCallee(); + [[nodiscard]] bool isInvoke() const { + return instruction_ != nullptr && llvm::isa(instruction_); } - /// Return the function being called if this is a direct call, otherwise - /// return null (if it's an indirect call). - FunTy* getCalledFunction() const { - return dyn_cast(getCalledValue()); + [[nodiscard]] bool isCallBr() const { + return instruction_ != nullptr && llvm::isa(instruction_); } - /// Return true if the callsite is an indirect call. - bool isIndirectCall() const { - const Value* V = getCalledValue(); - if (!V) - return false; - if (isa(V) || isa(V)) - return false; - if (const CallBase* CB = dyn_cast(getInstruction())) - if (CB->isInlineAsm()) - return false; + [[nodiscard]] bool isIndirectCall() const { + if (const CallBase* CB = dyn_cast_or_null(instruction_)) { + return CB->isIndirectCall(); + } return true; } - /// Set the callee to the specified value. Unlike the function of the same - /// name on CallBase, does not modify the type! - void setCalledFunction(Value* V) { - const auto elem_type = [&V]() { -#if LLVM_VERSION_MAJOR > 13 - return V->getType()->getPointerElementType(); -#else - return cast(V->getType())->getElementType(); -#endif - }; - assert(getInstruction() && "Not a call, callbr, or invoke instruction!"); - - assert(elem_type() == cast(getInstruction())->getFunctionType() && - "New callee type does not match FunctionType on call"); - *getCallee() = V; - } - - /// Return the intrinsic ID of the intrinsic called by this CallSite, - /// or Intrinsic::not_intrinsic if the called function is not an - /// intrinsic, or if this CallSite is an indirect call. - Intrinsic::ID getIntrinsicID() const { - if (auto* F = getCalledFunction()) - return F->getIntrinsicID(); - // Don't use Intrinsic::not_intrinsic, as it will require pulling - // Intrinsics.h into every header that uses CallSite. - return static_cast(0); - } - - /// Determine whether the passed iterator points to the callee operand's Use. - bool isCallee(Value::const_user_iterator UI) const { - return isCallee(&UI.getUse()); - } - - /// Determine whether this Use is the callee operand's Use. - bool isCallee(const Use* U) const { - return getCallee() == U; - } - - /// Determine whether the passed iterator points to an argument operand. - bool isArgOperand(Value::const_user_iterator UI) const { - return isArgOperand(&UI.getUse()); - } - - /// Determine whether the passed use points to an argument operand. - bool isArgOperand(const Use* U) const { - assert(getInstruction() == U->getUser()); - return arg_begin() <= U && U < arg_end(); - } - - /// Determine whether the passed iterator points to a bundle operand. - bool isBundleOperand(Value::const_user_iterator UI) const { - return isBundleOperand(&UI.getUse()); - } - - /// Determine whether the passed use points to a bundle operand. - bool isBundleOperand(const Use* U) const { - assert(getInstruction() == U->getUser()); - if (!hasOperandBundles()) - return false; - unsigned OperandNo = U - (*this)->op_begin(); - return getBundleOperandsStartIndex() <= OperandNo && OperandNo < getBundleOperandsEndIndex(); - } - - /// Determine whether the passed iterator points to a data operand. - bool isDataOperand(Value::const_user_iterator UI) const { - return isDataOperand(&UI.getUse()); - } - - /// Determine whether the passed use points to a data operand. - bool isDataOperand(const Use* U) const { - return data_operands_begin() <= U && U < data_operands_end(); - } - - ValTy* getArgument(unsigned ArgNo) const { - assert(arg_begin() + ArgNo < arg_end() && "Argument # out of range!"); - return *(arg_begin() + ArgNo); - } - - void setArgument(unsigned ArgNo, Value* newVal) { - assert(getInstruction() && "Not a call, invoke or callbr instruction!"); - assert(arg_begin() + ArgNo < arg_end() && "Argument # out of range!"); - getInstruction()->setOperand(ArgNo, newVal); + [[nodiscard]] llvm::Function* getCalledFunction() const { + if (auto* call_base = llvm::dyn_cast_or_null(instruction_)) { + return call_base->getCalledFunction(); + } + return nullptr; } - /// Given a value use iterator, returns the argument that corresponds to it. - /// Iterator must actually correspond to an argument. - unsigned getArgumentNo(Value::const_user_iterator I) const { - return getArgumentNo(&I.getUse()); + [[nodiscard]] auto arg_begin() const { + auto* call_base = llvm::cast(instruction_); + return call_base->arg_begin(); } - /// Given a use for an argument, get the argument number that corresponds to - /// it. - unsigned getArgumentNo(const Use* U) const { - assert(getInstruction() && "Not a call, invoke or callbr instruction!"); - assert(isArgOperand(U) && "Argument # out of range!"); - return U - arg_begin(); + [[nodiscard]] auto arg_end() const { + auto* call_base = llvm::cast(instruction_); + return call_base->arg_end(); } - /// The type of iterator to use when looping over actual arguments at this - /// call site. - using arg_iterator = IterTy; - - iterator_range args() const { + [[nodiscard]] auto args() const { return make_range(arg_begin(), arg_end()); } - bool arg_empty() const { - return arg_end() == arg_begin(); - } - unsigned arg_size() const { - return unsigned(arg_end() - arg_begin()); - } - /// Given a value use iterator, return the data operand corresponding to it. - /// Iterator must actually correspond to a data operand. - unsigned getDataOperandNo(Value::const_user_iterator UI) const { - return getDataOperandNo(&UI.getUse()); + [[nodiscard]] auto getArgOperand(unsigned int number) const { + auto* call_base = llvm::cast(instruction_); + return call_base->getArgOperand(number); } - /// Given a use for a data operand, get the data operand number that - /// corresponds to it. - unsigned getDataOperandNo(const Use* U) const { - assert(getInstruction() && "Not a call, invoke or callbr instruction!"); - assert(isDataOperand(U) && "Data operand # out of range!"); - return U - data_operands_begin(); - } - - /// Type of iterator to use when looping over data operands at this call site - /// (see below). - using data_operand_iterator = IterTy; - - /// data_operands_begin/data_operands_end - Return iterators iterating over - /// the call / invoke / callbr argument list and bundle operands. For invokes, - /// this is the set of instruction operands except the invoke target and the - /// two successor blocks; for calls this is the set of instruction operands - /// except the call target; for callbrs the number of labels to skip must be - /// determined first. - - IterTy data_operands_begin() const { - assert(getInstruction() && "Not a call or invoke instruction!"); - return cast(getInstruction())->data_operands_begin(); + auto getIntrinsicID() const { + auto* call_base = llvm::cast(instruction_); + return call_base->getIntrinsicID(); } - IterTy data_operands_end() const { - assert(getInstruction() && "Not a call or invoke instruction!"); - return cast(getInstruction())->data_operands_end(); - } - iterator_range data_ops() const { - return make_range(data_operands_begin(), data_operands_end()); - } - bool data_operands_empty() const { - return data_operands_end() == data_operands_begin(); - } - unsigned data_operands_size() const { - return std::distance(data_operands_begin(), data_operands_end()); - } - - /// Return the type of the instruction that generated this call site. - Type* getType() const { - return (*this)->getType(); - } - - /// Return the caller function for this call site. - FunTy* getCaller() const { - return (*this)->getParent()->getParent(); - } - - /// Tests if this call site must be tail call optimized. Only a CallInst can - /// be tail call optimized. - bool isMustTailCall() const { - return isCall() && cast(getInstruction())->isMustTailCall(); - } - - /// Tests if this call site is marked as a tail call. - bool isTailCall() const { - return isCall() && cast(getInstruction())->isTailCall(); - } - -#define CALLSITE_DELEGATE_GETTER(METHOD) \ - InstrTy* II = getInstruction(); \ - return isCall() ? cast(II)->METHOD \ - : isCallBr() ? cast(II)->METHOD \ - : cast(II)->METHOD - -#define CALLSITE_DELEGATE_SETTER(METHOD) \ - InstrTy* II = getInstruction(); \ - if (isCall()) \ - cast(II)->METHOD; \ - else if (isCallBr()) \ - cast(II)->METHOD; \ - else \ - cast(II)->METHOD - - unsigned getNumArgOperands() const { - CALLSITE_DELEGATE_GETTER(getNumArgOperands()); - } - - ValTy* getArgOperand(unsigned i) const { - CALLSITE_DELEGATE_GETTER(getArgOperand(i)); - } - - ValTy* getReturnedArgOperand() const { - CALLSITE_DELEGATE_GETTER(getReturnedArgOperand()); - } - - bool isInlineAsm() const { - return cast(getInstruction())->isInlineAsm(); - } - - /// Get the calling convention of the call. - CallingConv::ID getCallingConv() const { - CALLSITE_DELEGATE_GETTER(getCallingConv()); - } - /// Set the calling convention of the call. - void setCallingConv(CallingConv::ID CC) { - CALLSITE_DELEGATE_SETTER(setCallingConv(CC)); - } - - FunctionType* getFunctionType() const { - CALLSITE_DELEGATE_GETTER(getFunctionType()); - } - - void mutateFunctionType(FunctionType* Ty) const { - CALLSITE_DELEGATE_SETTER(mutateFunctionType(Ty)); - } - - /// Get the parameter attributes of the call. - AttributeList getAttributes() const { - CALLSITE_DELEGATE_GETTER(getAttributes()); - } - /// Set the parameter attributes of the call. - void setAttributes(AttributeList PAL) { - CALLSITE_DELEGATE_SETTER(setAttributes(PAL)); - } - - void addAttribute(unsigned i, Attribute::AttrKind Kind) { - CALLSITE_DELEGATE_SETTER(addAttribute(i, Kind)); - } - - void addAttribute(unsigned i, Attribute Attr) { - CALLSITE_DELEGATE_SETTER(addAttribute(i, Attr)); - } - - void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) { - CALLSITE_DELEGATE_SETTER(addParamAttr(ArgNo, Kind)); - } - - void removeAttribute(unsigned i, Attribute::AttrKind Kind) { - CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind)); - } - - void removeAttribute(unsigned i, StringRef Kind) { - CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind)); - } - - void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) { - CALLSITE_DELEGATE_SETTER(removeParamAttr(ArgNo, Kind)); - } - - /// Return true if this function has the given attribute. - bool hasFnAttr(Attribute::AttrKind Kind) const { - CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); - } - - /// Return true if this function has the given attribute. - bool hasFnAttr(StringRef Kind) const { - CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); - } - - /// Return true if this return value has the given attribute. - bool hasRetAttr(Attribute::AttrKind Kind) const { - CALLSITE_DELEGATE_GETTER(hasRetAttr(Kind)); - } - - /// Return true if the call or the callee has the given attribute. - bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const { - CALLSITE_DELEGATE_GETTER(paramHasAttr(ArgNo, Kind)); - } - - Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { - CALLSITE_DELEGATE_GETTER(getAttribute(i, Kind)); - } - - Attribute getAttribute(unsigned i, StringRef Kind) const { - CALLSITE_DELEGATE_GETTER(getAttribute(i, Kind)); - } - - /// Return true if the data operand at index \p i directly or indirectly has - /// the attribute \p A. - /// - /// Normal call, invoke or callbr arguments have per operand attributes, as - /// specified in the attribute set attached to this instruction, while operand - /// bundle operands may have some attributes implied by the type of its - /// containing operand bundle. - bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const { - CALLSITE_DELEGATE_GETTER(dataOperandHasImpliedAttr(i, Kind)); - } - - /// Extract the alignment of the return value. - unsigned getRetAlignment() const { - CALLSITE_DELEGATE_GETTER(getRetAlignment()); - } - - /// Extract the alignment for a call or parameter (0=unknown). - unsigned getParamAlignment(unsigned ArgNo) const { - CALLSITE_DELEGATE_GETTER(getParamAlignment(ArgNo)); - } - - /// Extract the byval type for a call or parameter (nullptr=unknown). - Type* getParamByValType(unsigned ArgNo) const { - CALLSITE_DELEGATE_GETTER(getParamByValType(ArgNo)); - } - - /// Extract the number of dereferenceable bytes for a call or parameter - /// (0=unknown). - uint64_t getDereferenceableBytes(unsigned i) const { - CALLSITE_DELEGATE_GETTER(getDereferenceableBytes(i)); - } - - /// Extract the number of dereferenceable_or_null bytes for a call or - /// parameter (0=unknown). - uint64_t getDereferenceableOrNullBytes(unsigned i) const { - CALLSITE_DELEGATE_GETTER(getDereferenceableOrNullBytes(i)); - } - - /// Determine if the return value is marked with NoAlias attribute. - bool returnDoesNotAlias() const { - CALLSITE_DELEGATE_GETTER(returnDoesNotAlias()); - } - - /// Return true if the call should not be treated as a call to a builtin. - bool isNoBuiltin() const { - CALLSITE_DELEGATE_GETTER(isNoBuiltin()); - } - - /// Return true if the call requires strict floating point semantics. - bool isStrictFP() const { - CALLSITE_DELEGATE_GETTER(isStrictFP()); - } - - /// Return true if the call should not be inlined. - bool isNoInline() const { - CALLSITE_DELEGATE_GETTER(isNoInline()); - } - void setIsNoInline(bool Value = true) { - CALLSITE_DELEGATE_SETTER(setIsNoInline(Value)); - } - - /// Determine if the call does not access memory. - bool doesNotAccessMemory() const { - CALLSITE_DELEGATE_GETTER(doesNotAccessMemory()); - } - void setDoesNotAccessMemory() { - CALLSITE_DELEGATE_SETTER(setDoesNotAccessMemory()); - } - - /// Determine if the call does not access or only reads memory. - bool onlyReadsMemory() const { - CALLSITE_DELEGATE_GETTER(onlyReadsMemory()); - } - void setOnlyReadsMemory() { - CALLSITE_DELEGATE_SETTER(setOnlyReadsMemory()); - } - - /// Determine if the call does not access or only writes memory. - bool doesNotReadMemory() const { - CALLSITE_DELEGATE_GETTER(doesNotReadMemory()); - } - void setDoesNotReadMemory() { - CALLSITE_DELEGATE_SETTER(setDoesNotReadMemory()); - } - - /// Determine if the call can access memory only using pointers based - /// on its arguments. - bool onlyAccessesArgMemory() const { - CALLSITE_DELEGATE_GETTER(onlyAccessesArgMemory()); - } - void setOnlyAccessesArgMemory() { - CALLSITE_DELEGATE_SETTER(setOnlyAccessesArgMemory()); - } - - /// Determine if the function may only access memory that is - /// inaccessible from the IR. - bool onlyAccessesInaccessibleMemory() const { - CALLSITE_DELEGATE_GETTER(onlyAccessesInaccessibleMemory()); - } - void setOnlyAccessesInaccessibleMemory() { - CALLSITE_DELEGATE_SETTER(setOnlyAccessesInaccessibleMemory()); - } - - /// Determine if the function may only access memory that is - /// either inaccessible from the IR or pointed to by its arguments. - bool onlyAccessesInaccessibleMemOrArgMem() const { - CALLSITE_DELEGATE_GETTER(onlyAccessesInaccessibleMemOrArgMem()); - } - void setOnlyAccessesInaccessibleMemOrArgMem() { - CALLSITE_DELEGATE_SETTER(setOnlyAccessesInaccessibleMemOrArgMem()); - } - - /// Determine if the call cannot return. - bool doesNotReturn() const { - CALLSITE_DELEGATE_GETTER(doesNotReturn()); - } - void setDoesNotReturn() { - CALLSITE_DELEGATE_SETTER(setDoesNotReturn()); - } - - /// Determine if the call cannot unwind. - bool doesNotThrow() const { - CALLSITE_DELEGATE_GETTER(doesNotThrow()); - } - void setDoesNotThrow() { - CALLSITE_DELEGATE_SETTER(setDoesNotThrow()); - } - - /// Determine if the call can be duplicated. - bool cannotDuplicate() const { - CALLSITE_DELEGATE_GETTER(cannotDuplicate()); - } - void setCannotDuplicate() { - CALLSITE_DELEGATE_SETTER(setCannotDuplicate()); - } - - /// Determine if the call is convergent. - bool isConvergent() const { - CALLSITE_DELEGATE_GETTER(isConvergent()); - } - void setConvergent() { - CALLSITE_DELEGATE_SETTER(setConvergent()); - } - void setNotConvergent() { - CALLSITE_DELEGATE_SETTER(setNotConvergent()); - } - - unsigned getNumOperandBundles() const { - CALLSITE_DELEGATE_GETTER(getNumOperandBundles()); - } - - bool hasOperandBundles() const { - CALLSITE_DELEGATE_GETTER(hasOperandBundles()); - } - - unsigned getBundleOperandsStartIndex() const { - CALLSITE_DELEGATE_GETTER(getBundleOperandsStartIndex()); - } - - unsigned getBundleOperandsEndIndex() const { - CALLSITE_DELEGATE_GETTER(getBundleOperandsEndIndex()); - } - - unsigned getNumTotalBundleOperands() const { - CALLSITE_DELEGATE_GETTER(getNumTotalBundleOperands()); - } - - OperandBundleUse getOperandBundleAt(unsigned Index) const { - CALLSITE_DELEGATE_GETTER(getOperandBundleAt(Index)); - } - - Optional getOperandBundle(StringRef Name) const { - CALLSITE_DELEGATE_GETTER(getOperandBundle(Name)); - } - - Optional getOperandBundle(uint32_t ID) const { - CALLSITE_DELEGATE_GETTER(getOperandBundle(ID)); - } - - unsigned countOperandBundlesOfType(uint32_t ID) const { - CALLSITE_DELEGATE_GETTER(countOperandBundlesOfType(ID)); - } - - bool isBundleOperand(unsigned Idx) const { - CALLSITE_DELEGATE_GETTER(isBundleOperand(Idx)); - } - - IterTy arg_begin() const { - CALLSITE_DELEGATE_GETTER(arg_begin()); - } - - IterTy arg_end() const { - CALLSITE_DELEGATE_GETTER(arg_end()); - } - -#undef CALLSITE_DELEGATE_GETTER -#undef CALLSITE_DELEGATE_SETTER - - void getOperandBundlesAsDefs(SmallVectorImpl& Defs) const { - // Since this is actually a getter that "looks like" a setter, don't use the - // above macros to avoid confusion. - cast(getInstruction())->getOperandBundlesAsDefs(Defs); - } - - /// Determine whether this data operand is not captured. - bool doesNotCapture(unsigned OpNo) const { - return dataOperandHasImpliedAttr(OpNo + 1, Attribute::NoCapture); - } - - /// Determine whether this argument is passed by value. - bool isByValArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo, Attribute::ByVal); - } - - /// Determine whether this argument is passed in an alloca. - bool isInAllocaArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo, Attribute::InAlloca); - } - - /// Determine whether this argument is passed by value or in an alloca. - bool isByValOrInAllocaArgument(unsigned ArgNo) const { - return paramHasAttr(ArgNo, Attribute::ByVal) || paramHasAttr(ArgNo, Attribute::InAlloca); - } - - /// Determine if there are is an inalloca argument. Only the last argument can - /// have the inalloca attribute. - bool hasInAllocaArgument() const { - return !arg_empty() && paramHasAttr(arg_size() - 1, Attribute::InAlloca); - } - - bool doesNotAccessMemory(unsigned OpNo) const { - return dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone); - } - - bool onlyReadsMemory(unsigned OpNo) const { - return dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadOnly) || - dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone); - } - - bool doesNotReadMemory(unsigned OpNo) const { - return dataOperandHasImpliedAttr(OpNo + 1, Attribute::WriteOnly) || - dataOperandHasImpliedAttr(OpNo + 1, Attribute::ReadNone); - } - - /// Return true if the return value is known to be not null. - /// This may be because it has the nonnull attribute, or because at least - /// one byte is dereferenceable and the pointer is in addrspace(0). - bool isReturnNonNull() const { - if (hasRetAttr(Attribute::NonNull)) - return true; - else if (getDereferenceableBytes(AttributeList::ReturnIndex) > 0 && - !NullPointerIsDefined(getCaller(), getType()->getPointerAddressSpace())) - return true; - - return false; - } - - /// Returns true if this CallSite passes the given Value* as an argument to - /// the called function. - bool hasArgument(const Value* Arg) const { - for (arg_iterator AI = this->arg_begin(), E = this->arg_end(); AI != E; ++AI) - if (AI->get() == Arg) - return true; - return false; - } - - private: - IterTy getCallee() const { - return cast(getInstruction())->op_end() - 1; - } -}; - -class CallSite : public CallSiteBase { - public: - CallSite() = default; - CallSite(CallSiteBase B) : CallSiteBase(B) { - } - CallSite(CallInst* CI) : CallSiteBase(CI) { - } - CallSite(InvokeInst* II) : CallSiteBase(II) { - } - CallSite(CallBrInst* CBI) : CallSiteBase(CBI) { - } - explicit CallSite(Instruction* II) : CallSiteBase(II) { - } - explicit CallSite(Value* V) : CallSiteBase(V) { - } - - bool operator==(const CallSite& CS) const { - return I == CS.I; - } - bool operator!=(const CallSite& CS) const { - return I != CS.I; - } - bool operator<(const CallSite& CS) const { - return getInstruction() < CS.getInstruction(); - } - - private: - friend struct DenseMapInfo; - - User::op_iterator getCallee() const; }; - -/// Establish a view to a call site for examination. -class ImmutableCallSite : public CallSiteBase<> { - public: - ImmutableCallSite() = default; - ImmutableCallSite(const CallInst* CI) : CallSiteBase(CI) { - } - ImmutableCallSite(const InvokeInst* II) : CallSiteBase(II) { - } - ImmutableCallSite(const CallBrInst* CBI) : CallSiteBase(CBI) { - } - explicit ImmutableCallSite(const Instruction* II) : CallSiteBase(II) { - } - explicit ImmutableCallSite(const Value* V) : CallSiteBase(V) { - } - ImmutableCallSite(CallSite CS) : CallSiteBase(CS.getInstruction()) { - } -}; - } // namespace llvm -#pragma GCC diagnostic pop -#endif -#endif // LLVM_IR_CALLSITE_H \ No newline at end of file +#endif diff --git a/lib/passes/configuration/CMakeLists.txt b/lib/passes/configuration/CMakeLists.txt new file mode 100644 index 00000000..c589b114 --- /dev/null +++ b/lib/passes/configuration/CMakeLists.txt @@ -0,0 +1,39 @@ +set(CONFIG_SOURCES + FileConfiguration.cpp + EnvironmentConfiguration.cpp + PassConfiguration.cpp + TypeARTOptions.cpp +) + +add_library(${TYPEART_PREFIX}_PassConfiguration STATIC ${CONFIG_SOURCES}) + +set_target_properties( + ${TYPEART_PREFIX}_PassConfiguration + PROPERTIES + OUTPUT_NAME "${PROJECT_NAME}PassConfiguration" + EXPORT_NAME "PassConfiguration" +) + +add_library(typeart::PassConfiguration ALIAS ${TYPEART_PREFIX}_PassConfiguration) + +target_compile_definitions( + ${TYPEART_PREFIX}_PassConfiguration PRIVATE TYPEART_LOG_LEVEL=${TYPEART_LOG_LEVEL} + LLVM_VERSION_MAJOR=${LLVM_VERSION_MAJOR} +) + +set_target_properties(${TYPEART_PREFIX}_PassConfiguration PROPERTIES POSITION_INDEPENDENT_CODE ON) + +target_include_directories( + ${TYPEART_PREFIX}_PassConfiguration ${warning_guard} + PUBLIC $ + $ + $ +) + +target_include_directories(${TYPEART_PREFIX}_PassConfiguration SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS}) + +make_tidy_check(${TYPEART_PREFIX}_PassConfiguration "${CONFIG_SOURCES}") + +typeart_target_compile_options(${TYPEART_PREFIX}_PassConfiguration) +typeart_target_define_file_basename(${TYPEART_PREFIX}_PassConfiguration) +typeart_target_coverage_options(${TYPEART_PREFIX}_PassConfiguration) diff --git a/lib/support/Configuration.h b/lib/passes/configuration/Configuration.h similarity index 69% rename from lib/support/Configuration.h rename to lib/passes/configuration/Configuration.h index 9464fc5f..8a386567 100644 --- a/lib/support/Configuration.h +++ b/lib/passes/configuration/Configuration.h @@ -15,8 +15,9 @@ #include "support/Logger.h" -#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringMap.h" +#include #include #include #include @@ -24,31 +25,6 @@ namespace typeart::config { -struct ConfigStdArgs final { -#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description) static constexpr char name[] = path; -#include "ConfigurationBaseOptions.h" -#undef TYPEART_CONFIG_OPTION -}; - -struct ConfigStdArgValues final { -#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description) \ - static constexpr decltype(def_value) name{def_value}; -#include "ConfigurationBaseOptions.h" -#undef TYPEART_CONFIG_OPTION -}; - -struct ConfigStdArgTypes final { -#define TYPEART_CONFIG_OPTION(name, path, type, default_value, description) using name##_ty = type; -#include "ConfigurationBaseOptions.h" -#undef TYPEART_CONFIG_OPTION -}; - -struct ConfigStdArgDescriptions final { -#define TYPEART_CONFIG_OPTION(name, path, type, default_value, description) static constexpr char name[] = description; -#include "ConfigurationBaseOptions.h" -#undef TYPEART_CONFIG_OPTION -}; - namespace detail { template struct VariantContains; @@ -113,16 +89,15 @@ class OptionValue final { } }; +using OptionsMap = llvm::StringMap; +using OptOccurrenceMap = llvm::StringMap; + class Configuration { public: - [[nodiscard]] virtual llvm::Optional getValue(std::string_view opt_path) const = 0; + [[nodiscard]] virtual std::optional getValue(std::string_view opt_path) const = 0; - [[nodiscard]] virtual OptionValue getValueOr(std::string_view opt_path, OptionValue alt) const { - const auto val = getValue(opt_path); - if (val.hasValue()) { - return val.getValue(); - } - return alt; + [[nodiscard]] virtual OptionValue getValueOr(std::string_view opt_path, const OptionValue& alt) const { + return getValue(opt_path).value_or(alt); } [[nodiscard]] virtual OptionValue operator[](std::string_view opt_path) const { diff --git a/lib/passes/configuration/EnvironmentConfiguration.cpp b/lib/passes/configuration/EnvironmentConfiguration.cpp new file mode 100644 index 00000000..339ff524 --- /dev/null +++ b/lib/passes/configuration/EnvironmentConfiguration.cpp @@ -0,0 +1,215 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#include "EnvironmentConfiguration.h" + +#include "Configuration.h" +#include "OptionsUtil.h" +#include "PassConfiguration.h" +#include "configuration/TypeARTOptions.h" +#include "support/ConfigurationBase.h" +#include "support/Logger.h" +#include "support/Util.h" + +#include "llvm/ADT/StringSwitch.h" + +#include +#include +#include +#include + +using namespace llvm; + +namespace typeart::config::env { +std::optional get_env_flag(std::string_view flag) { + const char* env_value = std::getenv(flag.data()); + const bool exists = env_value != nullptr; + if (exists) { + LOG_DEBUG("Using env var " << flag << "=" << env_value) + return std::string{env_value}; + } + LOG_DEBUG("Not using env var " << flag << "=") + return {}; +} + +} // namespace typeart::config::env + +namespace typeart::config::env { + +struct EnvironmentStdArgsValues final { +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ + static constexpr char name[] = #def_value; +#include "support/ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; + +struct EnvironmentStdOptionsArgsValues final { + static constexpr char option[] = "TYPEART_OPTIONS"; + static constexpr char option_stack[] = "TYPEART_OPTIONS_STACK"; + static constexpr char option_heap[] = "TYPEART_OPTIONS_HEAP"; +}; + +namespace detail { +template +OptionValue make_opt(std::string_view cl_value) { + // LOG_DEBUG("Parsing value " << cl_value) + auto value = util::make_opt(cl_value.data()); + if constexpr (std::is_enum_v) { + return OptionValue{static_cast(value)}; + } else { + return OptionValue{value}; + } +} + +template +std::pair make_entry(std::string_view key, std::string_view cl_opt, + const std::string& default_value) { + const auto env_value = get_env_flag(cl_opt); + return {key, detail::make_opt(env_value.value_or(default_value))}; +} + +template +std::pair make_occurr_entry(std::string_view key, ClOpt&& cl_opt) { + const bool occurred = (get_env_flag(cl_opt).has_value()); + return {key, occurred}; +} + +void merge_mapping_with_passconfig(OptionsMap& mapping_, OptOccurrenceMap& occurence_mapping_, + const pass::PassConfig& result) { + const auto typeart_options = helper::options_to_map(result.first.get()); + for (const auto& entry : result.second) { + const auto key = entry.getKey(); + if (entry.second && !occurence_mapping_[key]) { // single ENV priority over TYPEART_OPTIONS + LOG_DEBUG("Replacing " << key) + mapping_[key] = typeart_options.lookup(key); + occurence_mapping_[key] = true; + } + } +} +} // namespace detail + +EnvironmentFlagsOptions::EnvironmentFlagsOptions() { + using namespace config; + using namespace typeart::config::env::detail; + + LOG_DEBUG("Construct environment flag options") + + mapping_ = { + make_entry(ConfigStdArgs::types, config::EnvironmentStdArgs::types, ConfigStdArgValues::types), + make_entry(ConfigStdArgs::stats, EnvironmentStdArgs::stats, + EnvironmentStdArgsValues::stats), + make_entry(ConfigStdArgs::heap, EnvironmentStdArgs::heap, + EnvironmentStdArgsValues::heap), + make_entry(ConfigStdArgs::global, EnvironmentStdArgs::global, + EnvironmentStdArgsValues::global), + make_entry(ConfigStdArgs::stack, EnvironmentStdArgs::stack, + EnvironmentStdArgsValues::stack), + make_entry( + ConfigStdArgs::stack_lifetime, EnvironmentStdArgs::stack_lifetime, EnvironmentStdArgsValues::stack_lifetime), + make_entry(ConfigStdArgs::typegen, EnvironmentStdArgs::typegen, + ConfigStdArgValues::typegen), + make_entry(ConfigStdArgs::filter, EnvironmentStdArgs::filter, + EnvironmentStdArgsValues::filter), + make_entry(ConfigStdArgs::filter_impl, EnvironmentStdArgs::filter_impl, + ConfigStdArgValues::filter_impl), + + make_entry(ConfigStdArgs::filter_glob, EnvironmentStdArgs::filter_glob, + ConfigStdArgValues::filter_glob), + make_entry( + ConfigStdArgs::filter_glob_deep, EnvironmentStdArgs::filter_glob_deep, ConfigStdArgValues::filter_glob_deep), + make_entry( + ConfigStdArgs::filter_cg_file, EnvironmentStdArgs::filter_cg_file, ConfigStdArgValues::filter_cg_file), + make_entry(ConfigStdArgs::analysis_filter_global, + EnvironmentStdArgs::analysis_filter_global, + EnvironmentStdArgsValues::analysis_filter_global), + make_entry( + ConfigStdArgs::analysis_filter_heap_alloc, EnvironmentStdArgs::analysis_filter_heap_alloc, + EnvironmentStdArgsValues::analysis_filter_heap_alloc), + make_entry( + ConfigStdArgs::analysis_filter_pointer_alloc, EnvironmentStdArgs::analysis_filter_pointer_alloc, + EnvironmentStdArgsValues::analysis_filter_pointer_alloc), + make_entry( + ConfigStdArgs::analysis_filter_alloca_non_array, EnvironmentStdArgs::analysis_filter_alloca_non_array, + EnvironmentStdArgsValues::analysis_filter_alloca_non_array), + }; + + occurence_mapping_ = { + make_occurr_entry(ConfigStdArgs::types, config::EnvironmentStdArgs::types), + make_occurr_entry(ConfigStdArgs::stats, EnvironmentStdArgs::stats), + make_occurr_entry(ConfigStdArgs::heap, EnvironmentStdArgs::heap), + make_occurr_entry(ConfigStdArgs::global, EnvironmentStdArgs::global), + make_occurr_entry(ConfigStdArgs::stack, EnvironmentStdArgs::stack), + make_occurr_entry(ConfigStdArgs::stack_lifetime, EnvironmentStdArgs::stack_lifetime), + make_occurr_entry(ConfigStdArgs::typegen, EnvironmentStdArgs::typegen), + make_occurr_entry(ConfigStdArgs::filter, EnvironmentStdArgs::filter), + make_occurr_entry(ConfigStdArgs::filter_impl, EnvironmentStdArgs::filter_impl), + make_occurr_entry(ConfigStdArgs::filter_glob, EnvironmentStdArgs::filter_glob), + make_occurr_entry(ConfigStdArgs::filter_glob_deep, EnvironmentStdArgs::filter_glob_deep), + make_occurr_entry(ConfigStdArgs::filter_cg_file, EnvironmentStdArgs::filter_cg_file), + make_occurr_entry(ConfigStdArgs::analysis_filter_global, EnvironmentStdArgs::analysis_filter_global), + make_occurr_entry(ConfigStdArgs::analysis_filter_heap_alloc, EnvironmentStdArgs::analysis_filter_heap_alloc), + make_occurr_entry(ConfigStdArgs::analysis_filter_pointer_alloc, + EnvironmentStdArgs::analysis_filter_pointer_alloc), + make_occurr_entry(ConfigStdArgs::analysis_filter_alloca_non_array, + EnvironmentStdArgs::analysis_filter_alloca_non_array), + }; + + if (!occurence_mapping_.lookup(ConfigStdArgs::global) && occurence_mapping_.lookup(ConfigStdArgs::stack)) { + const auto stack_value = mapping_.lookup(ConfigStdArgs::stack); + mapping_[ConfigStdArgs::global] = OptionValue{static_cast(stack_value)}; + occurence_mapping_[ConfigStdArgs::global] = true; + } + + auto result = + pass::parse_typeart_config_with_occurrence(get_env_flag(EnvironmentStdOptionsArgsValues::option).value_or("")); + if (!result.first) { + LOG_INFO("No parseable " << EnvironmentStdOptionsArgsValues::option << ": " << result.first.takeError()) + } else { + LOG_DEBUG("Parsed " << EnvironmentStdOptionsArgsValues::option << "\n" << *result.first) + merge_mapping_with_passconfig(mapping_, occurence_mapping_, result); + } +} + +void EnvironmentFlagsOptions::parsePhaseEnvFlags(const Phase& phase) { + if (phase.heap) { + auto result = pass::parse_typeart_config_with_occurrence( + get_env_flag(EnvironmentStdOptionsArgsValues::option_heap).value_or("")); + if (result.first) { + LOG_DEBUG("Parsing " << EnvironmentStdOptionsArgsValues::option_heap) + detail::merge_mapping_with_passconfig(mapping_, occurence_mapping_, result); + } + } + + if (phase.stack) { + auto result = pass::parse_typeart_config_with_occurrence( + get_env_flag(EnvironmentStdOptionsArgsValues::option_stack).value_or("")); + if (result.first) { + LOG_DEBUG("Parsing " << EnvironmentStdOptionsArgsValues::option_stack) + detail::merge_mapping_with_passconfig(mapping_, occurence_mapping_, result); + } + } +} + +std::optional EnvironmentFlagsOptions::getValue(std::string_view opt_path) const { + auto key = llvm::StringRef(opt_path.data()); + if (occurence_mapping_.lookup(key)) { // only have value if it occurred + return mapping_.lookup(key); + } + return {}; +} + +[[maybe_unused]] bool EnvironmentFlagsOptions::valueSpecified(std::string_view opt_path) const { + auto key = llvm::StringRef(opt_path.data()); + return occurence_mapping_.lookup(key); +} + +} // namespace typeart::config::env diff --git a/lib/passes/configuration/EnvironmentConfiguration.h b/lib/passes/configuration/EnvironmentConfiguration.h new file mode 100644 index 00000000..68ceb184 --- /dev/null +++ b/lib/passes/configuration/EnvironmentConfiguration.h @@ -0,0 +1,41 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#ifndef TYPEART_ENVIRONMENT_CONFIGURATION_H +#define TYPEART_ENVIRONMENT_CONFIGURATION_H + +#include "configuration/Configuration.h" + +namespace typeart::config::env { + +struct Phase { + bool heap; + bool stack; +}; + +std::optional get_env_flag(std::string_view flag); + +class EnvironmentFlagsOptions final : public config::Configuration { + private: + OptionsMap mapping_; + OptOccurrenceMap occurence_mapping_; + + public: + EnvironmentFlagsOptions(); + [[nodiscard]] std::optional getValue(std::string_view opt_path) const override; + [[maybe_unused]] [[nodiscard]] bool valueSpecified(std::string_view opt_path) const; + void parsePhaseEnvFlags(const Phase& phase); +}; + +} // namespace typeart::config::env + +#endif diff --git a/lib/passes/configuration/FileConfiguration.cpp b/lib/passes/configuration/FileConfiguration.cpp new file mode 100644 index 00000000..71a05032 --- /dev/null +++ b/lib/passes/configuration/FileConfiguration.cpp @@ -0,0 +1,130 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#include "FileConfiguration.h" + +#include "Configuration.h" +#include "TypeARTConfiguration.h" +#include "TypeARTOptions.h" +#include "analysis/MemInstFinder.h" +#include "typegen/TypeGenerator.h" + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/YAMLTraits.h" + +#include +#include +#include + +using namespace llvm; + +namespace typeart::config::file { + +std::string write_file_configuration_as_text(const FileOptions& file_options); + +class YamlFileConfiguration final : public FileOptions { + private: + OptionsMap mapping_; + + public: + explicit YamlFileConfiguration(const TypeARTConfigOptions& conf_file); + + [[nodiscard]] std::optional getValue(std::string_view opt_path) const override; + + [[nodiscard]] OptionsMap getConfiguration() const override; + + [[nodiscard]] std::string getConfigurationAsString() const override; + + ~YamlFileConfiguration() override = default; +}; + +YamlFileConfiguration::YamlFileConfiguration(const TypeARTConfigOptions& conf_file) + : mapping_(helper::options_to_map(conf_file)) { +} + +std::optional YamlFileConfiguration::getValue(std::string_view opt_path) const { + auto key = llvm::StringRef(opt_path.data()); + if (mapping_.count(key) != 0U) { + return mapping_.lookup(key); + } + return {}; +} + +OptionsMap YamlFileConfiguration::getConfiguration() const { + return this->mapping_; +} + +std::string YamlFileConfiguration::getConfigurationAsString() const { + return write_file_configuration_as_text(*this); +} + +namespace compat { +auto open_flag() { +#if LLVM_VERSION_MAJOR < 13 + return llvm::sys::fs::OpenFlags::F_Text; +#else + return llvm::sys::fs::OpenFlags::OF_Text; +#endif +} +} // namespace compat + +[[maybe_unused]] llvm::ErrorOr> make_file_configuration(std::string_view file_path) { + using namespace llvm; + + ErrorOr> memBuffer = MemoryBuffer::getFile(file_path.data()); + + if (std::error_code error = memBuffer.getError(); error) { + LOG_WARNING("Warning while loading configuration file \'" << file_path.data() << "\'. Reason: " << error.message()); + return error; + } + + llvm::yaml::Input input_yaml(memBuffer.get()->getMemBufferRef()); + const auto file_content = io::yaml::yaml_read_file(input_yaml); + + return std::make_unique(file_content); +} + +llvm::ErrorOr> make_default_file_configuration() { + TypeARTConfigOptions options; + return std::make_unique(options); +} + +llvm::ErrorOr> make_from_configuration(const TypeARTConfigOptions& options) { + return std::make_unique(options); +} + +llvm::ErrorOr write_file_configuration(llvm::raw_ostream& out_stream, const FileOptions& options) { + using namespace llvm; + + llvm::yaml::Output out(out_stream); + + auto data = options.getConfiguration(); + + auto conf_file = helper::map_to_options(options.getConfiguration()); + io::yaml::yaml_output_file(out, conf_file); + + return true; +} + +std::string write_file_configuration_as_text(const FileOptions& file_options) { + std::string config_text; + llvm::raw_string_ostream sstream(config_text); + if (!write_file_configuration(sstream, file_options)) { + LOG_WARNING("Could not write config file to string stream.") + } + return sstream.str(); +} + +} // namespace typeart::config::file diff --git a/lib/support/FileConfiguration.h b/lib/passes/configuration/FileConfiguration.h similarity index 67% rename from lib/support/FileConfiguration.h rename to lib/passes/configuration/FileConfiguration.h index 177bf19f..5ed453d9 100644 --- a/lib/support/FileConfiguration.h +++ b/lib/passes/configuration/FileConfiguration.h @@ -13,26 +13,30 @@ #ifndef TYPEART_FILECONFIGURATION_H #define TYPEART_FILECONFIGURATION_H -#include "support/Configuration.h" +#include "configuration/Configuration.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/ErrorOr.h" -namespace typeart::config::file { +namespace typeart::config { +struct TypeARTConfigOptions; +} // namespace typeart::config -using FileOptionsMap = llvm::StringMap; +namespace typeart::config::file { class FileOptions : public config::Configuration { public: - [[nodiscard]] llvm::Optional getValue(std::string_view opt_path) const override = 0; - [[nodiscard]] virtual FileOptionsMap getConfiguration() const = 0; - [[nodiscard]] virtual std::string getConfigurationAsString() const = 0; - ~FileOptions() override = default; + [[nodiscard]] std::optional getValue(std::string_view opt_path) const override = 0; + [[nodiscard]] virtual OptionsMap getConfiguration() const = 0; + [[nodiscard]] virtual std::string getConfigurationAsString() const = 0; + ~FileOptions() override = default; }; [[maybe_unused]] llvm::ErrorOr> make_file_configuration(std::string_view file_path); [[maybe_unused]] llvm::ErrorOr> make_default_file_configuration(); +[[maybe_unused]] llvm::ErrorOr> make_from_configuration( + const TypeARTConfigOptions& options); [[maybe_unused]] llvm::ErrorOr write_file_configuration(llvm::raw_ostream& out_stream, const FileOptions& file_options); diff --git a/lib/passes/configuration/OptionsUtil.h b/lib/passes/configuration/OptionsUtil.h new file mode 100644 index 00000000..1c308565 --- /dev/null +++ b/lib/passes/configuration/OptionsUtil.h @@ -0,0 +1,72 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#ifndef TYPEART_CONFIGURATION_OPTIONS_UTIL_H +#define TYPEART_CONFIGURATION_OPTIONS_UTIL_H + +#include "analysis/MemInstFinder.h" +#include "support/Logger.h" +#include "typegen/TypeGenerator.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +namespace typeart::config::util { + +template +bool with_any_of(llvm::StringRef lhs, Strings&&... rhs) { + return !lhs.empty() && ((lhs == rhs) || ...); +} + +template +ClType string_to_enum(llvm::StringRef cl_value) { + using ::typeart::TypegenImplementation; + using ::typeart::analysis::FilterImplementation; + if constexpr (std::is_same_v) { + auto val = llvm::StringSwitch(cl_value) + .Case("ir", TypegenImplementation::IR) + .Case("dimeta", TypegenImplementation::DIMETA) + .Default(TypegenImplementation::DIMETA); + return val; + } else { + auto val = llvm::StringSwitch(cl_value) + .Case("cg", FilterImplementation::cg) + .Case("none", FilterImplementation::none) + .Case("std", FilterImplementation::standard) + .Default(FilterImplementation::standard); + return val; + } +} + +template +ClType make_opt(llvm::StringRef cl_value) { + LOG_DEBUG("Parsing value " << cl_value) + if constexpr (std::is_same_v) { + const bool is_true_val = with_any_of(cl_value, "true", "TRUE", "1"); + const bool is_false_val = with_any_of(cl_value, "false", "FALSE", "0"); + if (!(is_true_val || is_false_val)) { + LOG_WARNING("Illegal bool value") + } + assert((is_true_val || is_false_val) && "Illegal bool value for environment flag"); + return is_true_val; + } else { + if constexpr (std::is_enum_v) { + auto enum_value = string_to_enum(cl_value); + return enum_value; + } else { + return std::string{cl_value}; + } + } +} + +} // namespace typeart::config::util +#endif /* TYPEART_CONFIGURATION_OPTIONS_UTIL_H */ diff --git a/lib/passes/configuration/PassBuilderUtil.h b/lib/passes/configuration/PassBuilderUtil.h new file mode 100644 index 00000000..bebeda9d --- /dev/null +++ b/lib/passes/configuration/PassBuilderUtil.h @@ -0,0 +1,75 @@ + +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +// Taken and adapted from llvm/Passes/PassBuilder.h +#ifndef TYPEART_PASS_BUILDER_UTIL_H +#define TYPEART_PASS_BUILDER_UTIL_H + +#include "support/Logger.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +namespace typeart::util::pass { + +inline bool checkParametrizedPassName(llvm::StringRef Name, llvm::StringRef PassName) { + using namespace llvm; + if (!Name.consume_front(PassName)) + return false; + // normal pass name w/o parameters == default parameters + if (Name.empty()) + return true; +#if LLVM_VERSION_MAJOR > 15 + return Name.starts_with("<") && Name.ends_with(">"); +#else + return Name.startswith("<") && Name.endswith(">"); +#endif +} + +/// This performs customized parsing of pass name with parameters. +/// +/// We do not need parametrization of passes in textual pipeline very often, +/// yet on a rare occasion ability to specify parameters right there can be +/// useful. +/// +/// \p Name - parameterized specification of a pass from a textual pipeline +/// is a string in a form of : +/// PassName '<' parameter-list '>' +/// +/// Parameter list is being parsed by the parser callable argument, \p Parser, +/// It takes a string-ref of parameters and returns either StringError or a +/// parameter list in a form of a custom parameters type, all wrapped into +/// Expected<> template class. +/// +template +inline auto parsePassParameters(ParametersParseCallableT&& Parser, llvm::StringRef Name, llvm::StringRef PassName) + -> decltype(Parser(llvm::StringRef{})) { + using namespace llvm; + using ParametersT = typename decltype(Parser(StringRef{}))::value_type; + + StringRef Params = Name; + if (!Params.consume_front(PassName)) { + llvm_unreachable("unable to strip pass name from parametrized pass specification"); + } + if (!Params.empty() && (!Params.consume_front("<") || !Params.consume_back(">"))) { + llvm_unreachable("invalid format for parametrized pass name"); + } + + Expected Result = Parser(Params); + assert((Result || Result.template errorIsA()) && "Pass parameter parser can only return StringErrors."); + return Result; +} + +} // namespace typeart::util::pass + +#endif /* TYPEART_PASS_BUILDER_UTIL_H */ diff --git a/lib/passes/configuration/PassConfiguration.cpp b/lib/passes/configuration/PassConfiguration.cpp new file mode 100644 index 00000000..24177765 --- /dev/null +++ b/lib/passes/configuration/PassConfiguration.cpp @@ -0,0 +1,158 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#include "PassConfiguration.h" + +#include "OptionsUtil.h" +#include "analysis/MemInstFinder.h" +#include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" +#include "support/ConfigurationBaseOptions.h" +#include "support/Error.h" +#include "support/Logger.h" + +#include "llvm/Support/FormatVariadicDetails.h" + +#include +#include +#include + +namespace typeart::config::pass { + +struct PassStdArgsEq final { +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ + static constexpr char name[] = path "="; +#include "support/ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; + +llvm::Expected parse_typeart_config(llvm::StringRef parameters) { + return parse_typeart_config_with_occurrence(parameters).first; +} + +PassConfig parse_typeart_config_with_occurrence(llvm::StringRef parameters) { + LOG_DEBUG("Parsing string: " << parameters) + TypeARTConfigOptions result; + OptOccurrenceMap occurrence_map; + bool global_set{false}; + bool stack_set{false}; + + while (!parameters.empty()) { + llvm::StringRef parameter_name; + std::tie(parameter_name, parameters) = parameters.split(';'); + + const bool enable = !parameter_name.consume_front("no-"); + + if (parameter_name == ConfigStdArgs::heap) { + result.heap = enable; + occurrence_map[ConfigStdArgs::heap] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::stack) { + result.stack = enable; + occurrence_map[ConfigStdArgs::stack] = true; + stack_set = true; + continue; + } + + if (parameter_name == ConfigStdArgs::global) { + global_set = true; + result.global = enable; + occurrence_map[ConfigStdArgs::global] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::filter) { + result.filter = enable; + occurrence_map[ConfigStdArgs::filter] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::stats) { + result.statistics = enable; + occurrence_map[ConfigStdArgs::stats] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::stack_lifetime) { + result.stack_lifetime = enable; + occurrence_map[ConfigStdArgs::stack_lifetime] = true; + continue; + } + + if (parameter_name.consume_front(PassStdArgsEq::typegen)) { + result.typegen = util::string_to_enum(parameter_name); + occurrence_map[ConfigStdArgs::typegen] = true; + continue; + } + + if (parameter_name.consume_front(PassStdArgsEq::filter_impl)) { + result.filter_config.implementation = util::string_to_enum(parameter_name); + occurrence_map[ConfigStdArgs::filter_impl] = true; + continue; + } + + if (parameter_name.consume_front(PassStdArgsEq::filter_glob)) { + result.filter_config.glob = parameter_name; + occurrence_map[ConfigStdArgs::filter_glob] = true; + continue; + } + if (parameter_name.consume_front(PassStdArgsEq::filter_glob_deep)) { + result.filter_config.glob_deep = parameter_name; + occurrence_map[ConfigStdArgs::filter_glob_deep] = true; + continue; + } + if (parameter_name == ConfigStdArgs::analysis_filter_global) { + result.analysis_config.filter_global = enable; + occurrence_map[ConfigStdArgs::analysis_filter_global] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::analysis_filter_alloca_non_array) { + result.analysis_config.filter_alloca_non_array = enable; + occurrence_map[ConfigStdArgs::analysis_filter_alloca_non_array] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::analysis_filter_heap_alloc) { + result.analysis_config.filter_heap_alloc = enable; + occurrence_map[ConfigStdArgs::analysis_filter_heap_alloc] = true; + continue; + } + + if (parameter_name == ConfigStdArgs::analysis_filter_pointer_alloc) { + result.analysis_config.filter_pointer_alloc = enable; + occurrence_map[ConfigStdArgs::analysis_filter_pointer_alloc] = true; + continue; + } + { + // undefined symbol issue: llvm::formatv("Unknown TypeART option {0} with unparsed list {1}", parameter_name, + // parameters).str() + std::string out_string; + llvm::raw_string_ostream out_stream(out_string); + out_stream << "Unknown TypeART option " << parameter_name; + if (!parameters.empty()) { + out_stream << " with unparsed list " << parameters; + } + return {error::make_string_error(out_stream.str()), occurrence_map}; + } + } + if (!global_set && stack_set) { + // Stack implies global + result.global = result.stack; + occurrence_map[ConfigStdArgs::global] = true; + } + return {result, occurrence_map}; +} + +} // namespace typeart::config::pass \ No newline at end of file diff --git a/lib/passes/configuration/PassConfiguration.h b/lib/passes/configuration/PassConfiguration.h new file mode 100644 index 00000000..9dda8566 --- /dev/null +++ b/lib/passes/configuration/PassConfiguration.h @@ -0,0 +1,31 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#ifndef TYPEART_PASS_CONFIGURATION_H +#define TYPEART_PASS_CONFIGURATION_H + +#include "Configuration.h" +#include "TypeARTOptions.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +namespace typeart::config::pass { + +using PassConfig = std::pair, OptOccurrenceMap>; + +llvm::Expected parse_typeart_config(llvm::StringRef parameters); +PassConfig parse_typeart_config_with_occurrence(llvm::StringRef parameters); + +} // namespace typeart::config::pass + +#endif /* TYPEART_PASS_CONFIGURATION_H */ diff --git a/lib/passes/configuration/TypeARTOptions.cpp b/lib/passes/configuration/TypeARTOptions.cpp new file mode 100644 index 00000000..00a1d113 --- /dev/null +++ b/lib/passes/configuration/TypeARTOptions.cpp @@ -0,0 +1,196 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#include "TypeARTOptions.h" + +#include "Configuration.h" +#include "FileConfiguration.h" + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace llvm::yaml; +using namespace typeart::config::file; + +template <> +struct llvm::yaml::ScalarEnumerationTraits { + static void enumeration(IO& io, typeart::analysis::FilterImplementation& value) { + io.enumCase(value, "cg", typeart::analysis::FilterImplementation::cg); + io.enumCase(value, "std", typeart::analysis::FilterImplementation::standard); + io.enumCase(value, "none", typeart::analysis::FilterImplementation::none); + } +}; + +template <> +struct llvm::yaml::ScalarEnumerationTraits { + static void enumeration(IO& io, typeart::TypegenImplementation& value) { + io.enumCase(value, "dimeta", typeart::TypegenImplementation::DIMETA); + io.enumCase(value, "ir", typeart::TypegenImplementation::IR); + } +}; + +template <> +struct llvm::yaml::MappingTraits { + static void mapping(IO& yml_io, typeart::config::TypeARTAnalysisOptions& info) { + using typeart::config::ConfigStdArgs; + const auto drop_prefix = [](const std::string& path, std::string_view prefix = "analysis-") { + llvm::StringRef prefix_less{path}; + prefix_less.consume_front(prefix.data()); + return prefix_less; + }; + yml_io.mapOptional(drop_prefix(ConfigStdArgs::analysis_filter_global).data(), info.filter_global); + yml_io.mapOptional(drop_prefix(ConfigStdArgs::analysis_filter_heap_alloc).data(), info.filter_heap_alloc); + yml_io.mapOptional(drop_prefix(ConfigStdArgs::analysis_filter_pointer_alloc).data(), info.filter_pointer_alloc); + yml_io.mapOptional(drop_prefix(ConfigStdArgs::analysis_filter_alloca_non_array).data(), + info.filter_alloca_non_array); + } +}; + +template <> +struct llvm::yaml::MappingTraits { + static void mapping(IO& yml_io, typeart::config::TypeARTCallFilterOptions& info) { + using typeart::config::ConfigStdArgs; + const auto drop_prefix = [](const std::string& path, std::string_view prefix = "filter-") { + llvm::StringRef prefix_less{path}; + prefix_less.consume_front(prefix.data()); + return prefix_less; + }; + yml_io.mapOptional(drop_prefix(ConfigStdArgs::filter_impl).data(), info.implementation); + yml_io.mapOptional(drop_prefix(ConfigStdArgs::filter_glob).data(), info.glob); + yml_io.mapOptional(drop_prefix(ConfigStdArgs::filter_glob_deep).data(), info.glob_deep); + yml_io.mapOptional(drop_prefix(ConfigStdArgs::filter_cg_file).data(), info.cg_file); + } +}; + +template <> +struct llvm::yaml::MappingTraits { + static void mapping(IO& yml_io, typeart::config::TypeARTConfigOptions& info) { + using typeart::config::ConfigStdArgs; + yml_io.mapRequired(ConfigStdArgs::types, info.types); + yml_io.mapRequired(ConfigStdArgs::heap, info.heap); + yml_io.mapRequired(ConfigStdArgs::stack, info.stack); + yml_io.mapOptional(ConfigStdArgs::global, info.global); + yml_io.mapOptional(ConfigStdArgs::stats, info.statistics); + yml_io.mapOptional(ConfigStdArgs::stack_lifetime, info.stack_lifetime); + yml_io.mapRequired(ConfigStdArgs::typegen, info.typegen); + yml_io.mapRequired(ConfigStdArgs::filter, info.filter); + yml_io.mapOptional("call-filter", info.filter_config); + yml_io.mapOptional("analysis", info.analysis_config); + // yml_io.mapOptional("file-format", info.version); + } +}; + +namespace typeart::config::io::yaml { + +TypeARTConfigOptions yaml_read_file(llvm::yaml::Input& input) { + TypeARTConfigOptions file_content{}; + input >> file_content; + + return file_content; +} + +void yaml_output_file(llvm::yaml::Output& output, const TypeARTConfigOptions& config) { + output << const_cast(config); +} + +} // namespace typeart::config::io::yaml + +namespace typeart::config { + +llvm::raw_ostream& operator<<(llvm::raw_ostream& out_stream, const TypeARTConfigOptions& options) { + std::string config_text; + llvm::raw_string_ostream sstream(config_text); + llvm::yaml::Output out(sstream); + io::yaml::yaml_output_file(out, options); + out_stream.flush(); + out_stream << sstream.str(); + return out_stream; +} + +namespace helper { + +template +TypeARTConfigOptions construct_with(Constructor&& make_entry) { + TypeARTConfigOptions config; + make_entry(ConfigStdArgs::types, config.types); + make_entry(ConfigStdArgs::stats, config.statistics); + make_entry(ConfigStdArgs::heap, config.heap); + make_entry(ConfigStdArgs::global, config.global); + make_entry(ConfigStdArgs::stack, config.stack); + make_entry(ConfigStdArgs::stack_lifetime, config.stack_lifetime); + make_entry(ConfigStdArgs::filter, config.filter); + make_entry(ConfigStdArgs::filter_impl, config.filter_config.implementation); + make_entry(ConfigStdArgs::filter_glob, config.filter_config.glob); + make_entry(ConfigStdArgs::filter_glob_deep, config.filter_config.glob_deep); + make_entry(ConfigStdArgs::filter_cg_file, config.filter_config.cg_file); + make_entry(ConfigStdArgs::analysis_filter_global, config.analysis_config.filter_global); + make_entry(ConfigStdArgs::analysis_filter_heap_alloc, config.analysis_config.filter_heap_alloc); + make_entry(ConfigStdArgs::analysis_filter_pointer_alloc, config.analysis_config.filter_pointer_alloc); + make_entry(ConfigStdArgs::analysis_filter_alloca_non_array, config.analysis_config.filter_alloca_non_array); + make_entry(ConfigStdArgs::typegen, config.typegen); + return config; +} + +TypeARTConfigOptions map_to_options(const OptionsMap& mapping) { + const auto make_entry = [&](std::string_view entry, auto& ref) { + auto key = llvm::StringRef(entry.data()); + ref = static_cast::type>(mapping.lookup(key)); + }; + return construct_with(make_entry); +} + +TypeARTConfigOptions config_to_options(const Configuration& configuration) { + const auto make_entry = [&](std::string_view entry, auto& ref) { + auto key = llvm::StringRef(entry.data()); + ref = static_cast::type>(configuration[key]); + }; + return construct_with(make_entry); +} + +template +auto make_entry(std::string_view key, const T& field_value) + -> std::pair { + if constexpr (std::is_enum_v) { + return {key, config::OptionValue{static_cast(field_value)}}; + } else { + return {key, config::OptionValue{field_value}}; + } +}; + +OptionsMap options_to_map(const TypeARTConfigOptions& config) { + OptionsMap mapping_ = { + make_entry(ConfigStdArgs::types, config.types), + make_entry(ConfigStdArgs::stats, config.statistics), + make_entry(ConfigStdArgs::heap, config.heap), + make_entry(ConfigStdArgs::global, config.global), + make_entry(ConfigStdArgs::stack, config.stack), + make_entry(ConfigStdArgs::stack_lifetime, config.stack_lifetime), + make_entry(ConfigStdArgs::typegen, config.typegen), + make_entry(ConfigStdArgs::filter, config.filter), + make_entry(ConfigStdArgs::filter_impl, config.filter_config.implementation), + make_entry(ConfigStdArgs::filter_glob, config.filter_config.glob), + make_entry(ConfigStdArgs::filter_glob_deep, config.filter_config.glob_deep), + make_entry(ConfigStdArgs::filter_cg_file, config.filter_config.cg_file), + make_entry(ConfigStdArgs::analysis_filter_global, config.analysis_config.filter_global), + make_entry(ConfigStdArgs::analysis_filter_heap_alloc, config.analysis_config.filter_heap_alloc), + make_entry(ConfigStdArgs::analysis_filter_pointer_alloc, config.analysis_config.filter_pointer_alloc), + make_entry(ConfigStdArgs::analysis_filter_alloca_non_array, config.analysis_config.filter_alloca_non_array), + }; + return mapping_; +} + +} // namespace helper + +} // namespace typeart::config diff --git a/lib/passes/configuration/TypeARTOptions.h b/lib/passes/configuration/TypeARTOptions.h new file mode 100644 index 00000000..7110bed1 --- /dev/null +++ b/lib/passes/configuration/TypeARTOptions.h @@ -0,0 +1,79 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#ifndef TYPEART_CONFIGURATION_OPTIONS_H +#define TYPEART_CONFIGURATION_OPTIONS_H + +#include "analysis/MemInstFinder.h" +#include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" +#include "typegen/TypeGenerator.h" + +namespace llvm::yaml { +class Input; +class Output; +} // namespace llvm::yaml + +namespace typeart::config { + +using typeart::analysis::FilterImplementation; +using typeart::config::ConfigStdArgValues; + +struct TypeARTCallFilterOptions { + FilterImplementation implementation{FilterImplementation::standard}; + std::string glob{ConfigStdArgValues::filter_glob}; + std::string glob_deep{ConfigStdArgValues::filter_glob_deep}; + std::string cg_file{ConfigStdArgValues::filter_cg_file}; +}; + +struct TypeARTAnalysisOptions { + bool filter_global{ConfigStdArgValues::analysis_filter_global}; + bool filter_heap_alloc{ConfigStdArgValues::analysis_filter_heap_alloc}; + bool filter_pointer_alloc{ConfigStdArgValues::analysis_filter_pointer_alloc}; + bool filter_alloca_non_array{ConfigStdArgValues::analysis_filter_alloca_non_array}; +}; + +struct TypeARTConfigOptions { + std::string types{ConfigStdArgValues::types}; + bool heap{ConfigStdArgValues::heap}; + bool stack{ConfigStdArgValues::stack}; + bool global{ConfigStdArgValues::global}; + bool statistics{ConfigStdArgValues::stats}; + bool stack_lifetime{ConfigStdArgValues::stack_lifetime}; + TypegenImplementation typegen{TypegenImplementation::DIMETA}; + bool filter{false}; + + TypeARTCallFilterOptions filter_config{}; + TypeARTAnalysisOptions analysis_config{}; +}; + +namespace helper { +TypeARTConfigOptions map_to_options(const OptionsMap&); + +TypeARTConfigOptions config_to_options(const Configuration&); + +OptionsMap options_to_map(const TypeARTConfigOptions&); +} // namespace helper + +namespace io::yaml { + +TypeARTConfigOptions yaml_read_file(llvm::yaml::Input& input); + +void yaml_output_file(llvm::yaml::Output& output, const TypeARTConfigOptions& config); + +} // namespace io::yaml + +llvm::raw_ostream& operator<<(llvm::raw_ostream& out_s, const TypeARTConfigOptions& options); + +} // namespace typeart::config + +#endif /* TYPEART_CONFIGURATION_OPTIONS_H */ diff --git a/lib/passes/filter/CGForwardFilter.cpp b/lib/passes/filter/CGForwardFilter.cpp index 60579b03..2570f5aa 100644 --- a/lib/passes/filter/CGForwardFilter.cpp +++ b/lib/passes/filter/CGForwardFilter.cpp @@ -85,7 +85,11 @@ FilterAnalysis CGFilterImpl::precheck(Value* in, Function* start, const FPath& f FilterAnalysis CGFilterImpl::decl(CallSite current, const Path& p) { if (deep_matcher && deep_matcher->match(current) == Matcher::MatchResult::Match) { +#if LLVM_VERSION_MAJOR < 15 auto result = correlate2void(current, p); +#else + auto result = correlate2pointer(current, p); +#endif switch (result) { case ArgCorrelation::GlobalMismatch: [[fallthrough]]; diff --git a/lib/passes/filter/CGInterface.cpp b/lib/passes/filter/CGInterface.cpp index fb56dec9..25dd24c8 100644 --- a/lib/passes/filter/CGInterface.cpp +++ b/lib/passes/filter/CGInterface.cpp @@ -15,7 +15,6 @@ #include "support/Logger.h" #include "support/Util.h" -#include "llvm/ADT/Optional.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/JSON.h" @@ -137,7 +136,7 @@ void JSONCG::construct_call_information(const std::string& entry_caller, const l const auto hasBody = caller->get("hasBody"); if (hasBody != nullptr) { assert(hasBody->kind() == llvm::json::Value::Kind::Boolean && "hasBody must be boolean"); - hasBodyMap[entry_caller] = hasBody->getAsBoolean().getValue(); + hasBodyMap[entry_caller] = *hasBody->getAsBoolean(); } const auto calls = caller->getArray("callees"); assert(calls != nullptr && "Json callee information is missing"); @@ -146,9 +145,9 @@ void JSONCG::construct_call_information(const std::string& entry_caller, const l for (const auto& callee : *calls) { assert(callee.kind() == llvm::json::Value::Kind::String && "Callees must be strings"); const auto callee_json_string = callee.getAsString(); - assert(callee_json_string.hasValue() && "Could not get callee as string"); - if (callee_json_string.hasValue()) { - const std::string callee_string = std::string{callee_json_string.getValue()}; + assert(callee_json_string && "Could not get callee as string"); + if (callee_json_string) { + const std::string callee_string = std::string{*callee_json_string}; directly_called_functions[entry_caller].insert(callee_string); } } @@ -159,9 +158,9 @@ void JSONCG::construct_call_information(const std::string& entry_caller, const l for (const auto& function : *overridingFunctions) { assert(function.kind() == llvm::json::Value::Kind::String && "Function names are always strings"); const auto functionStr = function.getAsString(); - assert(functionStr.hasValue() && "Retrieving overriding function as String failed"); - if (functionStr.hasValue()) { - const std::string functionName = std::string{functionStr.getValue()}; + assert(functionStr && "Retrieving overriding function as String failed"); + if (functionStr) { + const std::string functionName = std::string{*functionStr}; virtualTargets[entry_caller].insert(functionName); } } diff --git a/lib/passes/filter/FilterBase.h b/lib/passes/filter/FilterBase.h index fbb85acf..b46104ec 100644 --- a/lib/passes/filter/FilterBase.h +++ b/lib/passes/filter/FilterBase.h @@ -41,17 +41,17 @@ enum class FilterAnalysis { template class BaseFilter : public Filter { - CallSiteHandler handler; + CallSiteHandler callsite_handler; Search search_dir{}; bool malloc_mode{false}; llvm::Function* start_f{nullptr}; public: - explicit BaseFilter(const CallSiteHandler& handler) : handler(handler) { + explicit BaseFilter(const CallSiteHandler& handler) : callsite_handler(handler) { } template - explicit BaseFilter(Args&&... args) : handler(std::forward(args)...) { + explicit BaseFilter(Args&&... args) : callsite_handler(std::forward(args)...) { } bool filter(llvm::Value* in) override { @@ -83,7 +83,7 @@ class BaseFilter : public Filter { // is null in case of global: llvm::Function* currentF = fpath.getCurrentFunc(); if (currentF != nullptr) { - auto status = handler.precheck(current, currentF, fpath); + auto status = callsite_handler.precheck(current, currentF, fpath); switch (status) { case FilterAnalysis::Filter: fpath.pop(); @@ -119,7 +119,7 @@ class BaseFilter : public Filter { continue; } - llvm::CallSite c(csite.getValue()); + llvm::CallSite c(csite.value()); if (fpath.contains(c)) { // Avoid recursion: // TODO a continue may be wrong, if the function itself eventually calls "MPI"? @@ -151,7 +151,7 @@ class BaseFilter : public Filter { if (OmpHelper::isOmpExecutor(c)) { auto outlined = OmpHelper::getMicrotask(c); if (outlined) { - path2def.push(outlined.getValue()); + path2def.push(outlined.value()); } } } @@ -232,7 +232,7 @@ class BaseFilter : public Filter { // Indirect calls (sth. like function pointers) if (indirect_call) { if constexpr (CallSiteHandler::Support::Indirect) { - auto status = handler.indirect(site, path); + auto status = callsite_handler.indirect(site, path); LOG_DEBUG("Indirect call: " << util::try_demangle(site)) return status; } else { @@ -248,7 +248,7 @@ class BaseFilter : public Filter { if (is_decl) { if (is_intrinsic) { if constexpr (CallSiteHandler::Support::Intrinsic) { - auto status = handler.intrinsic(site, path); + auto status = callsite_handler.intrinsic(site, path); LOG_DEBUG("Intrinsic call: " << util::try_demangle(site)) return status; } else { @@ -272,7 +272,7 @@ class BaseFilter : public Filter { // Handle decl (like MPI calls) if constexpr (CallSiteHandler::Support::Declaration) { - auto status = handler.decl(site, path); + auto status = callsite_handler.decl(site, path); LOG_DEBUG("Decl call: " << util::try_demangle(site)) return status; } else { @@ -282,7 +282,7 @@ class BaseFilter : public Filter { } else { // Handle definitions if constexpr (CallSiteHandler::Support::Definition) { - auto status = handler.def(site, path); + auto status = callsite_handler.def(site, path); LOG_DEBUG("Defined call: " << util::try_demangle(site)) return status; } else { diff --git a/lib/passes/filter/FilterUtil.h b/lib/passes/filter/FilterUtil.h index 9b9a44a6..9878b8aa 100644 --- a/lib/passes/filter/FilterUtil.h +++ b/lib/passes/filter/FilterUtil.h @@ -19,8 +19,6 @@ #include "support/DefUseChain.h" #include "support/Logger.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" @@ -76,7 +74,7 @@ inline std::pair findArg(CallSite c, const Path& p) { return {nullptr, -1}; } - Value* in = arg.getValue(); + Value* in = arg.value(); const auto arg_pos = llvm::find_if(c.args(), [&in](const Use& arg_use) -> bool { return arg_use.get() == in; }); if (arg_pos == c.arg_end()) { @@ -90,7 +88,7 @@ inline std::pair findArg(CallSite c, const Path& p) { if (outlined) { // Calc the offset of arg in executor to actual arg of the outline function: auto offset = omp::OmpContext::getArgOffsetToMicrotask(c, arg_num); - Argument* argument = (outlined.getValue()->arg_begin() + offset); + Argument* argument = (outlined.value()->arg_begin() + offset); return {argument, offset}; } } @@ -139,10 +137,12 @@ ArgCorrelation correlate(CallSite c, const Path& p, TypeID&& isType) { } } // namespace detail +#if LLVM_VERSION_MAJOR < 15 inline ArgCorrelation correlate2void(CallSite c, const Path& p) { return detail::correlate( c, p, [](llvm::Type* type) { return type->isPointerTy() && type->getPointerElementType()->isIntegerTy(8); }); } +#endif inline ArgCorrelation correlate2pointer(CallSite c, const Path& p) { // weaker predicate than void pointer, but more generally applicable @@ -160,11 +160,11 @@ inline bool isTempAlloc(llvm::Value* in) { for (auto& args : f->args()) { if (&args == store->getValueOperand()) { match = true; - return util::DefUseChain::cancel; + return util::DefUseChain::kCancel; } } } - return util::DefUseChain::no_match; + return util::DefUseChain::kNoMatch; }); return match; diff --git a/lib/passes/filter/IRPath.h b/lib/passes/filter/IRPath.h index 23aafff2..ba10785e 100644 --- a/lib/passes/filter/IRPath.h +++ b/lib/passes/filter/IRPath.h @@ -15,12 +15,12 @@ #include "compat/CallSite.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Function.h" #include "llvm/IR/Value.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -35,25 +35,25 @@ struct IRPath { // we should likely skip search, see IRSearch.h std::unordered_map phi_cache; - llvm::Optional getStart() const { + std::optional getStart() const { if (path.empty()) { - return llvm::None; + return {}; } return *path.begin(); } - llvm::Optional getEnd() const { + std::optional getEnd() const { return getNodeFromEnd<1>(); } - llvm::Optional getEndPrev() const { + std::optional getEndPrev() const { return getNodeFromEnd<2>(); } template - llvm::Optional getNodeFromEnd() const { + std::optional getNodeFromEnd() const { if (path.empty() || path.size() < n) { - return llvm::None; + return {}; } return *std::prev(path.end(), n); } @@ -113,13 +113,13 @@ struct CallsitePath { using Node = std::pair; // Structure: [Function (start) or null for global]{1} -> [Path -> Function]* -> (Path)? - llvm::Optional start; + std::optional start; IRPath terminatingPath{}; std::vector intermediatePath; explicit CallsitePath(llvm::Function* root) { if (root == nullptr) { - start = llvm::None; + start = {}; } else { start = root; } @@ -133,32 +133,32 @@ struct CallsitePath { llvm::Function* getCurrentFunc() { if (intermediatePath.empty()) { if (start) { - return start.getValue(); + return start.value(); } return nullptr; } auto end = getEnd(); if (end) { - return end.getValue().first; + return end.value().first; } return nullptr; } - llvm::Optional getStart() const { + std::optional getStart() const { if (intermediatePath.empty()) { - return llvm::None; + return {}; } return *intermediatePath.begin(); } - llvm::Optional getEnd() const { + std::optional getEnd() const { return getNodeFromEnd<1>(); } template - llvm::Optional getNodeFromEnd() const { + std::optional getNodeFromEnd() const { if (intermediatePath.empty() || intermediatePath.size() < n) { - return llvm::None; + return {}; } return *std::prev(intermediatePath.end(), n); } @@ -167,11 +167,11 @@ struct CallsitePath { auto csite = p.getEnd(); if (csite) { // Omp extension: we may pass the outlined area directly as llvm::Function - if (auto f = llvm::dyn_cast(csite.getValue())) { + if (auto f = llvm::dyn_cast(csite.value())) { intermediatePath.emplace_back(f, p); return; } - llvm::CallSite c(csite.getValue()); + llvm::CallSite c(csite.value()); intermediatePath.emplace_back(c.getCalledFunction(), p); } } @@ -212,7 +212,7 @@ inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, const CallsitePath& if (vec.empty()) { os << "func_path = ["; if (p.start) { - os << p.start.getValue()->getName(); + os << p.start.value()->getName(); } else { os << "Module"; } diff --git a/lib/passes/filter/Matcher.h b/lib/passes/filter/Matcher.h index 66f54675..a5d56aaf 100644 --- a/lib/passes/filter/Matcher.h +++ b/lib/passes/filter/Matcher.h @@ -43,10 +43,10 @@ class NoMatcher final : public Matcher { }; class DefaultStringMatcher final : public Matcher { - Regex matcher; + llvm::Regex matcher; public: - explicit DefaultStringMatcher(const std::string& regex) : matcher(regex, Regex::NoFlags) { + explicit DefaultStringMatcher(const std::string& regex) : matcher(regex, llvm::Regex::NoFlags) { } MatchResult match(llvm::CallSite c) const override { @@ -75,20 +75,20 @@ class FunctionOracleMatcher final : public Matcher { const auto f = c.getCalledFunction(); if (f != nullptr) { const auto f_name = util::demangle(f->getName()); - StringRef f_name_ref{f_name}; + llvm::StringRef f_name_ref{f_name}; if (continue_set.count(f_name) > 0) { return MatchResult::ShouldContinue; } if (skip_set.count(f_name) > 0) { return MatchResult::ShouldSkip; } - if (f_name_ref.startswith("__typeart_")) { + if (util::starts_with_any_of(f_name_ref, "__typeart_")) { return MatchResult::ShouldSkip; } if (mem_operations.kind(f_name)) { return MatchResult::ShouldSkip; } - if (f_name_ref.startswith("__ubsan") || f_name_ref.startswith("__asan") || f_name_ref.startswith("__msan")) { + if (util::starts_with_any_of(f_name_ref, "__ubsan", "__asan", "__msan")) { return MatchResult::ShouldContinue; } } diff --git a/lib/passes/filter/OmpUtil.h b/lib/passes/filter/OmpUtil.h index 0cb798d5..31478ee0 100644 --- a/lib/passes/filter/OmpUtil.h +++ b/lib/passes/filter/OmpUtil.h @@ -13,16 +13,19 @@ #ifndef TYPEART_FILTER_OMPUTIL_H #define TYPEART_FILTER_OMPUTIL_H +#include "IRPath.h" #include "compat/CallSite.h" #include "support/DefUseChain.h" #include "support/OmpUtil.h" +#include "support/Util.h" -#include "llvm/ADT/Optional.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Operator.h" #include "llvm/Support/Casting.h" +#include + namespace typeart::filter::omp { struct EmptyContext { constexpr static bool WithOmp = false; @@ -35,7 +38,7 @@ struct OmpContext { const auto called = c.getCalledFunction(); if (called != nullptr) { // TODO probably not complete (openmp task?, see isOmpTask*()) - return called->getName().startswith("__kmpc_fork_call"); + return util::starts_with_any_of(called->getName(), "__kmpc_fork_call"); } return false; } @@ -43,7 +46,7 @@ struct OmpContext { static bool isOmpTaskAlloc(const llvm::CallSite& c) { const auto called = c.getCalledFunction(); if (called != nullptr) { - return called->getName().startswith("__kmpc_omp_task_alloc"); + return util::starts_with_any_of(called->getName(), "__kmpc_omp_task_alloc"); } return false; } @@ -51,7 +54,7 @@ struct OmpContext { static bool isOmpTaskCall(const llvm::CallSite& c) { const auto called = c.getCalledFunction(); if (called != nullptr) { - return called->getName().endswith("__kmpc_omp_task"); + return util::ends_with_any_of(called->getName(), "__kmpc_omp_task"); } return false; } @@ -59,7 +62,7 @@ struct OmpContext { static bool isOmpTaskRelated(const llvm::CallSite& c) { const auto called = c.getCalledFunction(); if (called != nullptr) { - return called->getName().startswith("__kmpc_omp_task"); + return util::starts_with_any_of(called->getName(), "__kmpc_omp_task"); } return false; } @@ -69,15 +72,14 @@ struct OmpContext { if (!is_execute) { const auto called = c.getCalledFunction(); if (called != nullptr) { - const auto name = called->getName(); // TODO extend this if required - return name.startswith("__kmpc") || name.startswith("omp_"); + return util::starts_with_any_of(called->getName(), "__kmpc", "omp_"); } } return false; } - static llvm::Optional getMicrotask(const llvm::CallSite& c) { + static std::optional getMicrotask(const llvm::CallSite& c) { using namespace llvm; if (isOmpExecutor(c)) { auto f = llvm::dyn_cast(c.getArgOperand(2)->stripPointerCasts()); @@ -87,7 +89,7 @@ struct OmpContext { auto f = llvm::dyn_cast(c.getArgOperand(5)->stripPointerCasts()); return {f}; } - return llvm::None; + return {}; } static bool canDiscardMicrotaskArg(llvm::CallSite c, const Path& path) { @@ -97,7 +99,7 @@ struct OmpContext { return false; } - Value* in = arg.getValue(); + Value* in = arg.value(); const auto arg_pos = llvm::find_if(c.args(), [&in](const Use& arg_use) -> bool { return arg_use.get() == in; }); if (arg_pos == c.arg_end()) { @@ -130,7 +132,7 @@ struct OmpContext { util::DefUseChain finder; finder.traverse_custom( alloc, - [](auto val) -> llvm::Optionalusers())> { + [](auto val) -> std::optionalusers())> { if (auto cinst = llvm::dyn_cast(val)) { return cinst->getValueOperand()->users(); } @@ -140,12 +142,13 @@ struct OmpContext { llvm::CallSite site(value); if (site.isCall() || site.isInvoke()) { const auto called = site.getCalledFunction(); - if (called != nullptr && called->getName().startswith("__kmpc_omp_task(")) { + + if (called != nullptr && util::starts_with_any_of(called->getName(), "__kmpc_omp_task(")) { found = true; - return util::DefUseChain::cancel; + return util::DefUseChain::kCancel; } } - return util::DefUseChain::no_match; + return util::DefUseChain::kNoMatch; }); return found; } @@ -167,9 +170,9 @@ struct OmpContext { auto calls = util::find_all(f, [&](auto& inst) { llvm::CallSite s(&inst); if (s.isCall() || s.isInvoke()) { - if (auto f = s.getCalledFunction()) { + if (auto called_function = s.getCalledFunction()) { // once true, the find_all should cancel - return f->getName().startswith("__kmpc_omp_task_alloc"); + return util::starts_with_any_of(called_function->getName(), "__kmpc_omp_task_alloc"); } } return false; @@ -181,9 +184,9 @@ struct OmpContext { chain.traverse(i, [&v, &found](auto val) { if (v == val) { found = true; - return util::DefUseChain::cancel; + return util::DefUseChain::kCancel; } - return util::DefUseChain::no_match; + return util::DefUseChain::kNoMatch; }); if (found) { return true; diff --git a/lib/passes/filter/StdForwardFilter.cpp b/lib/passes/filter/StdForwardFilter.cpp index ada09390..24a14beb 100644 --- a/lib/passes/filter/StdForwardFilter.cpp +++ b/lib/passes/filter/StdForwardFilter.cpp @@ -74,10 +74,15 @@ FilterAnalysis filter::ForwardFilterImpl::precheck(Value* in, Function* start, c FilterAnalysis filter::ForwardFilterImpl::decl(CallSite current, const Path& p) const { const bool match_sig = matcher->match(current) == Matcher::MatchResult::Match; + LOG_DEBUG("Matched sig: " << match_sig) if (match_sig) { // if we have a deep_matcher it needs to trigger, otherwise analyze if (!deep_matcher || deep_matcher->match(current) == Matcher::MatchResult::Match) { +#if LLVM_VERSION_MAJOR < 15 auto result = correlate2void(current, p); +#else + auto result = correlate2pointer(current, p); +#endif switch (result) { case ArgCorrelation::GlobalMismatch: [[fallthrough]]; @@ -110,7 +115,11 @@ FilterAnalysis filter::ForwardFilterImpl::def(CallSite current, const Path& p) c const bool match_sig = matcher->match(current) == Matcher::MatchResult::Match; if (match_sig) { if (!deep_matcher || deep_matcher->match(current) == Matcher::MatchResult::Match) { +#if LLVM_VERSION_MAJOR < 15 auto result = correlate2void(current, p); +#else + auto result = correlate2pointer(current, p); +#endif switch (result) { case ArgCorrelation::GlobalMismatch: [[fallthrough]]; diff --git a/lib/passes/instrumentation/Instrumentation.h b/lib/passes/instrumentation/Instrumentation.h index 556293dc..c32bae1d 100644 --- a/lib/passes/instrumentation/Instrumentation.h +++ b/lib/passes/instrumentation/Instrumentation.h @@ -49,7 +49,7 @@ struct ArgMap { } /* - const llvm::Optional operator[](ArgsContainer::key_type key) const { + const std::optional operator[](ArgsContainer::key_type key) const { auto it = args.find(key); if (it != args.end()) { return {it->second}; diff --git a/lib/passes/instrumentation/InstrumentationHelper.cpp b/lib/passes/instrumentation/InstrumentationHelper.cpp index 9a766378..7467847a 100644 --- a/lib/passes/instrumentation/InstrumentationHelper.cpp +++ b/lib/passes/instrumentation/InstrumentationHelper.cpp @@ -15,8 +15,6 @@ #include "support/Logger.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" @@ -25,6 +23,8 @@ #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" +#include + namespace typeart { using namespace llvm; @@ -44,7 +44,12 @@ llvm::Type* InstrumentationHelper::getTypeFor(IType id) { auto& c = module->getContext(); switch (id) { case IType::ptr: +#if LLVM_VERSION_MAJOR < 15 return Type::getInt8PtrTy(c); +#else + // TODO which address space? + return PointerType::get(c, 0); +#endif case IType::function_id: return Type::getInt32Ty(c); case IType::extent: @@ -62,15 +67,15 @@ llvm::Type* InstrumentationHelper::getTypeFor(IType id) { } llvm::ConstantInt* InstrumentationHelper::getConstantFor(IType id, size_t value) { - const auto make_int = [&]() -> Optional { + const auto make_int = [&]() -> std::optional { auto itype = dyn_cast_or_null(getTypeFor(id)); if (itype == nullptr) { LOG_FATAL("Pointer for the constant type is null, need aborting..."); - return None; + return {}; } return ConstantInt::get(itype, value); }; - return make_int().getValue(); + return make_int().value(); } void InstrumentationHelper::setModule(llvm::Module& m) { diff --git a/lib/passes/instrumentation/InstrumentationHelper.h b/lib/passes/instrumentation/InstrumentationHelper.h index c4c15bea..081f1d5d 100644 --- a/lib/passes/instrumentation/InstrumentationHelper.h +++ b/lib/passes/instrumentation/InstrumentationHelper.h @@ -14,7 +14,6 @@ #define LIB_INSTRUMENTATIONHELPER_H_ #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" diff --git a/lib/passes/instrumentation/MemOpArgCollector.cpp b/lib/passes/instrumentation/MemOpArgCollector.cpp index 09715e60..2da62cf5 100644 --- a/lib/passes/instrumentation/MemOpArgCollector.cpp +++ b/lib/passes/instrumentation/MemOpArgCollector.cpp @@ -14,6 +14,8 @@ #include "Instrumentation.h" #include "InstrumentationHelper.h" +#include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/TypeUtil.h" #include "support/Util.h" @@ -39,14 +41,18 @@ using namespace llvm; namespace typeart { -MemOpArgCollector::MemOpArgCollector(TypeGenerator* tm, InstrumentationHelper& instr) - : ArgumentCollector(), type_m(tm), instr_helper(&instr) { +MemOpArgCollector::MemOpArgCollector(const config::Configuration& typeart_conf, TypeGenerator* tm, + InstrumentationHelper& instr) + : ArgumentCollector(), typeart_config(typeart_conf), type_m(tm), instr_helper(&instr) { } HeapArgList MemOpArgCollector::collectHeap(const MallocDataList& mallocs) { HeapArgList list; list.reserve(mallocs.size()); + TypegenImplementation type_gen = typeart_config[config::ConfigStdArgs::typegen]; + const bool is_llvm_ir_type = static_cast(type_gen) == static_cast(TypegenImplementation::IR); + for (const MallocData& mdata : mallocs) { ArgMap arg_map; const auto malloc_call = mdata.call; @@ -58,7 +64,7 @@ HeapArgList MemOpArgCollector::collectHeap(const MallocDataList& mallocs) { continue; } - const auto type_size = type_m->getTypeDatabase().getTypeSize(type_id); + auto type_size = type_m->getTypeDatabase().getTypeSize(type_id); LOG_DEBUG("Type " << type_id << " with " << type_size << " and num elems " << num_elements) @@ -74,8 +80,8 @@ HeapArgList MemOpArgCollector::collectHeap(const MallocDataList& mallocs) { case MemOpKind::NewLike: [[fallthrough]]; case MemOpKind::MallocLike: - if (mdata.array_cookie.hasValue()) { - auto array_cookie_data = mdata.array_cookie.getValue(); + if (mdata.array_cookie) { + auto array_cookie_data = mdata.array_cookie.value(); element_count = array_cookie_data.cookie_store->getValueOperand(); pointer = array_cookie_data.array_ptr_gep; } @@ -84,7 +90,7 @@ HeapArgList MemOpArgCollector::collectHeap(const MallocDataList& mallocs) { break; case MemOpKind::CallocLike: { - if (mdata.primary == nullptr) { + if (mdata.primary == nullptr && is_llvm_ir_type) { // we need the second arg when the calloc type is identified as void* to calculate total bytes allocated type_size_const = malloc_call->getOperand(1); } @@ -129,8 +135,8 @@ FreeArgList MemOpArgCollector::collectFree(const FreeDataList& frees) { case MemOpKind::DeleteLike: [[fallthrough]]; case MemOpKind::FreeLike: - free_arg = fdata.array_cookie_gep.hasValue() ? fdata.array_cookie_gep.getValue()->getPointerOperand() - : free_call->getOperand(0); + free_arg = + fdata.array_cookie_gep ? fdata.array_cookie_gep.value()->getPointerOperand() : free_call->getOperand(0); break; default: LOG_ERROR("Unknown free kind. Not instrumenting. " << util::dump(*free_call)); @@ -160,7 +166,10 @@ StackArgList MemOpArgCollector::collectStack(const AllocaDataList& allocs) { continue; } - const auto type_size = type_m->getTypeDatabase().getTypeSize(type_id); + auto type_size = type_m->getTypeDatabase().getTypeSize(type_id); + if (type_id == TYPEART_VOID) { + type_size = 1; + } LOG_DEBUG("Alloca Type " << type_id << " with " << type_size << " and num elems " << num_elements) @@ -204,6 +213,10 @@ GlobalArgList MemOpArgCollector::collectGlobal(const GlobalDataList& globals) { } auto type_size = type_m->getTypeDatabase().getTypeSize(type_id); + if (type_id == TYPEART_VOID) { + type_size = 1; + } + LOG_DEBUG("Global Type " << type_id << " with " << type_size << " and num elems " << num_elements) auto* type_id_const = instr_helper->getConstantFor(IType::type_id, type_id); diff --git a/lib/passes/instrumentation/MemOpArgCollector.h b/lib/passes/instrumentation/MemOpArgCollector.h index 74ec0a03..5ccd1a0d 100644 --- a/lib/passes/instrumentation/MemOpArgCollector.h +++ b/lib/passes/instrumentation/MemOpArgCollector.h @@ -15,17 +15,22 @@ #include "Instrumentation.h" #include "analysis/MemOpData.h" +#include "configuration/Configuration.h" namespace typeart { +namespace config { +class Configuration; +} class TypeGenerator; class InstrumentationHelper; class MemOpArgCollector final : public ArgumentCollector { + const config::Configuration& typeart_config; TypeGenerator* type_m; InstrumentationHelper* instr_helper; public: - MemOpArgCollector(TypeGenerator*, InstrumentationHelper&); + MemOpArgCollector(const config::Configuration&, TypeGenerator*, InstrumentationHelper&); HeapArgList collectHeap(const MallocDataList& mallocs) override; FreeArgList collectFree(const FreeDataList& frees) override; StackArgList collectStack(const AllocaDataList& allocs) override; diff --git a/lib/passes/instrumentation/MemOpInstrumentation.cpp b/lib/passes/instrumentation/MemOpInstrumentation.cpp index a3bfec15..5a763dc2 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.cpp +++ b/lib/passes/instrumentation/MemOpInstrumentation.cpp @@ -16,10 +16,14 @@ #include "InstrumentationHelper.h" #include "TransformUtil.h" #include "TypeARTFunctions.h" +#include "TypeInterface.h" #include "analysis/MemOpData.h" +#include "configuration/Configuration.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" #include "support/OmpUtil.h" #include "support/Util.h" +#include "typegen/TypeGenerator.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/IR/BasicBlock.h" @@ -31,6 +35,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" @@ -46,73 +51,87 @@ using namespace llvm; namespace typeart { -MemOpInstrumentation::MemOpInstrumentation(TAFunctionQuery& fquery, InstrumentationHelper& instr, - bool lifetime_instrument) - : MemoryInstrument(), fquery(&fquery), instr_helper(&instr), instrument_lifetime(lifetime_instrument) { +MemOpInstrumentation::MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery& fquery, + InstrumentationHelper& instr) + : MemoryInstrument(), typeart_config(typeart_conf), function_query(&fquery), instrumentation_helper(&instr) { + instrument_lifetime = typeart_config[config::ConfigStdArgs::stack_lifetime]; } InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { InstrCount counter{0}; + auto type_gen = typeart_config[config::ConfigStdArgs::typegen]; + const bool is_llvm_ir_type = static_cast(type_gen) == static_cast(TypegenImplementation::IR); for (const auto& [malloc, args] : heap) { - auto kind = malloc.kind; - Instruction* malloc_call = args.get_as(ArgMap::ID::pointer); + auto kind = malloc.kind; + auto* malloc_call = args.get_as(ArgMap::ID::pointer); Instruction* insertBefore = malloc_call->getNextNode(); - if (malloc.array_cookie.hasValue()) { - insertBefore = malloc.array_cookie.getValue().array_ptr_gep->getNextNode(); + if (malloc.array_cookie) { + insertBefore = malloc.array_cookie.value().array_ptr_gep->getNextNode(); } else { if (malloc.is_invoke) { - const InvokeInst* inv = dyn_cast(malloc_call); - insertBefore = &(*inv->getNormalDest()->getFirstInsertionPt()); + const auto* inv = dyn_cast(malloc_call); + insertBefore = &(*inv->getNormalDest()->getFirstInsertionPt()); } } IRBuilder<> IRB(insertBefore); - auto typeIdConst = args.get_value(ArgMap::ID::type_id); - auto typeSizeConst = args.get_value(ArgMap::ID::type_size); + auto typeid_value = args.get_as(ArgMap::ID::type_id); + auto type_size_value = args.get_value(ArgMap::ID::type_size); bool single_byte_type{false}; - if (auto* const_int = llvm::dyn_cast(typeSizeConst)) { + if (auto* const_int = llvm::dyn_cast(type_size_value)) { single_byte_type = const_int->equalsInt(1); } - Value* elementCount{nullptr}; + Value* element_count{nullptr}; auto parent_f = malloc.call->getFunction(); const bool omp = util::omp::isOmpContext(parent_f); + const bool dimeta_calc_byte_size = !is_llvm_ir_type && (typeid_value->equalsInt(TYPEART_VOID)); + + const auto calculate_element_count = [&](const auto bytes) { + if (!(single_byte_type || dimeta_calc_byte_size)) { + return IRB.CreateUDiv(bytes, type_size_value); + } + return bytes; + }; + switch (kind) { case MemOpKind::AlignedAllocLike: [[fallthrough]]; case MemOpKind::NewLike: [[fallthrough]]; case MemOpKind::MallocLike: { - elementCount = args.lookup(ArgMap::ID::element_count); - if (elementCount == nullptr) { - auto bytes = args.get_value(ArgMap::ID::byte_count); // can be null (for calloc, realloc) - elementCount = single_byte_type ? bytes : IRB.CreateUDiv(bytes, typeSizeConst); + element_count = args.lookup(ArgMap::ID::element_count); + if (element_count == nullptr || dimeta_calc_byte_size) { + auto bytes = args.get_value(ArgMap::ID::byte_count); // can be null (for calloc, realloc) + element_count = calculate_element_count(bytes); } break; } case MemOpKind::CallocLike: { - if (malloc.primary == nullptr) { + const bool lacks_bitcast = malloc.primary == nullptr && is_llvm_ir_type; + if (lacks_bitcast || dimeta_calc_byte_size) { auto elems = args.get_value(ArgMap::ID::element_count); auto type_size = args.get_value(ArgMap::ID::type_size); - elementCount = IRB.CreateMul(elems, type_size); + element_count = IRB.CreateMul(elems, type_size); } else { - elementCount = args.get_value(ArgMap::ID::element_count); + element_count = args.get_value(ArgMap::ID::element_count); } break; } case MemOpKind::ReallocLike: { - auto mArg = args.get_value(ArgMap::ID::byte_count); - auto addrOp = args.get_value(ArgMap::ID::realloc_ptr); + auto bytes = args.get_value(ArgMap::ID::byte_count); + auto target_memory_address = args.get_value(ArgMap::ID::realloc_ptr); + element_count = calculate_element_count(bytes); - elementCount = single_byte_type ? mArg : IRB.CreateUDiv(mArg, typeSizeConst); - IRBuilder<> FreeB(malloc_call); + IRBuilder<> free_before_realloc(malloc_call); const auto callback_id = omp ? IFunc::free_omp : IFunc::free; - FreeB.CreateCall(fquery->getFunctionFor(callback_id), ArrayRef{addrOp}); + free_before_realloc.CreateCall(function_query->getFunctionFor(callback_id), + ArrayRef{target_memory_address}); break; } default: @@ -121,7 +140,8 @@ InstrCount MemOpInstrumentation::instrumentHeap(const HeapArgList& heap) { } const auto callback_id = omp ? IFunc::heap_omp : IFunc::heap; - IRB.CreateCall(fquery->getFunctionFor(callback_id), ArrayRef{malloc_call, typeIdConst, elementCount}); + IRB.CreateCall(function_query->getFunctionFor(callback_id), + ArrayRef{malloc_call, typeid_value, element_count}); ++counter; } @@ -157,7 +177,7 @@ InstrCount MemOpInstrumentation::instrumentFree(const FreeArgList& frees) { auto parent_f = fdata.call->getFunction(); const auto callback_id = util::omp::isOmpContext(parent_f) ? IFunc::free_omp : IFunc::free; - IRB.CreateCall(fquery->getFunctionFor(callback_id), ArrayRef{free_arg}); + IRB.CreateCall(function_query->getFunctionFor(callback_id), ArrayRef{free_arg}); ++counter; } @@ -176,7 +196,8 @@ InstrCount MemOpInstrumentation::instrumentStack(const StackArgList& stack) { const auto instrument_stack = [&](IRBuilder<>& IRB, Value* data_ptr, Instruction* anchor) { const auto callback_id = util::omp::isOmpContext(anchor->getFunction()) ? IFunc::stack_omp : IFunc::stack; - IRB.CreateCall(fquery->getFunctionFor(callback_id), ArrayRef{data_ptr, typeIdConst, numElementsVal}); + IRB.CreateCall(function_query->getFunctionFor(callback_id), + ArrayRef{data_ptr, typeIdConst, numElementsVal}); ++counter; auto* bblock = anchor->getParent(); @@ -189,7 +210,7 @@ InstrCount MemOpInstrumentation::instrumentStack(const StackArgList& stack) { const auto& lifetime_starts = sdata.lifetime_start; if (lifetime_starts.empty() || !instrument_lifetime) { IRBuilder<> IRB(alloca->getNextNode()); - auto* data_ptr = IRB.CreateBitOrPointerCast(alloca, instr_helper->getTypeFor(IType::ptr)); + auto* data_ptr = IRB.CreateBitOrPointerCast(alloca, instrumentation_helper->getTypeFor(IType::ptr)); instrument_stack(IRB, data_ptr, alloca); } else { for (auto* lifetime_s : lifetime_starts) { @@ -200,7 +221,7 @@ InstrCount MemOpInstrumentation::instrumentStack(const StackArgList& stack) { } if (function != nullptr) { - StackCounter scount(function, instr_helper, fquery); + StackCounter scount(function, instrumentation_helper, function_query); scount.addStackHandling(allocCounts); } @@ -216,14 +237,15 @@ InstrCount MemOpInstrumentation::instrumentGlobal(const GlobalArgList& globals) auto global = gdata.global; auto typeIdConst = args.get_value(ArgMap::ID::type_id); auto numElementsVal = args.get_value(ArgMap::ID::element_count); - auto globalPtr = IRB.CreateBitOrPointerCast(global, instr_helper->getTypeFor(IType::ptr)); - IRB.CreateCall(fquery->getFunctionFor(IFunc::global), ArrayRef{globalPtr, typeIdConst, numElementsVal}); + auto globalPtr = IRB.CreateBitOrPointerCast(global, instrumentation_helper->getTypeFor(IType::ptr)); + IRB.CreateCall(function_query->getFunctionFor(IFunc::global), + ArrayRef{globalPtr, typeIdConst, numElementsVal}); ++counter; } }; const auto makeCtorFuncBody = [&]() -> BasicBlock* { - auto m = instr_helper->getModule(); + auto m = instrumentation_helper->getModule(); auto& c = m->getContext(); auto ctorFunctionName = "__typeart_init_module_globals"; // + m->getSourceFileName(); // needed -- will not work with piping? diff --git a/lib/passes/instrumentation/MemOpInstrumentation.h b/lib/passes/instrumentation/MemOpInstrumentation.h index 10e2520e..0a8bd442 100644 --- a/lib/passes/instrumentation/MemOpInstrumentation.h +++ b/lib/passes/instrumentation/MemOpInstrumentation.h @@ -14,19 +14,24 @@ #define TYPEART_MEMOPINSTRUMENTATION_H #include "Instrumentation.h" +#include "configuration/Configuration.h" namespace typeart { - +namespace config { +class Configuration; +} class TAFunctionQuery; class InstrumentationHelper; class MemOpInstrumentation final : public MemoryInstrument { - TAFunctionQuery* fquery; - InstrumentationHelper* instr_helper; + const config::Configuration& typeart_config; + TAFunctionQuery* function_query; + InstrumentationHelper* instrumentation_helper; bool instrument_lifetime{false}; public: - MemOpInstrumentation(TAFunctionQuery& fquery, InstrumentationHelper& instr, bool lifetime_instrument = false); + MemOpInstrumentation(const config::Configuration& typeart_conf, TAFunctionQuery& fquery, + InstrumentationHelper& instr); InstrCount instrumentHeap(const HeapArgList& heap) override; InstrCount instrumentFree(const FreeArgList& frees) override; InstrCount instrumentStack(const StackArgList& stack) override; diff --git a/lib/passes/instrumentation/TransformUtil.h b/lib/passes/instrumentation/TransformUtil.h index 68c4f464..056e5927 100644 --- a/lib/passes/instrumentation/TransformUtil.h +++ b/lib/passes/instrumentation/TransformUtil.h @@ -26,49 +26,52 @@ namespace typeart::transform { struct StackCounter { using StackOpCounter = llvm::SmallDenseMap; - llvm::Function* f; - InstrumentationHelper* instr_helper; - TAFunctionQuery* fquery; + llvm::Function* target_function; + InstrumentationHelper* instrumentation_helper; + TAFunctionQuery* function_query; StackCounter(llvm::Function* f, InstrumentationHelper* instr, TAFunctionQuery* query) - : f(f), instr_helper(instr), fquery(query) { + : target_function(f), instrumentation_helper(instr), function_query(query) { } void addStackHandling(StackOpCounter& allocCounts) const { using namespace llvm; // LOG_DEBUG("Add alloca counter") // counter = 0 at beginning of function - IRBuilder<> CBuilder(f->getEntryBlock().getFirstNonPHI()); - auto* counter = CBuilder.CreateAlloca(instr_helper->getTypeFor(IType::stack_count), nullptr, "__ta_alloca_counter"); - CBuilder.CreateStore(instr_helper->getConstantFor(IType::stack_count), counter); + IRBuilder<> CBuilder(target_function->getEntryBlock().getFirstNonPHI()); + auto* counter = + CBuilder.CreateAlloca(instrumentation_helper->getTypeFor(IType::stack_count), nullptr, "__ta_alloca_counter"); + CBuilder.CreateStore(instrumentation_helper->getConstantFor(IType::stack_count), counter); // In each basic block: counter =+ num_alloca (in BB) for (auto data : allocCounts) { IRBuilder<> IRB(data.first->getTerminator()); - auto* load_counter = IRB.CreateLoad(instr_helper->getTypeFor(IType::stack_count), counter); + auto* load_counter = IRB.CreateLoad(instrumentation_helper->getTypeFor(IType::stack_count), counter); Value* increment_counter = - IRB.CreateAdd(instr_helper->getConstantFor(IType::stack_count, data.second), load_counter); + IRB.CreateAdd(instrumentation_helper->getConstantFor(IType::stack_count, data.second), load_counter); IRB.CreateStore(increment_counter, counter); } // Find return instructions: // if(counter > 0) call runtime for stack cleanup - const auto callback_id = util::omp::isOmpContext(f) ? IFunc::scope_omp : IFunc::scope; + const auto callback_id = util::omp::isOmpContext(target_function) ? IFunc::scope_omp : IFunc::scope; - EscapeEnumerator ee(*f); + EscapeEnumerator ee(*target_function); while (IRBuilder<>* irb = ee.Next()) { - auto* I = &(*irb->GetInsertPoint()); - auto* counter_load = irb->CreateLoad(instr_helper->getTypeFor(IType::stack_count), counter, "__ta_counter_load"); + auto* I = &(*irb->GetInsertPoint()); + auto* counter_load = + irb->CreateLoad(instrumentation_helper->getTypeFor(IType::stack_count), counter, "__ta_counter_load"); const auto all_preds_have_counter = llvm::all_of( llvm::predecessors(I->getParent()), [&allocCounts](const auto* bb) { return allocCounts.count(bb) > 0; }); if (!all_preds_have_counter) { - auto* cond = irb->CreateICmpNE(counter_load, instr_helper->getConstantFor(IType::stack_count), "__ta_cond"); + auto* cond = + irb->CreateICmpNE(counter_load, instrumentation_helper->getConstantFor(IType::stack_count), "__ta_cond"); auto* then_term = SplitBlockAndInsertIfThen(cond, I, false); irb->SetInsertPoint(then_term); } - irb->CreateCall(fquery->getFunctionFor(callback_id), ArrayRef{counter_load}); + irb->CreateCall(function_query->getFunctionFor(callback_id), ArrayRef{counter_load}); } } }; diff --git a/lib/passes/instrumentation/TypeARTFunctions.cpp b/lib/passes/instrumentation/TypeARTFunctions.cpp index 6ca5a629..f4955ec3 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.cpp +++ b/lib/passes/instrumentation/TypeARTFunctions.cpp @@ -37,21 +37,22 @@ using namespace llvm; namespace typeart { -TAFunctionDeclarator::TAFunctionDeclarator(Module& m, InstrumentationHelper&, TAFunctions& tafunc) - : m(m), tafunc(tafunc) { +TAFunctionDeclarator::TAFunctionDeclarator(Module& mod, InstrumentationHelper&, TAFunctions& typeart_funcs) + : module(mod), typeart_functions(typeart_funcs) { } -llvm::Function* TAFunctionDeclarator::make_function(IFunc id, llvm::StringRef basename, +llvm::Function* TAFunctionDeclarator::make_function(IFunc func_id, llvm::StringRef basename, llvm::ArrayRef args, bool with_omp, bool fixed_name) { - const auto make_fname = [&fixed_name](llvm::StringRef name, llvm::ArrayRef args, bool with_omp) { + const auto make_fname = [&fixed_name](llvm::StringRef name, llvm::ArrayRef callback_arguments, + bool with_omp_postfix) { std::string fname; llvm::raw_string_ostream os(fname); os << name; if (!fixed_name) { - os << "_" << std::to_string(args.size()); + os << "_" << std::to_string(callback_arguments.size()); } - if (with_omp) { + if (with_omp_postfix) { os << "_" << "omp"; } @@ -60,11 +61,11 @@ llvm::Function* TAFunctionDeclarator::make_function(IFunc id, llvm::StringRef ba const auto name = make_fname(basename, args, with_omp); - if (auto it = f_map.find(name); it != f_map.end()) { + if (auto it = function_map.find(name); it != function_map.end()) { return it->second; } - auto& c = m.getContext(); + auto& c = module.getContext(); const auto addOptimizerAttributes = [&](llvm::Function* function) { function->setDoesNotThrow(); function->setDoesNotFreeMemory(); @@ -84,13 +85,13 @@ llvm::Function* TAFunctionDeclarator::make_function(IFunc id, llvm::StringRef ba function->setLinkage(GlobalValue::ExternalLinkage); // f->setLinkage(GlobalValue::ExternalWeakLinkage); }; - const auto do_make = [&](auto& name, auto f_type) { - const bool has_func_declared = m.getFunction(name) != nullptr; - auto func_in_module = m.getOrInsertFunction(name, f_type); + const auto do_make = [&](auto& function_name, auto function_type) { + const bool has_func_declared = module.getFunction(function_name) != nullptr; + auto func_in_module = module.getOrInsertFunction(function_name, function_type); Function* function{nullptr}; if (has_func_declared) { - LOG_WARNING("Function " << name << " is already declared in the module.") + LOG_WARNING("Function " << function_name << " is already declared in the module.") function = dyn_cast(func_in_module.getCallee()->stripPointerCasts()); } else { function = dyn_cast(func_in_module.getCallee()); @@ -101,17 +102,17 @@ llvm::Function* TAFunctionDeclarator::make_function(IFunc id, llvm::StringRef ba return function; }; - auto f = do_make(name, FunctionType::get(Type::getVoidTy(c), args, false)); + auto generated_function = do_make(name, FunctionType::get(Type::getVoidTy(c), args, false)); - f_map[name] = f; + function_map[name] = generated_function; - tafunc.putFunctionFor(id, f); + typeart_functions.putFunctionFor(func_id, generated_function); - return f; + return generated_function; } const llvm::StringMap& TAFunctionDeclarator::getFunctionMap() const { - return f_map; + return function_map; } TAFunctions::TAFunctions() = default; diff --git a/lib/passes/instrumentation/TypeARTFunctions.h b/lib/passes/instrumentation/TypeARTFunctions.h index 9f6ec1f2..d707a933 100644 --- a/lib/passes/instrumentation/TypeARTFunctions.h +++ b/lib/passes/instrumentation/TypeARTFunctions.h @@ -61,13 +61,13 @@ class TAFunctions : public TAFunctionQuery { }; class TAFunctionDeclarator { - llvm::Module& m; + llvm::Module& module; // [[maybe_unused]] InstrumentationHelper& instr; - TAFunctions& tafunc; - llvm::StringMap f_map; + TAFunctions& typeart_functions; + llvm::StringMap function_map; public: - TAFunctionDeclarator(llvm::Module& m, InstrumentationHelper& instr, TAFunctions& tafunc); + TAFunctionDeclarator(llvm::Module& m, InstrumentationHelper& instr, TAFunctions& typeart_func); llvm::Function* make_function(IFunc function, llvm::StringRef basename, llvm::ArrayRef args, bool with_omp = false, bool fixed_name = true); const llvm::StringMap& getFunctionMap() const; diff --git a/lib/passes/support/DefUseChain.h b/lib/passes/support/DefUseChain.h index 327827c8..6d14928f 100644 --- a/lib/passes/support/DefUseChain.h +++ b/lib/passes/support/DefUseChain.h @@ -21,12 +21,13 @@ #include #include +#include namespace typeart::util { struct DefUseChain { public: - enum MatchResult { no_match = 0, match, cancel, skip }; + enum MatchResult { kNoMatch = 0, kMatch, kCancel, kSkip }; private: llvm::SmallVector working_set; @@ -51,8 +52,9 @@ struct DefUseChain { return nullptr; } auto user_iter = working_set.end() - 1; + auto* value = *user_iter; working_set.erase(user_iter); - return *user_iter; + return value; } template @@ -63,7 +65,7 @@ struct DefUseChain { const auto apply_search = [&](auto val) { auto value = search(val); if (value) { - addToWork(value.getValue()); + addToWork(value.value()); } }; @@ -74,11 +76,11 @@ struct DefUseChain { if (user == nullptr) { continue; } - if (MatchResult m = match(user); m != no_match) { + if (MatchResult m = match(user); m != kNoMatch) { switch (m) { - case skip: + case kSkip: continue; - case cancel: + case kCancel: break; default: break; @@ -96,7 +98,7 @@ struct DefUseChain { template void traverse(llvm::Value* start, CallBackF&& match) { LOG_DEBUG("Start traversal for value: " << util::dump(*start)); - do_traverse([](auto val) -> llvm::Optionalusers())> { return val->users(); }, start, + do_traverse([](auto val) -> std::optionalusers())> { return val->users(); }, start, std::forward(match)); LOG_DEBUG("Finished traversal"); } @@ -112,7 +114,7 @@ struct DefUseChain { void traverse_with_store(llvm::Value* start, CallBackF&& match) { LOG_DEBUG("Start traversal for value: " << util::dump(*start)); do_traverse( - [](auto val) -> llvm::Optionalusers())> { + [](auto val) -> std::optionalusers())> { if (auto cinst = llvm::dyn_cast(val)) { return cinst->getPointerOperand()->users(); } diff --git a/lib/passes/support/Error.h b/lib/passes/support/Error.h index 50b2e7e9..cea1e86e 100644 --- a/lib/passes/support/Error.h +++ b/lib/passes/support/Error.h @@ -15,15 +15,35 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" +#include + namespace typeart::error { +#define RETURN_NONE_IF(condition, ...) \ + if (condition) { \ + std::string message = llvm::formatv(__VA_ARGS__); \ + LOG_DEBUG(message); \ + return {}; \ + } + +#define RETURN_ON_NONE(expr) \ + if (!(expr)) { \ + return {}; \ + } + #define RETURN_ON_ERROR(expr) \ if (auto err = (expr).takeError()) { \ return {std::move(err)}; \ } inline llvm::Error make_string_error(const char* message) { - return llvm::make_error(llvm::inconvertibleErrorCode(), message); + return llvm::createStringError(llvm::inconvertibleErrorCode(), message); + // return llvm::make_error(llvm::inconvertibleErrorCode(), message); +} + +inline llvm::Error make_string_error(const std::string& message) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), message); + // return llvm::make_error( message); } #define RETURN_ERROR_IF(condition, ...) \ diff --git a/lib/passes/support/ModuleDumper.cpp b/lib/passes/support/ModuleDumper.cpp new file mode 100644 index 00000000..40148268 --- /dev/null +++ b/lib/passes/support/ModuleDumper.cpp @@ -0,0 +1,79 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#include "ModuleDumper.h" + +#include "support/Logger.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +namespace typeart::util::module::detail { + +void dump_module(const llvm::Module& module, llvm::raw_ostream& out_s) { + module.print(out_s, nullptr); +} + +std::string_view gets_source_file(const llvm::Module& module) { + return module.getSourceFileName(); +} + +std::string_view get_file_ext(ModulePhase phase) { + switch (phase) { + case ModulePhase::kBase: + return "_base.ll"; + case ModulePhase::kHeap: + return "_heap.ll"; + case ModulePhase::kOpt: + return "_opt.ll"; + case ModulePhase::kStack: + return "_stack.ll"; + } + return "_unknown.ll"; +} + +} // namespace typeart::util::module::detail + +namespace typeart::util::module { + +void dump_module(const llvm::Module& module, ModulePhase phase) { + if (std::getenv("TYPEART_PASS_INTERNAL_EMIT_IR") == nullptr) { + LOG_DEBUG("No dump required") + return; + } + + const auto source = std::filesystem::path{detail::gets_source_file(module)}; + + if (!source.has_filename()) { + LOG_ERROR("No filename for module") + return; + } + + const auto source_ll = source.parent_path() / (source.stem().string() + detail::get_file_ext(phase).data()); + LOG_DEBUG("Dumping to file " << source_ll); + + std::error_code error_code; + llvm::raw_fd_ostream file_out{source_ll.c_str(), error_code}; + if (error_code) { + LOG_FATAL("Error while opening file " << error_code.message()) + return; + } + + detail::dump_module(module, file_out); + file_out.close(); +} + +} // namespace typeart::util::module \ No newline at end of file diff --git a/lib/passes/support/ModuleDumper.h b/lib/passes/support/ModuleDumper.h new file mode 100644 index 00000000..cd6120a1 --- /dev/null +++ b/lib/passes/support/ModuleDumper.h @@ -0,0 +1,26 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#ifndef MODULE_DUMPER_UTIL_H +#define MODULE_DUMPER_UTIL_H + +#include "llvm/IR/Module.h" + +namespace typeart::util::module { + +enum class ModulePhase { kBase, kHeap, kOpt, kStack }; + +void dump_module(const llvm::Module& module, ModulePhase phase); + +} // namespace typeart::util::module + +#endif diff --git a/lib/passes/support/OmpUtil.h b/lib/passes/support/OmpUtil.h index 76023e5f..209c0e92 100644 --- a/lib/passes/support/OmpUtil.h +++ b/lib/passes/support/OmpUtil.h @@ -24,7 +24,7 @@ inline bool isOmpContext(llvm::Function* f) { if (f != nullptr) { const auto name_ = demangle(f->getName()); llvm::StringRef fname(name_); - return fname.startswith(".omp") || fname.startswith("__kmpc") || fname.startswith("__omp"); + return util::starts_with_any_of(fname, ".omp", "__kmpc", "__omp"); } return false; } diff --git a/lib/passes/support/TypeUtil.cpp b/lib/passes/support/TypeUtil.cpp index 12ecf90b..334cafaf 100644 --- a/lib/passes/support/TypeUtil.cpp +++ b/lib/passes/support/TypeUtil.cpp @@ -28,6 +28,7 @@ using namespace llvm; namespace typeart::util::type { +#if LLVM_VERSION_MAJOR < 15 bool isi64Ptr(llvm::Type* type) { return type->isPointerTy() && type->getPointerElementType()->isIntegerTy(64); } @@ -35,6 +36,7 @@ bool isi64Ptr(llvm::Type* type) { bool isVoidPtr(llvm::Type* type) { return type->isPointerTy() && type->getPointerElementType()->isIntegerTy(8); } +#endif /** * Code was imported from jplehr/llvm-memprofiler project @@ -104,32 +106,4 @@ unsigned getPointerSizeInBytes(llvm::Type* /*ptrT*/, const llvm::DataLayout& dl) return dl.getPointerSizeInBits() / 8; } -unsigned getTypeSizeForArrayAlloc(llvm::AllocaInst* ai, const llvm::DataLayout& dl) { - // TODO: Not used at the moment. Integrate VLA check into replacement methods (getArrayLengthFlattened). - - auto type = ai->getAllocatedType(); - unsigned bytes; - if (type->isArrayTy()) { - bytes = getTypeSizeInBytes(type->getArrayElementType(), dl); - } else { - bytes = getTypeSizeInBytes(type, dl); - } - if (ai->isArrayAllocation()) { - if (auto ci = dyn_cast(ai->getArraySize())) { - bytes *= ci->getLimitedValue(); - } else { - // If this can not be determined statically, we have to compute it at - // runtime. We insert additional instructions to calculate the - // numBytes of that array on the fly. (VLAs produce this kind of - // behavior) - // ATTENTION: We can have multiple such arrays in a single BB. We need - // to have a small vector to store whether we already generated - // instructions, to possibly refer to the results for further - // calculations. - LOG_WARNING("We hit not yet determinable array size expression: " << *ai); - } - } - return bytes; -} - } // namespace typeart::util::type diff --git a/lib/passes/support/TypeUtil.h b/lib/passes/support/TypeUtil.h index 052397c7..97b1175b 100644 --- a/lib/passes/support/TypeUtil.h +++ b/lib/passes/support/TypeUtil.h @@ -22,9 +22,11 @@ class LLVMContext; namespace typeart::util::type { +#if LLVM_VERSION_MAJOR < 15 bool isi64Ptr(llvm::Type* type); bool isVoidPtr(llvm::Type* type); +#endif unsigned getTypeSizeInBytes(llvm::Type* t, const llvm::DataLayout& dl); @@ -42,10 +44,6 @@ unsigned getStructSizeInBytes(llvm::Type* structT, const llvm::DataLayout& dl); unsigned getPointerSizeInBytes(llvm::Type* ptrT, const llvm::DataLayout& dl); -unsigned getTypeSizeForArrayAlloc(llvm::AllocaInst* ai, const llvm::DataLayout& dl); - -// bool compareTypes(llvm::Type* t1, llvm::Type* t2); - } // namespace typeart::util::type #endif diff --git a/lib/passes/support/Util.h b/lib/passes/support/Util.h index 46674572..e3804104 100644 --- a/lib/passes/support/Util.h +++ b/lib/passes/support/Util.h @@ -13,14 +13,19 @@ #ifndef LIB_UTIL_H_ #define LIB_UTIL_H_ -//#include "Logger.h" +// #include "Logger.h" #include "compat/CallSite.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/IR/Function.h" #include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include + namespace typeart::util { namespace detail { @@ -85,7 +90,11 @@ inline std::string dump(const Val& s) { template inline std::string demangle(String&& s) { std::string name = std::string{s}; - auto demangle = llvm::itaniumDemangle(name.data(), nullptr, nullptr, nullptr); +#if LLVM_VERSION_MAJOR < 15 + auto demangle = llvm::itaniumDemangle(name.data(), nullptr, nullptr, nullptr); +#else + auto demangle = llvm::itaniumDemangle(name.data(), false); +#endif if (demangle && !std::string(demangle).empty()) { return {demangle}; } @@ -121,18 +130,6 @@ inline std::vector find_all(llvm::Function* f, Predicate&& p return v; } -template -inline llvm::Instruction* find_first_of(llvm::Function* f, Predicate&& p) { - for (auto& bb : *f) { - for (auto& inst : bb) { - if (p(inst)) { - return &inst; - } - } - } - return nullptr; -} - inline bool regex_matches(const std::string& regex, const std::string& in, bool case_sensitive = false) { using namespace llvm; Regex r(regex, !case_sensitive ? Regex::IgnoreCase : Regex::NoFlags); @@ -182,6 +179,29 @@ inline std::string glob2regex(const std::string& glob) { return glob_reg; } +template +bool with_any_of(llvm::StringRef lhs, StringTy&&... rhs) { + return !lhs.empty() && ((lhs == rhs) || ...); +} + +template +inline bool starts_with_any_of(llvm::StringRef lhs, StringTy... rhs) { +#if LLVM_VERSION_MAJOR > 15 + return !lhs.empty() && ((lhs.starts_with(rhs)) || ...); +#else + return !lhs.empty() && ((lhs.startswith(rhs)) || ...); +#endif +} + +template +inline bool ends_with_any_of(llvm::StringRef lhs, StringTy... rhs) { +#if LLVM_VERSION_MAJOR > 15 + return !lhs.empty() && ((lhs.ends_with(rhs)) || ...); +#else + return !lhs.empty() && ((lhs.endswith(rhs)) || ...); +#endif +} + } // namespace typeart::util #endif /* LIB_UTIL_H_ */ diff --git a/lib/passes/typegen/CMakeLists.txt b/lib/passes/typegen/CMakeLists.txt index 59a6da31..15b75859 100644 --- a/lib/passes/typegen/CMakeLists.txt +++ b/lib/passes/typegen/CMakeLists.txt @@ -1,2 +1,4 @@ -add_subdirectory(ir) +if(${LLVM_VERSION_MAJOR} VERSION_LESS_EQUAL "14") + add_subdirectory(ir) +endif() add_subdirectory(dimeta) \ No newline at end of file diff --git a/lib/passes/typegen/TypeGenerator.cpp b/lib/passes/typegen/TypeGenerator.cpp index 37969d89..176aa30c 100644 --- a/lib/passes/typegen/TypeGenerator.cpp +++ b/lib/passes/typegen/TypeGenerator.cpp @@ -73,6 +73,10 @@ std::unique_ptr make_typegen(std::string_view file, TypegenImplem default: break; } +#if LLVM_VERSION_MAJOR > 14 + LOG_ERROR("TypeGen for LLVM IR (typegen=ir) unsupported with LLVM version > 14. Returning typegen=dimeta") + return types::make_dimeta_typeidgen(file, std::move(database)); +#endif LOG_DEBUG("Loading IR type parser") return make_ir_typeidgen(file, std::move(database)); } diff --git a/lib/passes/typegen/TypeGenerator.h b/lib/passes/typegen/TypeGenerator.h index 4f94ea18..977c228e 100644 --- a/lib/passes/typegen/TypeGenerator.h +++ b/lib/passes/typegen/TypeGenerator.h @@ -13,8 +13,8 @@ #ifndef TYPEART_TYPEGENERATOR_H #define TYPEART_TYPEGENERATOR_H -#include "TypeDatabase.h" #include "analysis/MemOpData.h" +#include "typelib/TypeDatabase.h" #include "typelib/TypeInterface.h" #include diff --git a/lib/passes/typegen/dimeta/CMakeLists.txt b/lib/passes/typegen/dimeta/CMakeLists.txt index 191b17a7..a6d2ebe7 100644 --- a/lib/passes/typegen/dimeta/CMakeLists.txt +++ b/lib/passes/typegen/dimeta/CMakeLists.txt @@ -41,7 +41,7 @@ set_target_properties( typeart_target_coverage_options(${TYPEART_PREFIX}_TypeGenDimetaStatic) target_link_libraries(${TYPEART_PREFIX}_TypeGenDimetaStatic PUBLIC typeart::TypesStatic) -target_link_libraries(${TYPEART_PREFIX}_TypeGenDimetaStatic PUBLIC dimeta::Types) +target_link_libraries(${TYPEART_PREFIX}_TypeGenDimetaStatic PRIVATE dimeta::Types) target_include_directories( ${TYPEART_PREFIX}_TypeGenDimetaStatic ${warning_guard} diff --git a/lib/passes/typegen/dimeta/DimetaTypeGen.cpp b/lib/passes/typegen/dimeta/DimetaTypeGen.cpp index 8bdcd52d..57384498 100644 --- a/lib/passes/typegen/dimeta/DimetaTypeGen.cpp +++ b/lib/passes/typegen/dimeta/DimetaTypeGen.cpp @@ -54,41 +54,81 @@ template std::pair, int> typeid_if_ptr(const Type& type) { using namespace dimeta; const auto& quals = type.qual; - int count{0}; - if (!quals.empty()) { - count = llvm::count_if(quals, [](auto& qual) { return qual == Qualifier::kPtr || qual == Qualifier::kRef; }); - if (count > 0) { - return {{TYPEART_POINTER}, count}; + const int count = + llvm::count_if(quals, [](auto& qual) { return qual == Qualifier::kPtr || qual == Qualifier::kRef; }); + + if constexpr (std::is_same_v) { + switch (type.type.encoding) { + case FundamentalType::Encoding::kVtablePtr: + return {TYPEART_VTABLE_POINTER, count}; + case FundamentalType::Encoding::kNullptr: + return {TYPEART_NULLPOINTER, count}; + case FundamentalType::Encoding::kVoid: + return {TYPEART_VOID, count}; + default: + break; } } + if (count > 0) { + return {{TYPEART_POINTER}, count}; + } + return {{}, count}; } namespace detail { template -auto apply_func(const Type& type, Func&& handle_qualified_type) { +auto apply_function(const Type& type, Func&& handle_qualified_type) { using namespace dimeta; if constexpr (std::is_same_v || std::is_same_v) { return std::forward(handle_qualified_type)(type); } else { - return std::visit(overload{[&](const dimeta::QualifiedFundamental& f) { - return apply_func(f, std::forward(handle_qualified_type)); - }, - [&](const dimeta::QualifiedCompound& q) { - return apply_func(q, std::forward(handle_qualified_type)); - }}, - type); + return std::visit( + [&](auto&& qualified_type) { + return apply_function(qualified_type, std::forward(handle_qualified_type)); + }, + type); } } } // namespace detail +namespace workaround { +void remove_pointer_level(const llvm::AllocaInst* alloc, dimeta::LocatedType& val) { + // If the alloca instruction is not a pointer, but the located_type has a pointer-like qualifier, we remove it. + // Workaround for inlining issue, see test typemapping/05_milc_inline_metadata.c + // TODO Should be removed if dimeta fixes it. + if (!alloc->getAllocatedType()->isPointerTy()) { + LOG_DEBUG("Alloca is not a pointer") + + const auto remove_pointer_level = [](auto& qual) { + auto pointer_like_iter = llvm::find_if(qual, [](auto qualifier) { + switch (qualifier) { + case dimeta::Qualifier::kPtr: + case dimeta::Qualifier::kRef: + case dimeta::Qualifier::kPtrToMember: + return true; + default: + break; + } + return false; + }); + if (pointer_like_iter != std::end(qual)) { + LOG_DEBUG("Removing pointer level " << static_cast(*pointer_like_iter)) + qual.erase(pointer_like_iter); + } + }; + std::visit([&](auto&& qualified_type) { remove_pointer_level(qualified_type.qual); }, val.type); + } +} +} // namespace workaround + template dimeta::ArraySize vector_num_elements(const Type& type) { - return detail::apply_func(type, [](const auto& t) -> dimeta::Extent { + return detail::apply_function(type, [](const auto& t) -> dimeta::Extent { if (t.is_vector) { int pos{-1}; // Find kVector tag-position to determine vector size @@ -141,7 +181,7 @@ std::string get_anon_struct_identifier(const dimeta::QualifiedCompound& compound template dimeta::ArraySize array_size(const Type& type) { - return detail::apply_func(type, [](const auto& t) -> dimeta::Extent { + return detail::apply_function(type, [](const auto& t) -> dimeta::Extent { if (t.array_size.size() > 1 || (t.is_vector && t.array_size.size() > 2)) { LOG_ERROR("Unsupported array size number count > 1 for array type or > 2 for vector") } @@ -157,7 +197,7 @@ dimeta::ArraySize array_size(const Type& type) { template std::string name_or_typedef_of(const Type& type) { - return detail::apply_func(type, [](const auto& qual_type) { + return detail::apply_function(type, [](const auto& qual_type) { const bool no_name = qual_type.type.name.empty(); if constexpr (std::is_same_v) { const bool no_identifier = qual_type.type.identifier.empty(); @@ -192,41 +232,87 @@ std::optional get_builtin_typeid(const dimeta::QualifiedFu const auto encoding = type.type.encoding; switch (encoding) { + case FundamentalType::Encoding::kVtablePtr: + return TYPEART_VTABLE_POINTER; case FundamentalType::Encoding::kUnknown: return TYPEART_UNKNOWN_TYPE; case FundamentalType::Encoding::kVoid: - return TYPEART_INT8; - case FundamentalType::Encoding::kUTFChar: + return TYPEART_VOID; + case FundamentalType::kNullptr: + return TYPEART_NULLPOINTER; + case FundamentalType::Encoding::kUTFChar: { + switch (extent) { + case 4: + return TYPEART_UTF_CHAR_32; + case 2: + return TYPEART_UTF_CHAR_16; + case 1: + return TYPEART_UTF_CHAR_8; + default: + return TYPEART_UNKNOWN_TYPE; + } + } case FundamentalType::Encoding::kChar: case FundamentalType::Encoding::kSignedChar: + return TYPEART_CHAR_8; case FundamentalType::Encoding::kUnsignedChar: + return TYPEART_UCHAR_8; case FundamentalType::Encoding::kBool: - case FundamentalType::Encoding::kSignedInt: + return TYPEART_BOOL; case FundamentalType::Encoding::kUnsignedInt: { switch (extent) { case 4: - return TYPEART_INT32; + return TYPEART_UINT_32; case 8: - return TYPEART_INT64; + return TYPEART_UINT_64; case 2: - return TYPEART_INT16; + return TYPEART_UINT_16; case 1: - return TYPEART_INT8; + return TYPEART_UINT_8; + case 16: + return TYPEART_UINT_128; + default: + return TYPEART_UNKNOWN_TYPE; + } + } + case FundamentalType::Encoding::kSignedInt: { + switch (extent) { + case 4: + return TYPEART_INT_32; + case 8: + return TYPEART_INT_64; + case 2: + return TYPEART_INT_16; + case 1: + return TYPEART_INT_8; + case 16: + return TYPEART_INT_128; + default: + return TYPEART_UNKNOWN_TYPE; + } + } + case FundamentalType::Encoding::kComplex: { + switch (extent) { + case 8: + return TYPEART_COMPLEX_64; + case 16: + return TYPEART_COMPLEX_128; + case 32: + return TYPEART_COMPLEX_256; default: return TYPEART_UNKNOWN_TYPE; } } - case FundamentalType::Encoding::kComplex: case FundamentalType::Encoding::kFloat: { switch (extent) { case 4: - return TYPEART_FLOAT; + return TYPEART_FLOAT_32; case 8: - return TYPEART_DOUBLE; + return TYPEART_FLOAT_64; case 2: - return TYPEART_HALF; + return TYPEART_FLOAT_16; case 16: - return TYPEART_FP128; + return TYPEART_FLOAT_128; default: return TYPEART_UNKNOWN_TYPE; } @@ -326,17 +412,31 @@ class DimetaTypeManager final : public TypeIDGenerator { if (q.is_forward_decl) { struct_info.flag = StructTypeFlag::FWD_DECL; } else { - struct_info.flag = StructTypeFlag::USER_DEFINED; + if (q.type.type == CompoundType::Tag::kUnion) { + struct_info.flag = StructTypeFlag::UNION; + } else { + struct_info.flag = StructTypeFlag::USER_DEFINED; + } } - struct_info.extent = compound.extent; - struct_info.offsets = compound.offsets; - struct_info.num_members = compound.bases.size() + compound.members.size(); + struct_info.extent = compound.extent; + size_t num_bases{0}; for (const auto& base : compound.bases) { + if (base->is_empty_base_class) { + continue; + } + num_bases++; struct_info.member_types.push_back(getOrRegister(base->base)); struct_info.array_sizes.push_back(array_size(base->base)); + struct_info.offsets.push_back(base->offset); } + + struct_info.num_members = compound.members.size() + num_bases; + struct_info.offsets.insert(std::end(struct_info.offsets), // + std::begin(compound.offsets), // + std::end(compound.offsets)); + for (const auto& member : compound.members) { struct_info.member_types.push_back(getOrRegister(member->member)); struct_info.array_sizes.push_back(array_size(member->member)); @@ -380,6 +480,7 @@ class DimetaTypeManager final : public TypeIDGenerator { auto val = dimeta::located_type_for(alloc); if (val) { LOG_DEBUG("Registering alloca") + workaround::remove_pointer_level(alloc, val.value()); const auto type_id = getOrRegister(val->type, false); const auto array_size_val = array_size(val->type); LOG_DEBUG(array_size_val) diff --git a/lib/passes/typegen/ir/StructTypeHandler.cpp b/lib/passes/typegen/ir/StructTypeHandler.cpp index 08d04d92..e4e3fc7d 100644 --- a/lib/passes/typegen/ir/StructTypeHandler.cpp +++ b/lib/passes/typegen/ir/StructTypeHandler.cpp @@ -23,6 +23,8 @@ #include "llvm/Support/TypeSize.h" #include "llvm/Support/raw_ostream.h" +#include + namespace typeart { std::string StructTypeHandler::getName(llvm::StructType* type) { @@ -36,7 +38,7 @@ std::string StructTypeHandler::getName() const { return getName(type); } -llvm::Optional StructTypeHandler::getID() const { +std::optional StructTypeHandler::getID() const { const auto name = StructTypeHandler::getName(type); if (auto it = m_struct_map->find(name); it != m_struct_map->end()) { const auto type_id = it->second; @@ -46,7 +48,7 @@ llvm::Optional StructTypeHandler::getID() const { } return type_id; } - return llvm::None; + return {}; } } // namespace typeart \ No newline at end of file diff --git a/lib/passes/typegen/ir/StructTypeHandler.h b/lib/passes/typegen/ir/StructTypeHandler.h index 9cef29b5..d3306a7b 100644 --- a/lib/passes/typegen/ir/StructTypeHandler.h +++ b/lib/passes/typegen/ir/StructTypeHandler.h @@ -13,10 +13,9 @@ #ifndef TYPEART_STRUCTTYPEHANDLER_H #define TYPEART_STRUCTTYPEHANDLER_H -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringMap.h" +#include #include namespace llvm { @@ -36,7 +35,7 @@ struct StructTypeHandler { [[nodiscard]] std::string getName() const; - [[nodiscard]] llvm::Optional getID() const; + [[nodiscard]] std::optional getID() const; }; } // namespace typeart diff --git a/lib/passes/typegen/ir/TypeManager.cpp b/lib/passes/typegen/ir/TypeManager.cpp index 6698ee56..0ce54df2 100644 --- a/lib/passes/typegen/ir/TypeManager.cpp +++ b/lib/passes/typegen/ir/TypeManager.cpp @@ -20,7 +20,6 @@ #include "support/Util.h" #include "typelib/TypeInterface.h" -#include "llvm/ADT/None.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/Constants.h" @@ -35,6 +34,7 @@ #include #include +#include #include #include #include @@ -50,41 +50,38 @@ std::unique_ptr make_ir_typeidgen(std::string_view file, using namespace llvm; -llvm::Optional get_builtin_typeid(llvm::Type* type) { +std::optional get_builtin_typeid(llvm::Type* type) { auto& c = type->getContext(); switch (type->getTypeID()) { case llvm::Type::IntegerTyID: { if (type == Type::getInt8Ty(c)) { - return TYPEART_INT8; + return TYPEART_INT_8; } if (type == Type::getInt16Ty(c)) { - return TYPEART_INT16; + return TYPEART_INT_16; } if (type == Type::getInt32Ty(c)) { - return TYPEART_INT32; + return TYPEART_INT_32; } if (type == Type::getInt64Ty(c)) { - return TYPEART_INT64; + return TYPEART_INT_64; } return TYPEART_UNKNOWN_TYPE; } case llvm::Type::HalfTyID: - return TYPEART_HALF; + return TYPEART_FLOAT_16; case llvm::Type::FloatTyID: - return TYPEART_FLOAT; + return TYPEART_FLOAT_32; case llvm::Type::DoubleTyID: - return TYPEART_DOUBLE; - case llvm::Type::FP128TyID: - return TYPEART_FP128; + return TYPEART_FLOAT_64; case llvm::Type::X86_FP80TyID: - return TYPEART_X86_FP80; - case llvm::Type::PPC_FP128TyID: - return TYPEART_PPC_FP128; + case llvm::Type::FP128TyID: + return TYPEART_FLOAT_128; case llvm::Type::PointerTyID: return TYPEART_POINTER; default: - return None; + return {}; } } @@ -94,7 +91,7 @@ int TypeManager::getOrRegisterVector(llvm::VectorType* type, const llvm::DataLay VectorTypeHandler handler{&structMap, typeDB.get(), type, dl, *this}; const auto type_id = handler.getID(); if (type_id) { - return type_id.getValue(); + return type_id.value(); } // Type is not registered - reserve new ID and create struct info object: @@ -111,8 +108,8 @@ int TypeManager::getOrRegisterVector(llvm::VectorType* type, const llvm::DataLay const int id = reserveNextTypeId(); - const auto [element_id, element_type, element_name] = element_data.getValue(); - const auto [vector_name, vector_bytes, vector_size] = vector_data.getValue(); + const auto [element_id, element_type, element_name] = element_data.value(); + const auto [vector_name, vector_bytes, vector_size] = vector_data.value(); std::vector memberTypeIDs; std::vector arraySizes; @@ -150,7 +147,7 @@ int TypeManager::getOrRegisterVector(llvm::VectorType* type, const llvm::DataLay int TypeManager::getTypeID(llvm::Type* type, const DataLayout& dl) const { auto builtin_id = get_builtin_typeid(type); if (builtin_id) { - return builtin_id.getValue(); + return builtin_id.value(); } switch (type->getTypeID()) { @@ -163,7 +160,7 @@ int TypeManager::getTypeID(llvm::Type* type, const DataLayout& dl) const { VectorTypeHandler handle{&structMap, typeDB.get(), dyn_cast(type), dl, *this}; const auto type_id = handle.getID(); if (type_id) { - return type_id.getValue(); + return type_id.value(); } break; } @@ -171,7 +168,7 @@ int TypeManager::getTypeID(llvm::Type* type, const DataLayout& dl) const { StructTypeHandler handle{&structMap, typeDB.get(), dyn_cast(type)}; const auto type_id = handle.getID(); if (type_id) { - return type_id.getValue(); + return type_id.value(); } break; } @@ -191,7 +188,7 @@ int TypeManager::getTypeID(llvm::Type* type, const DataLayout& dl) const { int TypeManager::getOrRegisterType(llvm::Type* type, const llvm::DataLayout& dl) { auto builtin_id = get_builtin_typeid(type); if (builtin_id) { - return builtin_id.getValue(); + return builtin_id.value(); } switch (type->getTypeID()) { @@ -217,7 +214,7 @@ int TypeManager::getOrRegisterStruct(llvm::StructType* type, const llvm::DataLay StructTypeHandler handle{&structMap, typeDB.get(), type}; const auto type_id = handle.getID(); if (type_id) { - return type_id.getValue(); + return type_id.value(); } const auto name = handle.getName(); diff --git a/lib/passes/typegen/ir/VectorTypeHandler.cpp b/lib/passes/typegen/ir/VectorTypeHandler.cpp index b363e8be..f674e80f 100644 --- a/lib/passes/typegen/ir/VectorTypeHandler.cpp +++ b/lib/passes/typegen/ir/VectorTypeHandler.cpp @@ -62,7 +62,7 @@ Type* VectorTypeHandler::getElementType(llvm::VectorType* type) { return element_type; } -llvm::Optional VectorTypeHandler::getVectorData() const { +std::optional VectorTypeHandler::getVectorData() const { size_t vectorBytes = dl.getTypeAllocSize(type); size_t vectorSize = compat::num_elements(type); @@ -70,27 +70,27 @@ llvm::Optional VectorTypeHandler::getVectorData() if (!element_data) { LOG_DEBUG("Element data empty for: " << util::dump(*type)) - return None; + return {}; } - auto vec_name = getName(element_data.getValue()); + auto vec_name = getName(element_data.value()); return VectorData{vec_name, vectorBytes, vectorSize}; } -llvm::Optional VectorTypeHandler::getElementData() const { +std::optional VectorTypeHandler::getElementData() const { const auto element_id = getElementID(); - if (!element_id || element_id.getValue() == TYPEART_UNKNOWN_TYPE) { + if (!element_id || element_id.value() == TYPEART_UNKNOWN_TYPE) { LOG_WARNING("Unknown vector element id.") - return None; + return {}; } - auto element_name = m_type_db->getTypeName(element_id.getValue()); + auto element_name = m_type_db->getTypeName(element_id.value()); auto element_type = VectorTypeHandler::getElementType(type); - return ElementData{element_id.getValue(), element_type, element_name}; + return ElementData{element_id.value(), element_type, element_name}; } -llvm::Optional VectorTypeHandler::getElementID() const { +std::optional VectorTypeHandler::getElementID() const { auto element_type = getElementType(type); const auto element_id = m.getTypeID(element_type, dl); @@ -109,7 +109,7 @@ std::string VectorTypeHandler::getName(const ElementData& data) const { return name; } -llvm::Optional VectorTypeHandler::getID() const { +std::optional VectorTypeHandler::getID() const { auto element_data = getElementData(); if (!element_data) { @@ -117,7 +117,7 @@ llvm::Optional VectorTypeHandler::getID() const { return TYPEART_UNKNOWN_TYPE; } - const auto name = getName(element_data.getValue()); + const auto name = getName(element_data.value()); if (auto it = m_struct_map->find(name); it != m_struct_map->end()) { if (!m_type_db->isVectorType(it->second)) { @@ -127,7 +127,7 @@ llvm::Optional VectorTypeHandler::getID() const { return it->second; } - return None; + return {}; } } // namespace typeart diff --git a/lib/passes/typegen/ir/VectorTypeHandler.h b/lib/passes/typegen/ir/VectorTypeHandler.h index 6e932cbe..b7fe09b9 100644 --- a/lib/passes/typegen/ir/VectorTypeHandler.h +++ b/lib/passes/typegen/ir/VectorTypeHandler.h @@ -13,10 +13,9 @@ #ifndef TYPEART_VECTORTYPEHANDLER_H #define TYPEART_VECTORTYPEHANDLER_H -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringMap.h" +#include #include namespace llvm { @@ -55,15 +54,15 @@ struct VectorTypeHandler { static llvm::Type* getElementType(llvm::VectorType* type); - [[nodiscard]] llvm::Optional getVectorData() const; + [[nodiscard]] std::optional getVectorData() const; - [[nodiscard]] llvm::Optional getElementData() const; + [[nodiscard]] std::optional getElementData() const; - [[nodiscard]] llvm::Optional getElementID() const; + [[nodiscard]] std::optional getElementID() const; [[nodiscard]] std::string getName(const ElementData& data) const; - [[nodiscard]] llvm::Optional getID() const; + [[nodiscard]] std::optional getID() const; }; } // namespace typeart diff --git a/lib/runtime/AccessCountPrinter.h b/lib/runtime/AccessCountPrinter.h index ded70b59..89976096 100644 --- a/lib/runtime/AccessCountPrinter.h +++ b/lib/runtime/AccessCountPrinter.h @@ -57,7 +57,7 @@ void serialize(const Recorder& r, std::ostringstream& buf) { const auto memory_use = memory::estimate(r.getMaxStackAllocs(), r.getMaxHeapAllocs(), r.getGlobalAllocs()); Table t("Alloc Stats from softcounters"); - t.wrap_length = true; + t.wrap_length_ = true; t.put(Row::make("Total heap", r.getHeapAllocs(), r.getHeapArray())); t.put(Row::make("Total stack", r.getStackAllocs(), r.getStackArray())); t.put(Row::make("Total global", r.getGlobalAllocs(), r.getGlobalArray())); @@ -100,7 +100,7 @@ void serialize(const Recorder& r, std::ostringstream& buf) { }; Table type_table("Allocation type detail (heap, stack, global)"); - type_table.table_header = '#'; + type_table.table_header_ = '#'; for (auto type_id : type_id_set) { type_table.put(Row::make(std::to_string(type_id), count(r.getHeapAlloc(), type_id), count(r.getStackAlloc(), type_id), count(r.getGlobalAlloc(), type_id), @@ -110,7 +110,7 @@ void serialize(const Recorder& r, std::ostringstream& buf) { type_table.print(buf); Table type_table_free("Free allocation type detail (heap, stack)"); - type_table_free.table_header = '#'; + type_table_free.table_header_ = '#'; for (auto type_id : type_id_set) { type_table_free.put(Row::make(std::to_string(type_id), count(r.getHeapFree(), type_id), count(r.getStackFree(), type_id), typeart_get_type_name(type_id))); @@ -122,7 +122,7 @@ void serialize(const Recorder& r, std::ostringstream& buf) { std::stringstream ss; ss << "Per-thread counter values (" << numThreads << " threads)"; Table thread_table(ss.str()); - thread_table.table_header = '#'; + thread_table.table_header_ = '#'; auto print_thread_row = [&thread_table](std::string name, const std::vector& vals) { Row row(std::move(name)); diff --git a/lib/runtime/AccessCounter.h b/lib/runtime/AccessCounter.h index 3a37c461..f72d02e1 100644 --- a/lib/runtime/AccessCounter.h +++ b/lib/runtime/AccessCounter.h @@ -16,6 +16,7 @@ #include "RuntimeData.h" #include "RuntimeInterface.h" +#include #include #include #include @@ -55,7 +56,7 @@ inline void updateMax(std::atomic& maxVal, T newVal) noexcept { struct CounterStats { private: CounterStats(double sum, double min, double max, double mean, double std) - : sum(sum), minVal(min), maxVal(max), meanVal(mean), stdVal(std) { + : sum_value(sum), min_value(min), max_value(max), mean_value(mean), std_value(std) { } CounterStats() = default; @@ -75,11 +76,11 @@ struct CounterStats { return CounterStats(sum, min, max, mean, std); } - const double sum{0}; - const double minVal{0}; - const double maxVal{0}; - const double meanVal{0}; - const double stdVal{0}; + const double sum_value{}; + const double min_value{}; + const double max_value{}; + const double mean_value{}; + const double std_value{}; }; } // namespace detail @@ -323,7 +324,7 @@ class AccessRecorder { return heapAllocs; } Counter getStackAllocs() const { - return getStackAllocsThreadStats().sum; + return getStackAllocsThreadStats().sum_value; } Counter getGlobalAllocs() const { return globalAllocs; @@ -332,7 +333,7 @@ class AccessRecorder { return maxHeapAllocs; } Counter getMaxStackAllocs() const { - return getMaxStackAllocsThreadStats().maxVal; + return getMaxStackAllocsThreadStats().max_value; } Counter getCurHeapAllocs() const { return curHeapAllocs; @@ -347,7 +348,7 @@ class AccessRecorder { return addrChecked; } Counter getStackArray() const { - return getStackArrayThreadStats().sum; + return getStackArrayThreadStats().sum_value; } Counter getHeapArray() const { return heapArray; @@ -356,10 +357,10 @@ class AccessRecorder { return globalArray; } Counter getStackAllocsFree() const { - return getStackAllocsFreeThreadStats().sum; + return getStackAllocsFreeThreadStats().sum_value; } Counter getStackArrayFree() const { - return getStackArrayFreeThreadStats().sum; + return getStackArrayFreeThreadStats().sum_value; } Counter getHeapAllocsFree() const { return heapAllocsFree; @@ -568,7 +569,7 @@ class NoneRecorder { } // namespace softcounter -#if ENABLE_SOFTCOUNTER == 1 +#if defined(ENABLE_SOFTCOUNTER) && ENABLE_SOFTCOUNTER == 1 using Recorder = softcounter::AccessRecorder; #else using Recorder = softcounter::NoneRecorder; diff --git a/lib/runtime/AllocMapWrapper.h b/lib/runtime/AllocMapWrapper.h index 8cb50210..6c6fc8ec 100644 --- a/lib/runtime/AllocMapWrapper.h +++ b/lib/runtime/AllocMapWrapper.h @@ -15,9 +15,8 @@ #include "RuntimeData.h" -#include "llvm/ADT/Optional.h" - #include +#include namespace typeart { namespace mixin { @@ -69,9 +68,9 @@ struct MapOp { } template - [[nodiscard]] inline static llvm::Optional find(PointerMap&& slocked_map, MemAddr addr) { + [[nodiscard]] inline static std::optional find(PointerMap&& slocked_map, MemAddr addr) { if (slocked_map->empty() || addr < slocked_map->begin()->first) { - return llvm::None; + return {}; } auto it = slocked_map->lower_bound(addr); @@ -89,14 +88,14 @@ struct MapOp { } template - [[nodiscard]] inline static llvm::Optional remove(PointerMap&& xlocked_map, MemAddr addr) { + [[nodiscard]] inline static std::optional remove(PointerMap&& xlocked_map, MemAddr addr) { const auto it = xlocked_map->find(addr); if (it != xlocked_map->end()) { auto removed = it->second; xlocked_map->erase(it); return removed; } - return llvm::None; + return {}; } template @@ -114,7 +113,7 @@ struct MapOp { template struct StandardMapBase : protected BaseOp { - [[nodiscard]] inline llvm::Optional find(MemAddr addr) const { + [[nodiscard]] inline std::optional find(MemAddr addr) const { return BaseOp::find(detail::as_ptr(this->map()), addr); } @@ -122,7 +121,7 @@ struct StandardMapBase : protected BaseOp { return BaseOp::put(detail::as_ptr(this->map()), addr, entry); } - [[nodiscard]] inline llvm::Optional remove(MemAddr addr) { + [[nodiscard]] inline std::optional remove(MemAddr addr) { return BaseOp::remove(detail::as_ptr(this->map()), addr); } @@ -139,7 +138,7 @@ struct SharedMutexMap : public BaseOp { mutable std::shared_mutex alloc_m; public: - [[nodiscard]] inline llvm::Optional find(MemAddr addr) const { + [[nodiscard]] inline std::optional find(MemAddr addr) const { std::shared_lock guard(alloc_m); return BaseOp::find(addr); } @@ -149,7 +148,7 @@ struct SharedMutexMap : public BaseOp { return BaseOp::put(addr, entry); } - [[nodiscard]] inline llvm::Optional remove(MemAddr addr) { + [[nodiscard]] inline std::optional remove(MemAddr addr) { std::lock_guard guard(alloc_m); return BaseOp::remove(addr); } @@ -164,7 +163,7 @@ struct SharedMutexMap : public BaseOp { #ifdef USE_SAFEPTR template struct SafePtrdMap : protected BaseOp { - [[nodiscard]] inline llvm::Optional find(MemAddr addr) const { + [[nodiscard]] inline std::optional find(MemAddr addr) const { auto slockedAllocs = sf::slock_safe_ptr(this->map()); return BaseOp::find(slockedAllocs, addr); } @@ -174,7 +173,7 @@ struct SafePtrdMap : protected BaseOp { return BaseOp::put(guard, addr, entry); } - [[nodiscard]] inline llvm::Optional remove(MemAddr addr) { + [[nodiscard]] inline std::optional remove(MemAddr addr) { auto guard = sf::xlock_safe_ptr(this->map()); return BaseOp::remove(guard, addr); } diff --git a/lib/runtime/AllocationTracking.cpp b/lib/runtime/AllocationTracking.cpp index a2035216..54735548 100644 --- a/lib/runtime/AllocationTracking.cpp +++ b/lib/runtime/AllocationTracking.cpp @@ -19,7 +19,6 @@ #include "TypeDB.h" #include "support/Logger.h" -#include "llvm/ADT/Optional.h" #include "llvm/Support/raw_ostream.h" #include @@ -105,22 +104,22 @@ thread_local ThreadData threadData; } // namespace -AllocationTracker::AllocationTracker(const TypeDB& db, Recorder& recorder) : typeDB{db}, recorder{recorder} { +AllocationTracker::AllocationTracker(const TypeDB& db, Recorder& recorder) : typeDB{db}, runtime_recorder{recorder} { } void AllocationTracker::onAlloc(const void* addr, int typeId, size_t count, const void* retAddr) { const auto status = doAlloc(addr, typeId, count, retAddr); if (status != AllocState::ADDR_SKIPPED) { - recorder.incHeapAlloc(typeId, count); + runtime_recorder.incHeapAlloc(typeId, count); } - LOG_TRACE("Alloc " << toString(addr, typeId, count, retAddr) << " " << 'H'); + LOG_TRACE("Alloc " << toString(addr, typeId, count, retAddr, true) << " " << 'H'); } void AllocationTracker::onAllocStack(const void* addr, int typeId, size_t count, const void* retAddr) { const auto status = doAlloc(addr, typeId, count, retAddr); if (status != AllocState::ADDR_SKIPPED) { threadData.stackVars.push_back(addr); - recorder.incStackAlloc(typeId, count); + runtime_recorder.incStackAlloc(typeId, count); } LOG_TRACE("Alloc " << toString(addr, typeId, count, retAddr) << " " << 'S'); } @@ -128,7 +127,7 @@ void AllocationTracker::onAllocStack(const void* addr, int typeId, size_t count, void AllocationTracker::onAllocGlobal(const void* addr, int typeId, size_t count, const void* retAddr) { const auto status = doAlloc(addr, typeId, count, retAddr); if (status != AllocState::ADDR_SKIPPED) { - recorder.incGlobalAlloc(typeId, count); + runtime_recorder.incGlobalAlloc(typeId, count); } LOG_TRACE("Alloc " << toString(addr, typeId, count, retAddr) << " " << 'G'); } @@ -144,16 +143,16 @@ AllocState AllocationTracker::doAlloc(const void* addr, int typeId, size_t count // In the second case, the allocation is tracked anyway so that onFree() does not report an error. // On the other hand, an allocation on address 0x0 with size > 0 is an actual error. if (unlikely(count == 0)) { - recorder.incZeroLengthAddr(); + runtime_recorder.incZeroLengthAddr(); status |= AllocState::ZERO_COUNT; LOG_WARNING("Zero-size allocation " << toString(addr, typeId, count, retAddr)); if (addr == nullptr) { - recorder.incZeroLengthAndNullAddr(); + runtime_recorder.incZeroLengthAndNullAddr(); LOG_ERROR("Zero-size and nullptr allocation " << toString(addr, typeId, count, retAddr)); return status | AllocState::NULL_ZERO | AllocState::ADDR_SKIPPED; } } else if (unlikely(addr == nullptr)) { - recorder.incNullAddr(); + runtime_recorder.incNullAddr(); LOG_ERROR("Nullptr allocation " << toString(addr, typeId, count, retAddr)); return status | AllocState::NULL_PTR | AllocState::ADDR_SKIPPED; } @@ -161,7 +160,7 @@ AllocState AllocationTracker::doAlloc(const void* addr, int typeId, size_t count const auto overridden = wrapper.put(addr, PointerInfo{typeId, count, retAddr}); if (unlikely(overridden)) { - recorder.incAddrReuse(); + runtime_recorder.incAddrReuse(); status |= AllocState::ADDR_REUSE; LOG_WARNING("Pointer already in map " << toString(addr, typeId, count, retAddr)); // LOG_WARNING("Overridden data in map " << toString(addr, def)); @@ -177,7 +176,7 @@ FreeState AllocationTracker::doFreeHeap(const void* addr, const void* retAddr) { return FreeState::ADDR_SKIPPED | FreeState::NULL_PTR; } - llvm::Optional removed = wrapper.remove(addr); + std::optional removed = wrapper.remove(addr); if (unlikely(!removed)) { LOG_ERROR("Free on unregistered address " << addr << " (" << retAddr << ")"); @@ -186,7 +185,7 @@ FreeState AllocationTracker::doFreeHeap(const void* addr, const void* retAddr) { LOG_TRACE("Free " << toString(addr, *removed)); if constexpr (!std::is_same_v) { - recorder.incHeapFree(removed->typeId, removed->count); + runtime_recorder.incHeapFree(removed->typeId, removed->count); } return FreeState::OK; } @@ -194,7 +193,7 @@ FreeState AllocationTracker::doFreeHeap(const void* addr, const void* retAddr) { void AllocationTracker::onFreeHeap(const void* addr, const void* retAddr) { const auto status = doFreeHeap(addr, retAddr); if (FreeState::OK == status) { - recorder.decHeapAlloc(); + runtime_recorder.decHeapAlloc(); } } @@ -209,23 +208,23 @@ void AllocationTracker::onLeaveScope(int alloca_count, const void* retAddr) { const auto start_pos = (cend - alloca_count); LOG_TRACE("Freeing stack (" << alloca_count << ") " << std::distance(start_pos, threadData.stackVars.cend())) - wrapper.remove_range(start_pos, cend, [&](llvm::Optional& removed, MemAddr addr) { + wrapper.remove_range(start_pos, cend, [&](std::optional& removed, MemAddr addr) { if (unlikely(!removed)) { LOG_ERROR("Free on unregistered address " << addr << " (" << retAddr << ")"); } else { LOG_TRACE("Free " << toString(addr, *removed)); if constexpr (!std::is_same_v) { - recorder.incStackFree(removed->typeId, removed->count); + runtime_recorder.incStackFree(removed->typeId, removed->count); } } }); threadData.stackVars.erase(start_pos, cend); - recorder.decStackAlloc(alloca_count); + runtime_recorder.decStackAlloc(alloca_count); LOG_TRACE("Stack after free: " << threadData.stackVars.size()); } // Base address -llvm::Optional AllocationTracker::findBaseAlloc(const void* addr) { +std::optional AllocationTracker::findBaseAlloc(const void* addr) { return wrapper.find(addr); } diff --git a/lib/runtime/AllocationTracking.h b/lib/runtime/AllocationTracking.h index adbd2786..ab1156ee 100644 --- a/lib/runtime/AllocationTracking.h +++ b/lib/runtime/AllocationTracking.h @@ -18,11 +18,7 @@ #include "RuntimeData.h" #include - -namespace llvm { -template -class Optional; -} // namespace llvm +#include namespace typeart { @@ -50,7 +46,7 @@ enum class FreeState : unsigned { class AllocationTracker { PointerMap wrapper; const TypeDB& typeDB; - Recorder& recorder; + Recorder& runtime_recorder; public: AllocationTracker(const TypeDB& db, Recorder& recorder); @@ -65,7 +61,7 @@ class AllocationTracker { void onLeaveScope(int alloca_count, const void* retAddr); - llvm::Optional findBaseAlloc(const void* addr); + std::optional findBaseAlloc(const void* addr); private: AllocState doAlloc(const void* addr, int typeID, size_t count, const void* retAddr); diff --git a/lib/runtime/Runtime.cpp b/lib/runtime/Runtime.cpp index 0727f613..49786879 100644 --- a/lib/runtime/Runtime.cpp +++ b/lib/runtime/Runtime.cpp @@ -16,9 +16,10 @@ #include "AccessCounter.h" #include "RuntimeData.h" #include "TypeIO.h" +#include "TypeInterface.h" +#include "support/ConfigurationBase.h" #include "support/Logger.h" - -//#include "llvm/Support/raw_ostream.h" +// #include "llvm/Support/raw_ostream.h" #include #include @@ -31,21 +32,25 @@ namespace typeart { namespace debug { -std::string toString(const void* memAddr, int typeId, size_t count, size_t typeSize, const void* calledFrom) { +std::string toString(const void* memAddr, int typeId, size_t count, size_t typeSize, const void* calledFrom, + bool heap) { std::string buf; llvm::raw_string_ostream s(buf); const auto name = typeart::RuntimeSystem::get().typeResolution.db().getTypeName(typeId); + if ((typeId == TYPEART_VOID) && heap) { + count /= typeSize; + } s << memAddr << " " << typeId << " " << name << " " << typeSize << " " << count << " (" << calledFrom << ")"; return s.str(); } -std::string toString(const void* memAddr, int typeId, size_t count, const void* calledFrom) { +std::string toString(const void* memAddr, int typeId, size_t count, const void* calledFrom, bool heap) { const auto typeSize = typeart::RuntimeSystem::get().typeResolution.db().getTypeSize(typeId); - return toString(memAddr, typeId, count, typeSize, calledFrom); + return toString(memAddr, typeId, count, typeSize, calledFrom, heap); } -std::string toString(const void* addr, const PointerInfo& info) { - return toString(addr, info.typeId, info.count, info.debug); +std::string toString(const void* addr, const PointerInfo& info, bool heap) { + return toString(addr, info.typeId, info.count, info.debug, heap); } inline void printTraceStart() { @@ -57,7 +62,7 @@ inline void printTraceStart() { } // namespace debug -static constexpr const char* defaultTypeFileName = "types.yaml"; +static constexpr const char* defaultTypeFileName = config::ConfigStdArgValues::types; RuntimeSystem::RuntimeSystem() : rtScopeInit(), typeResolution(typeDB, recorder), allocTracker(typeDB, recorder) { debug::printTraceStart(); @@ -71,18 +76,18 @@ RuntimeSystem::RuntimeSystem() : rtScopeInit(), typeResolution(typeDB, recorder) std::error_code error; // Try to load types from specified file first. // Then look at default location. - const char* type_file = std::getenv("TYPEART_TYPE_FILE"); + const char* type_file = std::getenv(config::EnvironmentStdArgs::types); if (type_file == nullptr) { // FIXME Deprecated name - type_file = std::getenv("TA_TYPE_FILE"); + type_file = std::getenv("TYPEART_TYPE_FILE"); if (type_file != nullptr) { - LOG_WARNING("Use of deprecated env var TA_TYPE_FILE."); + LOG_WARNING("Use of deprecated env var TYPEART_TYPE_FILE."); } } if (type_file != nullptr) { if (!loadTypes(type_file, error)) { - LOG_FATAL("Failed to load recorded types from TYPEART_TYPE_FILE=" << type_file - << ". Reason: " << error.message()); + LOG_FATAL("Failed to load recorded types from " << config::EnvironmentStdArgs::types << "=" << type_file + << " .Reason: " << error.message()); std::exit(EXIT_FAILURE); // TODO: Error handling } } else { diff --git a/lib/runtime/Runtime.h b/lib/runtime/Runtime.h index 0dd1d3ba..d0e52036 100644 --- a/lib/runtime/Runtime.h +++ b/lib/runtime/Runtime.h @@ -26,11 +26,12 @@ struct PointerInfo; namespace debug { -std::string toString(const void* memAddr, int typeId, size_t count, size_t typeSize, const void* calledFrom); +std::string toString(const void* memAddr, int typeId, size_t count, size_t typeSize, const void* calledFrom, + bool heap = false); -std::string toString(const void* memAddr, int typeId, size_t count, const void* calledFrom); +std::string toString(const void* memAddr, int typeId, size_t count, const void* calledFrom, bool heap = false); -std::string toString(const void* addr, const PointerInfo& info); +std::string toString(const void* addr, const PointerInfo& info, bool heap = false); } // namespace debug diff --git a/lib/runtime/RuntimeData.h b/lib/runtime/RuntimeData.h index 77bcf207..998ae803 100644 --- a/lib/runtime/RuntimeData.h +++ b/lib/runtime/RuntimeData.h @@ -23,6 +23,7 @@ #endif #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" +#pragma GCC diagnostic ignored "-Wshadow" #include "absl/container/btree_map.h" #pragma GCC diagnostic pop #endif diff --git a/lib/runtime/RuntimeInterface.h b/lib/runtime/RuntimeInterface.h index 97ee6d27..774519f2 100644 --- a/lib/runtime/RuntimeInterface.h +++ b/lib/runtime/RuntimeInterface.h @@ -46,15 +46,24 @@ typedef struct typeart_struct_layout_t { // NOLINT const size_t* count; } typeart_struct_layout; +typedef struct typeart_base_type_info_t { + const void* address; + int type_id; + size_t count; +} typeart_base_type_info; + +typedef struct typeart_type_info_t { + const void* address; + int type_id; + size_t count; + typeart_base_type_info base_type_info; // API dependent +} typeart_type_info; + /** * Determines the type and array element count at the given address. * For nested types with classes/structs, the containing type is resolved recursively, until an exact with the address * is found. - * See typeart_get_type_length and typeart_get_type_id for resolving only one such parameter - * - * Note that this function will always return the outermost type lining up with the address. - * Given a pointer to the start of a struct, the returned type will therefore be that of the struct, not of the first - * member. + * base_type_info is the outermost type and array element count at the given address. * * Code example: * { @@ -68,8 +77,7 @@ typedef struct typeart_struct_layout_t { // NOLINT * } * * \param[in] addr The address. - * \param[out] type_id Type ID - * \param[out] count Allocation size + * \param[out] base_type allocation info at the address addr. The address equals [in] param addr. * * \return A status code: * - TYPEART_OK: The query was successful and the contents of type and count are valid. @@ -77,11 +85,7 @@ typedef struct typeart_struct_layout_t { // NOLINT * - TYPEART_BAD_ALIGNMENT: The given address does not line up with the start of the atomic type at that location. * - TYPEART_INVALID_ID: Encountered unregistered ID during lookup. */ -typeart_status typeart_get_type(const void* addr, int* type_id, size_t* count); - -typeart_status typeart_get_type_length(const void* addr, size_t* count); - -typeart_status typeart_get_type_id(const void* addr, int* type_id); +typeart_status typeart_get_type(const void* addr, typeart_type_info* type_info); /** * Determines the outermost type and array element count at the given address. @@ -117,17 +121,18 @@ typeart_status typeart_get_type_id(const void* addr, int* type_id); * to &data[0]) * } * - * \param[in] addr The address. - * \param[out] type_id Type ID of the containing type - * \param[out] count Number of elements in the containing buffer, not counting elements before the given address. - * \param[out] base_address Address of the containing buffer. + * \param[in] type The result of a `typeart_get_type` call on some address. + * \param[out] containing_type Type information of the containing type. * \param[out] byte_offset The byte offset within that buffer element. * * \return A status code. * - TYPEART_OK: The query was successful. * - TYPEART_UNKNOWN_ADDRESS: The given address is either not allocated, or was not correctly recorded by the runtime. */ -typeart_status typeart_get_containing_type(const void* addr, int* type_id, size_t* count, const void** base_address, +// typeart_status typeart_get_containing_type(const void* addr, int* type_id, size_t* count, const void** base_address, +// size_t* byte_offset); + +typeart_status typeart_get_containing_type(typeart_type_info type_info, typeart_base_type_info* containing_type, size_t* byte_offset); /** @@ -156,13 +161,11 @@ typeart_status typeart_get_containing_type(const void* addr, int* type_id, size_ * -> subtype_count: 1 (length of member float[2] at offset 20) * } * + * \param[in] container_layout typeart_struct_layout corresponding to the containing type * \param[in] baseAddr Pointer to the start of the containing type. * \param[in] offset Byte offset within the containing type. - * \param[in] container_layout typeart_struct_layout corresponding to the containing type - * \param[out] subtype_id The type ID corresponding to the subtype. - * \param[out] subtype_base_addr Pointer to the start of the subtype. + * \param[out] subtype_info The type container to the subtype. * \param[out] subtype_byte_offset Byte offset within the subtype. - * \param[out] subtype_count Number of elements in subarray. * * \return One of the following status codes: * - TYPEART_OK: Success. @@ -170,10 +173,8 @@ typeart_status typeart_get_containing_type(const void* addr, int* type_id, size_ * - TYPEART_BAD_OFFSET: The provided offset is invalid. * - TYPEART_ERROR: The typeart_struct_layout is invalid. */ -typeart_status typeart_get_subtype(const void* base_addr, size_t offset, const typeart_struct_layout* container_layout, - int* subtype_id, const void** subtype_base_addr, size_t* subtype_byte_offset, - size_t* subtype_count); - +typeart_status typeart_get_subtype(const typeart_struct_layout* container_layout, const void* base_addr, size_t offset, + typeart_base_type_info* subtype_info, size_t* subtype_byte_offset); /** * Returns the stored debug address generated by __builtin_return_address(0). * @@ -204,22 +205,6 @@ typeart_status typeart_get_return_address(const void* addr, const void** return_ */ typeart_status typeart_get_source_location(const void* addr, char** file, char** function, char** line); -/** - * Given an address, this function provides information about the corresponding struct type. - * This is more expensive than the below version, since the pointer addr must be resolved. - * - * \param[in] addr The pointer address - * \param[out] struct_layout Data layout of the struct. - * - * \return One of the following status codes: - * - TYPEART_OK: Success. - * - TYPEART_WRONG_KIND: ID does not correspond to a struct type. - * - TYPEART_UNKNOWN_ADDRESS: The given address is either not allocated, or was not correctly recorded by the runtime. - * - TYPEART_BAD_ALIGNMENT: The given address does not line up with the start of the atomic type at that location. - * - TYPEART_INVALID_ID: Encountered unregistered ID during lookup. - */ -typeart_status typeart_resolve_type_addr(const void* addr, typeart_struct_layout* struct_layout); - /** * Given a type ID, this function provides information about the corresponding struct type. * @@ -282,13 +267,21 @@ bool typeart_is_struct_type(int type_id); /** * Returns true if the type ID is a user-defined structure type - * (struct, class etc.) + * (struct, class, union etc.) * * \param[in] type_id The type ID. * \return true, false */ bool typeart_is_userdefined_type(int type_id); +/** + * Returns true if the type ID is a (user-defined) union + * + * \param[in] type_id The type ID. + * \return true, false + */ +bool typeart_is_union(int type_id); + /** * Returns true if the type ID is a LLVM SIMD vector type * diff --git a/lib/runtime/TypeResolution.cpp b/lib/runtime/TypeResolution.cpp index 6f2d4917..71e4bdaf 100644 --- a/lib/runtime/TypeResolution.cpp +++ b/lib/runtime/TypeResolution.cpp @@ -16,10 +16,10 @@ #include "Runtime.h" #include "RuntimeData.h" #include "RuntimeInterface.h" +#include "TypeInterface.h" #include "support/Logger.h" #include "support/System.h" -#include "llvm/ADT/Optional.h" #include "llvm/Support/raw_ostream.h" #include @@ -67,7 +67,8 @@ inline size_t get_member_index_at(const typeart_struct_layout& structInfo, size_ } // namespace detail -TypeResolution::TypeResolution(const TypeDB& type_db, Recorder& recorder) : typeDB{type_db}, recorder{recorder} { +TypeResolution::TypeResolution(const TypeDB& type_db, Recorder& recorder) + : type_database{type_db}, runtime_recorder{recorder} { } TypeResolution::TypeArtStatus TypeResolution::getSubTypeInfo(const void* baseAddr, size_t offset, @@ -87,14 +88,17 @@ TypeResolution::TypeArtStatus TypeResolution::getSubTypeInfo(const void* baseAdd const int memberType = containerInfo.member_types[memberIndex]; const size_t baseOffset = containerInfo.offsets[memberIndex]; - const size_t internalOffset = offset - baseOffset; - const size_t typeSize = typeDB.getTypeSize(memberType); + const size_t internalOffset = offset - baseOffset; + const size_t typeSize = type_database.getTypeSize(memberType); + if (typeSize == 0) { + return TYPEART_INVALID_ID; + } const size_t offsetInTypeSize = internalOffset / typeSize; const size_t newOffset = internalOffset % typeSize; // If newOffset != 0, the subtype cannot be atomic, i.e. must be a struct if (newOffset != 0) { - if (typeDB.isReservedType(memberType)) { + if (type_database.isReservedType(memberType)) { return TYPEART_BAD_ALIGNMENT; } } @@ -176,7 +180,7 @@ TypeResolution::TypeArtStatus TypeResolution::getTypeInfo(const void* addr, cons TypeArtStatus status = getContainingTypeInfo(addr, basePtr, ptrInfo, &containing_type_count, &internal_byte_offset); if (status != TYPEART_OK) { if (status == TYPEART_UNKNOWN_ADDRESS) { - recorder.incAddrMissing(addr); + runtime_recorder.incAddrMissing(addr); } return status; } @@ -188,13 +192,13 @@ TypeResolution::TypeArtStatus TypeResolution::getTypeInfo(const void* addr, cons return TYPEART_OK; } - if (typeDB.isBuiltinType(containing_type)) { + if (type_database.isBuiltinType(containing_type)) { // Address points to the middle of a builtin type return TYPEART_BAD_ALIGNMENT; } // Resolve struct recursively - const auto* structInfo = typeDB.getStructInfo(containing_type); + const auto* structInfo = type_database.getStructInfo(containing_type); if (structInfo != nullptr) { const void* containingTypeAddr = detail::add_byte_offset(addr, -std::ptrdiff_t(internal_byte_offset)); return getTypeInfoInternal(containingTypeAddr, internal_byte_offset, *structInfo, type, count); @@ -207,7 +211,10 @@ TypeResolution::TypeArtStatus TypeResolution::getContainingTypeInfo(const void* const PointerInfo& ptrInfo, size_t* count, size_t* offset) const { const auto& basePtrInfo = ptrInfo; - size_t typeSize = typeDB.getTypeSize(basePtrInfo.typeId); + size_t typeSize = type_database.getTypeSize(basePtrInfo.typeId); + if (basePtrInfo.typeId == TYPEART_VOID || basePtrInfo.typeId == TYPEART_POINTER) { + // typeSize = 1; + } // Check for exact match -> no further checks and offsets calculations needed if (basePtr == addr) { @@ -216,6 +223,10 @@ TypeResolution::TypeArtStatus TypeResolution::getContainingTypeInfo(const void* return TYPEART_OK; } + if (typeSize == 0) { + return TYPEART_ERROR; + } + // The address points inside a known array const void* blockEnd = detail::add_byte_offset(basePtr, basePtrInfo.count * typeSize); @@ -249,11 +260,11 @@ TypeResolution::TypeArtStatus TypeResolution::getContainingTypeInfo(const void* TypeResolution::TypeArtStatus TypeResolution::getStructInfo(int type_id, const StructTypeInfo** structInfo) const { // Requested ID must correspond to a struct - if (!typeDB.isStructType(type_id)) { + if (!type_database.isStructType(type_id)) { return TYPEART_WRONG_KIND; } - const auto* result = typeDB.getStructInfo(type_id); + const auto* result = type_database.getStructInfo(type_id); if (result != nullptr) { *structInfo = result; @@ -263,7 +274,7 @@ TypeResolution::TypeArtStatus TypeResolution::getStructInfo(int type_id, const S } const TypeDB& TypeResolution::db() const { - return typeDB; + return type_database; } namespace detail { @@ -276,6 +287,23 @@ inline typeart_status query_type(const void* addr, int* type, size_t* count) { return TYPEART_UNKNOWN_ADDRESS; } +inline typeart_status query_type(const void* addr, typeart_type_info& info) { + auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr); + typeart::RuntimeSystem::get().recorder.incUsedInRequest(addr); + if (alloc) { + typeart_base_type_info base; + base.address = alloc->first; + base.type_id = alloc->second.typeId; + base.count = alloc->second.count; + info.base_type_info = base; + info.address = addr; + const auto result = typeart::RuntimeSystem::get().typeResolution.getTypeInfo(addr, alloc->first, alloc->second, + &info.type_id, &info.count); + return result; + } + return TYPEART_UNKNOWN_ADDRESS; +} + inline typeart_status query_struct_layout(int type_id, typeart_struct_layout* struct_layout) { const typeart::StructTypeInfo* struct_info; typeart_status status = typeart::RuntimeSystem::get().typeResolution.getStructInfo(type_id, &struct_info); @@ -284,9 +312,9 @@ inline typeart_status query_struct_layout(int type_id, typeart_struct_layout* st struct_layout->name = struct_info->name.c_str(); struct_layout->num_members = struct_info->num_members; struct_layout->extent = struct_info->extent; - struct_layout->offsets = &struct_info->offsets[0]; - struct_layout->member_types = &struct_info->member_types[0]; - struct_layout->count = &struct_info->array_sizes[0]; + struct_layout->offsets = (struct_info->offsets).data(); + struct_layout->member_types = (struct_info->member_types).data(); + struct_layout->count = (struct_info->array_sizes).data(); } else { struct_layout->type_id = std::numeric_limits::min(); struct_layout->name = ""; @@ -308,7 +336,7 @@ char* string2char(std::string_view src) { return nullptr; } - typeart::RuntimeSystem::get().allocTracker.onAlloc(string_copy, TYPEART_INT8, source_length, ret_addr); + typeart::RuntimeSystem::get().allocTracker.onAlloc(string_copy, TYPEART_CHAR_8, source_length, ret_addr); memcpy(string_copy, src.data(), source_length); @@ -323,57 +351,33 @@ char* string2char(std::string_view src) { * */ -typeart_status typeart_get_type(const void* addr, int* type_id, size_t* count) { - typeart::RTGuard guard; - return typeart::detail::query_type(addr, type_id, count); -} - -typeart_status typeart_get_type_length(const void* addr, size_t* count) { - typeart::RTGuard guard; - int type{0}; - return typeart::detail::query_type(addr, &type, count); -} - -typeart_status typeart_get_type_id(const void* addr, int* type_id) { +typeart_status typeart_get_type(const void* addr, typeart_type_info* base_type) { typeart::RTGuard guard; - size_t count{0}; - return typeart::detail::query_type(addr, type_id, &count); + return typeart::detail::query_type(addr, *base_type); } -typeart_status typeart_get_containing_type(const void* addr, int* type_id, size_t* count, const void** base_address, +typeart_status typeart_get_containing_type(typeart_type_info type, typeart_base_type_info* containing_type, size_t* byte_offset) { typeart::RTGuard guard; - auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr); - if (alloc) { - // auto& allocVal = alloc.getValue(); - *type_id = alloc->second.typeId; - *base_address = alloc->first; - return typeart::RuntimeSystem::get().typeResolution.getContainingTypeInfo(addr, alloc->first, alloc->second, count, - byte_offset); - } - return TYPEART_UNKNOWN_ADDRESS; + containing_type->type_id = type.base_type_info.type_id; + containing_type->count = type.base_type_info.count; + containing_type->address = type.base_type_info.address; + const typeart::PointerInfo info{type.base_type_info.type_id, type.base_type_info.count}; + const auto result = typeart::RuntimeSystem::get().typeResolution.getContainingTypeInfo( + type.address, containing_type->address, info, &containing_type->count, byte_offset); + + return result; } -typeart_status typeart_get_subtype(const void* base_addr, size_t offset, const typeart_struct_layout* container_layout, - int* subtype_id, const void** subtype_base_addr, size_t* subtype_byte_offset, - size_t* subtype_count) { +typeart_status typeart_get_subtype(const typeart_struct_layout* container_layout, const void* base_addr, size_t offset, + typeart_base_type_info* subtype_info, size_t* subtype_byte_offset) { typeart::RTGuard guard; auto status = typeart::RuntimeSystem::get().typeResolution.getSubTypeInfo( - base_addr, offset, *container_layout, subtype_id, subtype_base_addr, subtype_byte_offset, subtype_count); + base_addr, offset, *container_layout, &subtype_info->type_id, &subtype_info->address, subtype_byte_offset, + &subtype_info->count); return status; } -typeart_status typeart_resolve_type_addr(const void* addr, typeart_struct_layout* struct_layout) { - typeart::RTGuard guard; - int type_id{0}; - size_t size{0}; - auto status = typeart::detail::query_type(addr, &type_id, &size); - if (status != TYPEART_OK) { - return status; - } - return typeart::detail::query_struct_layout(type_id, struct_layout); -} - typeart_status typeart_resolve_type_id(int type_id, typeart_struct_layout* struct_layout) { typeart::RTGuard guard; return typeart::detail::query_struct_layout(type_id, struct_layout); @@ -384,7 +388,7 @@ typeart_status typeart_get_return_address(const void* addr, const void** return_ auto alloc = typeart::RuntimeSystem::get().allocTracker.findBaseAlloc(addr); if (alloc) { - *return_addr = alloc.getValue().second.debug; + *return_addr = alloc.value().second.debug; return TYPEART_OK; } *return_addr = nullptr; @@ -447,6 +451,11 @@ bool typeart_is_userdefined_type(int type_id) { return typeart::RuntimeSystem::get().typeResolution.db().isUserDefinedType(type_id); } +bool typeart_is_union(int type_id) { + typeart::RTGuard guard; + return typeart::RuntimeSystem::get().typeResolution.db().isUnion(type_id); +} + size_t typeart_get_type_size(int type_id) { typeart::RTGuard guard; return typeart::RuntimeSystem::get().typeResolution.db().getTypeSize(type_id); diff --git a/lib/runtime/TypeResolution.h b/lib/runtime/TypeResolution.h index 0e4b982f..f47ca4b3 100644 --- a/lib/runtime/TypeResolution.h +++ b/lib/runtime/TypeResolution.h @@ -27,8 +27,8 @@ namespace typeart { struct PointerInfo; class TypeResolution { - const TypeDB& typeDB; - Recorder& recorder; + const TypeDB& type_database; + Recorder& runtime_recorder; public: using TypeArtStatus = typeart_status; diff --git a/lib/support/ConfigurationBase.h b/lib/support/ConfigurationBase.h new file mode 100644 index 00000000..ab085acc --- /dev/null +++ b/lib/support/ConfigurationBase.h @@ -0,0 +1,55 @@ +// TypeART library +// +// Copyright (c) 2017-2025 TypeART Authors +// Distributed under the BSD 3-Clause license. +// (See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/BSD-3-Clause) +// +// Project home: https://github.com/tudasc/TypeART +// +// SPDX-License-Identifier: BSD-3-Clause +// + +#ifndef TYPEART_CONFIG_OPTION_BASE_H +#define TYPEART_CONFIG_OPTION_BASE_H + +#include + +namespace typeart::config { + +struct ConfigStdArgs final { +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) static constexpr char name[] = path; +#include "ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; + +struct ConfigStdArgValues final { +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ + static constexpr decltype(def_value) name{def_value}; +#include "ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; + +struct ConfigStdArgTypes final { +#define TYPEART_CONFIG_OPTION(name, path, type, default_value, description, upper_path) using name##_ty = type; +#include "ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; + +struct ConfigStdArgDescriptions final { +#define TYPEART_CONFIG_OPTION(name, path, type, default_value, description, upper_path) \ + static constexpr char name[] = description; +#include "ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; + +struct EnvironmentStdArgs final { +#define TYPEART_CONFIG_OPTION(name, path, type, def_value, description, upper_path) \ + static constexpr char name[] = "TYPEART_" upper_path; +#include "support/ConfigurationBaseOptions.h" +#undef TYPEART_CONFIG_OPTION +}; + +} // namespace typeart::config + +#endif /* TYPEART_CONFIG_OPTION_BASE_H */ diff --git a/lib/support/ConfigurationBaseOptions.h b/lib/support/ConfigurationBaseOptions.h index 5ee52ec5..a8fe1e4d 100644 --- a/lib/support/ConfigurationBaseOptions.h +++ b/lib/support/ConfigurationBaseOptions.h @@ -11,33 +11,38 @@ // #ifndef TYPEART_CONFIG_OPTION -#define TYPEART_CONFIG_OPTION(name, path, type, default_value, description) +#define TYPEART_CONFIG_OPTION(name, path, type, default_value, description, upper_path) #endif -TYPEART_CONFIG_OPTION(types, "types", std::string, "types.yaml", "Location of the generated type file.") -TYPEART_CONFIG_OPTION(stats, "stats", bool, false, "Show statistics for TypeArt type pass.") -TYPEART_CONFIG_OPTION(heap, "heap", bool, true, "Instrument heap allocation/free instructions.") -TYPEART_CONFIG_OPTION(stack, "stack", bool, false, "Instrument stack allocations.") -TYPEART_CONFIG_OPTION(global, "global", bool, false, "Instrument global allocations.") +TYPEART_CONFIG_OPTION(types, "types", std::string, "typeart-types.yaml", "Location of the generated type file.", + "TYPES") +TYPEART_CONFIG_OPTION(stats, "stats", bool, false, "Show statistics for TypeArt type pass.", "STATS") +TYPEART_CONFIG_OPTION(heap, "heap", bool, true, "Instrument heap allocation/free instructions.", "HEAP") +TYPEART_CONFIG_OPTION(stack, "stack", bool, false, "Instrument stack allocations.", "STACK") +TYPEART_CONFIG_OPTION(global, "global", bool, false, "Instrument global allocations.", "GLOBAL") TYPEART_CONFIG_OPTION(stack_lifetime, "stack-lifetime", bool, true, - "Instrument lifetime.start intrinsic instead of alloca.") + "Instrument lifetime.start intrinsic instead of alloca.", "STACK_LIFETIME") TYPEART_CONFIG_OPTION(filter, "filter", bool, false, - "Filter allocas (stack/global) that are passed to relevant function calls.") + "Filter allocas (stack/global) that are passed to relevant function calls.", "FILTER") TYPEART_CONFIG_OPTION(filter_impl, "filter-implementation", std::string, "std", - "Select the call filter implementation.") + "Select the call filter implementation.", "FILTER_IMPLEMENTATION") TYPEART_CONFIG_OPTION(filter_glob, "filter-glob", std::string, "*MPI_*", - "Filter allocas based on the function name (glob) .") + "Filter allocas based on the function name (glob) .", "FILTER_GLOB") TYPEART_CONFIG_OPTION(filter_glob_deep, "filter-glob-deep", std::string, "MPI_*", "Filter allocas based on specific API: Values passed as void* are correlated when string matched " - "and kept when correlated successfully.") -TYPEART_CONFIG_OPTION(filter_cg_file, "filter-cg-file", std::string, "", "Location of call-graph file to use.") -TYPEART_CONFIG_OPTION(analysis_filter_global, "analysis-filter-global", bool, true, "Filter globals of a module.") + "and kept when correlated successfully.", + "FILTER_GLOB_DEEP") +TYPEART_CONFIG_OPTION(filter_cg_file, "filter-cg-file", std::string, "", "Location of call-graph file to use.", + "FILTER_CG_FILE") +TYPEART_CONFIG_OPTION(analysis_filter_global, "analysis-filter-global", bool, true, "Filter globals of a module.", + "ANALYSIS_FILTER_GLOBAL") TYPEART_CONFIG_OPTION(analysis_filter_heap_alloc, "analysis-filter-heap-alloca", bool, false, - "Filter alloca instructions that have a store from a heap allocation.") + "Filter alloca instructions that have a store from a heap allocation.", + "ANALYSIS_FILTER_HEAP_ALLOCA") TYPEART_CONFIG_OPTION(analysis_filter_pointer_alloc, "analysis-filter-pointer-alloca", bool, true, - "Filter allocas of pointer types.") + "Filter allocas of pointer types.", "ANALYSIS_FILTER_POINTER_ALLOCA") TYPEART_CONFIG_OPTION(analysis_filter_alloca_non_array, "analysis-filter-non-array-alloca", bool, false, - "Filter scalar valued allocas.") -TYPEART_CONFIG_OPTION(typegen, "typegen", std::string, "dimeta", "Select type layout generator.") + "Filter scalar valued allocas.", "ANALYSIS_FILTER_NON_ARRAY_ALLOCA") +TYPEART_CONFIG_OPTION(typegen, "typegen", std::string, "dimeta", "Select type layout generator.", "TYPEGEN") #undef TYPEART_CONFIG_OPTION diff --git a/lib/support/FileConfiguration.cpp b/lib/support/FileConfiguration.cpp deleted file mode 100644 index 450380dc..00000000 --- a/lib/support/FileConfiguration.cpp +++ /dev/null @@ -1,280 +0,0 @@ -// TypeART library -// -// Copyright (c) 2017-2025 TypeART Authors -// Distributed under the BSD 3-Clause license. -// (See accompanying file LICENSE.txt or copy at -// https://opensource.org/licenses/BSD-3-Clause) -// -// Project home: https://github.com/tudasc/TypeART -// -// SPDX-License-Identifier: BSD-3-Clause -// - -#include "FileConfiguration.h" - -#include "support/Configuration.h" - -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/YAMLTraits.h" - -using namespace llvm; - -namespace typeart::config::file { - -using typeart::config::ConfigStdArgValues; - -struct ConfigurationOptions { - std::string types{ConfigStdArgValues::types}; - bool heap{ConfigStdArgValues::heap}; - bool stack{ConfigStdArgValues::stack}; - bool global{ConfigStdArgValues::global}; - bool statistics{ConfigStdArgValues::stats}; - bool stack_lifetime{ConfigStdArgValues::stack_lifetime}; - std::string typegen{ConfigStdArgValues::typegen}; - bool filter{true}; - struct CallFilter { - std::string implementation{ConfigStdArgValues::filter_impl}; - std::string glob{ConfigStdArgValues::filter_glob}; - std::string glob_deep{ConfigStdArgValues::filter_glob_deep}; - std::string cg_file{ConfigStdArgValues::filter_cg_file}; - }; - CallFilter call_filter_configuration{}; - struct Analysis { - bool filter_global{ConfigStdArgValues::analysis_filter_global}; - bool filter_heap_alloc{ConfigStdArgValues::analysis_filter_heap_alloc}; - bool filter_pointer_alloc{ConfigStdArgValues::analysis_filter_pointer_alloc}; - bool filter_alloca_non_array{ConfigStdArgValues::analysis_filter_alloca_non_array}; - }; - Analysis analysis_configuration{}; - int version{1}; -}; - -namespace helper { - -ConfigurationOptions map2config(const FileOptionsMap& mapping) { - const auto make_entry = [&mapping](std::string_view entry, auto& ref) { - auto key = llvm::StringRef(entry.data()); - ref = static_cast::type>(mapping.lookup(key)); - }; - - ConfigurationOptions conf_file; - make_entry(ConfigStdArgs::types, conf_file.types); - make_entry(ConfigStdArgs::stats, conf_file.statistics); - make_entry(ConfigStdArgs::heap, conf_file.heap); - make_entry(ConfigStdArgs::global, conf_file.global); - make_entry(ConfigStdArgs::stack, conf_file.stack); - make_entry(ConfigStdArgs::stack_lifetime, conf_file.stack_lifetime); - make_entry(ConfigStdArgs::filter, conf_file.filter); - make_entry(ConfigStdArgs::filter_impl, conf_file.call_filter_configuration.implementation); - make_entry(ConfigStdArgs::filter_glob, conf_file.call_filter_configuration.glob); - make_entry(ConfigStdArgs::filter_glob_deep, conf_file.call_filter_configuration.glob_deep); - make_entry(ConfigStdArgs::filter_cg_file, conf_file.call_filter_configuration.cg_file); - make_entry(ConfigStdArgs::analysis_filter_global, conf_file.analysis_configuration.filter_global); - make_entry(ConfigStdArgs::analysis_filter_heap_alloc, conf_file.analysis_configuration.filter_heap_alloc); - make_entry(ConfigStdArgs::analysis_filter_pointer_alloc, conf_file.analysis_configuration.filter_pointer_alloc); - make_entry(ConfigStdArgs::analysis_filter_alloca_non_array, conf_file.analysis_configuration.filter_alloca_non_array); - make_entry(ConfigStdArgs::typegen, conf_file.typegen); - return conf_file; -} - -FileOptionsMap config2map(const ConfigurationOptions& conf_file) { - using namespace detail; - - const auto make_entry = [](std::string&& key, - const auto& field_value) -> std::pair { - LOG_DEBUG(key << "->" << field_value) - return {key, config::OptionValue{field_value}}; - }; - FileOptionsMap mapping_ = { - make_entry(ConfigStdArgs::types, conf_file.types), - make_entry(ConfigStdArgs::stats, conf_file.statistics), - make_entry(ConfigStdArgs::heap, conf_file.heap), - make_entry(ConfigStdArgs::global, conf_file.global), - make_entry(ConfigStdArgs::stack, conf_file.stack), - make_entry(ConfigStdArgs::stack_lifetime, conf_file.stack_lifetime), - make_entry(ConfigStdArgs::typegen, conf_file.typegen), - make_entry(ConfigStdArgs::filter, conf_file.filter), - make_entry(ConfigStdArgs::filter_impl, conf_file.call_filter_configuration.implementation), - make_entry(ConfigStdArgs::filter_glob, conf_file.call_filter_configuration.glob), - make_entry(ConfigStdArgs::filter_glob_deep, conf_file.call_filter_configuration.glob_deep), - make_entry(ConfigStdArgs::filter_cg_file, conf_file.call_filter_configuration.cg_file), - make_entry(ConfigStdArgs::analysis_filter_global, conf_file.analysis_configuration.filter_global), - make_entry(ConfigStdArgs::analysis_filter_heap_alloc, conf_file.analysis_configuration.filter_heap_alloc), - make_entry(ConfigStdArgs::analysis_filter_pointer_alloc, conf_file.analysis_configuration.filter_pointer_alloc), - make_entry(ConfigStdArgs::analysis_filter_alloca_non_array, - conf_file.analysis_configuration.filter_alloca_non_array), - }; - return mapping_; -} - -} // namespace helper - -std::string write_file_configuration_as_text(const FileOptions& file_options); - -class YamlFileConfiguration final : public FileOptions { - private: - FileOptionsMap mapping_; - - public: - explicit YamlFileConfiguration(const ConfigurationOptions& conf_file); - - [[nodiscard]] Optional getValue(std::string_view opt_path) const override; - - [[nodiscard]] FileOptionsMap getConfiguration() const override; - - [[nodiscard]] std::string getConfigurationAsString() const override; - - ~YamlFileConfiguration() override = default; -}; - -YamlFileConfiguration::YamlFileConfiguration(const ConfigurationOptions& conf_file) - : mapping_(helper::config2map(conf_file)) { -} - -llvm::Optional YamlFileConfiguration::getValue(std::string_view opt_path) const { - auto key = llvm::StringRef(opt_path.data()); - if (mapping_.count(key) != 0U) { - return mapping_.lookup(key); - } - return llvm::None; -} - -FileOptionsMap YamlFileConfiguration::getConfiguration() const { - return this->mapping_; -} - -std::string YamlFileConfiguration::getConfigurationAsString() const { - return write_file_configuration_as_text(*this); -} - -namespace yaml { -ConfigurationOptions yaml_read_file(llvm::yaml::Input& input); -void yaml_output_file(llvm::yaml::Output& output, ConfigurationOptions& config); -} // namespace yaml - -namespace compat { -auto open_flag() { -#if LLVM_VERSION_MAJOR < 13 - return llvm::sys::fs::OpenFlags::F_Text; -#else - return llvm::sys::fs::OpenFlags::OF_Text; -#endif -} -} // namespace compat - -[[maybe_unused]] llvm::ErrorOr> make_file_configuration(std::string_view file_path) { - using namespace llvm; - - ErrorOr> memBuffer = MemoryBuffer::getFile(file_path.data()); - - if (std::error_code error = memBuffer.getError(); error) { - LOG_WARNING("Warning while loading configuration file \'" << file_path.data() << "\'. Reason: " << error.message()); - return error; - } - - llvm::yaml::Input input_yaml(memBuffer.get()->getMemBufferRef()); - const auto file_content = typeart::config::file::yaml::yaml_read_file(input_yaml); - - return std::make_unique(file_content); -} - -llvm::ErrorOr> make_default_file_configuration() { - ConfigurationOptions options{}; - return std::make_unique(options); -} - -llvm::ErrorOr write_file_configuration(llvm::raw_ostream& oss, const FileOptions& options) { - using namespace llvm; - - llvm::yaml::Output out(oss); - - auto data = options.getConfiguration(); - - auto conf_file = helper::map2config(options.getConfiguration()); - yaml::yaml_output_file(out, conf_file); - - return true; -} - -std::string write_file_configuration_as_text(const FileOptions& file_options) { - std::string config_text; - llvm::raw_string_ostream sstream(config_text); - if (!write_file_configuration(sstream, file_options)) { - LOG_WARNING("Could not write config file to string stream.") - } - return sstream.str(); -} - -} // namespace typeart::config::file - -using namespace llvm::yaml; -using namespace typeart::config::file; - -template <> -struct llvm::yaml::MappingTraits { - static void mapping(IO& yml_io, typeart::config::file::ConfigurationOptions::Analysis& info) { - using typeart::config::ConfigStdArgs; - const auto drop_prefix = [](const std::string& path, std::string_view prefix = "analysis-") { - llvm::StringRef prefix_less{path}; - prefix_less.consume_front(prefix.data()); - return prefix_less; - }; - yml_io.mapOptional(drop_prefix(ConfigStdArgs::analysis_filter_global).data(), info.filter_global); - yml_io.mapOptional(drop_prefix(ConfigStdArgs::analysis_filter_heap_alloc).data(), info.filter_heap_alloc); - yml_io.mapOptional(drop_prefix(ConfigStdArgs::analysis_filter_pointer_alloc).data(), info.filter_pointer_alloc); - yml_io.mapOptional(drop_prefix(ConfigStdArgs::analysis_filter_alloca_non_array).data(), - info.filter_alloca_non_array); - } -}; - -template <> -struct llvm::yaml::MappingTraits { - static void mapping(IO& yml_io, typeart::config::file::ConfigurationOptions::CallFilter& info) { - using typeart::config::ConfigStdArgs; - const auto drop_prefix = [](const std::string& path, std::string_view prefix = "filter-") { - llvm::StringRef prefix_less{path}; - prefix_less.consume_front(prefix.data()); - return prefix_less; - }; - yml_io.mapOptional(drop_prefix(ConfigStdArgs::filter_impl).data(), info.implementation); - yml_io.mapOptional(drop_prefix(ConfigStdArgs::filter_glob).data(), info.glob); - yml_io.mapOptional(drop_prefix(ConfigStdArgs::filter_glob_deep).data(), info.glob_deep); - yml_io.mapOptional(drop_prefix(ConfigStdArgs::filter_cg_file).data(), info.cg_file); - } -}; - -template <> -struct llvm::yaml::MappingTraits { - static void mapping(IO& yml_io, typeart::config::file::ConfigurationOptions& info) { - using typeart::config::ConfigStdArgs; - yml_io.mapRequired(ConfigStdArgs::types, info.types); - yml_io.mapRequired(ConfigStdArgs::heap, info.heap); - yml_io.mapRequired(ConfigStdArgs::stack, info.stack); - yml_io.mapOptional(ConfigStdArgs::global, info.global); - yml_io.mapOptional(ConfigStdArgs::stats, info.statistics); - yml_io.mapOptional(ConfigStdArgs::stack_lifetime, info.stack_lifetime); - yml_io.mapRequired(ConfigStdArgs::typegen, info.typegen); - yml_io.mapRequired(ConfigStdArgs::filter, info.filter); - yml_io.mapOptional("call-filter", info.call_filter_configuration); - yml_io.mapOptional("analysis", info.analysis_configuration); - yml_io.mapOptional("file-format", info.version); - } -}; - -namespace typeart::config::file::yaml { - -ConfigurationOptions yaml_read_file(llvm::yaml::Input& input) { - ConfigurationOptions file_content{}; - input >> file_content; - - return file_content; -} - -void yaml_output_file(llvm::yaml::Output& output, ConfigurationOptions& config) { - output << config; -} - -} // namespace typeart::config::file::yaml diff --git a/lib/support/System.cpp b/lib/support/System.cpp index 02e78309..1173fa3a 100644 --- a/lib/support/System.cpp +++ b/lib/support/System.cpp @@ -45,7 +45,7 @@ long Process::getMaxRSS() { class CommandPipe { using UniqueFile = std::unique_ptr; - UniqueFile command; + UniqueFile command_; explicit CommandPipe(UniqueFile command); @@ -55,7 +55,7 @@ class CommandPipe { [[nodiscard]] std::string nextLine() const; }; -CommandPipe::CommandPipe(CommandPipe::UniqueFile command) : command(std::move(command)) { +CommandPipe::CommandPipe(CommandPipe::UniqueFile command) : command_(std::move(command)) { } std::optional CommandPipe::create(std::string_view command) { @@ -73,7 +73,7 @@ std::string CommandPipe::nextLine() const { size_t buffer_length{0}; std::string result; - if (getline(&buffer, &buffer_length, command.get()) != -1) { + if (getline(&buffer, &buffer_length, command_.get()) != -1) { result = buffer; } @@ -89,9 +89,9 @@ std::string CommandPipe::nextLine() const { } bool test_command(std::string_view command, std::string_view test_arg) { - const auto available = [](const std::string_view command) -> bool { + const auto available = [](const std::string_view command_to_try) -> bool { constexpr int command_not_found{127}; - auto* proc = popen(command.data(), "r"); + auto* proc = popen(command_to_try.data(), "r"); const int ret_val = pclose(proc); return WEXITSTATUS(ret_val) != command_not_found; }; @@ -155,22 +155,22 @@ struct RemoveEnvInScope { } // namespace system -std::optional SourceLocation::create(const void* addr, intptr_t offset_ptr) { +std::optional SourceLocation::create(const void* raw_address, intptr_t offset_ptr) { // Preload might cause infinite recursion, hence temp. remove this flag in this scope only: system::RemoveEnvInScope rm_preload_var{"LD_PRELOAD"}; - const auto pipe = [](const void* paddr, intptr_t offset_ptr) -> std::optional { + const auto pipe = [](const void* paddr, intptr_t offset_ptr_value) -> std::optional { const auto& sloc_helper = system::SourceLocHelper::get(); const auto& proc = system::Process::get(); // FIXME: Inst Pointer points one past what we need with __built_in_return_addr(0), hacky way to fix: - const auto addr = [](const auto addr) { // reinterpret_cast(paddr) - offset_ptr; + const auto addr = [](const auto address_to_offset) { // reinterpret_cast(paddr) - offset_ptr; // Transform addr to VMA Addr: Dl_info info; link_map* link_map; - dladdr1((void*)addr, &info, (void**)&link_map, RTLD_DL_LINKMAP); - return addr - link_map->l_addr; - }(reinterpret_cast(paddr) - offset_ptr); + dladdr1((void*)address_to_offset, &info, (void**)&link_map, RTLD_DL_LINKMAP); + return address_to_offset - link_map->l_addr; + }(reinterpret_cast(paddr) - offset_ptr_value); if (sloc_helper.hasLLVMSymbolizer()) { std::ostringstream command; @@ -191,7 +191,7 @@ std::optional SourceLocation::create(const void* addr, intptr_t } return {}; - }(addr, offset_ptr); + }(raw_address, offset_ptr); if (!pipe) { return {}; diff --git a/lib/support/System.h b/lib/support/System.h index 392b327c..75410533 100644 --- a/lib/support/System.h +++ b/lib/support/System.h @@ -13,6 +13,7 @@ #ifndef TYPEART_SYSTEM_H #define TYPEART_SYSTEM_H +#include #include #include #include diff --git a/lib/support/Table.h b/lib/support/Table.h index 180411cb..17f02728 100644 --- a/lib/support/Table.h +++ b/lib/support/Table.h @@ -13,6 +13,7 @@ #ifndef TYPEART_TABLE_H #define TYPEART_TABLE_H +#include #include #include #include @@ -37,32 +38,33 @@ inline std::string num2str(Number num) { struct JustifiedString final { enum align_as { left, right }; - std::string_view string; - int width; - align_as alignment; + std::string_view string_; + int width_; + align_as alignment_; public: - JustifiedString(std::string_view string, int w, align_as a) : string(string), width(w), alignment(a) { + JustifiedString(std::string_view string, int width, align_as alignment) + : string_(string), width_(width), alignment_(alignment) { } friend std::ostream& operator<<(std::ostream& os, const JustifiedString& js) { - os << std::setw(js.width) << (js.alignment == JustifiedString::align_as::left ? std::left : std::right) - << js.string; + os << std::setw(js.width_) << (js.alignment_ == JustifiedString::align_as::left ? std::left : std::right) + << js.string_; return os; } }; } // namespace detail struct Cell { - enum align_as { left, right }; + enum align_as { kLeft, kRight }; - std::string c; - int w; - align_as align; + std::string cell_value_; + int width_; + align_as alignment_; - explicit Cell(std::string v) : c(std::move(v)), w(c.size()), align(left) { - w = c.size(); - align = left; + explicit Cell(std::string value) : cell_value_(std::move(value)), width_(cell_value_.size()), alignment_(kLeft) { + width_ = cell_value_.size(); + alignment_ = kLeft; } explicit Cell(const char* v) : Cell(std::string(v)) { @@ -70,66 +72,66 @@ struct Cell { template explicit Cell(number v) : Cell(detail::num2str(v)) { - align = right; + alignment_ = kRight; } }; struct Row { - Cell label; - std::vector cells; + Cell label_; + std::vector cells_; - explicit Row(std::string name) : label(std::move(name)) { + explicit Row(std::string name) : label_(std::move(name)) { } - Row& put(Cell&& c) { - cells.emplace_back(c); + Row& put(Cell&& cell) { + cells_.emplace_back(cell); return *this; } static Row make_row(std::string name) { - auto r = Row(std::move(name)); - return r; + auto row = Row(std::move(name)); + return row; } template - static Row make(std::string name, Cells&&... c) { - auto r = make_row(std::move(name)); - (r.put(Cell(c)), ...); - return r; + static Row make(std::string name, Cells&&... cells) { + auto row = make_row(std::move(name)); + (row.put(Cell(cells)), ...); + return row; } }; struct Table { - std::string title{"Table"}; - std::vector row_vec; - int columns{0}; - int rows{0}; - int max_row_label_width{1}; - std::string cell_sep{" , "}; - std::string empty_cell{"-"}; - char table_header{'-'}; - bool wrap_header{false}; - bool wrap_length{false}; - bool colon_empty{false}; - - explicit Table(std::string title) : title(std::move(title)) { + std::string title_{"Table"}; + std::vector row_vec_; + int columns_{0}; + int rows_{0}; + int max_row_label_width_{1}; + std::string cell_sep_{" , "}; + std::string empty_cell_{"-"}; + char table_header_{'-'}; + bool wrap_header_{false}; + bool wrap_length_{false}; + bool colon_empty_{false}; + + explicit Table(std::string title) : title_(std::move(title)) { } - void put(Row&& r) { - row_vec.emplace_back(r); - columns = std::max(columns, r.cells.size()); - ++rows; - max_row_label_width = std::max(max_row_label_width, r.label.w); + void put(Row&& row) { + row_vec_.emplace_back(row); + columns_ = std::max(columns_, row.cells_.size()); + ++rows_; + max_row_label_width_ = std::max(max_row_label_width_, row.label_.width_); } template - static Table make(std::string title, Rows&&... r) { + static Table make(std::string title, Rows&&... rows) { Table t{std::move(title)}; - (t.put(std::forward(r)), ...); + (t.put(std::forward(rows)), ...); return t; } - void print(std::ostream& s) const { + void print(std::ostream& out_stream) const { const auto left_justify = [](std::string_view cell_str, int width) { using namespace detail; return JustifiedString(cell_str, width, JustifiedString::left); @@ -140,55 +142,56 @@ struct Table { return JustifiedString(cell_str, width, JustifiedString::right); }; - const auto max_row_id = max_row_label_width + 1; + const auto max_row_id = max_row_label_width_ + 1; // determine per column width - std::vector col_width(columns, 4); - for (const auto& row : row_vec) { + std::vector col_width(columns_, 4); + for (const auto& row : row_vec_) { int col_num{0}; - for (const auto& col : row.cells) { - col_width[col_num] = std::max(col_width[col_num], col.w + 1); + for (const auto& col : row.cells_) { + col_width[col_num] = std::max(col_width[col_num], col.width_ + 1); ++col_num; } } // how long is the header separation supposed to be const auto head_rep_count = [&]() -> int { - if (wrap_length) { + if (wrap_length_) { const int sum_col_width = std::accumulate(std::begin(col_width), std::end(col_width), 0); - const int title_width = std::max(max_row_id, title.size()); + const int title_width = std::max(max_row_id, title_.size()); - return title_width + sum_col_width + columns * cell_sep.size(); + return title_width + sum_col_width + columns_ * cell_sep_.size(); } - return std::max(max_row_id, title.size()); + return std::max(max_row_id, title_.size()); }; - s << std::string(head_rep_count(), table_header) << "\n"; - s << title << "\n"; - for (const auto& row : row_vec) { - s << left_justify(row.label.c, max_row_id); + out_stream << std::string(head_rep_count(), table_header_) << "\n"; + out_stream << title_ << "\n"; + for (const auto& row : row_vec_) { + out_stream << left_justify(row.label_.cell_value_, max_row_id); - if (!row.cells.empty() || colon_empty) { - s << ":"; + if (!row.cells_.empty() || colon_empty_) { + out_stream << ":"; } int col_num{0}; - auto num_beg = std::begin(row.cells); - const auto has_cells = num_beg != std::end(row.cells); + auto num_beg = std::begin(row.cells_); + const auto has_cells = num_beg != std::end(row.cells_); if (has_cells) { // print first row cell, then subsequent cells with *cell_sep* as prefix - s << right_justify(num_beg->c, col_width[col_num]); - std::for_each(std::next(num_beg), std::end(row.cells), [&](const auto& v) { - const auto width = col_width[++col_num]; - const auto aligned_cell = v.align == Cell::right ? right_justify(v.c, width) : left_justify(v.c, width); - s << cell_sep << aligned_cell; + out_stream << right_justify(num_beg->cell_value_, col_width[col_num]); + std::for_each(std::next(num_beg), std::end(row.cells_), [&](const Cell& v) { + const auto width = col_width[++col_num]; + const auto aligned_cell = + v.alignment_ == Cell::kRight ? right_justify(v.cell_value_, width) : left_justify(v.cell_value_, width); + out_stream << cell_sep_ << aligned_cell; }); } // fill up empty columns with empty_cell - const int padding = columns - col_num - 1; - if (padding > 0 && !empty_cell.empty()) { + const int padding = columns_ - col_num - 1; + if (padding > 0 && !empty_cell_.empty()) { const auto iterate_w = [&]() -> int { const auto width = col_width[++col_num]; return width; @@ -196,21 +199,21 @@ struct Table { // print first empty padding, then subsequent padding with *cell_sep* as prefix if (!has_cells) { - s << right_justify(empty_cell, iterate_w()); + out_stream << right_justify(empty_cell_, iterate_w()); } for (int pad = 0; pad < padding; ++pad) { - s << cell_sep << right_justify(empty_cell, iterate_w()); + out_stream << cell_sep_ << right_justify(empty_cell_, iterate_w()); } } - s << "\n"; + out_stream << "\n"; } - if (wrap_header) { + if (wrap_header_) { // Put header separation at bottom too - s << std::string(head_rep_count(), table_header) << "\n"; + out_stream << std::string(head_rep_count(), table_header_) << "\n"; } - s.flush(); + out_stream.flush(); } }; } // namespace typeart diff --git a/lib/typelib/TypeDB.cpp b/lib/typelib/TypeDB.cpp index f7dedad2..1dda449d 100644 --- a/lib/typelib/TypeDB.cpp +++ b/lib/typelib/TypeDB.cpp @@ -16,34 +16,75 @@ #include "support/Logger.h" #include "typelib/TypeInterface.h" +#include +#include +#include #include +#include #include namespace typeart { -std::pair, std::error_code> make_database(const std::string& file) { +namespace builtins { + +namespace { +inline constexpr auto size_complex_float = sizeof(std::complex); +inline constexpr auto size_complex_double = sizeof(std::complex); +inline constexpr auto size_complex_long_double = sizeof(std::complex); +} // namespace + +#define FOR_EACH_TYPEART_BUILTIN(X) \ + X(TYPEART_UNKNOWN_TYPE, "typeart_unknown_type", 0) \ + X(TYPEART_POINTER, "ptr", sizeof(void*)) \ + X(TYPEART_VTABLE_POINTER, "vtable_ptr", sizeof(void*)) \ + X(TYPEART_VOID, "void*", sizeof(void*)) \ + X(TYPEART_NULLPOINTER, "nullptr_t", sizeof(void*)) \ + X(TYPEART_BOOL, "bool", sizeof(bool)) \ + X(TYPEART_CHAR_8, "char", sizeof(char)) \ + X(TYPEART_UCHAR_8, "unsigned char", sizeof(unsigned char)) \ + X(TYPEART_UTF_CHAR_8, "char8_t", sizeof(char)) \ + X(TYPEART_UTF_CHAR_16, "char16_t", sizeof(char16_t)) \ + X(TYPEART_UTF_CHAR_32, "char32_t", sizeof(char32_t)) \ + X(TYPEART_INT_8, "int8_t", sizeof(int8_t)) \ + X(TYPEART_INT_16, "short", sizeof(int16_t)) \ + X(TYPEART_INT_32, "int", sizeof(int32_t)) \ + X(TYPEART_INT_64, "long int", sizeof(int64_t)) \ + X(TYPEART_INT_128, "int128_t", 16) \ + X(TYPEART_UINT_8, "uint8_t", sizeof(uint8_t)) \ + X(TYPEART_UINT_16, "unsigned short", sizeof(uint16_t)) \ + X(TYPEART_UINT_32, "unsigned int", sizeof(uint32_t)) \ + X(TYPEART_UINT_64, "unsigned long int", sizeof(uint64_t)) \ + X(TYPEART_UINT_128, "uint128_t", 16) \ + X(TYPEART_FLOAT_8, "float8_t", 1) \ + X(TYPEART_FLOAT_16, "float16_t", 2) \ + X(TYPEART_FLOAT_32, "float", sizeof(float)) \ + X(TYPEART_FLOAT_64, "double", sizeof(double)) \ + X(TYPEART_FLOAT_128, "long double", sizeof(long double)) \ + X(TYPEART_COMPLEX_64, "float complex", size_complex_float) \ + X(TYPEART_COMPLEX_128, "double complex", size_complex_double) \ + X(TYPEART_COMPLEX_256, "long double complex", size_complex_long_double) + +#define TYPENAME(enum_name, str_name, size) std::string{str_name}, +#define SIZE(enum_name, str_name, size) (size), +BuiltInQuery::BuiltInQuery() : names{FOR_EACH_TYPEART_BUILTIN(TYPENAME)}, sizes{FOR_EACH_TYPEART_BUILTIN(SIZE)} { +} +#undef SIZE +#undef TYPENAME + +} // namespace builtins + +std::pair, std::error_code> make_database(std::string_view file) { auto type_db = std::make_unique(); - auto loaded = io::load(type_db.get(), file); + auto loaded = io::load(type_db.get(), file.data()); if (!loaded) { LOG_DEBUG("Database file not found: " << file) } return {std::move(type_db), loaded.getError()}; } -const std::array TypeDB::BuiltinNames = { - "int8", "int16", "int32", "int64", "half", "float", "double", "float128", "x86_float80", "ppc_float128", "pointer"}; - -// TODO: Builtin ID changes lead tsto wrong type sizes/names -const std::array TypeDB::BuiltinSizes = {1, 2, - 4, 8, - 2, 4, - 8, 16, - 16, // TODO: Always correct? - 16, sizeof(void*)}; - -// TypeInfo TypeDB::InvalidType = TypeInfo{BUILTIN, TA_UNKNOWN_TYPE}; +using namespace builtins; -const std::string TypeDB::UnknownStructName{"typeart_unknown_struct"}; +const std::string unknown_struck_name{"typeart_unknown_struct"}; void TypeDB::clear() { struct_info_vec.clear(); @@ -52,23 +93,33 @@ void TypeDB::clear() { } bool TypeDB::isBuiltinType(int type_id) const { - return type_id >= TYPEART_INT8 && type_id < TYPEART_NUM_VALID_IDS; + return BuiltInQuery::is_builtin_type(type_id); } bool TypeDB::isReservedType(int type_id) const { - return type_id < TYPEART_NUM_RESERVED_IDS; + return BuiltInQuery::is_reserved_type(type_id); } bool TypeDB::isStructType(int type_id) const { - return type_id >= TYPEART_NUM_RESERVED_IDS; + return BuiltInQuery::is_userdef_type(type_id); +} + +bool TypeDB::isUnknown(int type_id) const { + return BuiltInQuery::is_unknown_type(type_id); +} + +bool TypeDB::isPointerType(int type_id) const { + return type_id == TYPEART_VOID || type_id == TYPEART_POINTER; } bool TypeDB::isUserDefinedType(int type_id) const { const auto* structInfo = getStructInfo(type_id); LOG_DEBUG(structInfo->name << " " << static_cast(structInfo->flag) << " " - << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::USER_DEFINED))) + << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::USER_DEFINED)) + << " " << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION))) return (structInfo != nullptr) && - (static_cast(structInfo->flag) == static_cast(StructTypeFlag::USER_DEFINED)); + (static_cast(structInfo->flag) == static_cast(StructTypeFlag::USER_DEFINED) || + static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION)); } bool TypeDB::isVectorType(int type_id) const { @@ -79,6 +130,13 @@ bool TypeDB::isVectorType(int type_id) const { (static_cast(structInfo->flag) == static_cast(StructTypeFlag::LLVM_VECTOR)); } +bool TypeDB::isUnion(int type_id) const { + const auto* structInfo = getStructInfo(type_id); + LOG_DEBUG(structInfo->name << " " << static_cast(structInfo->flag) << " " + << (static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION))) + return (structInfo != nullptr) && (static_cast(structInfo->flag) == static_cast(StructTypeFlag::UNION)); +} + bool TypeDB::isValid(int type_id) const { if (isBuiltinType(type_id)) { return true; @@ -106,13 +164,14 @@ void TypeDB::registerStruct(const StructTypeInfo& struct_type, bool overwrite) { } return; } + struct_info_vec.push_back(struct_type); typeid_to_list_index.insert({struct_type.type_id, struct_info_vec.size() - 1}); } const std::string& TypeDB::getTypeName(int type_id) const { if (isBuiltinType(type_id)) { - return BuiltinNames[type_id]; + return builtins.get_name(type_id); } if (isStructType(type_id)) { const auto* structInfo = getStructInfo(type_id); @@ -120,13 +179,14 @@ const std::string& TypeDB::getTypeName(int type_id) const { return structInfo->name; } } - return UnknownStructName; + + return unknown_struck_name; } size_t TypeDB::getTypeSize(int type_id) const { if (isReservedType(type_id)) { if (isBuiltinType(type_id)) { - return BuiltinSizes[type_id]; + return builtins.get_size(type_id); } return 0; } @@ -158,8 +218,4 @@ const std::vector& TypeDB::getStructList() const { return struct_info_vec; } -bool TypeDB::isUnknown(int type_id) const { - return type_id == TYPEART_UNKNOWN_TYPE; -} - } // namespace typeart diff --git a/lib/typelib/TypeDB.h b/lib/typelib/TypeDB.h index 63d75c3a..25227547 100644 --- a/lib/typelib/TypeDB.h +++ b/lib/typelib/TypeDB.h @@ -14,6 +14,7 @@ #define LLVM_MUST_SUPPORT_TYPECONFIG_H #include "TypeDatabase.h" +#include "TypeInterface.h" #include #include @@ -23,6 +24,51 @@ namespace typeart { +namespace builtins { + +struct BuiltInQuery { + private: + std::array names; + std::array sizes; + + template + static constexpr auto type_info(const U& type_data, int type_id) -> decltype(type_data[type_id]) { + if (type_id < 0 || type_id >= TYPEART_NUM_VALID_IDS) { + return type_data[TYPEART_UNKNOWN_TYPE]; + } + return type_data[type_id]; + } + + public: + BuiltInQuery(); + + [[nodiscard]] constexpr size_t get_size(int type_id) const { + return type_info(sizes, type_id); + } + + [[nodiscard]] const std::string& get_name(int type_id) const { + return type_info(names, type_id); + } + + static constexpr bool is_builtin_type(int type_id) { + return type_id > TYPEART_UNKNOWN_TYPE && type_id < TYPEART_NUM_VALID_IDS; + } + + static constexpr bool is_reserved_type(int type_id) { + return type_id < TYPEART_NUM_RESERVED_IDS; + } + + static constexpr bool is_userdef_type(int type_id) { + return type_id >= TYPEART_NUM_RESERVED_IDS; + } + + static constexpr bool is_unknown_type(int type_id) { + return type_id == TYPEART_UNKNOWN_TYPE; + } +}; + +} // namespace builtins + class TypeDB final : public TypeDatabase { public: void clear() override; @@ -37,12 +83,16 @@ class TypeDB final : public TypeDatabase { bool isBuiltinType(int type_id) const override; + bool isPointerType(int type_id) const override; + bool isStructType(int type_id) const override; bool isUserDefinedType(int type_id) const override; bool isVectorType(int type_id) const override; + bool isUnion(int type_id) const override; + const std::string& getTypeName(int type_id) const override; const StructTypeInfo* getStructInfo(int type_id) const override; @@ -52,11 +102,8 @@ class TypeDB final : public TypeDatabase { const std::vector& getStructList() const override; - static const std::array BuiltinNames; - static const std::array BuiltinSizes; - static const std::string UnknownStructName; - private: + builtins::BuiltInQuery builtins; std::vector struct_info_vec; std::unordered_map typeid_to_list_index; }; diff --git a/lib/typelib/TypeDatabase.h b/lib/typelib/TypeDatabase.h index fbf42ea7..b32b521b 100644 --- a/lib/typelib/TypeDatabase.h +++ b/lib/typelib/TypeDatabase.h @@ -15,13 +15,14 @@ #include #include +#include #include #include #include namespace typeart { -enum class StructTypeFlag : int { USER_DEFINED = 1, LLVM_VECTOR = 2, FWD_DECL = 4 }; +enum class StructTypeFlag : int { USER_DEFINED = 1, LLVM_VECTOR = 2, FWD_DECL = 4, UNION = 8 }; struct StructTypeInfo { int type_id; @@ -48,12 +49,16 @@ class TypeDatabase { [[nodiscard]] virtual bool isBuiltinType(int type_id) const = 0; + [[nodiscard]] virtual bool isPointerType(int type_id) const = 0; + [[nodiscard]] virtual bool isStructType(int type_id) const = 0; [[nodiscard]] virtual bool isUserDefinedType(int type_id) const = 0; [[nodiscard]] virtual bool isVectorType(int type_id) const = 0; + [[nodiscard]] virtual bool isUnion(int type_id) const = 0; + [[nodiscard]] virtual const std::string& getTypeName(int type_id) const = 0; [[nodiscard]] virtual const StructTypeInfo* getStructInfo(int type_id) const = 0; @@ -67,7 +72,7 @@ class TypeDatabase { virtual ~TypeDatabase() = default; }; -std::pair, std::error_code> make_database(const std::string& file); +std::pair, std::error_code> make_database(std::string_view file); } // namespace typeart diff --git a/lib/typelib/TypeIO.cpp b/lib/typelib/TypeIO.cpp index 47fe3b68..6c99bf26 100644 --- a/lib/typelib/TypeIO.cpp +++ b/lib/typelib/TypeIO.cpp @@ -54,7 +54,7 @@ struct llvm::yaml::ScalarTraits { } else { value = static_cast(flag); } - return StringRef(); + return {}; } // Determine if this scalar needs quotes. diff --git a/lib/typelib/TypeInterface.h b/lib/typelib/TypeInterface.h index 9efc55c2..f22083e9 100644 --- a/lib/typelib/TypeInterface.h +++ b/lib/typelib/TypeInterface.h @@ -13,31 +13,53 @@ #ifndef TYPEART_TYPEINTERFACE_H #define TYPEART_TYPEINTERFACE_H -#ifdef __cplusplus -#include -#else -#include -#endif - #ifdef __cplusplus extern "C" { #endif -typedef enum typeart_builtin_type_t { // NOLINT - TYPEART_INT8 = 0, // 8 bit signed integer - TYPEART_INT16 = 1, // 16 bit signed integer - TYPEART_INT32 = 2, // 32 bit signed integer - TYPEART_INT64 = 3, // 64 bit signed integer - TYPEART_HALF = 4, // IEEE 754 half precision floating point type - TYPEART_FLOAT = 5, // IEEE 754 single precision floating point type - TYPEART_DOUBLE = 6, // IEEE 754 double precision floating point type - TYPEART_FP128 = 7, // IEEE 754 quadruple precision floating point type - TYPEART_X86_FP80 = 8, // x86 extended precision 80-bit floating point type - TYPEART_PPC_FP128 = 9, // ICM extended precision 128-bit floating point type - TYPEART_POINTER = 10, // Represents all pointer types - TYPEART_NUM_VALID_IDS = TYPEART_POINTER + 1, // Number of valid built-in types - TYPEART_UNKNOWN_TYPE = 255, // Placeholder for unknown types - TYPEART_NUM_RESERVED_IDS = TYPEART_UNKNOWN_TYPE + 1 // Represents user-defined types +typedef enum typeart_builtin_type_t { // NOLINT + TYPEART_UNKNOWN_TYPE = 0, + + TYPEART_POINTER, + TYPEART_VTABLE_POINTER, + TYPEART_VOID, + TYPEART_NULLPOINTER, + + TYPEART_BOOL, + + TYPEART_CHAR_8, + + TYPEART_UCHAR_8, + + TYPEART_UTF_CHAR_8, + TYPEART_UTF_CHAR_16, + TYPEART_UTF_CHAR_32, + + TYPEART_INT_8, + TYPEART_INT_16, + TYPEART_INT_32, + TYPEART_INT_64, + TYPEART_INT_128, + + TYPEART_UINT_8, + TYPEART_UINT_16, + TYPEART_UINT_32, + TYPEART_UINT_64, + TYPEART_UINT_128, + + TYPEART_FLOAT_8, + TYPEART_FLOAT_16, + TYPEART_FLOAT_32, + TYPEART_FLOAT_64, + TYPEART_FLOAT_128, + + TYPEART_COMPLEX_64, + TYPEART_COMPLEX_128, + TYPEART_COMPLEX_256, + + TYPEART_NUM_VALID_IDS, + + TYPEART_NUM_RESERVED_IDS = 256 } typeart_builtin_type; #ifdef __cplusplus diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 57cffa8b..02261556 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -1,6 +1,6 @@ function(typeart_configure_script input output) cmake_parse_arguments( - ARG "" "" "INSTALL_MODE;COMPILER;WITH_FILTER;APPLY_MODE" ${ARGN} + ARG "" "" "INSTALL_MODE;COMPILER;WITH_FILTER;APPLY_MODE;OPT" ${ARGN} ) set(TYPEART_SAN_FLAGS "") @@ -31,16 +31,16 @@ function(typeart_configure_script input output) set(TYPEART_PASS_DIR ${LIBRARY_OUTPUT_PATH}) set(TYPEART_ANALYSIS_PASS_DIR ${LIBRARY_OUTPUT_PATH}) else() - set(TYPEART_MPI_INTERCEPT_DIR ${CMAKE_BINARY_DIR}/lib/mpi_interceptor) - set(TYPEART_RT_DIR ${CMAKE_BINARY_DIR}/lib/runtime) - set(TYPEART_PASS_DIR ${CMAKE_BINARY_DIR}/lib/passes) + set(TYPEART_MPI_INTERCEPT_DIR ${CMAKE_CURRENT_BINARY_DIR}/../lib/mpi_interceptor) + set(TYPEART_RT_DIR ${CMAKE_CURRENT_BINARY_DIR}/../lib/runtime) + set(TYPEART_PASS_DIR ${CMAKE_CURRENT_BINARY_DIR}/../lib/passes) set(TYPEART_ANALYSIS_PASS_DIR ${TYPEART_PASS_DIR}/analysis) endif() if(EXECUTABLE_OUTPUT_PATH) set(TYPEART_BINARY_DIR ${EXECUTABLE_OUTPUT_PATH}) else() - set(TYPEART_BINARY_DIR ${CMAKE_BINARY_DIR}) + set(TYPEART_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..) endif() set(TYPEART_RELOCATABLE 0) @@ -59,8 +59,10 @@ function(typeart_configure_script input output) endif() set(TYPEART_OPT "${TYPEART_OPT_EXEC}") - if(${LLVM_VERSION_MAJOR} VERSION_GREATER_EQUAL "13") - set(TYPEART_OPT "${TYPEART_OPT} -enable-new-pm=0") + set(NEW_PM_REQUIRED 1) + + if(ARG_OPT) + set(TYPEART_OPT "${CMAKE_BINARY_DIR}/scripts/opt-shim") endif() set(TYPEART_LLC "${TYPEART_LLC_EXEC}") @@ -72,7 +74,7 @@ function(typeart_configure_script input output) endif() if(ARG_WITH_FILTER) - set(TYPEART_CALLFILTER "--typeart-filter") + set(TYPEART_CALLFILTER ";filter") endif() if(TYPEART_TSAN) @@ -91,6 +93,15 @@ function(typeart_configure_script input output) list(JOIN TYPEART_SAN_FLAGS " " TYPEART_SAN_FLAGS) + if(${LLVM_VERSION_MAJOR} GREATER_EQUAL 18) + # FIXME workaround, enabled by default? > not compat with dimeta + set(TYPEART_INITIAL_FLAGS "-Xclang -fexperimental-assignment-tracking=disabled") + endif() + + if(ARG_WITH_FILTER) + set(TYPEART_FILTER_FLAG "export TYPEART_FILTER=\${TYPEART_FILTER:-1}") + endif() + typeart_target_generate_file(${input} ${output}) endfunction() @@ -168,38 +179,40 @@ endfunction() typeart_configure_coverage_script(llvm-gcov.sh.in llvm-gcov.sh) -typeart_configure_script(typeart-tmpl.sh.in run.sh) +typeart_configure_script(opt-shim.in opt-shim) + +typeart_configure_script(typeart-tmpl.sh.in run.sh + OPT ON) typeart_configure_script(typeart-tmpl.sh.in apply.sh APPLY_MODE ON + OPT ON ) -typeart_configure_script( - typeart-tmpl.sh.in typeart-run${CMAKE_DEBUG_POSTFIX}.sh - INSTALL_MODE ON -) -typeart_configure_script( - typeart-tmpl.sh.in typeart-apply${CMAKE_DEBUG_POSTFIX}.sh - INSTALL_MODE ON - APPLY_MODE ON -) +typeart_configure_script(reduce-tester.in reduce-tester.sh) + +if(TYPEART_USE_LEGACY_WRAPPER) + set(TYPEART_WRAPPER_FILE typeart-wrapper.in) +else() + set(TYPEART_WRAPPER_FILE typeart-wrapperv2.in) +endif() typeart_configure_script( - typeart-wrapper.in typeart-clang${CMAKE_DEBUG_POSTFIX} + ${TYPEART_WRAPPER_FILE} typeart-clang${CMAKE_DEBUG_POSTFIX} INSTALL_MODE ON COMPILER ${TYPEART_CLANG_EXEC} ) typeart_configure_script( - typeart-wrapper.in typeart-clang++${CMAKE_DEBUG_POSTFIX} + ${TYPEART_WRAPPER_FILE} typeart-clang++${CMAKE_DEBUG_POSTFIX} INSTALL_MODE ON COMPILER ${TYPEART_CLANGCXX_EXEC} ) typeart_configure_script( - typeart-wrapper.in typeart-clang-test + ${TYPEART_WRAPPER_FILE} typeart-clang-test COMPILER ${TYPEART_CLANG_EXEC} ) typeart_configure_script( - typeart-wrapper.in typeart-clang++-test + ${TYPEART_WRAPPER_FILE} typeart-clang++-test COMPILER ${TYPEART_CLANGCXX_EXEC} ) @@ -209,13 +222,13 @@ endif() if(MPI_C_FOUND) typeart_configure_script( - typeart-wrapper.in typeart-mpicc${CMAKE_DEBUG_POSTFIX} + ${TYPEART_WRAPPER_FILE} typeart-mpicc${CMAKE_DEBUG_POSTFIX} INSTALL_MODE ON WITH_FILTER ON COMPILER "${TYPEART_MPICC}" ) typeart_configure_script( - typeart-wrapper.in typeart-mpicc-test + ${TYPEART_WRAPPER_FILE} typeart-mpicc-test WITH_FILTER ON COMPILER "${TYPEART_MPICC}" ) @@ -223,13 +236,13 @@ endif() if(MPI_CXX_FOUND) typeart_configure_script( - typeart-wrapper.in typeart-mpic++${CMAKE_DEBUG_POSTFIX} + ${TYPEART_WRAPPER_FILE} typeart-mpic++${CMAKE_DEBUG_POSTFIX} INSTALL_MODE ON WITH_FILTER ON COMPILER "${TYPEART_MPICXX}" ) typeart_configure_script( - typeart-wrapper.in typeart-mpic++-test + ${TYPEART_WRAPPER_FILE} typeart-mpic++-test WITH_FILTER ON COMPILER "${TYPEART_MPICXX}" ) @@ -240,16 +253,12 @@ set(TYPEART_INSTALL_SCRIPT_CANDIDATE typeart-mpic++ typeart-clang++ typeart-clang - typeart-run - typeart-apply CACHE INTERNAL "Names of TypeART scripts which can be installed." ) install( PROGRAMS - $<$:${CMAKE_CURRENT_BINARY_DIR}/typeart-run${CMAKE_DEBUG_POSTFIX}.sh> - $<$:${CMAKE_CURRENT_BINARY_DIR}/typeart-apply${CMAKE_DEBUG_POSTFIX}.sh> ${CMAKE_CURRENT_BINARY_DIR}/typeart-clang++${CMAKE_DEBUG_POSTFIX} ${CMAKE_CURRENT_BINARY_DIR}/typeart-clang${CMAKE_DEBUG_POSTFIX} $<$,$>:${CMAKE_CURRENT_BINARY_DIR}/typeart-mpicc${CMAKE_DEBUG_POSTFIX}> diff --git a/scripts/opt-shim.in b/scripts/opt-shim.in new file mode 100644 index 00000000..c3dc9af0 --- /dev/null +++ b/scripts/opt-shim.in @@ -0,0 +1,88 @@ +#!/bin/bash + +function typeart_test_parse_cmd_line_fn() { + while (("$#")); do + case "$1" in + --typeart-stats=*) + export TYPEART_STATS="${1#--typeart-stats=}" + shift + ;; + --typeart-heap=*) + export TYPEART_HEAP="${1#--typeart-heap=}" + shift + ;; + --typeart-stack=*) + export TYPEART_STACK="${1#--typeart-stack=}" + shift + ;; + --typeart-global=*) + export TYPEART_GLOBAL="${1#--typeart-global=}" + shift + ;; + --typeart-types=*) + export TYPEART_TYPE_FILE="${1#--typeart-types=}" + shift + ;; + --typeart-stack-lifetime=*) + export TYPEART_STACK_LIFETIME="${1#--typeart-stack-lifetime=}" + shift + ;; + --typeart-typegen=*) + export TYPEART_TYPEGEN="${1#--typeart-typegen=}" + shift + ;; + --typeart-filter=*) + export TYPEART_FILTER="${1#--typeart-filter=}" + shift + ;; + --typeart-filter-implementation=*) + export TYPEART_FILTER_IMPLEMENTATION="${1#--typeart-filter-implementation=}" + shift + ;; + --typeart-filter-glob=*) + export TYPEART_FILTER_GLOB="${1#--typeart-filter-glob=}" + shift + ;; + --typeart-filter-glob-deep=*) + export TYPEART_FILTER_GLOB_DEEP="${1#--typeart-filter-glob-deep=}" + shift + ;; + --typeart-filter-cg-file=*) + export TYPEART_FILTER_CG_FILE="${1#--typeart-filter-cg-file=}" + shift + ;; + --typeart-analysis-filter-non-array-alloca=*) + export TYPEART_ANALYSIS_FILTER_NON_ARRAY_ALLOCA="${1#--typeart-analysis-filter-non-array-alloca=}" + shift + ;; + --typeart-analysis-filter-heap-alloca=*) + export TYPEART_ANALYSIS_FILTER_HEAP_ALLOCA="${1#--typeart-analysis-filter-heap-alloca=}" + shift + ;; + --typeart-analysis-filter-global=*) + export TYPEART_ANALYSIS_FILTER_GLOBAL="${1#--typeart-analysis-filter-global=}" + shift + ;; + --typeart-analysis-filter-pointer-alloca=*) + export TYPEART_ANALYSIS_FILTER_POINTER_ALLOCA="${1#--typeart-analysis-filter-pointer-alloca=}" + shift + ;; + *) + typeart_test_pass_wrapper_more_args+=" $1" + shift 1 + ;; + esac + done +} + +function typeart_test_main_opt_fn() { + readonly typeart_opt_tool="@TYPEART_OPT_EXEC@" + if [ "@NEW_PM_REQUIRED@" == "1" ]; then + typeart_test_parse_cmd_line_fn "$@" + else + typeart_test_pass_wrapper_more_args+="$@" + fi + $typeart_opt_tool ${typeart_test_pass_wrapper_more_args} +} + +typeart_test_main_opt_fn "$@" diff --git a/scripts/reduce-tester.in b/scripts/reduce-tester.in new file mode 100644 index 00000000..3566f6f9 --- /dev/null +++ b/scripts/reduce-tester.in @@ -0,0 +1,10 @@ +#!/bin/bash + +# Usage: llvm-reduce --test=path/to/reduce-tester.sh input.ll +# Usage: TYPEART_REDUCE=Segmentation llvm-reduce --test=path/to/reduce-tester.sh input.ll + +verifier_pass="@TYPEART_PASS_DIR@/$" +test_interest=${TYPEART_REDUCE:-Assert} +typeart_mode=${TYPEART_MODE:-heap} + +@TYPEART_OPT@ -load-pass-plugin ${verifier_pass} -passes="typeart<${typeart_mode}>" --disable-output $1 |& grep "${test_interest}" diff --git a/scripts/show-source-ll.sh b/scripts/show-source-ll.sh deleted file mode 100755 index 0d13e19c..00000000 --- a/scripts/show-source-ll.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# -# TypeART library -# -# Copyright (c) 2017-2025 TypeART Authors -# Distributed under the BSD 3-Clause license. -# (See accompanying file LICENSE.txt or copy at -# https://opensource.org/licenses/BSD-3-Clause) -# -# Project home: https://github.com/tudasc/TypeART -# -# SPDX-License-Identifier: BSD-3-Clause -# -# - -target=$1 -extension="${target##*.}" - -if [ $extension == "c" ]; then - compiler=clang -else - compiler=clang++ -fi - -echo "|----------------------------------------------------------|" -echo "|------------------------Source----------------------------|" -echo "|----------------------------------------------------------|" -cat "$target" -echo "|----------------------------------------------------------|" -echo "|--------------------------LL------------------------------|" -echo "|----------------------------------------------------------|" -$compiler -S -emit-llvm -fno-discard-value-names "$target" -o - diff --git a/scripts/typeart-tmpl.sh.in b/scripts/typeart-tmpl.sh.in index 87632013..0d5b88b2 100644 --- a/scripts/typeart-tmpl.sh.in +++ b/scripts/typeart-tmpl.sh.in @@ -143,16 +143,16 @@ function global_init() { -l$" # shellcheck disable=SC2027 - typeart_plugin="-load "${typeart_pass}" -typeart" + typeart_plugin="-load-pass-plugin "${typeart_pass}" -passes=typeart<" case "${TYPEART_TYPEGEN_IR}" in on | ON | 1 | true | TRUE) - typeart_plugin+=" --typeart-typegen=ir" + typeart_plugin+="typegen=ir;" ;; esac - readonly typeart_stack_mode_args="-typeart-heap=false -typeart-stack -typeart-stats" - readonly typeart_heap_mode_args="-typeart-heap=true -typeart-stats" - readonly typeart_combined_mode_args="${typeart_heap_mode_args} -typeart-stack" + readonly typeart_stack_mode_args="no-heap;stack;stats>" + readonly typeart_heap_mode_args="heap;stats>" + readonly typeart_combined_mode_args="heap;stats;stack>" } function toolchain_init() { @@ -179,13 +179,15 @@ function toolchain_init() { readonly typeart_san_flags="@TYPEART_SAN_FLAGS@" - if [ -e "types.yaml" ]; then - rm "types.yaml" + if [ -e "typeart-types.yaml" ]; then + rm "typeart-types.yaml" fi } function source_to_llvm() { - $compiler ${omp_flags} ${typeart_includes} ${typeart_san_flags} \ + # flag errors with implicit conversions when changing API + local error_flags="-Werror=incompatible-pointer-types" + $compiler ${error_flags} ${omp_flags} ${typeart_includes} ${typeart_san_flags} \ -O1 -g ${compile_flags} -Xclang -disable-llvm-passes -S -emit-llvm "${source_file}" -o - } @@ -197,9 +199,9 @@ function apply_typeart() { function apply_typeart_optim() { source_to_llvm | - $opt_tool ${typeart_plugin} ${typeart_heap_mode_args} ${ta_more_args} | + $opt_tool ${typeart_plugin}${typeart_heap_mode_args} ${ta_more_args} | $opt_tool ${optimize} -S | - $opt_tool ${typeart_plugin} ${typeart_stack_mode_args} ${ta_more_args} + $opt_tool ${typeart_plugin}${typeart_stack_mode_args} ${ta_more_args} } function make_no_optim() { @@ -211,7 +213,7 @@ function make_no_optim() { apply_typeart fi else - # First create types.yaml: + # First create typeart-types.yaml: apply_typeart >/dev/null if [ $show_ir == 0 ]; then @@ -231,7 +233,7 @@ function make_with_optim() { apply_typeart_optim fi else - # First create types.yaml: + # First create typeart-types.yaml: apply_typeart_optim >/dev/null if [ $show_ir == 0 ]; then @@ -258,8 +260,8 @@ function main_link() { function execute() { if [ $clean_types_file == 1 ]; then - if [ -e "types.yaml" ]; then - rm "types.yaml" + if [ -e "typeart-types.yaml" ]; then + rm "typeart-types.yaml" fi fi diff --git a/scripts/typeart-wrapper.in b/scripts/typeart-wrapper.in index 9661574c..2d5b0abc 100755 --- a/scripts/typeart-wrapper.in +++ b/scripts/typeart-wrapper.in @@ -13,17 +13,6 @@ # function typeart_global_env_var_init_fn() { - if [ -n "${TYPEART_WRAPPER_CONFIG+x}" ]; then - typeart_cmdline_args_heap="${TYPEART_WRAPPER_CONFIG}" - typeart_cmdline_args_stack="${TYPEART_WRAPPER_CONFIG}" - fi - if [ -n "${TYPEART_WRAPPER_HEAP_CONFIG+x}" ]; then - typeart_cmdline_args_heap="${TYPEART_WRAPPER_HEAP_CONFIG}" - fi - if [ -n "${TYPEART_WRAPPER_STACK_CONFIG+x}" ]; then - typeart_cmdline_args_stack="${TYPEART_WRAPPER_STACK_CONFIG}" - fi - # shellcheck disable=SC2153 case "${TYPEART_WRAPPER_EMIT_IR}" in on | ON | 1 | true | TRUE) @@ -72,20 +61,17 @@ function typeart_global_init_fn() { -l$" readonly typeart_san_flags="@TYPEART_SAN_FLAGS@" - typeart_plugin="-load "${typeart_pass}" -typeart" - # shellcheck disable=SC2027 + typeart_plugin="-load-pass-plugin "${typeart_pass}" -passes=typeart<" + case "${TYPEART_TYPEGEN_IR}" in on | ON | 1 | true | TRUE) - typeart_plugin+=" --typeart-typegen=ir" + typeart_plugin+="typegen=ir;" ;; esac - readonly typeart_stack_mode_args="--typeart-heap=false --typeart-stack --typeart-stats @TYPEART_CALLFILTER@" - readonly typeart_heap_mode_args="--typeart-heap=true --typeart-stats" + readonly typeart_stack_mode_args="no-heap;stack;stats@TYPEART_CALLFILTER@>" + readonly typeart_heap_mode_args="heap;stats>" - # Used for values passed to wrapper: - typeart_cmdline_args_heap="" - typeart_cmdline_args_stack="" typeart_global_env_var_init_fn readonly typeart_to_llvm_flags="-g -O1 -Xclang -disable-llvm-passes -c -emit-llvm" @@ -197,32 +183,6 @@ function typeart_handle_binary_fn() { return 2 } -function typeart_parse_typeart_cmd_line_fn() { - typeart_other_args="" - - while (("$#")); do - case "$1" in - --typeart-config=*) - typeart_cmdline_args_heap="${1##-typeart-config=}" - typeart_cmdline_args_stack="${1##-typeart-config=}" - shift - ;; - --typeart-heap-config=*) - typeart_cmdline_args_heap="${1##-typeart-heap-config=}" - shift - ;; - --typeart-stack-config=*) - typeart_cmdline_args_stack="${1##-typeart-stack-config=}" - shift - ;; - *) # preserve other arguments - typeart_other_args+=" $1" - shift - ;; - esac - done -} - # shellcheck disable=SC2034 function typeart_parse_cmd_line_fn() { typeart_found_src_file=0 @@ -320,8 +280,7 @@ function typeart_parse_cmd_line_fn() { } function typeart_parse_commands_fn() { - typeart_parse_typeart_cmd_line_fn "$@" - typeart_parse_cmd_line_fn ${typeart_other_args} + typeart_parse_cmd_line_fn "$@" } function typeart_main_link_fn() { @@ -401,9 +360,9 @@ function typeart_main_compile_fn() { # shellcheck disable=SC2086 typeart_compiler_fn "${out_basename}"_base.ll ${typeart_wrapper_more_args} ${typeart_includes} ${typeart_san_flags} \ ${typeart_to_llvm_flags} ${typeart_to_llvm_more_flags} "${typeart_source_file}" -o - | - typeart_opt_fn "${out_basename}"_heap.ll ${typeart_plugin} ${typeart_heap_mode_args} ${typeart_cmdline_args_heap} | + typeart_opt_fn "${out_basename}"_heap.ll ${typeart_plugin}${typeart_heap_mode_args} | typeart_opt_fn "${out_basename}"_opt.ll ${typeart_optimize} | - typeart_opt_fn "${out_basename}"_stack.ll ${typeart_plugin} ${typeart_stack_mode_args} ${typeart_cmdline_args_stack} | + typeart_opt_fn "${out_basename}"_stack.ll ${typeart_plugin}${typeart_stack_mode_args} | typeart_tu_out_fn } diff --git a/scripts/typeart-wrapperv2.in b/scripts/typeart-wrapperv2.in new file mode 100644 index 00000000..ef0557c8 --- /dev/null +++ b/scripts/typeart-wrapperv2.in @@ -0,0 +1,105 @@ +#!/bin/bash +# +# TypeART library +# +# Copyright (c) 2017-2025 TypeART Authors +# Distributed under the BSD 3-Clause license. +# (See accompanying file LICENSE.txt or copy at +# https://opensource.org/licenses/BSD-3-Clause) +# +# Project home: https://github.com/tudasc/TypeART +# +# SPDX-License-Identifier: BSD-3-Clause +# + +function typeart_is_wrapper_disabled_fn() { + case "${TYPEART_WRAPPER}" in + off | OFF | 0 | false | FALSE) + return 1 + ;; + esac + return 0 +} + +function typeart_global_init_fn() { + local -r typeart_use_rel_path=@TYPEART_RELOCATABLE@ + if [ "$typeart_use_rel_path" == 0 ]; then + local -r typeart_bin_dir="@TYPEART_BINARY_DIR@" + local -r typeart_lib_dir="@TYPEART_RT_DIR@" + local -r typeart_include_dir="@TYPEART_INCLUDE_DIRS@" + local -r typeart_pass="@TYPEART_PASS_DIR@/$" + else + # shellcheck disable=SC2155 + local -r typeart_bin_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + # shellcheck disable=SC2155 + local -r typeart_install_dir="$(dirname "${typeart_bin_dir}")" + local -r typeart_lib_dir="${typeart_install_dir}/@CMAKE_INSTALL_LIBDIR@" + local -r typeart_include_dir="-I${typeart_install_dir}/@CMAKE_INSTALL_INCLUDEDIR@/@PROJECT_NAME@" + local -r typeart_pass="${typeart_lib_dir}/$" + fi + + readonly typeart_compiler="@TYPEART_COMPILER@" + + readonly typeart_includes="${typeart_include_dir}" + readonly typeart_ldflags="-L${typeart_lib_dir}/ \ + -Wl,-rpath,${typeart_lib_dir}/ \ + -l$" + readonly typeart_san_flags="@TYPEART_SAN_FLAGS@" + readonly typeart_plugin="-fpass-plugin="${typeart_pass}"" + + typeart_more_flags="@TYPEART_INITIAL_FLAGS@" + @TYPEART_FILTER_FLAG@ + case "${TYPEART_WRAPPER_EMIT_IR}" in + on | ON | 1 | true | TRUE) + export TYPEART_PASS_INTERNAL_EMIT_IR=1 + typeart_more_flags+=" -fno-discard-value-names" + ;; + esac +} + +function typeart_is_linking_fn() { + local arg="" + for arg in "$@"; do + case "$arg" in + -c | -S | -E | -emit-llvm) + return 0 + ;; + esac + done + return 1 +} + +function typeart_parse_cmd_line_fn() { + local typeart_has_debug=0 + for arg in "$@"; do + if [ "$arg" = "-g" ]; then + typeart_has_debug=1 + break + fi + done + if [ $typeart_has_debug == 0 ]; then + typeart_more_flags+=" -g" + fi +} + +function typeart_main_driver_fn() { + typeart_global_init_fn + + typeart_is_wrapper_disabled_fn + if [ "$?" == 1 ]; then + # shellcheck disable=SC2068 + $typeart_compiler $@ + return 0 + fi + + typeart_parse_cmd_line_fn "$@" + + typeart_is_linking_fn "$@" + if [ "$?" == 1 ]; then + typeart_more_flags+=" ${typeart_ldflags}" + fi + + $typeart_compiler ${typeart_plugin} ${typeart_includes} ${typeart_more_flags} ${typeart_san_flags} $@ +} + +typeart_main_driver_fn "$@" diff --git a/scripts/typeart_ir_viewer.py b/scripts/typeart_ir_viewer.py index bf8547d0..6a430d2f 100755 --- a/scripts/typeart_ir_viewer.py +++ b/scripts/typeart_ir_viewer.py @@ -115,7 +115,7 @@ def make_typeart_ir(config): env = { **os.environ, "TYPEART_WRAPPER_EMIT_IR": "1", - "TYPEART_TYPE_FILE": str(config.types_file), + "TYPEART_TYPES": str(config.types_file), } subprocess.check_call([typeart_wrapper] + config.wrapper_args + [config.source_file], env=env, cwd=source_dir) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1d9b2fd7..c6ed9114 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,6 +12,8 @@ typeart_find_llvm_progs(TYPEART_LIT_EXEC ABORT_IF_MISSING ) +# add_subdirectory(compat) + macro(pythonize_bool truth_var var) if(${truth_var}) set(${var} True) @@ -53,9 +55,10 @@ function(typeart_configure_lit_site input output) set(TYPEART_COVERAGE True) endif() - if(${LLVM_VERSION_MAJOR} VERSION_GREATER_EQUAL "13") - set(TYPEART_OPT_ARGS "-enable-new-pm=0") - endif() + set(TYPEART_USE_NEW_PM True) + set(TYPEART_OPT_EXEC "${CMAKE_BINARY_DIR}/scripts/opt-shim") + + pythonize_bool(TYPEART_USE_LEGACY_WRAPPER TYPEARTPASS_LEGACY_WRAPPER) set(LIT_SITE_CFG_IN_HEADER "## Autogenerated by TypeART generation from ${input}\n## Do not edit!" @@ -93,13 +96,16 @@ function(typeart_add_lit_testsuite target comment) endfunction() function(typeart_add_lit_target) - cmake_parse_arguments(ARG "" "" "SUITES" ${ARGN}) + cmake_parse_arguments(ARG "" "" "SUITES;WORKERS" ${ARGN}) - foreach(suite IN LISTS ARG_SUITES) + foreach(suite workers IN ZIP_LISTS ARG_SUITES ARG_WORKERS) if("${suite}" STREQUAL "all") set(SUITE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) set(TARGET_NAME check-typeart) else() + if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${suite}) + continue() + endif() set(SUITE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${suite}) set(TARGET_NAME check-typeart-${suite}) endif() @@ -112,7 +118,7 @@ function(typeart_add_lit_target) typeart_add_lit_testsuite(${TARGET_NAME} "Running the lit suite TypeART::${suite}" ${SUITE_PATH} - ARGS -v -j 1 + ARGS --show-unsupported -v -j ${workers} PARAMS typeartpass_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg DEPENDS ${TYPEART_TEST_DEPENDS} ) @@ -125,15 +131,33 @@ set(TYPEART_TEST_DEPENDS typeart::Types ) +include(ProcessorCount) +ProcessorCount(NUM_CPU) +if(NUM_CPU EQUAL 0) + set(NUM_CPU 1) +elseif(NUM_CPU GREATER_EQUAL 8) + set(NUM_CPU 8) +endif() + set(TYPEART_SUITES all pass runtime script typemapping + staging +) + +set(TYPEART_SUITES_WORKERS + 1 + ${NUM_CPU} + 1 + 1 + ${NUM_CPU} + 1 ) -typeart_add_lit_target(SUITES ${TYPEART_SUITES}) +typeart_add_lit_target(SUITES ${TYPEART_SUITES} WORKERS ${TYPEART_SUITES_WORKERS}) add_test( NAME typeart-lit-suite diff --git a/test/lit.cfg b/test/lit.cfg index 81ea0c70..d7cde5df 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -19,7 +19,9 @@ if not loaded_site_cfg: config.test_format = lit.formats.ShTest(execute_external=True) config.suffixes = ['.c','.cpp', '.llin', '.sh'] -config.excludes = ['Inputs', 'mpi_interceptor', 'lulesh'] +config.excludes = ['Inputs'] + +config.available_features.add('llvm-{}'.format(config.llvm_version)) if config.softcounter_used: config.available_features.add('softcounter') @@ -49,6 +51,9 @@ if config.tsan or config.asan or config.ubsan: if config.coverage: config.available_features.add('coverage') +if config.has_legacy_wrapper: + config.available_features.add('legacywrapper') + profile_files = getattr(config, 'profile_file', None) typeart_base_lib_dir= getattr(config, 'typeart_base_lib_dir', None) typeart_lib_root = getattr(config, 'typeart_lib_dir', None) @@ -57,9 +62,10 @@ typeart_script_dir = getattr(config, 'typeart_script_dir', None) transform_name = getattr(config, 'typeart_pass', None) typelib_name = getattr(config, 'typeart_types', None) transform_pass = '{}/{}'.format(typeart_lib_root, transform_name) -std_plugin_args = '-typeart --typeart-stats' +# std_plugin_args = 'typeart --typeart-stats=true' +std_plugin_args_newpm = 'typeart -#include - -/* Comm Routines */ - -#define ALLOW_UNPACKED_PLANE false -#define ALLOW_UNPACKED_ROW false -#define ALLOW_UNPACKED_COL false - -/* - There are coherence issues for packing and unpacking message - buffers. Ideally, you would like a lot of threads to - cooperate in the assembly/dissassembly of each message. - To do that, each thread should really be operating in a - different coherence zone. - - Let's assume we have three fields, f1 through f3, defined on - a 61x61x61 cube. If we want to send the block boundary - information for each field to each neighbor processor across - each cube face, then we have three cases for the - memory layout/coherence of data on each of the six cube - boundaries: - - (a) Two of the faces will be in contiguous memory blocks - (b) Two of the faces will be comprised of pencils of - contiguous memory. - (c) Two of the faces will have large strides between - every value living on the face. - - How do you pack and unpack this data in buffers to - simultaneous achieve the best memory efficiency and - the most thread independence? - - Do do you pack field f1 through f3 tighly to reduce message - size? Do you align each field on a cache coherence boundary - within the message so that threads can pack and unpack each - field independently? For case (b), do you align each - boundary pencil of each field separately? This increases - the message size, but could improve cache coherence so - each pencil could be processed independently by a separate - thread with no conflicts. - - Also, memory access for case (c) would best be done without - going through the cache (the stride is so large it just causes - a lot of useless cache evictions). Is it worth creating - a special case version of the packing algorithm that uses - non-coherent load/store opcodes? -*/ - -/******************************************/ - - -/* doRecv flag only works with regular block structure */ -void CommRecv(Domain& domain, int msgType, Index_t xferFields, - Index_t dx, Index_t dy, Index_t dz, bool doRecv, bool planeOnly) { - - if (domain.numRanks() == 1) - return ; - - /* post recieve buffers for all incoming messages */ - int myRank ; - Index_t maxPlaneComm = xferFields * domain.maxPlaneSize() ; - Index_t maxEdgeComm = xferFields * domain.maxEdgeSize() ; - Index_t pmsg = 0 ; /* plane comm msg */ - Index_t emsg = 0 ; /* edge comm msg */ - Index_t cmsg = 0 ; /* corner comm msg */ - MPI_Datatype baseType = ((sizeof(Real_t) == 4) ? MPI_FLOAT : MPI_DOUBLE) ; - bool rowMin, rowMax, colMin, colMax, planeMin, planeMax ; - - /* assume communication to 6 neighbors by default */ - rowMin = rowMax = colMin = colMax = planeMin = planeMax = true ; - - if (domain.rowLoc() == 0) { - rowMin = false ; - } - if (domain.rowLoc() == (domain.tp()-1)) { - rowMax = false ; - } - if (domain.colLoc() == 0) { - colMin = false ; - } - if (domain.colLoc() == (domain.tp()-1)) { - colMax = false ; - } - if (domain.planeLoc() == 0) { - planeMin = false ; - } - if (domain.planeLoc() == (domain.tp()-1)) { - planeMax = false ; - } - - for (Index_t i=0; i<26; ++i) { - domain.recvRequest[i] = MPI_REQUEST_NULL ; - } - - MPI_Comm_rank(MPI_COMM_WORLD, &myRank) ; - - /* post receives */ - - /* receive data from neighboring domain faces */ - if (planeMin && doRecv) { - /* contiguous memory */ - int fromRank = myRank - domain.tp()*domain.tp() ; - int recvCount = dx * dy * xferFields ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm], - recvCount, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg]) ; - ++pmsg ; - } - if (planeMax) { - /* contiguous memory */ - int fromRank = myRank + domain.tp()*domain.tp() ; - int recvCount = dx * dy * xferFields ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm], - recvCount, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg]) ; - ++pmsg ; - } - if (rowMin && doRecv) { - /* semi-contiguous memory */ - int fromRank = myRank - domain.tp() ; - int recvCount = dx * dz * xferFields ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm], - recvCount, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg]) ; - ++pmsg ; - } - if (rowMax) { - /* semi-contiguous memory */ - int fromRank = myRank + domain.tp() ; - int recvCount = dx * dz * xferFields ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm], - recvCount, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg]) ; - ++pmsg ; - } - if (colMin && doRecv) { - /* scattered memory */ - int fromRank = myRank - 1 ; - int recvCount = dy * dz * xferFields ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm], - recvCount, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg]) ; - ++pmsg ; - } - if (colMax) { - /* scattered memory */ - int fromRank = myRank + 1 ; - int recvCount = dy * dz * xferFields ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm], - recvCount, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg]) ; - ++pmsg ; - } - - if (!planeOnly) { - /* receive data from domains connected only by an edge */ - if (rowMin && colMin && doRecv) { - int fromRank = myRank - domain.tp() - 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dz * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (rowMin && planeMin && doRecv) { - int fromRank = myRank - domain.tp()*domain.tp() - domain.tp() ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dx * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (colMin && planeMin && doRecv) { - int fromRank = myRank - domain.tp()*domain.tp() - 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dy * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (rowMax && colMax) { - int fromRank = myRank + domain.tp() + 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dz * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (rowMax && planeMax) { - int fromRank = myRank + domain.tp()*domain.tp() + domain.tp() ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dx * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (colMax && planeMax) { - int fromRank = myRank + domain.tp()*domain.tp() + 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dy * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (rowMax && colMin) { - int fromRank = myRank + domain.tp() - 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dz * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (rowMin && planeMax) { - int fromRank = myRank + domain.tp()*domain.tp() - domain.tp() ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dx * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (colMin && planeMax) { - int fromRank = myRank + domain.tp()*domain.tp() - 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dy * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (rowMin && colMax && doRecv) { - int fromRank = myRank - domain.tp() + 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dz * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (rowMax && planeMin && doRecv) { - int fromRank = myRank - domain.tp()*domain.tp() + domain.tp() ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dx * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - if (colMax && planeMin && doRecv) { - int fromRank = myRank - domain.tp()*domain.tp() + 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm], - dy * xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg]) ; - ++emsg ; - } - - /* receive data from domains connected only by a corner */ - if (rowMin && colMin && planeMin && doRecv) { - /* corner at domain logical coord (0, 0, 0) */ - int fromRank = myRank - domain.tp()*domain.tp() - domain.tp() - 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm + - cmsg * CACHE_COHERENCE_PAD_REAL], - xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg+cmsg]) ; - ++cmsg ; - } - if (rowMin && colMin && planeMax) { - /* corner at domain logical coord (0, 0, 1) */ - int fromRank = myRank + domain.tp()*domain.tp() - domain.tp() - 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm + - cmsg * CACHE_COHERENCE_PAD_REAL], - xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg+cmsg]) ; - ++cmsg ; - } - if (rowMin && colMax && planeMin && doRecv) { - /* corner at domain logical coord (1, 0, 0) */ - int fromRank = myRank - domain.tp()*domain.tp() - domain.tp() + 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm + - cmsg * CACHE_COHERENCE_PAD_REAL], - xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg+cmsg]) ; - ++cmsg ; - } - if (rowMin && colMax && planeMax) { - /* corner at domain logical coord (1, 0, 1) */ - int fromRank = myRank + domain.tp()*domain.tp() - domain.tp() + 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm + - cmsg * CACHE_COHERENCE_PAD_REAL], - xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg+cmsg]) ; - ++cmsg ; - } - if (rowMax && colMin && planeMin && doRecv) { - /* corner at domain logical coord (0, 1, 0) */ - int fromRank = myRank - domain.tp()*domain.tp() + domain.tp() - 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm + - cmsg * CACHE_COHERENCE_PAD_REAL], - xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg+cmsg]) ; - ++cmsg ; - } - if (rowMax && colMin && planeMax) { - /* corner at domain logical coord (0, 1, 1) */ - int fromRank = myRank + domain.tp()*domain.tp() + domain.tp() - 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm + - cmsg * CACHE_COHERENCE_PAD_REAL], - xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg+cmsg]) ; - ++cmsg ; - } - if (rowMax && colMax && planeMin && doRecv) { - /* corner at domain logical coord (1, 1, 0) */ - int fromRank = myRank - domain.tp()*domain.tp() + domain.tp() + 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm + - cmsg * CACHE_COHERENCE_PAD_REAL], - xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg+cmsg]) ; - ++cmsg ; - } - if (rowMax && colMax && planeMax) { - /* corner at domain logical coord (1, 1, 1) */ - int fromRank = myRank + domain.tp()*domain.tp() + domain.tp() + 1 ; - MPI_Irecv(&domain.commDataRecv[pmsg * maxPlaneComm + - emsg * maxEdgeComm + - cmsg * CACHE_COHERENCE_PAD_REAL], - xferFields, baseType, fromRank, msgType, - MPI_COMM_WORLD, &domain.recvRequest[pmsg+emsg+cmsg]) ; - ++cmsg ; - } - } -} - -/******************************************/ - -void CommSend(Domain& domain, int msgType, - Index_t xferFields, Domain_member *fieldData, - Index_t dx, Index_t dy, Index_t dz, bool doSend, bool planeOnly) -{ - - if (domain.numRanks() == 1) - return ; - - /* post recieve buffers for all incoming messages */ - int myRank ; - Index_t maxPlaneComm = xferFields * domain.maxPlaneSize() ; - Index_t maxEdgeComm = xferFields * domain.maxEdgeSize() ; - Index_t pmsg = 0 ; /* plane comm msg */ - Index_t emsg = 0 ; /* edge comm msg */ - Index_t cmsg = 0 ; /* corner comm msg */ - MPI_Datatype baseType = ((sizeof(Real_t) == 4) ? MPI_FLOAT : MPI_DOUBLE) ; - MPI_Status status[26] ; - Real_t *destAddr ; - bool rowMin, rowMax, colMin, colMax, planeMin, planeMax ; - /* assume communication to 6 neighbors by default */ - rowMin = rowMax = colMin = colMax = planeMin = planeMax = true ; - if (domain.rowLoc() == 0) { - rowMin = false ; - } - if (domain.rowLoc() == (domain.tp()-1)) { - rowMax = false ; - } - if (domain.colLoc() == 0) { - colMin = false ; - } - if (domain.colLoc() == (domain.tp()-1)) { - colMax = false ; - } - if (domain.planeLoc() == 0) { - planeMin = false ; - } - if (domain.planeLoc() == (domain.tp()-1)) { - planeMax = false ; - } - - for (Index_t i=0; i<26; ++i) { - domain.sendRequest[i] = MPI_REQUEST_NULL ; - } - - MPI_Comm_rank(MPI_COMM_WORLD, &myRank) ; - - /* post sends */ - - if (planeMin | planeMax) { - /* ASSUMING ONE DOMAIN PER RANK, CONSTANT BLOCK SIZE HERE */ - int sendCount = dx * dy ; - - if (planeMin) { - destAddr = &domain.commDataSend[pmsg * maxPlaneComm] ; - for (Index_t fi=0 ; fi -#if USE_MPI -# include -#endif -#if _OPENMP -#include -#endif -#include -#include -#include -#include -#include -#include "lulesh.h" - -///////////////////////////////////////////////////////////////////// -Domain::Domain(Int_t numRanks, Index_t colLoc, - Index_t rowLoc, Index_t planeLoc, - Index_t nx, int tp, int nr, int balance, Int_t cost) - : - m_e_cut(Real_t(1.0e-7)), - m_p_cut(Real_t(1.0e-7)), - m_q_cut(Real_t(1.0e-7)), - m_v_cut(Real_t(1.0e-10)), - m_u_cut(Real_t(1.0e-7)), - m_hgcoef(Real_t(3.0)), - m_ss4o3(Real_t(4.0)/Real_t(3.0)), - m_qstop(Real_t(1.0e+12)), - m_monoq_max_slope(Real_t(1.0)), - m_monoq_limiter_mult(Real_t(2.0)), - m_qlc_monoq(Real_t(0.5)), - m_qqc_monoq(Real_t(2.0)/Real_t(3.0)), - m_qqc(Real_t(2.0)), - m_eosvmax(Real_t(1.0e+9)), - m_eosvmin(Real_t(1.0e-9)), - m_pmin(Real_t(0.)), - m_emin(Real_t(-1.0e+15)), - m_dvovmax(Real_t(0.1)), - m_refdens(Real_t(1.0)) -{ - - Index_t edgeElems = nx ; - Index_t edgeNodes = edgeElems+1 ; - this->cost() = cost; - - m_tp = tp ; - m_numRanks = numRanks ; - - /////////////////////////////// - // Initialize Sedov Mesh - /////////////////////////////// - - // construct a uniform box for this processor - - m_colLoc = colLoc ; - m_rowLoc = rowLoc ; - m_planeLoc = planeLoc ; - - m_sizeX = edgeElems ; - m_sizeY = edgeElems ; - m_sizeZ = edgeElems ; - m_numElem = edgeElems*edgeElems*edgeElems ; - - m_numNode = edgeNodes*edgeNodes*edgeNodes ; - - m_regNumList = new Index_t[numElem()] ; // material indexset - - // Elem-centered - AllocateElemPersistent(numElem()) ; - - // Node-centered - AllocateNodePersistent(numNode()) ; - - SetupCommBuffers(edgeNodes); - - // Basic Field Initialization - for (Index_t i=0; i 1) { - // set up node-centered indexing of elements - Index_t *nodeElemCount = new Index_t[numNode()] ; - - for (Index_t i=0; i numElem()*8)) { - fprintf(stderr, - "AllocateNodeElemIndexes(): nodeElemCornerList entry out of range!\n"); -#if USE_MPI - MPI_Abort(MPI_COMM_WORLD, -1); -#else - exit(-1); -#endif - } - } - - delete [] nodeElemCount ; - } - else { - // These arrays are not used if we're not threaded - m_nodeElemStart = NULL; - m_nodeElemCornerList = NULL; - } -} - - -//////////////////////////////////////////////////////////////////////////////// -void -Domain::SetupCommBuffers(Int_t edgeNodes) -{ - // allocate a buffer large enough for nodal ghost data - Index_t maxEdgeSize = MAX(this->sizeX(), MAX(this->sizeY(), this->sizeZ()))+1 ; - m_maxPlaneSize = CACHE_ALIGN_REAL(maxEdgeSize*maxEdgeSize) ; - m_maxEdgeSize = CACHE_ALIGN_REAL(maxEdgeSize) ; - - // assume communication to 6 neighbors by default - m_rowMin = (m_rowLoc == 0) ? 0 : 1; - m_rowMax = (m_rowLoc == m_tp-1) ? 0 : 1; - m_colMin = (m_colLoc == 0) ? 0 : 1; - m_colMax = (m_colLoc == m_tp-1) ? 0 : 1; - m_planeMin = (m_planeLoc == 0) ? 0 : 1; - m_planeMax = (m_planeLoc == m_tp-1) ? 0 : 1; - -#if USE_MPI - // account for face communication - Index_t comBufSize = - (m_rowMin + m_rowMax + m_colMin + m_colMax + m_planeMin + m_planeMax) * - m_maxPlaneSize * MAX_FIELDS_PER_MPI_COMM ; - - // account for edge communication - comBufSize += - ((m_rowMin & m_colMin) + (m_rowMin & m_planeMin) + (m_colMin & m_planeMin) + - (m_rowMax & m_colMax) + (m_rowMax & m_planeMax) + (m_colMax & m_planeMax) + - (m_rowMax & m_colMin) + (m_rowMin & m_planeMax) + (m_colMin & m_planeMax) + - (m_rowMin & m_colMax) + (m_rowMax & m_planeMin) + (m_colMax & m_planeMin)) * - m_maxEdgeSize * MAX_FIELDS_PER_MPI_COMM ; - - // account for corner communication - // factor of 16 is so each buffer has its own cache line - comBufSize += ((m_rowMin & m_colMin & m_planeMin) + - (m_rowMin & m_colMin & m_planeMax) + - (m_rowMin & m_colMax & m_planeMin) + - (m_rowMin & m_colMax & m_planeMax) + - (m_rowMax & m_colMin & m_planeMin) + - (m_rowMax & m_colMin & m_planeMax) + - (m_rowMax & m_colMax & m_planeMin) + - (m_rowMax & m_colMax & m_planeMax)) * CACHE_COHERENCE_PAD_REAL ; - - this->commDataSend = new Real_t[comBufSize] ; - this->commDataRecv = new Real_t[comBufSize] ; - // prevent floating point exceptions - memset(this->commDataSend, 0, comBufSize*sizeof(Real_t)) ; - memset(this->commDataRecv, 0, comBufSize*sizeof(Real_t)) ; -#endif - - // Boundary nodesets - if (m_colLoc == 0) - m_symmX.resize(edgeNodes*edgeNodes); - if (m_rowLoc == 0) - m_symmY.resize(edgeNodes*edgeNodes); - if (m_planeLoc == 0) - m_symmZ.resize(edgeNodes*edgeNodes); -} - - -//////////////////////////////////////////////////////////////////////////////// -void -Domain::CreateRegionIndexSets(Int_t nr, Int_t balance) -{ -#if USE_MPI - Index_t myRank; - MPI_Comm_rank(MPI_COMM_WORLD, &myRank) ; - srand(myRank); -#else - srand(0); - Index_t myRank = 0; -#endif - this->numReg() = nr; - m_regElemSize = new Index_t[numReg()]; - m_regElemlist = new Index_t*[numReg()]; - Index_t nextIndex = 0; - //if we only have one region just fill it - // Fill out the regNumList with material numbers, which are always - // the region index plus one - if(numReg() == 1) { - while (nextIndex < numElem()) { - this->regNumList(nextIndex) = 1; - nextIndex++; - } - regElemSize(0) = 0; - } - //If we have more than one region distribute the elements. - else { - Int_t regionNum; - Int_t regionVar; - Int_t lastReg = -1; - Int_t binSize; - Index_t elements; - Index_t runto = 0; - Int_t costDenominator = 0; - Int_t* regBinEnd = new Int_t[numReg()]; - //Determine the relative weights of all the regions. This is based off the -b flag. Balance is the value passed into b. - for (Index_t i=0 ; i= regBinEnd[i]) - i++; - //rotate the regions based on MPI rank. Rotation is Rank % NumRegions this makes each domain have a different region with - //the highest representation - regionNum = ((i + myRank) % numReg()) + 1; - // make sure we don't pick the same region twice in a row - while(regionNum == lastReg) { - regionVar = rand() % costDenominator; - i = 0; - while(regionVar >= regBinEnd[i]) - i++; - regionNum = ((i + myRank) % numReg()) + 1; - } - //Pick the bin size of the region and determine the number of elements. - binSize = rand() % 1000; - if(binSize < 773) { - elements = rand() % 15 + 1; - } - else if(binSize < 937) { - elements = rand() % 16 + 16; - } - else if(binSize < 970) { - elements = rand() % 32 + 32; - } - else if(binSize < 974) { - elements = rand() % 64 + 64; - } - else if(binSize < 978) { - elements = rand() % 128 + 128; - } - else if(binSize < 981) { - elements = rand() % 256 + 256; - } - else - elements = rand() % 1537 + 512; - runto = elements + nextIndex; - //Store the elements. If we hit the end before we run out of elements then just stop. - while (nextIndex < runto && nextIndex < numElem()) { - this->regNumList(nextIndex) = regionNum; - nextIndex++; - } - lastReg = regionNum; - } - } - // Convert regNumList to region index sets - // First, count size of each region - for (Index_t i=0 ; iregNumList(i)-1; // region index == regnum-1 - regElemSize(r)++; - } - // Second, allocate each region index set - for (Index_t i=0 ; i CACHE_COHERENCE_PAD_REAL) { - printf("corner element comm buffers too small. Fix code.\n") ; -#if USE_MPI - MPI_Abort(MPI_COMM_WORLD, -1) ; -#else - exit(-1); -#endif - } - - dx = testProcs ; - dy = testProcs ; - dz = testProcs ; - - // temporary test - if (dx*dy*dz != numRanks) { - printf("error -- must have as many domains as procs\n") ; -#if USE_MPI - MPI_Abort(MPI_COMM_WORLD, -1) ; -#else - exit(-1); -#endif - } - Int_t remainder = dx*dy*dz % numRanks ; - if (myRank < remainder) { - myDom = myRank*( 1+ (dx*dy*dz / numRanks)) ; - } - else { - myDom = remainder*( 1+ (dx*dy*dz / numRanks)) + - (myRank - remainder)*(dx*dy*dz/numRanks) ; - } - - *col = myDom % dx ; - *row = (myDom / dx) % dy ; - *plane = myDom / (dx*dy) ; - *side = testProcs; - - return; -} diff --git a/test/lulesh/lulesh-util.cc b/test/lulesh/lulesh-util.cc deleted file mode 100644 index 2fac8fd9..00000000 --- a/test/lulesh/lulesh-util.cc +++ /dev/null @@ -1,219 +0,0 @@ -#include -#include -#include -#include -#if USE_MPI -#include -#endif -#include "lulesh.h" - -/* Helper function for converting strings to ints, with error checking */ -int StrToInt(const char *token, int *retVal) -{ - const char *c ; - char *endptr ; - const int decimal_base = 10 ; - - if (token == NULL) - return 0 ; - - c = token ; - *retVal = (int)strtol(c, &endptr, decimal_base) ; - if((endptr != c) && ((*endptr == ' ') || (*endptr == '\0'))) - return 1 ; - else - return 0 ; -} - -static void PrintCommandLineOptions(char *execname, int myRank) -{ - if (myRank == 0) { - - printf("Usage: %s [opts]\n", execname); - printf(" where [opts] is one or more of:\n"); - printf(" -q : quiet mode - suppress all stdout\n"); - printf(" -i : number of cycles to run\n"); - printf(" -s : length of cube mesh along side\n"); - printf(" -r : Number of distinct regions (def: 11)\n"); - printf(" -b : Load balance between regions of a domain (def: 1)\n"); - printf(" -c : Extra cost of more expensive regions (def: 1)\n"); - printf(" -f : Number of files to split viz dump into (def: (np+10)/9)\n"); - printf(" -p : Print out progress\n"); - printf(" -v : Output viz file (requires compiling with -DVIZ_MESH\n"); - printf(" -h : This message\n"); - printf("\n\n"); - } -} - -static void ParseError(const char *message, int myRank) -{ - if (myRank == 0) { - printf("%s\n", message); -#if USE_MPI - MPI_Abort(MPI_COMM_WORLD, -1); -#else - exit(-1); -#endif - } -} - -void ParseCommandLineOptions(int argc, char *argv[], - int myRank, struct cmdLineOpts *opts) -{ - if(argc > 1) { - int i = 1; - - while(i < argc) { - int ok; - /* -i */ - if(strcmp(argv[i], "-i") == 0) { - if (i+1 >= argc) { - ParseError("Missing integer argument to -i", myRank); - } - ok = StrToInt(argv[i+1], &(opts->its)); - if(!ok) { - ParseError("Parse Error on option -i integer value required after argument\n", myRank); - } - i+=2; - } - /* -s */ - else if(strcmp(argv[i], "-s") == 0) { - if (i+1 >= argc) { - ParseError("Missing integer argument to -s\n", myRank); - } - ok = StrToInt(argv[i+1], &(opts->nx)); - if(!ok) { - ParseError("Parse Error on option -s integer value required after argument\n", myRank); - } - i+=2; - } - /* -r */ - else if (strcmp(argv[i], "-r") == 0) { - if (i+1 >= argc) { - ParseError("Missing integer argument to -r\n", myRank); - } - ok = StrToInt(argv[i+1], &(opts->numReg)); - if (!ok) { - ParseError("Parse Error on option -r integer value required after argument\n", myRank); - } - i+=2; - } - /* -f */ - else if (strcmp(argv[i], "-f") == 0) { - if (i+1 >= argc) { - ParseError("Missing integer argument to -f\n", myRank); - } - ok = StrToInt(argv[i+1], &(opts->numFiles)); - if (!ok) { - ParseError("Parse Error on option -f integer value required after argument\n", myRank); - } - i+=2; - } - /* -p */ - else if (strcmp(argv[i], "-p") == 0) { - opts->showProg = 1; - i++; - } - /* -q */ - else if (strcmp(argv[i], "-q") == 0) { - opts->quiet = 1; - i++; - } - else if (strcmp(argv[i], "-b") == 0) { - if (i+1 >= argc) { - ParseError("Missing integer argument to -b\n", myRank); - } - ok = StrToInt(argv[i+1], &(opts->balance)); - if (!ok) { - ParseError("Parse Error on option -b integer value required after argument\n", myRank); - } - i+=2; - } - else if (strcmp(argv[i], "-c") == 0) { - if (i+1 >= argc) { - ParseError("Missing integer argument to -c\n", myRank); - } - ok = StrToInt(argv[i+1], &(opts->cost)); - if (!ok) { - ParseError("Parse Error on option -c integer value required after argument\n", myRank); - } - i+=2; - } - /* -v */ - else if (strcmp(argv[i], "-v") == 0) { -#if VIZ_MESH - opts->viz = 1; -#else - ParseError("Use of -v requires compiling with -DVIZ_MESH\n", myRank); -#endif - i++; - } - /* -h */ - else if (strcmp(argv[i], "-h") == 0) { - PrintCommandLineOptions(argv[0], myRank); -#if USE_MPI - MPI_Abort(MPI_COMM_WORLD, 0); -#else - exit(0); -#endif - } - else { - char msg[80]; - PrintCommandLineOptions(argv[0], myRank); - sprintf(msg, "ERROR: Unknown command line argument: %s\n", argv[i]); - ParseError(msg, myRank); - } - } - } -} - -///////////////////////////////////////////////////////////////////// - -void VerifyAndWriteFinalOutput(Real_t elapsed_time, - Domain& locDom, - Int_t nx, - Int_t numRanks) -{ - // GrindTime1 only takes a single domain into account, and is thus a good way to measure - // processor speed indepdendent of MPI parallelism. - // GrindTime2 takes into account speedups from MPI parallelism - Real_t grindTime1 = ((elapsed_time*1e6)/locDom.cycle())/(nx*nx*nx); - Real_t grindTime2 = ((elapsed_time*1e6)/locDom.cycle())/(nx*nx*nx*numRanks); - - Index_t ElemId = 0; - printf("Run completed: \n"); - printf(" Problem size = %i \n", nx); - printf(" MPI tasks = %i \n", numRanks); - printf(" Iteration count = %i \n", locDom.cycle()); - printf(" Final Origin Energy = %12.6e \n", locDom.e(ElemId)); - - Real_t MaxAbsDiff = Real_t(0.0); - Real_t TotalAbsDiff = Real_t(0.0); - Real_t MaxRelDiff = Real_t(0.0); - - for (Index_t j=0; j -#include -#include -#include -#include "lulesh.h" - -#ifdef VIZ_MESH - -#ifdef __cplusplus - extern "C" { -#endif -#include "silo.h" -#if USE_MPI -# include "pmpio.h" -#endif -#ifdef __cplusplus - } -#endif - -// Function prototypes -static void -DumpDomainToVisit(DBfile *db, Domain& domain, int myRank); -static - - -#if USE_MPI -// For some reason, earlier versions of g++ (e.g. 4.2) won't let me -// put the 'static' qualifier on this prototype, even if it's done -// consistently in the prototype and definition -void -DumpMultiblockObjects(DBfile *db, PMPIO_baton_t *bat, - char basename[], int numRanks); - -// Callback prototypes for PMPIO interface (only useful if we're -// running parallel) -static void * -LULESH_PMPIO_Create(const char *fname, - const char *dname, - void *udata); -static void * -LULESH_PMPIO_Open(const char *fname, - const char *dname, - PMPIO_iomode_t ioMode, - void *udata); -static void -LULESH_PMPIO_Close(void *file, void *udata); - -#else -void -DumpMultiblockObjects(DBfile *db, char basename[], int numRanks); -#endif - - -/**********************************************************************/ -void DumpToVisit(Domain& domain, int numFiles, int myRank, int numRanks) -{ - char subdirName[32]; - char basename[32]; - DBfile *db; - - - sprintf(basename, "lulesh_plot_c%d", domain.cycle()); - sprintf(subdirName, "data_%d", myRank); - -#if USE_MPI - - PMPIO_baton_t *bat = PMPIO_Init(numFiles, - PMPIO_WRITE, - MPI_COMM_WORLD, - 10101, - LULESH_PMPIO_Create, - LULESH_PMPIO_Open, - LULESH_PMPIO_Close, - NULL); - - int myiorank = PMPIO_GroupRank(bat, myRank); - - char fileName[64]; - - if (myiorank == 0) - strcpy(fileName, basename); - else - sprintf(fileName, "%s.%03d", basename, myiorank); - - db = (DBfile*)PMPIO_WaitForBaton(bat, fileName, subdirName); - - DumpDomainToVisit(db, domain, myRank); - - // Processor 0 writes out bit of extra data to its file that - // describes how to stitch all the pieces together - if (myRank == 0) { - DumpMultiblockObjects(db, bat, basename, numRanks); - } - - PMPIO_HandOffBaton(bat, db); - - PMPIO_Finish(bat); -#else - - db = (DBfile*)DBCreate(basename, DB_CLOBBER, DB_LOCAL, NULL, DB_HDF5X); - - if (db) { - DBMkDir(db, subdirName); - DBSetDir(db, subdirName); - DumpDomainToVisit(db, domain, myRank); - DumpMultiblockObjects(db, basename, numRanks); - } - else { - printf("Error writing out viz file - rank %d\n", myRank); - } - -#endif -} - - - -/**********************************************************************/ - -static void -DumpDomainToVisit(DBfile *db, Domain& domain, int myRank) -{ - int ok = 0; - - /* Create an option list that will give some hints to VisIt for - * printing out the cycle and time in the annotations */ - DBoptlist *optlist; - - - /* Write out the mesh connectivity in fully unstructured format */ - int shapetype[1] = {DB_ZONETYPE_HEX}; - int shapesize[1] = {8}; - int shapecnt[1] = {domain.numElem()}; - int *conn = new int[domain.numElem()*8] ; - int ci = 0 ; - for (int ei=0; ei < domain.numElem(); ++ei) { - Index_t *elemToNode = domain.nodelist(ei) ; - for (int ni=0; ni < 8; ++ni) { - conn[ci++] = elemToNode[ni] ; - } - } - ok += DBPutZonelist2(db, "connectivity", domain.numElem(), 3, - conn, domain.numElem()*8, - 0,0,0, /* Not carrying ghost zones */ - shapetype, shapesize, shapecnt, - 1, NULL); - delete [] conn ; - - /* Write out the mesh coordinates associated with the mesh */ - const char* coordnames[3] = {"X", "Y", "Z"}; - float *coords[3] ; - coords[0] = new float[domain.numNode()] ; - coords[1] = new float[domain.numNode()] ; - coords[2] = new float[domain.numNode()] ; - for (int ni=0; ni < domain.numNode() ; ++ni) { - coords[0][ni] = float(domain.x(ni)) ; - coords[1][ni] = float(domain.y(ni)) ; - coords[2][ni] = float(domain.z(ni)) ; - } - optlist = DBMakeOptlist(2); - ok += DBAddOption(optlist, DBOPT_DTIME, &domain.time()); - ok += DBAddOption(optlist, DBOPT_CYCLE, &domain.cycle()); - ok += DBPutUcdmesh(db, "mesh", 3, (char**)&coordnames[0], (float**)coords, - domain.numNode(), domain.numElem(), "connectivity", - 0, DB_FLOAT, optlist); - ok += DBFreeOptlist(optlist); - delete [] coords[2] ; - delete [] coords[1] ; - delete [] coords[0] ; - - /* Write out the materials */ - int *matnums = new int[domain.numReg()]; - int dims[1] = {domain.numElem()}; // No mixed elements - for(int i=0 ; i : number of cycles to run - -s : length of cube mesh along side - -r : Number of distinct regions (def: 11) - -b : Load balance between regions of a domain (def: 1) - -c : Extra cost of more expensive regions (def: 1) - -f : Number of file parts for viz output (def: np/9) - -p : Print out progress - -v : Output viz file (requires compiling with -DVIZ_MESH - -h : This message - - printf("Usage: %s [opts]\n", execname); - printf(" where [opts] is one or more of:\n"); - printf(" -q : quiet mode - suppress all stdout\n"); - printf(" -i : number of cycles to run\n"); - printf(" -s : length of cube mesh along side\n"); - printf(" -r : Number of distinct regions (def: 11)\n"); - printf(" -b : Load balance between regions of a domain (def: 1)\n"); - printf(" -c : Extra cost of more expensive regions (def: 1)\n"); - printf(" -f : Number of files to split viz dump into (def: (np+10)/9)\n"); - printf(" -p : Print out progress\n"); - printf(" -v : Output viz file (requires compiling with -DVIZ_MESH\n"); - printf(" -h : This message\n"); - printf("\n\n"); - -*Notable changes in LULESH 2.0 - -* Split functionality into different files -lulesh.cc - where most (all?) of the timed functionality lies -lulesh-comm.cc - MPI functionality -lulesh-init.cc - Setup code -lulesh-viz.cc - Support for visualization option -lulesh-util.cc - Non-timed functions -* -* The concept of "regions" was added, although every region is the same ideal -* gas material, and the same sedov blast wave problem is still the only -* problem its hardcoded to solve. -* Regions allow two things important to making this proxy app more representative: -* Four of the LULESH routines are now performed on a region-by-region basis, -* making the memory access patterns non-unit stride -* Artificial load imbalances can be easily introduced that could impact -* parallelization strategies. -* The load balance flag changes region assignment. Region number is raised to -* the power entered for assignment probability. Most likely regions changes -* with MPI process id. -* The cost flag raises the cost of ~45% of the regions to evaluate EOS by the -* entered multiple. The cost of 5% is 10x the entered multiple. -* MPI and OpenMP were added, and coalesced into a single version of the source -* that can support serial builds, MPI-only, OpenMP-only, and MPI+OpenMP -* Added support to write plot files using "poor mans parallel I/O" when linked -* with the silo library, which in turn can be read by VisIt. -* Enabled variable timestep calculation by default (courant condition), which -* results in an additional reduction. -* Default domain (mesh) size reduced from 45^3 to 30^3 -* Command line options to allow numerous test cases without needing to recompile -* Performance optimizations and code cleanup beyond LULESH 1.0 -* Added a "Figure of Merit" calculation (elements solved per microsecond) and -* output in support of using LULESH 2.0 for the 2017 CORAL procurement -* -* Possible Differences in Final Release (other changes possible) -* -* High Level mesh structure to allow data structure transformations -* Different default parameters -* Minor code performance changes and cleanup - -TODO in future versions -* Add reader for (truly) unstructured meshes, probably serial only -* CMake based build system - -////////////// - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the disclaimer below. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the disclaimer (as noted below) - in the documentation and/or other materials provided with the - distribution. - - * Neither the name of the LLNS/LLNL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, LLC, -THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Additional BSD Notice - -1. This notice is required to be provided under our contract with the U.S. - Department of Energy (DOE). This work was produced at Lawrence Livermore - National Laboratory under Contract No. DE-AC52-07NA27344 with the DOE. - -2. Neither the United States Government nor Lawrence Livermore National - Security, LLC nor any of their employees, makes any warranty, express - or implied, or assumes any liability or responsibility for the accuracy, - completeness, or usefulness of any information, apparatus, product, or - process disclosed, or represents that its use would not infringe - privately-owned rights. - -3. Also, reference herein to any specific commercial products, process, or - services by trade name, trademark, manufacturer or otherwise does not - necessarily constitute or imply its endorsement, recommendation, or - favoring by the United States Government or Lawrence Livermore National - Security, LLC. The views and opinions of authors expressed herein do not - necessarily state or reflect those of the United States Government or - Lawrence Livermore National Security, LLC, and shall not be used for - advertising or product endorsement purposes. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if _OPENMP -# include -#endif - -#include "lulesh.h" - - -/*********************************/ -/* Data structure implementation */ -/*********************************/ - -/* might want to add access methods so that memory can be */ -/* better managed, as in luleshFT */ - -template -T *Allocate(size_t size) -{ - return static_cast(malloc(sizeof(T)*size)) ; -} - -template -void Release(T **ptr) -{ - if (*ptr != NULL) { - free(*ptr) ; - *ptr = NULL ; - } -} - - - -/******************************************/ - -/* Work Routines */ - -static inline -void TimeIncrement(Domain& domain) -{ - Real_t targetdt = domain.stoptime() - domain.time() ; - - if ((domain.dtfixed() <= Real_t(0.0)) && (domain.cycle() != Int_t(0))) { - Real_t ratio ; - Real_t olddt = domain.deltatime() ; - - /* This will require a reduction in parallel */ - Real_t gnewdt = Real_t(1.0e+20) ; - Real_t newdt ; - if (domain.dtcourant() < gnewdt) { - gnewdt = domain.dtcourant() / Real_t(2.0) ; - } - if (domain.dthydro() < gnewdt) { - gnewdt = domain.dthydro() * Real_t(2.0) / Real_t(3.0) ; - } - -#if USE_MPI - MPI_Allreduce(&gnewdt, &newdt, 1, - ((sizeof(Real_t) == 4) ? MPI_FLOAT : MPI_DOUBLE), - MPI_MIN, MPI_COMM_WORLD) ; -#else - newdt = gnewdt; -#endif - - ratio = newdt / olddt ; - if (ratio >= Real_t(1.0)) { - if (ratio < domain.deltatimemultlb()) { - newdt = olddt ; - } - else if (ratio > domain.deltatimemultub()) { - newdt = olddt*domain.deltatimemultub() ; - } - } - - if (newdt > domain.dtmax()) { - newdt = domain.dtmax() ; - } - domain.deltatime() = newdt ; - } - - /* TRY TO PREVENT VERY SMALL SCALING ON THE NEXT CYCLE */ - if ((targetdt > domain.deltatime()) && - (targetdt < (Real_t(4.0) * domain.deltatime() / Real_t(3.0))) ) { - targetdt = Real_t(2.0) * domain.deltatime() / Real_t(3.0) ; - } - - if (targetdt < domain.deltatime()) { - domain.deltatime() = targetdt ; - } - - domain.time() += domain.deltatime() ; - - ++domain.cycle() ; -} - -/******************************************/ - -static inline -void CollectDomainNodesToElemNodes(Domain &domain, - const Index_t* elemToNode, - Real_t elemX[8], - Real_t elemY[8], - Real_t elemZ[8]) -{ - Index_t nd0i = elemToNode[0] ; - Index_t nd1i = elemToNode[1] ; - Index_t nd2i = elemToNode[2] ; - Index_t nd3i = elemToNode[3] ; - Index_t nd4i = elemToNode[4] ; - Index_t nd5i = elemToNode[5] ; - Index_t nd6i = elemToNode[6] ; - Index_t nd7i = elemToNode[7] ; - - elemX[0] = domain.x(nd0i); - elemX[1] = domain.x(nd1i); - elemX[2] = domain.x(nd2i); - elemX[3] = domain.x(nd3i); - elemX[4] = domain.x(nd4i); - elemX[5] = domain.x(nd5i); - elemX[6] = domain.x(nd6i); - elemX[7] = domain.x(nd7i); - - elemY[0] = domain.y(nd0i); - elemY[1] = domain.y(nd1i); - elemY[2] = domain.y(nd2i); - elemY[3] = domain.y(nd3i); - elemY[4] = domain.y(nd4i); - elemY[5] = domain.y(nd5i); - elemY[6] = domain.y(nd6i); - elemY[7] = domain.y(nd7i); - - elemZ[0] = domain.z(nd0i); - elemZ[1] = domain.z(nd1i); - elemZ[2] = domain.z(nd2i); - elemZ[3] = domain.z(nd3i); - elemZ[4] = domain.z(nd4i); - elemZ[5] = domain.z(nd5i); - elemZ[6] = domain.z(nd6i); - elemZ[7] = domain.z(nd7i); - -} - -/******************************************/ - -static inline -void InitStressTermsForElems(Domain &domain, - Real_t *sigxx, Real_t *sigyy, Real_t *sigzz, - Index_t numElem) -{ - // - // pull in the stresses appropriate to the hydro integration - // - -#pragma omp parallel for firstprivate(numElem) - for (Index_t i = 0 ; i < numElem ; ++i){ - sigxx[i] = sigyy[i] = sigzz[i] = - domain.p(i) - domain.q(i) ; - } -} - -/******************************************/ - -static inline -void CalcElemShapeFunctionDerivatives( Real_t const x[], - Real_t const y[], - Real_t const z[], - Real_t b[][8], - Real_t* const volume ) -{ - const Real_t x0 = x[0] ; const Real_t x1 = x[1] ; - const Real_t x2 = x[2] ; const Real_t x3 = x[3] ; - const Real_t x4 = x[4] ; const Real_t x5 = x[5] ; - const Real_t x6 = x[6] ; const Real_t x7 = x[7] ; - - const Real_t y0 = y[0] ; const Real_t y1 = y[1] ; - const Real_t y2 = y[2] ; const Real_t y3 = y[3] ; - const Real_t y4 = y[4] ; const Real_t y5 = y[5] ; - const Real_t y6 = y[6] ; const Real_t y7 = y[7] ; - - const Real_t z0 = z[0] ; const Real_t z1 = z[1] ; - const Real_t z2 = z[2] ; const Real_t z3 = z[3] ; - const Real_t z4 = z[4] ; const Real_t z5 = z[5] ; - const Real_t z6 = z[6] ; const Real_t z7 = z[7] ; - - Real_t fjxxi, fjxet, fjxze; - Real_t fjyxi, fjyet, fjyze; - Real_t fjzxi, fjzet, fjzze; - Real_t cjxxi, cjxet, cjxze; - Real_t cjyxi, cjyet, cjyze; - Real_t cjzxi, cjzet, cjzze; - - fjxxi = Real_t(.125) * ( (x6-x0) + (x5-x3) - (x7-x1) - (x4-x2) ); - fjxet = Real_t(.125) * ( (x6-x0) - (x5-x3) + (x7-x1) - (x4-x2) ); - fjxze = Real_t(.125) * ( (x6-x0) + (x5-x3) + (x7-x1) + (x4-x2) ); - - fjyxi = Real_t(.125) * ( (y6-y0) + (y5-y3) - (y7-y1) - (y4-y2) ); - fjyet = Real_t(.125) * ( (y6-y0) - (y5-y3) + (y7-y1) - (y4-y2) ); - fjyze = Real_t(.125) * ( (y6-y0) + (y5-y3) + (y7-y1) + (y4-y2) ); - - fjzxi = Real_t(.125) * ( (z6-z0) + (z5-z3) - (z7-z1) - (z4-z2) ); - fjzet = Real_t(.125) * ( (z6-z0) - (z5-z3) + (z7-z1) - (z4-z2) ); - fjzze = Real_t(.125) * ( (z6-z0) + (z5-z3) + (z7-z1) + (z4-z2) ); - - /* compute cofactors */ - cjxxi = (fjyet * fjzze) - (fjzet * fjyze); - cjxet = - (fjyxi * fjzze) + (fjzxi * fjyze); - cjxze = (fjyxi * fjzet) - (fjzxi * fjyet); - - cjyxi = - (fjxet * fjzze) + (fjzet * fjxze); - cjyet = (fjxxi * fjzze) - (fjzxi * fjxze); - cjyze = - (fjxxi * fjzet) + (fjzxi * fjxet); - - cjzxi = (fjxet * fjyze) - (fjyet * fjxze); - cjzet = - (fjxxi * fjyze) + (fjyxi * fjxze); - cjzze = (fjxxi * fjyet) - (fjyxi * fjxet); - - /* calculate partials : - this need only be done for l = 0,1,2,3 since , by symmetry , - (6,7,4,5) = - (0,1,2,3) . - */ - b[0][0] = - cjxxi - cjxet - cjxze; - b[0][1] = cjxxi - cjxet - cjxze; - b[0][2] = cjxxi + cjxet - cjxze; - b[0][3] = - cjxxi + cjxet - cjxze; - b[0][4] = -b[0][2]; - b[0][5] = -b[0][3]; - b[0][6] = -b[0][0]; - b[0][7] = -b[0][1]; - - b[1][0] = - cjyxi - cjyet - cjyze; - b[1][1] = cjyxi - cjyet - cjyze; - b[1][2] = cjyxi + cjyet - cjyze; - b[1][3] = - cjyxi + cjyet - cjyze; - b[1][4] = -b[1][2]; - b[1][5] = -b[1][3]; - b[1][6] = -b[1][0]; - b[1][7] = -b[1][1]; - - b[2][0] = - cjzxi - cjzet - cjzze; - b[2][1] = cjzxi - cjzet - cjzze; - b[2][2] = cjzxi + cjzet - cjzze; - b[2][3] = - cjzxi + cjzet - cjzze; - b[2][4] = -b[2][2]; - b[2][5] = -b[2][3]; - b[2][6] = -b[2][0]; - b[2][7] = -b[2][1]; - - /* calculate jacobian determinant (volume) */ - *volume = Real_t(8.) * ( fjxet * cjxet + fjyet * cjyet + fjzet * cjzet); -} - -/******************************************/ - -static inline -void SumElemFaceNormal(Real_t *normalX0, Real_t *normalY0, Real_t *normalZ0, - Real_t *normalX1, Real_t *normalY1, Real_t *normalZ1, - Real_t *normalX2, Real_t *normalY2, Real_t *normalZ2, - Real_t *normalX3, Real_t *normalY3, Real_t *normalZ3, - const Real_t x0, const Real_t y0, const Real_t z0, - const Real_t x1, const Real_t y1, const Real_t z1, - const Real_t x2, const Real_t y2, const Real_t z2, - const Real_t x3, const Real_t y3, const Real_t z3) -{ - Real_t bisectX0 = Real_t(0.5) * (x3 + x2 - x1 - x0); - Real_t bisectY0 = Real_t(0.5) * (y3 + y2 - y1 - y0); - Real_t bisectZ0 = Real_t(0.5) * (z3 + z2 - z1 - z0); - Real_t bisectX1 = Real_t(0.5) * (x2 + x1 - x3 - x0); - Real_t bisectY1 = Real_t(0.5) * (y2 + y1 - y3 - y0); - Real_t bisectZ1 = Real_t(0.5) * (z2 + z1 - z3 - z0); - Real_t areaX = Real_t(0.25) * (bisectY0 * bisectZ1 - bisectZ0 * bisectY1); - Real_t areaY = Real_t(0.25) * (bisectZ0 * bisectX1 - bisectX0 * bisectZ1); - Real_t areaZ = Real_t(0.25) * (bisectX0 * bisectY1 - bisectY0 * bisectX1); - - *normalX0 += areaX; - *normalX1 += areaX; - *normalX2 += areaX; - *normalX3 += areaX; - - *normalY0 += areaY; - *normalY1 += areaY; - *normalY2 += areaY; - *normalY3 += areaY; - - *normalZ0 += areaZ; - *normalZ1 += areaZ; - *normalZ2 += areaZ; - *normalZ3 += areaZ; -} - -/******************************************/ - -static inline -void CalcElemNodeNormals(Real_t pfx[8], - Real_t pfy[8], - Real_t pfz[8], - const Real_t x[8], - const Real_t y[8], - const Real_t z[8]) -{ - for (Index_t i = 0 ; i < 8 ; ++i) { - pfx[i] = Real_t(0.0); - pfy[i] = Real_t(0.0); - pfz[i] = Real_t(0.0); - } - /* evaluate face one: nodes 0, 1, 2, 3 */ - SumElemFaceNormal(&pfx[0], &pfy[0], &pfz[0], - &pfx[1], &pfy[1], &pfz[1], - &pfx[2], &pfy[2], &pfz[2], - &pfx[3], &pfy[3], &pfz[3], - x[0], y[0], z[0], x[1], y[1], z[1], - x[2], y[2], z[2], x[3], y[3], z[3]); - /* evaluate face two: nodes 0, 4, 5, 1 */ - SumElemFaceNormal(&pfx[0], &pfy[0], &pfz[0], - &pfx[4], &pfy[4], &pfz[4], - &pfx[5], &pfy[5], &pfz[5], - &pfx[1], &pfy[1], &pfz[1], - x[0], y[0], z[0], x[4], y[4], z[4], - x[5], y[5], z[5], x[1], y[1], z[1]); - /* evaluate face three: nodes 1, 5, 6, 2 */ - SumElemFaceNormal(&pfx[1], &pfy[1], &pfz[1], - &pfx[5], &pfy[5], &pfz[5], - &pfx[6], &pfy[6], &pfz[6], - &pfx[2], &pfy[2], &pfz[2], - x[1], y[1], z[1], x[5], y[5], z[5], - x[6], y[6], z[6], x[2], y[2], z[2]); - /* evaluate face four: nodes 2, 6, 7, 3 */ - SumElemFaceNormal(&pfx[2], &pfy[2], &pfz[2], - &pfx[6], &pfy[6], &pfz[6], - &pfx[7], &pfy[7], &pfz[7], - &pfx[3], &pfy[3], &pfz[3], - x[2], y[2], z[2], x[6], y[6], z[6], - x[7], y[7], z[7], x[3], y[3], z[3]); - /* evaluate face five: nodes 3, 7, 4, 0 */ - SumElemFaceNormal(&pfx[3], &pfy[3], &pfz[3], - &pfx[7], &pfy[7], &pfz[7], - &pfx[4], &pfy[4], &pfz[4], - &pfx[0], &pfy[0], &pfz[0], - x[3], y[3], z[3], x[7], y[7], z[7], - x[4], y[4], z[4], x[0], y[0], z[0]); - /* evaluate face six: nodes 4, 7, 6, 5 */ - SumElemFaceNormal(&pfx[4], &pfy[4], &pfz[4], - &pfx[7], &pfy[7], &pfz[7], - &pfx[6], &pfy[6], &pfz[6], - &pfx[5], &pfy[5], &pfz[5], - x[4], y[4], z[4], x[7], y[7], z[7], - x[6], y[6], z[6], x[5], y[5], z[5]); -} - -/******************************************/ - -static inline -void SumElemStressesToNodeForces( const Real_t B[][8], - const Real_t stress_xx, - const Real_t stress_yy, - const Real_t stress_zz, - Real_t fx[], Real_t fy[], Real_t fz[] ) -{ - for(Index_t i = 0; i < 8; i++) { - fx[i] = -( stress_xx * B[0][i] ); - fy[i] = -( stress_yy * B[1][i] ); - fz[i] = -( stress_zz * B[2][i] ); - } -} - -/******************************************/ - -static inline -void IntegrateStressForElems( Domain &domain, - Real_t *sigxx, Real_t *sigyy, Real_t *sigzz, - Real_t *determ, Index_t numElem, Index_t numNode) -{ -#if _OPENMP - Index_t numthreads = omp_get_max_threads(); -#else - Index_t numthreads = 1; -#endif - - Index_t numElem8 = numElem * 8 ; - Real_t *fx_elem; - Real_t *fy_elem; - Real_t *fz_elem; - Real_t fx_local[8] ; - Real_t fy_local[8] ; - Real_t fz_local[8] ; - - - if (numthreads > 1) { - fx_elem = Allocate(numElem8) ; - fy_elem = Allocate(numElem8) ; - fz_elem = Allocate(numElem8) ; - } - // loop over all elements - -#pragma omp parallel for firstprivate(numElem) - for( Index_t k=0 ; k 1) { - // Eliminate thread writing conflicts at the nodes by giving - // each element its own copy to write to - SumElemStressesToNodeForces( B, sigxx[k], sigyy[k], sigzz[k], - &fx_elem[k*8], - &fy_elem[k*8], - &fz_elem[k*8] ) ; - } - else { - SumElemStressesToNodeForces( B, sigxx[k], sigyy[k], sigzz[k], - fx_local, fy_local, fz_local ) ; - - // copy nodal force contributions to global force arrray. - for( Index_t lnode=0 ; lnode<8 ; ++lnode ) { - Index_t gnode = elemToNode[lnode]; - domain.fx(gnode) += fx_local[lnode]; - domain.fy(gnode) += fy_local[lnode]; - domain.fz(gnode) += fz_local[lnode]; - } - } - } - - if (numthreads > 1) { - // If threaded, then we need to copy the data out of the temporary - // arrays used above into the final forces field -#pragma omp parallel for firstprivate(numNode) - for( Index_t gnode=0 ; gnode 1) { - fx_elem = Allocate(numElem8) ; - fy_elem = Allocate(numElem8) ; - fz_elem = Allocate(numElem8) ; - } - - Real_t gamma[4][8]; - - gamma[0][0] = Real_t( 1.); - gamma[0][1] = Real_t( 1.); - gamma[0][2] = Real_t(-1.); - gamma[0][3] = Real_t(-1.); - gamma[0][4] = Real_t(-1.); - gamma[0][5] = Real_t(-1.); - gamma[0][6] = Real_t( 1.); - gamma[0][7] = Real_t( 1.); - gamma[1][0] = Real_t( 1.); - gamma[1][1] = Real_t(-1.); - gamma[1][2] = Real_t(-1.); - gamma[1][3] = Real_t( 1.); - gamma[1][4] = Real_t(-1.); - gamma[1][5] = Real_t( 1.); - gamma[1][6] = Real_t( 1.); - gamma[1][7] = Real_t(-1.); - gamma[2][0] = Real_t( 1.); - gamma[2][1] = Real_t(-1.); - gamma[2][2] = Real_t( 1.); - gamma[2][3] = Real_t(-1.); - gamma[2][4] = Real_t( 1.); - gamma[2][5] = Real_t(-1.); - gamma[2][6] = Real_t( 1.); - gamma[2][7] = Real_t(-1.); - gamma[3][0] = Real_t(-1.); - gamma[3][1] = Real_t( 1.); - gamma[3][2] = Real_t(-1.); - gamma[3][3] = Real_t( 1.); - gamma[3][4] = Real_t( 1.); - gamma[3][5] = Real_t(-1.); - gamma[3][6] = Real_t( 1.); - gamma[3][7] = Real_t(-1.); - -/*************************************************/ -/* compute the hourglass modes */ - - -#pragma omp parallel for firstprivate(numElem, hourg) - for(Index_t i2=0;i2 1) { - fx_local = &fx_elem[i3] ; - fx_local[0] = hgfx[0]; - fx_local[1] = hgfx[1]; - fx_local[2] = hgfx[2]; - fx_local[3] = hgfx[3]; - fx_local[4] = hgfx[4]; - fx_local[5] = hgfx[5]; - fx_local[6] = hgfx[6]; - fx_local[7] = hgfx[7]; - - fy_local = &fy_elem[i3] ; - fy_local[0] = hgfy[0]; - fy_local[1] = hgfy[1]; - fy_local[2] = hgfy[2]; - fy_local[3] = hgfy[3]; - fy_local[4] = hgfy[4]; - fy_local[5] = hgfy[5]; - fy_local[6] = hgfy[6]; - fy_local[7] = hgfy[7]; - - fz_local = &fz_elem[i3] ; - fz_local[0] = hgfz[0]; - fz_local[1] = hgfz[1]; - fz_local[2] = hgfz[2]; - fz_local[3] = hgfz[3]; - fz_local[4] = hgfz[4]; - fz_local[5] = hgfz[5]; - fz_local[6] = hgfz[6]; - fz_local[7] = hgfz[7]; - } - else { - domain.fx(n0si2) += hgfx[0]; - domain.fy(n0si2) += hgfy[0]; - domain.fz(n0si2) += hgfz[0]; - - domain.fx(n1si2) += hgfx[1]; - domain.fy(n1si2) += hgfy[1]; - domain.fz(n1si2) += hgfz[1]; - - domain.fx(n2si2) += hgfx[2]; - domain.fy(n2si2) += hgfy[2]; - domain.fz(n2si2) += hgfz[2]; - - domain.fx(n3si2) += hgfx[3]; - domain.fy(n3si2) += hgfy[3]; - domain.fz(n3si2) += hgfz[3]; - - domain.fx(n4si2) += hgfx[4]; - domain.fy(n4si2) += hgfy[4]; - domain.fz(n4si2) += hgfz[4]; - - domain.fx(n5si2) += hgfx[5]; - domain.fy(n5si2) += hgfy[5]; - domain.fz(n5si2) += hgfz[5]; - - domain.fx(n6si2) += hgfx[6]; - domain.fy(n6si2) += hgfy[6]; - domain.fz(n6si2) += hgfz[6]; - - domain.fx(n7si2) += hgfx[7]; - domain.fy(n7si2) += hgfy[7]; - domain.fz(n7si2) += hgfz[7]; - } - } - - if (numthreads > 1) { - // Collect the data from the local arrays into the final force arrays -#pragma omp parallel for firstprivate(numNode) - for( Index_t gnode=0 ; gnode(numElem8) ; - Real_t *dvdy = Allocate(numElem8) ; - Real_t *dvdz = Allocate(numElem8) ; - Real_t *x8n = Allocate(numElem8) ; - Real_t *y8n = Allocate(numElem8) ; - Real_t *z8n = Allocate(numElem8) ; - - /* start loop over elements */ -#pragma omp parallel for firstprivate(numElem) - for (Index_t i=0 ; i Real_t(0.) ) { - CalcFBHourglassForceForElems( domain, - determ, x8n, y8n, z8n, dvdx, dvdy, dvdz, - hgcoef, numElem, domain.numNode()) ; - } - - Release(&z8n) ; - Release(&y8n) ; - Release(&x8n) ; - Release(&dvdz) ; - Release(&dvdy) ; - Release(&dvdx) ; - - return ; -} - -/******************************************/ - -static inline -void CalcVolumeForceForElems(Domain& domain) -{ - Index_t numElem = domain.numElem() ; - if (numElem != 0) { - Real_t hgcoef = domain.hgcoef() ; - Real_t *sigxx = Allocate(numElem) ; - Real_t *sigyy = Allocate(numElem) ; - Real_t *sigzz = Allocate(numElem) ; - Real_t *determ = Allocate(numElem) ; - - /* Sum contributions to total stress tensor */ - InitStressTermsForElems(domain, sigxx, sigyy, sigzz, numElem); - - // call elemlib stress integration loop to produce nodal forces from - // material stresses. - IntegrateStressForElems( domain, - sigxx, sigyy, sigzz, determ, numElem, - domain.numNode()) ; - - // check for negative element volume -#pragma omp parallel for firstprivate(numElem) - for ( Index_t k=0 ; k 0) { - const Real_t deltatime = domain.deltatime() ; - - domain.AllocateStrains(numElem); - - CalcKinematicsForElems(domain, vnew, deltatime, numElem) ; - - // element loop to do some stuff not included in the elemlib function. -#pragma omp parallel for firstprivate(numElem) - for ( Index_t k=0 ; k monoq_max_slope) phixi = monoq_max_slope; - - - /* phieta */ - norm = Real_t(1.) / ( domain.delv_eta(i) + ptiny ) ; - - switch (bcMask & ETA_M) { - case ETA_M_COMM: /* needs comm data */ - case 0: delvm = domain.delv_eta(domain.letam(i)) ; break ; - case ETA_M_SYMM: delvm = domain.delv_eta(i) ; break ; - case ETA_M_FREE: delvm = Real_t(0.0) ; break ; - default: fprintf(stderr, "Error in switch at %s line %d\n", - __FILE__, __LINE__); - delvm = 0; /* ERROR - but quiets the compiler */ - break; - } - switch (bcMask & ETA_P) { - case ETA_P_COMM: /* needs comm data */ - case 0: delvp = domain.delv_eta(domain.letap(i)) ; break ; - case ETA_P_SYMM: delvp = domain.delv_eta(i) ; break ; - case ETA_P_FREE: delvp = Real_t(0.0) ; break ; - default: fprintf(stderr, "Error in switch at %s line %d\n", - __FILE__, __LINE__); - delvp = 0; /* ERROR - but quiets the compiler */ - break; - } - - delvm = delvm * norm ; - delvp = delvp * norm ; - - phieta = Real_t(.5) * ( delvm + delvp ) ; - - delvm *= monoq_limiter_mult ; - delvp *= monoq_limiter_mult ; - - if ( delvm < phieta ) phieta = delvm ; - if ( delvp < phieta ) phieta = delvp ; - if ( phieta < Real_t(0.)) phieta = Real_t(0.) ; - if ( phieta > monoq_max_slope) phieta = monoq_max_slope; - - /* phizeta */ - norm = Real_t(1.) / ( domain.delv_zeta(i) + ptiny ) ; - - switch (bcMask & ZETA_M) { - case ZETA_M_COMM: /* needs comm data */ - case 0: delvm = domain.delv_zeta(domain.lzetam(i)) ; break ; - case ZETA_M_SYMM: delvm = domain.delv_zeta(i) ; break ; - case ZETA_M_FREE: delvm = Real_t(0.0) ; break ; - default: fprintf(stderr, "Error in switch at %s line %d\n", - __FILE__, __LINE__); - delvm = 0; /* ERROR - but quiets the compiler */ - break; - } - switch (bcMask & ZETA_P) { - case ZETA_P_COMM: /* needs comm data */ - case 0: delvp = domain.delv_zeta(domain.lzetap(i)) ; break ; - case ZETA_P_SYMM: delvp = domain.delv_zeta(i) ; break ; - case ZETA_P_FREE: delvp = Real_t(0.0) ; break ; - default: fprintf(stderr, "Error in switch at %s line %d\n", - __FILE__, __LINE__); - delvp = 0; /* ERROR - but quiets the compiler */ - break; - } - - delvm = delvm * norm ; - delvp = delvp * norm ; - - phizeta = Real_t(.5) * ( delvm + delvp ) ; - - delvm *= monoq_limiter_mult ; - delvp *= monoq_limiter_mult ; - - if ( delvm < phizeta ) phizeta = delvm ; - if ( delvp < phizeta ) phizeta = delvp ; - if ( phizeta < Real_t(0.)) phizeta = Real_t(0.); - if ( phizeta > monoq_max_slope ) phizeta = monoq_max_slope; - - /* Remove length scale */ - - if ( domain.vdov(i) > Real_t(0.) ) { - qlin = Real_t(0.) ; - qquad = Real_t(0.) ; - } - else { - Real_t delvxxi = domain.delv_xi(i) * domain.delx_xi(i) ; - Real_t delvxeta = domain.delv_eta(i) * domain.delx_eta(i) ; - Real_t delvxzeta = domain.delv_zeta(i) * domain.delx_zeta(i) ; - - if ( delvxxi > Real_t(0.) ) delvxxi = Real_t(0.) ; - if ( delvxeta > Real_t(0.) ) delvxeta = Real_t(0.) ; - if ( delvxzeta > Real_t(0.) ) delvxzeta = Real_t(0.) ; - - Real_t rho = domain.elemMass(i) / (domain.volo(i) * vnew[i]) ; - - qlin = -qlc_monoq * rho * - ( delvxxi * (Real_t(1.) - phixi) + - delvxeta * (Real_t(1.) - phieta) + - delvxzeta * (Real_t(1.) - phizeta) ) ; - - qquad = qqc_monoq * rho * - ( delvxxi*delvxxi * (Real_t(1.) - phixi*phixi) + - delvxeta*delvxeta * (Real_t(1.) - phieta*phieta) + - delvxzeta*delvxzeta * (Real_t(1.) - phizeta*phizeta) ) ; - } - - domain.qq(i) = qquad ; - domain.ql(i) = qlin ; - } -} - -/******************************************/ - -static inline -void CalcMonotonicQForElems(Domain& domain, Real_t vnew[]) -{ - // - // initialize parameters - // - const Real_t ptiny = Real_t(1.e-36) ; - - // - // calculate the monotonic q for all regions - // - for (Index_t r=0 ; r 0) { - CalcMonotonicQRegionForElems(domain, r, vnew, ptiny) ; - } - } -} - -/******************************************/ - -static inline -void CalcQForElems(Domain& domain, Real_t vnew[]) -{ - // - // MONOTONIC Q option - // - - Index_t numElem = domain.numElem() ; - - if (numElem != 0) { - Int_t allElem = numElem + /* local elem */ - 2*domain.sizeX()*domain.sizeY() + /* plane ghosts */ - 2*domain.sizeX()*domain.sizeZ() + /* row ghosts */ - 2*domain.sizeY()*domain.sizeZ() ; /* col ghosts */ - - domain.AllocateGradients(numElem, allElem); - -#if USE_MPI - CommRecv(domain, MSG_MONOQ, 3, - domain.sizeX(), domain.sizeY(), domain.sizeZ(), - true, true) ; -#endif - - /* Calculate velocity gradients */ - CalcMonotonicQGradientsForElems(domain, vnew); - -#if USE_MPI - Domain_member fieldData[3] ; - - /* Transfer veloctiy gradients in the first order elements */ - /* problem->commElements->Transfer(CommElements::monoQ) ; */ - - fieldData[0] = &Domain::delv_xi ; - fieldData[1] = &Domain::delv_eta ; - fieldData[2] = &Domain::delv_zeta ; - - CommSend(domain, MSG_MONOQ, 3, fieldData, - domain.sizeX(), domain.sizeY(), domain.sizeZ(), - true, true) ; - - CommMonoQ(domain) ; -#endif - - CalcMonotonicQForElems(domain, vnew) ; - - // Free up memory - domain.DeallocateGradients(); - - /* Don't allow excessive artificial viscosity */ - Index_t idx = -1; - for (Index_t i=0; i domain.qstop() ) { - idx = i ; - break ; - } - } - - if(idx >= 0) { -#if USE_MPI - MPI_Abort(MPI_COMM_WORLD, QStopError) ; -#else - exit(QStopError); -#endif - } - } -} - -/******************************************/ - -static inline -void CalcPressureForElems(Real_t* p_new, Real_t* bvc, - Real_t* pbvc, Real_t* e_old, - Real_t* compression, Real_t *vnewc, - Real_t pmin, - Real_t p_cut, Real_t eosvmax, - Index_t length, Index_t *regElemList) -{ -#pragma omp parallel for firstprivate(length) - for (Index_t i = 0; i < length ; ++i) { - Real_t c1s = Real_t(2.0)/Real_t(3.0) ; - bvc[i] = c1s * (compression[i] + Real_t(1.)); - pbvc[i] = c1s; - } - -#pragma omp parallel for firstprivate(length, pmin, p_cut, eosvmax) - for (Index_t i = 0 ; i < length ; ++i){ - Index_t elem = regElemList[i]; - - p_new[i] = bvc[i] * e_old[i] ; - - if (FABS(p_new[i]) < p_cut ) - p_new[i] = Real_t(0.0) ; - - if ( vnewc[elem] >= eosvmax ) /* impossible condition here? */ - p_new[i] = Real_t(0.0) ; - - if (p_new[i] < pmin) - p_new[i] = pmin ; - } -} - -/******************************************/ - -static inline -void CalcEnergyForElems(Real_t* p_new, Real_t* e_new, Real_t* q_new, - Real_t* bvc, Real_t* pbvc, - Real_t* p_old, Real_t* e_old, Real_t* q_old, - Real_t* compression, Real_t* compHalfStep, - Real_t* vnewc, Real_t* work, Real_t* delvc, Real_t pmin, - Real_t p_cut, Real_t e_cut, Real_t q_cut, Real_t emin, - Real_t* qq_old, Real_t* ql_old, - Real_t rho0, - Real_t eosvmax, - Index_t length, Index_t *regElemList) -{ - Real_t *pHalfStep = Allocate(length) ; - -#pragma omp parallel for firstprivate(length, emin) - for (Index_t i = 0 ; i < length ; ++i) { - e_new[i] = e_old[i] - Real_t(0.5) * delvc[i] * (p_old[i] + q_old[i]) - + Real_t(0.5) * work[i]; - - if (e_new[i] < emin ) { - e_new[i] = emin ; - } - } - - CalcPressureForElems(pHalfStep, bvc, pbvc, e_new, compHalfStep, vnewc, - pmin, p_cut, eosvmax, length, regElemList); - -#pragma omp parallel for firstprivate(length, rho0) - for (Index_t i = 0 ; i < length ; ++i) { - Real_t vhalf = Real_t(1.) / (Real_t(1.) + compHalfStep[i]) ; - - if ( delvc[i] > Real_t(0.) ) { - q_new[i] /* = qq_old[i] = ql_old[i] */ = Real_t(0.) ; - } - else { - Real_t ssc = ( pbvc[i] * e_new[i] - + vhalf * vhalf * bvc[i] * pHalfStep[i] ) / rho0 ; - - if ( ssc <= Real_t(.1111111e-36) ) { - ssc = Real_t(.3333333e-18) ; - } else { - ssc = SQRT(ssc) ; - } - - q_new[i] = (ssc*ql_old[i] + qq_old[i]) ; - } - - e_new[i] = e_new[i] + Real_t(0.5) * delvc[i] - * ( Real_t(3.0)*(p_old[i] + q_old[i]) - - Real_t(4.0)*(pHalfStep[i] + q_new[i])) ; - } - -#pragma omp parallel for firstprivate(length, emin, e_cut) - for (Index_t i = 0 ; i < length ; ++i) { - - e_new[i] += Real_t(0.5) * work[i]; - - if (FABS(e_new[i]) < e_cut) { - e_new[i] = Real_t(0.) ; - } - if ( e_new[i] < emin ) { - e_new[i] = emin ; - } - } - - CalcPressureForElems(p_new, bvc, pbvc, e_new, compression, vnewc, - pmin, p_cut, eosvmax, length, regElemList); - -#pragma omp parallel for firstprivate(length, rho0, emin, e_cut) - for (Index_t i = 0 ; i < length ; ++i){ - const Real_t sixth = Real_t(1.0) / Real_t(6.0) ; - Index_t elem = regElemList[i]; - Real_t q_tilde ; - - if (delvc[i] > Real_t(0.)) { - q_tilde = Real_t(0.) ; - } - else { - Real_t ssc = ( pbvc[i] * e_new[i] - + vnewc[elem] * vnewc[elem] * bvc[i] * p_new[i] ) / rho0 ; - - if ( ssc <= Real_t(.1111111e-36) ) { - ssc = Real_t(.3333333e-18) ; - } else { - ssc = SQRT(ssc) ; - } - - q_tilde = (ssc*ql_old[i] + qq_old[i]) ; - } - - e_new[i] = e_new[i] - ( Real_t(7.0)*(p_old[i] + q_old[i]) - - Real_t(8.0)*(pHalfStep[i] + q_new[i]) - + (p_new[i] + q_tilde)) * delvc[i]*sixth ; - - if (FABS(e_new[i]) < e_cut) { - e_new[i] = Real_t(0.) ; - } - if ( e_new[i] < emin ) { - e_new[i] = emin ; - } - } - - CalcPressureForElems(p_new, bvc, pbvc, e_new, compression, vnewc, - pmin, p_cut, eosvmax, length, regElemList); - -#pragma omp parallel for firstprivate(length, rho0, q_cut) - for (Index_t i = 0 ; i < length ; ++i){ - Index_t elem = regElemList[i]; - - if ( delvc[i] <= Real_t(0.) ) { - Real_t ssc = ( pbvc[i] * e_new[i] - + vnewc[elem] * vnewc[elem] * bvc[i] * p_new[i] ) / rho0 ; - - if ( ssc <= Real_t(.1111111e-36) ) { - ssc = Real_t(.3333333e-18) ; - } else { - ssc = SQRT(ssc) ; - } - - q_new[i] = (ssc*ql_old[i] + qq_old[i]) ; - - if (FABS(q_new[i]) < q_cut) q_new[i] = Real_t(0.) ; - } - } - - Release(&pHalfStep) ; - - return ; -} - -/******************************************/ - -static inline -void CalcSoundSpeedForElems(Domain &domain, - Real_t *vnewc, Real_t rho0, Real_t *enewc, - Real_t *pnewc, Real_t *pbvc, - Real_t *bvc, Real_t ss4o3, - Index_t len, Index_t *regElemList) -{ -#pragma omp parallel for firstprivate(rho0, ss4o3) - for (Index_t i = 0; i < len ; ++i) { - Index_t elem = regElemList[i]; - Real_t ssTmp = (pbvc[i] * enewc[i] + vnewc[elem] * vnewc[elem] * - bvc[i] * pnewc[i]) / rho0; - if (ssTmp <= Real_t(.1111111e-36)) { - ssTmp = Real_t(.3333333e-18); - } - else { - ssTmp = SQRT(ssTmp); - } - domain.ss(elem) = ssTmp ; - } -} - -/******************************************/ - -static inline -void EvalEOSForElems(Domain& domain, Real_t *vnewc, - Int_t numElemReg, Index_t *regElemList, Int_t rep) -{ - Real_t e_cut = domain.e_cut() ; - Real_t p_cut = domain.p_cut() ; - Real_t ss4o3 = domain.ss4o3() ; - Real_t q_cut = domain.q_cut() ; - - Real_t eosvmax = domain.eosvmax() ; - Real_t eosvmin = domain.eosvmin() ; - Real_t pmin = domain.pmin() ; - Real_t emin = domain.emin() ; - Real_t rho0 = domain.refdens() ; - - // These temporaries will be of different size for - // each call (due to different sized region element - // lists) - Real_t *e_old = Allocate(numElemReg) ; - Real_t *delvc = Allocate(numElemReg) ; - Real_t *p_old = Allocate(numElemReg) ; - Real_t *q_old = Allocate(numElemReg) ; - Real_t *compression = Allocate(numElemReg) ; - Real_t *compHalfStep = Allocate(numElemReg) ; - Real_t *qq_old = Allocate(numElemReg) ; - Real_t *ql_old = Allocate(numElemReg) ; - Real_t *work = Allocate(numElemReg) ; - Real_t *p_new = Allocate(numElemReg) ; - Real_t *e_new = Allocate(numElemReg) ; - Real_t *q_new = Allocate(numElemReg) ; - Real_t *bvc = Allocate(numElemReg) ; - Real_t *pbvc = Allocate(numElemReg) ; - - //loop to add load imbalance based on region number - for(Int_t j = 0; j < rep; j++) { - /* compress data, minimal set */ -#pragma omp parallel - { -#pragma omp for nowait firstprivate(numElemReg) - for (Index_t i=0; i eosvmax or v < eosvmin */ - if ( eosvmin != Real_t(0.) ) { -#pragma omp for nowait firstprivate(numElemReg, eosvmin) - for(Index_t i=0 ; i= eosvmax) { /* impossible due to calling func? */ - p_old[i] = Real_t(0.) ; - compression[i] = Real_t(0.) ; - compHalfStep[i] = Real_t(0.) ; - } - } - } - -#pragma omp for nowait firstprivate(numElemReg) - for (Index_t i = 0 ; i < numElemReg ; ++i) { - work[i] = Real_t(0.) ; - } - } - CalcEnergyForElems(p_new, e_new, q_new, bvc, pbvc, - p_old, e_old, q_old, compression, compHalfStep, - vnewc, work, delvc, pmin, - p_cut, e_cut, q_cut, emin, - qq_old, ql_old, rho0, eosvmax, - numElemReg, regElemList); - } - -#pragma omp parallel for firstprivate(numElemReg) - for (Index_t i=0; i eosvmax) - vnew[i] = eosvmax ; - } - } - - // This check may not make perfect sense in LULESH, but - // it's representative of something in the full code - - // just leave it in, please -#pragma omp for nowait firstprivate(numElem) - for (Index_t i=0; i eosvmax) - vc = eosvmax ; - } - if (vc <= 0.) { -#if USE_MPI - MPI_Abort(MPI_COMM_WORLD, VolumeError) ; -#else - exit(VolumeError); -#endif - } - } - } - - for (Int_t r=0 ; r(numElem) ; /* new relative vol -- temp */ - - CalcLagrangeElements(domain, vnew) ; - - /* Calculate Q. (Monotonic q option requires communication) */ - CalcQForElems(domain, vnew) ; - - ApplyMaterialPropertiesForElems(domain, vnew) ; - - UpdateVolumesForElems(domain, vnew, - domain.v_cut(), numElem) ; - - Release(&vnew); -} - -/******************************************/ - -static inline -void CalcCourantConstraintForElems(Domain &domain, Index_t length, - Index_t *regElemlist, - Real_t qqc, Real_t& dtcourant) -{ -#if _OPENMP - Index_t threads = omp_get_max_threads(); - static Index_t *courant_elem_per_thread; - static Real_t *dtcourant_per_thread; - static bool first = true; - if (first) { - courant_elem_per_thread = new Index_t[threads]; - dtcourant_per_thread = new Real_t[threads]; - first = false; - } -#else - Index_t threads = 1; - Index_t courant_elem_per_thread[1]; - Real_t dtcourant_per_thread[1]; -#endif - - -#pragma omp parallel firstprivate(length, qqc) - { - Real_t qqc2 = Real_t(64.0) * qqc * qqc ; - Real_t dtcourant_tmp = dtcourant; - Index_t courant_elem = -1 ; - -#if _OPENMP - Index_t thread_num = omp_get_thread_num(); -#else - Index_t thread_num = 0; -#endif - -#pragma omp for - for (Index_t i = 0 ; i < length ; ++i) { - Index_t indx = regElemlist[i] ; - Real_t dtf = domain.ss(indx) * domain.ss(indx) ; - - if ( domain.vdov(indx) < Real_t(0.) ) { - dtf = dtf - + qqc2 * domain.arealg(indx) * domain.arealg(indx) - * domain.vdov(indx) * domain.vdov(indx) ; - } - - dtf = SQRT(dtf) ; - dtf = domain.arealg(indx) / dtf ; - - if (domain.vdov(indx) != Real_t(0.)) { - if ( dtf < dtcourant_tmp ) { - dtcourant_tmp = dtf ; - courant_elem = indx ; - } - } - } - - dtcourant_per_thread[thread_num] = dtcourant_tmp ; - courant_elem_per_thread[thread_num] = courant_elem ; - } - - for (Index_t i = 1; i < threads; ++i) { - if (dtcourant_per_thread[i] < dtcourant_per_thread[0] ) { - dtcourant_per_thread[0] = dtcourant_per_thread[i]; - courant_elem_per_thread[0] = courant_elem_per_thread[i]; - } - } - - if (courant_elem_per_thread[0] != -1) { - dtcourant = dtcourant_per_thread[0] ; - } - - return ; - -} - -/******************************************/ - -static inline -void CalcHydroConstraintForElems(Domain &domain, Index_t length, - Index_t *regElemlist, Real_t dvovmax, Real_t& dthydro) -{ -#if _OPENMP - Index_t threads = omp_get_max_threads(); - static Index_t *hydro_elem_per_thread; - static Real_t *dthydro_per_thread; - static bool first = true; - if (first) { - hydro_elem_per_thread = new Index_t[threads]; - dthydro_per_thread = new Real_t[threads]; - first = false; - } -#else - Index_t threads = 1; - Index_t hydro_elem_per_thread[1]; - Real_t dthydro_per_thread[1]; -#endif - -#pragma omp parallel firstprivate(length, dvovmax) - { - Real_t dthydro_tmp = dthydro ; - Index_t hydro_elem = -1 ; - -#if _OPENMP - Index_t thread_num = omp_get_thread_num(); -#else - Index_t thread_num = 0; -#endif - -#pragma omp for - for (Index_t i = 0 ; i < length ; ++i) { - Index_t indx = regElemlist[i] ; - - if (domain.vdov(indx) != Real_t(0.)) { - Real_t dtdvov = dvovmax / (FABS(domain.vdov(indx))+Real_t(1.e-20)) ; - - if ( dthydro_tmp > dtdvov ) { - dthydro_tmp = dtdvov ; - hydro_elem = indx ; - } - } - } - - dthydro_per_thread[thread_num] = dthydro_tmp ; - hydro_elem_per_thread[thread_num] = hydro_elem ; - } - - for (Index_t i = 1; i < threads; ++i) { - if(dthydro_per_thread[i] < dthydro_per_thread[0]) { - dthydro_per_thread[0] = dthydro_per_thread[i]; - hydro_elem_per_thread[0] = hydro_elem_per_thread[i]; - } - } - - if (hydro_elem_per_thread[0] != -1) { - dthydro = dthydro_per_thread[0] ; - } - - return ; -} - -/******************************************/ - -static inline -void CalcTimeConstraintsForElems(Domain& domain) { - - // Initialize conditions to a very large value - domain.dtcourant() = 1.0e+20; - domain.dthydro() = 1.0e+20; - - for (Index_t r=0 ; r < domain.numReg() ; ++r) { - /* evaluate time constraint */ - CalcCourantConstraintForElems(domain, domain.regElemSize(r), - domain.regElemlist(r), - domain.qqc(), - domain.dtcourant()) ; - - /* check hydro constraint */ - CalcHydroConstraintForElems(domain, domain.regElemSize(r), - domain.regElemlist(r), - domain.dvovmax(), - domain.dthydro()) ; - } -} - -/******************************************/ - -static inline -void LagrangeLeapFrog(Domain& domain) -{ -#ifdef SEDOV_SYNC_POS_VEL_LATE - Domain_member fieldData[6] ; -#endif - - /* calculate nodal forces, accelerations, velocities, positions, with - * applied boundary conditions and slide surface considerations */ - LagrangeNodal(domain); - - -#ifdef SEDOV_SYNC_POS_VEL_LATE -#endif - - /* calculate element quantities (i.e. velocity gradient & q), and update - * material states */ - LagrangeElements(domain, domain.numElem()); - -#if USE_MPI -#ifdef SEDOV_SYNC_POS_VEL_LATE - CommRecv(domain, MSG_SYNC_POS_VEL, 6, - domain.sizeX() + 1, domain.sizeY() + 1, domain.sizeZ() + 1, - false, false) ; - - fieldData[0] = &Domain::x ; - fieldData[1] = &Domain::y ; - fieldData[2] = &Domain::z ; - fieldData[3] = &Domain::xd ; - fieldData[4] = &Domain::yd ; - fieldData[5] = &Domain::zd ; - - CommSend(domain, MSG_SYNC_POS_VEL, 6, fieldData, - domain.sizeX() + 1, domain.sizeY() + 1, domain.sizeZ() + 1, - false, false) ; -#endif -#endif - - CalcTimeConstraintsForElems(domain); - -#if USE_MPI -#ifdef SEDOV_SYNC_POS_VEL_LATE - CommSyncPosVel(domain) ; -#endif -#endif -} - - -/******************************************/ - -int main(int argc, char *argv[]) -{ - Domain *locDom ; - Int_t numRanks ; - Int_t myRank ; - struct cmdLineOpts opts; - -#if USE_MPI - Domain_member fieldData ; - - MPI_Init(&argc, &argv) ; - MPI_Comm_size(MPI_COMM_WORLD, &numRanks) ; - MPI_Comm_rank(MPI_COMM_WORLD, &myRank) ; -#else - numRanks = 1; - myRank = 0; -#endif - - /* Set defaults that can be overridden by command line opts */ - opts.its = 9999999; - opts.nx = 30; - opts.numReg = 11; - opts.numFiles = (int)(numRanks+10)/9; - opts.showProg = 0; - opts.quiet = 0; - opts.viz = 0; - opts.balance = 1; - opts.cost = 1; - - ParseCommandLineOptions(argc, argv, myRank, &opts); - - if ((myRank == 0) && (opts.quiet == 0)) { - printf("Running problem size %d^3 per domain until completion\n", opts.nx); - printf("Num processors: %d\n", numRanks); -#if _OPENMP - printf("Num threads: %d\n", omp_get_max_threads()); -#endif - printf("Total number of elements: %lld\n\n", (long long int)(numRanks*opts.nx*opts.nx*opts.nx)); - printf("To run other sizes, use -s .\n"); - printf("To run a fixed number of iterations, use -i .\n"); - printf("To run a more or less balanced region set, use -b .\n"); - printf("To change the relative costs of regions, use -c .\n"); - printf("To print out progress, use -p\n"); - printf("To write an output file for VisIt, use -v\n"); - printf("See help (-h) for more options\n\n"); - } - - // Set up the mesh and decompose. Assumes regular cubes for now - Int_t col, row, plane, side; - InitMeshDecomp(numRanks, myRank, &col, &row, &plane, &side); - - // Build the main data structure and initialize it - locDom = new Domain(numRanks, col, row, plane, opts.nx, - side, opts.numReg, opts.balance, opts.cost) ; - - -#if USE_MPI - fieldData = &Domain::nodalMass ; - - // Initial domain boundary communication - CommRecv(*locDom, MSG_COMM_SBN, 1, - locDom->sizeX() + 1, locDom->sizeY() + 1, locDom->sizeZ() + 1, - true, false) ; - CommSend(*locDom, MSG_COMM_SBN, 1, &fieldData, - locDom->sizeX() + 1, locDom->sizeY() + 1, locDom->sizeZ() + 1, - true, false) ; - CommSBN(*locDom, 1, &fieldData) ; - - // End initialization - MPI_Barrier(MPI_COMM_WORLD); -#endif - - // BEGIN timestep to solution */ -#if USE_MPI - double start = MPI_Wtime(); -#else - timeval start; - gettimeofday(&start, NULL) ; -#endif -//debug to see region sizes -// for(Int_t i = 0; i < locDom->numReg(); i++) -// std::cout << "region" << i + 1<< "size" << locDom->regElemSize(i) <time() < locDom->stoptime()) && (locDom->cycle() < opts.its)) { - - TimeIncrement(*locDom) ; - LagrangeLeapFrog(*locDom) ; - - if ((opts.showProg != 0) && (opts.quiet == 0) && (myRank == 0)) { - printf("cycle = %d, time = %e, dt=%e\n", - locDom->cycle(), double(locDom->time()), double(locDom->deltatime()) ) ; - } - } - - // Use reduced max elapsed time - double elapsed_time; -#if USE_MPI - elapsed_time = MPI_Wtime() - start; -#else - timeval end; - gettimeofday(&end, NULL) ; - elapsed_time = (double)(end.tv_sec - start.tv_sec) + ((double)(end.tv_usec - start.tv_usec))/1000000 ; -#endif - double elapsed_timeG; -#if USE_MPI - MPI_Reduce(&elapsed_time, &elapsed_timeG, 1, MPI_DOUBLE, - MPI_MAX, 0, MPI_COMM_WORLD); -#else - elapsed_timeG = elapsed_time; -#endif - - // Write out final viz file */ - if (opts.viz) { - DumpToVisit(*locDom, opts.numFiles, myRank, numRanks) ; - } - - if ((myRank == 0) && (opts.quiet == 0)) { - VerifyAndWriteFinalOutput(elapsed_timeG, *locDom, opts.nx, numRanks); - } - -#if USE_MPI - MPI_Finalize() ; -#endif - - return 0 ; -} diff --git a/test/lulesh/lulesh.h b/test/lulesh/lulesh.h deleted file mode 100644 index 66c97eb9..00000000 --- a/test/lulesh/lulesh.h +++ /dev/null @@ -1,802 +0,0 @@ -#if !defined(USE_MPI) -#error "You should specify USE_MPI=0 or USE_MPI=1 on the compile line" -#endif - -// OpenMP will be compiled in if this flag is set to 1 AND the compiler beging -// used supports it (i.e. the _OPENMP symbol is defined) -#define USE_OMP 1 - -#if USE_MPI -#include - -/* - define one of these three symbols: - - SEDOV_SYNC_POS_VEL_NONE - SEDOV_SYNC_POS_VEL_EARLY - SEDOV_SYNC_POS_VEL_LATE -*/ - -#define SEDOV_SYNC_POS_VEL_EARLY 1 -#endif - -#include -#include - -//************************************************** -// Allow flexibility for arithmetic representations -//************************************************** - -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -// Precision specification -typedef float real4; -typedef double real8; -typedef long double real10; // 10 bytes on x86 - -typedef int Index_t; // array subscript and loop index -typedef real8 Real_t; // floating point representation -typedef int Int_t; // integer representation - -enum { VolumeError = -1, QStopError = -2 }; - -inline real4 SQRT(real4 arg) { - return sqrtf(arg); -} -inline real8 SQRT(real8 arg) { - return sqrt(arg); -} -inline real10 SQRT(real10 arg) { - return sqrtl(arg); -} - -inline real4 CBRT(real4 arg) { - return cbrtf(arg); -} -inline real8 CBRT(real8 arg) { - return cbrt(arg); -} -inline real10 CBRT(real10 arg) { - return cbrtl(arg); -} - -inline real4 FABS(real4 arg) { - return fabsf(arg); -} -inline real8 FABS(real8 arg) { - return fabs(arg); -} -inline real10 FABS(real10 arg) { - return fabsl(arg); -} - -// Stuff needed for boundary conditions -// 2 BCs on each of 6 hexahedral faces (12 bits) -#define XI_M 0x00007 -#define XI_M_SYMM 0x00001 -#define XI_M_FREE 0x00002 -#define XI_M_COMM 0x00004 - -#define XI_P 0x00038 -#define XI_P_SYMM 0x00008 -#define XI_P_FREE 0x00010 -#define XI_P_COMM 0x00020 - -#define ETA_M 0x001c0 -#define ETA_M_SYMM 0x00040 -#define ETA_M_FREE 0x00080 -#define ETA_M_COMM 0x00100 - -#define ETA_P 0x00e00 -#define ETA_P_SYMM 0x00200 -#define ETA_P_FREE 0x00400 -#define ETA_P_COMM 0x00800 - -#define ZETA_M 0x07000 -#define ZETA_M_SYMM 0x01000 -#define ZETA_M_FREE 0x02000 -#define ZETA_M_COMM 0x04000 - -#define ZETA_P 0x38000 -#define ZETA_P_SYMM 0x08000 -#define ZETA_P_FREE 0x10000 -#define ZETA_P_COMM 0x20000 - -// MPI Message Tags -#define MSG_COMM_SBN 1024 -#define MSG_SYNC_POS_VEL 2048 -#define MSG_MONOQ 3072 - -#define MAX_FIELDS_PER_MPI_COMM 6 - -// Assume 128 byte coherence -// Assume Real_t is an "integral power of 2" bytes wide -#define CACHE_COHERENCE_PAD_REAL (128 / sizeof(Real_t)) - -#define CACHE_ALIGN_REAL(n) (((n) + (CACHE_COHERENCE_PAD_REAL - 1)) & ~(CACHE_COHERENCE_PAD_REAL - 1)) - -////////////////////////////////////////////////////// -// Primary data structure -////////////////////////////////////////////////////// - -/* - * The implementation of the data abstraction used for lulesh - * resides entirely in the Domain class below. You can change - * grouping and interleaving of fields here to maximize data layout - * efficiency for your underlying architecture or compiler. - * - * For example, fields can be implemented as STL objects or - * raw array pointers. As another example, individual fields - * m_x, m_y, m_z could be budled into - * - * struct { Real_t x, y, z ; } *m_coord ; - * - * allowing accessor functions such as - * - * "Real_t &x(Index_t idx) { return m_coord[idx].x ; }" - * "Real_t &y(Index_t idx) { return m_coord[idx].y ; }" - * "Real_t &z(Index_t idx) { return m_coord[idx].z ; }" - */ - -class Domain { - public: - // Constructor - Domain(Int_t numRanks, Index_t colLoc, Index_t rowLoc, Index_t planeLoc, Index_t nx, Int_t tp, Int_t nr, - Int_t balance, Int_t cost); - - // - // ALLOCATION - // - - void AllocateNodePersistent(Int_t numNode) // Node-centered - { - m_x.resize(numNode); // coordinates - m_y.resize(numNode); - m_z.resize(numNode); - - m_xd.resize(numNode); // velocities - m_yd.resize(numNode); - m_zd.resize(numNode); - - m_xdd.resize(numNode); // accelerations - m_ydd.resize(numNode); - m_zdd.resize(numNode); - - m_fx.resize(numNode); // forces - m_fy.resize(numNode); - m_fz.resize(numNode); - - m_nodalMass.resize(numNode); // mass - } - - void AllocateElemPersistent(Int_t numElem) // Elem-centered - { - m_nodelist.resize(8 * numElem); - - // elem connectivities through face - m_lxim.resize(numElem); - m_lxip.resize(numElem); - m_letam.resize(numElem); - m_letap.resize(numElem); - m_lzetam.resize(numElem); - m_lzetap.resize(numElem); - - m_elemBC.resize(numElem); - - m_e.resize(numElem); - m_p.resize(numElem); - - m_q.resize(numElem); - m_ql.resize(numElem); - m_qq.resize(numElem); - - m_v.resize(numElem); - - m_volo.resize(numElem); - m_delv.resize(numElem); - m_vdov.resize(numElem); - - m_arealg.resize(numElem); - - m_ss.resize(numElem); - - m_elemMass.resize(numElem); - } - - void AllocateGradients(Int_t numElem, Int_t allElem) { - // Position gradients - m_delx_xi.resize(numElem); - m_delx_eta.resize(numElem); - m_delx_zeta.resize(numElem); - - // Velocity gradients - m_delv_xi.resize(allElem); - m_delv_eta.resize(allElem); - m_delv_zeta.resize(allElem); - } - - void DeallocateGradients() { - m_delx_zeta.clear(); - m_delx_eta.clear(); - m_delx_xi.clear(); - - m_delv_zeta.clear(); - m_delv_eta.clear(); - m_delv_xi.clear(); - } - - void AllocateStrains(Int_t numElem) { - m_dxx.resize(numElem); - m_dyy.resize(numElem); - m_dzz.resize(numElem); - } - - void DeallocateStrains() { - m_dzz.clear(); - m_dyy.clear(); - m_dxx.clear(); - } - - // - // ACCESSORS - // - - // Node-centered - - // Nodal coordinates - Real_t& x(Index_t idx) { - return m_x[idx]; - } - Real_t& y(Index_t idx) { - return m_y[idx]; - } - Real_t& z(Index_t idx) { - return m_z[idx]; - } - - // Nodal velocities - Real_t& xd(Index_t idx) { - return m_xd[idx]; - } - Real_t& yd(Index_t idx) { - return m_yd[idx]; - } - Real_t& zd(Index_t idx) { - return m_zd[idx]; - } - - // Nodal accelerations - Real_t& xdd(Index_t idx) { - return m_xdd[idx]; - } - Real_t& ydd(Index_t idx) { - return m_ydd[idx]; - } - Real_t& zdd(Index_t idx) { - return m_zdd[idx]; - } - - // Nodal forces - Real_t& fx(Index_t idx) { - return m_fx[idx]; - } - Real_t& fy(Index_t idx) { - return m_fy[idx]; - } - Real_t& fz(Index_t idx) { - return m_fz[idx]; - } - - // Nodal mass - Real_t& nodalMass(Index_t idx) { - return m_nodalMass[idx]; - } - - // Nodes on symmertry planes - Index_t symmX(Index_t idx) { - return m_symmX[idx]; - } - Index_t symmY(Index_t idx) { - return m_symmY[idx]; - } - Index_t symmZ(Index_t idx) { - return m_symmZ[idx]; - } - bool symmXempty() { - return m_symmX.empty(); - } - bool symmYempty() { - return m_symmY.empty(); - } - bool symmZempty() { - return m_symmZ.empty(); - } - - // - // Element-centered - // - Index_t& regElemSize(Index_t idx) { - return m_regElemSize[idx]; - } - Index_t& regNumList(Index_t idx) { - return m_regNumList[idx]; - } - Index_t* regNumList() { - return &m_regNumList[0]; - } - Index_t* regElemlist(Int_t r) { - return m_regElemlist[r]; - } - Index_t& regElemlist(Int_t r, Index_t idx) { - return m_regElemlist[r][idx]; - } - - Index_t* nodelist(Index_t idx) { - return &m_nodelist[Index_t(8) * idx]; - } - - // elem connectivities through face - Index_t& lxim(Index_t idx) { - return m_lxim[idx]; - } - Index_t& lxip(Index_t idx) { - return m_lxip[idx]; - } - Index_t& letam(Index_t idx) { - return m_letam[idx]; - } - Index_t& letap(Index_t idx) { - return m_letap[idx]; - } - Index_t& lzetam(Index_t idx) { - return m_lzetam[idx]; - } - Index_t& lzetap(Index_t idx) { - return m_lzetap[idx]; - } - - // elem face symm/free-surface flag - Int_t& elemBC(Index_t idx) { - return m_elemBC[idx]; - } - - // Principal strains - temporary - Real_t& dxx(Index_t idx) { - return m_dxx[idx]; - } - Real_t& dyy(Index_t idx) { - return m_dyy[idx]; - } - Real_t& dzz(Index_t idx) { - return m_dzz[idx]; - } - - // Velocity gradient - temporary - Real_t& delv_xi(Index_t idx) { - return m_delv_xi[idx]; - } - Real_t& delv_eta(Index_t idx) { - return m_delv_eta[idx]; - } - Real_t& delv_zeta(Index_t idx) { - return m_delv_zeta[idx]; - } - - // Position gradient - temporary - Real_t& delx_xi(Index_t idx) { - return m_delx_xi[idx]; - } - Real_t& delx_eta(Index_t idx) { - return m_delx_eta[idx]; - } - Real_t& delx_zeta(Index_t idx) { - return m_delx_zeta[idx]; - } - - // Energy - Real_t& e(Index_t idx) { - return m_e[idx]; - } - - // Pressure - Real_t& p(Index_t idx) { - return m_p[idx]; - } - - // Artificial viscosity - Real_t& q(Index_t idx) { - return m_q[idx]; - } - - // Linear term for q - Real_t& ql(Index_t idx) { - return m_ql[idx]; - } - // Quadratic term for q - Real_t& qq(Index_t idx) { - return m_qq[idx]; - } - - // Relative volume - Real_t& v(Index_t idx) { - return m_v[idx]; - } - Real_t& delv(Index_t idx) { - return m_delv[idx]; - } - - // Reference volume - Real_t& volo(Index_t idx) { - return m_volo[idx]; - } - - // volume derivative over volume - Real_t& vdov(Index_t idx) { - return m_vdov[idx]; - } - - // Element characteristic length - Real_t& arealg(Index_t idx) { - return m_arealg[idx]; - } - - // Sound speed - Real_t& ss(Index_t idx) { - return m_ss[idx]; - } - - // Element mass - Real_t& elemMass(Index_t idx) { - return m_elemMass[idx]; - } - - Index_t nodeElemCount(Index_t idx) { - return m_nodeElemStart[idx + 1] - m_nodeElemStart[idx]; - } - - Index_t* nodeElemCornerList(Index_t idx) { - return &m_nodeElemCornerList[m_nodeElemStart[idx]]; - } - - // Parameters - - // Cutoffs - Real_t u_cut() const { - return m_u_cut; - } - Real_t e_cut() const { - return m_e_cut; - } - Real_t p_cut() const { - return m_p_cut; - } - Real_t q_cut() const { - return m_q_cut; - } - Real_t v_cut() const { - return m_v_cut; - } - - // Other constants (usually are settable via input file in real codes) - Real_t hgcoef() const { - return m_hgcoef; - } - Real_t qstop() const { - return m_qstop; - } - Real_t monoq_max_slope() const { - return m_monoq_max_slope; - } - Real_t monoq_limiter_mult() const { - return m_monoq_limiter_mult; - } - Real_t ss4o3() const { - return m_ss4o3; - } - Real_t qlc_monoq() const { - return m_qlc_monoq; - } - Real_t qqc_monoq() const { - return m_qqc_monoq; - } - Real_t qqc() const { - return m_qqc; - } - - Real_t eosvmax() const { - return m_eosvmax; - } - Real_t eosvmin() const { - return m_eosvmin; - } - Real_t pmin() const { - return m_pmin; - } - Real_t emin() const { - return m_emin; - } - Real_t dvovmax() const { - return m_dvovmax; - } - Real_t refdens() const { - return m_refdens; - } - - // Timestep controls, etc... - Real_t& time() { - return m_time; - } - Real_t& deltatime() { - return m_deltatime; - } - Real_t& deltatimemultlb() { - return m_deltatimemultlb; - } - Real_t& deltatimemultub() { - return m_deltatimemultub; - } - Real_t& stoptime() { - return m_stoptime; - } - Real_t& dtcourant() { - return m_dtcourant; - } - Real_t& dthydro() { - return m_dthydro; - } - Real_t& dtmax() { - return m_dtmax; - } - Real_t& dtfixed() { - return m_dtfixed; - } - - Int_t& cycle() { - return m_cycle; - } - Index_t& numRanks() { - return m_numRanks; - } - - Index_t& colLoc() { - return m_colLoc; - } - Index_t& rowLoc() { - return m_rowLoc; - } - Index_t& planeLoc() { - return m_planeLoc; - } - Index_t& tp() { - return m_tp; - } - - Index_t& sizeX() { - return m_sizeX; - } - Index_t& sizeY() { - return m_sizeY; - } - Index_t& sizeZ() { - return m_sizeZ; - } - Index_t& numReg() { - return m_numReg; - } - Int_t& cost() { - return m_cost; - } - Index_t& numElem() { - return m_numElem; - } - Index_t& numNode() { - return m_numNode; - } - - Index_t& maxPlaneSize() { - return m_maxPlaneSize; - } - Index_t& maxEdgeSize() { - return m_maxEdgeSize; - } - - // - // MPI-Related additional data - // - -#if USE_MPI - // Communication Work space - Real_t* commDataSend; - Real_t* commDataRecv; - - // Maximum number of block neighbors - MPI_Request recvRequest[26]; // 6 faces + 12 edges + 8 corners - MPI_Request sendRequest[26]; // 6 faces + 12 edges + 8 corners -#endif - - private: - void BuildMesh(Int_t nx, Int_t edgeNodes, Int_t edgeElems); - void SetupThreadSupportStructures(); - void CreateRegionIndexSets(Int_t nreg, Int_t balance); - void SetupCommBuffers(Int_t edgeNodes); - void SetupSymmetryPlanes(Int_t edgeNodes); - void SetupElementConnectivities(Int_t edgeElems); - void SetupBoundaryConditions(Int_t edgeElems); - - // - // IMPLEMENTATION - // - - /* Node-centered */ - std::vector m_x; /* coordinates */ - std::vector m_y; - std::vector m_z; - - std::vector m_xd; /* velocities */ - std::vector m_yd; - std::vector m_zd; - - std::vector m_xdd; /* accelerations */ - std::vector m_ydd; - std::vector m_zdd; - - std::vector m_fx; /* forces */ - std::vector m_fy; - std::vector m_fz; - - std::vector m_nodalMass; /* mass */ - - std::vector m_symmX; /* symmetry plane nodesets */ - std::vector m_symmY; - std::vector m_symmZ; - - // Element-centered - - // Region information - Int_t m_numReg; - Int_t m_cost; // imbalance cost - Index_t* m_regElemSize; // Size of region sets - Index_t* m_regNumList; // Region number per domain element - Index_t** m_regElemlist; // region indexset - - std::vector m_nodelist; /* elemToNode connectivity */ - - std::vector m_lxim; /* element connectivity across each face */ - std::vector m_lxip; - std::vector m_letam; - std::vector m_letap; - std::vector m_lzetam; - std::vector m_lzetap; - - std::vector m_elemBC; /* symmetry/free-surface flags for each elem face */ - - std::vector m_dxx; /* principal strains -- temporary */ - std::vector m_dyy; - std::vector m_dzz; - - std::vector m_delv_xi; /* velocity gradient -- temporary */ - std::vector m_delv_eta; - std::vector m_delv_zeta; - - std::vector m_delx_xi; /* coordinate gradient -- temporary */ - std::vector m_delx_eta; - std::vector m_delx_zeta; - - std::vector m_e; /* energy */ - - std::vector m_p; /* pressure */ - std::vector m_q; /* q */ - std::vector m_ql; /* linear term for q */ - std::vector m_qq; /* quadratic term for q */ - - std::vector m_v; /* relative volume */ - std::vector m_volo; /* reference volume */ - std::vector m_vnew; /* new relative volume -- temporary */ - std::vector m_delv; /* m_vnew - m_v */ - std::vector m_vdov; /* volume derivative over volume */ - - std::vector m_arealg; /* characteristic length of an element */ - - std::vector m_ss; /* "sound speed" */ - - std::vector m_elemMass; /* mass */ - - // Cutoffs (treat as constants) - const Real_t m_e_cut; // energy tolerance - const Real_t m_p_cut; // pressure tolerance - const Real_t m_q_cut; // q tolerance - const Real_t m_v_cut; // relative volume tolerance - const Real_t m_u_cut; // velocity tolerance - - // Other constants (usually setable, but hardcoded in this proxy app) - - const Real_t m_hgcoef; // hourglass control - const Real_t m_ss4o3; - const Real_t m_qstop; // excessive q indicator - const Real_t m_monoq_max_slope; - const Real_t m_monoq_limiter_mult; - const Real_t m_qlc_monoq; // linear term coef for q - const Real_t m_qqc_monoq; // quadratic term coef for q - const Real_t m_qqc; - const Real_t m_eosvmax; - const Real_t m_eosvmin; - const Real_t m_pmin; // pressure floor - const Real_t m_emin; // energy floor - const Real_t m_dvovmax; // maximum allowable volume change - const Real_t m_refdens; // reference density - - // Variables to keep track of timestep, simulation time, and cycle - Real_t m_dtcourant; // courant constraint - Real_t m_dthydro; // volume change constraint - Int_t m_cycle; // iteration count for simulation - Real_t m_dtfixed; // fixed time increment - Real_t m_time; // current time - Real_t m_deltatime; // variable time increment - Real_t m_deltatimemultlb; - Real_t m_deltatimemultub; - Real_t m_dtmax; // maximum allowable time increment - Real_t m_stoptime; // end time for simulation - - Int_t m_numRanks; - - Index_t m_colLoc; - Index_t m_rowLoc; - Index_t m_planeLoc; - Index_t m_tp; - - Index_t m_sizeX; - Index_t m_sizeY; - Index_t m_sizeZ; - Index_t m_numElem; - Index_t m_numNode; - - Index_t m_maxPlaneSize; - Index_t m_maxEdgeSize; - - // OMP hack - Index_t* m_nodeElemStart; - Index_t* m_nodeElemCornerList; - - // Used in setup - Index_t m_rowMin, m_rowMax; - Index_t m_colMin, m_colMax; - Index_t m_planeMin, m_planeMax; -}; - -typedef Real_t& (Domain::*Domain_member)(Index_t); - -struct cmdLineOpts { - Int_t its; // -i - Int_t nx; // -s - Int_t numReg; // -r - Int_t numFiles; // -f - Int_t showProg; // -p - Int_t quiet; // -q - Int_t viz; // -v - Int_t cost; // -c - Int_t balance; // -b -}; - -// Function Prototypes - -// lulesh-par -Real_t CalcElemVolume(const Real_t x[8], const Real_t y[8], const Real_t z[8]); - -// lulesh-util -void ParseCommandLineOptions(int argc, char* argv[], Int_t myRank, struct cmdLineOpts* opts); -void VerifyAndWriteFinalOutput(Real_t elapsed_time, Domain& locDom, Int_t nx, Int_t numRanks); - -// lulesh-viz -void DumpToVisit(Domain& domain, int numFiles, int myRank, int numRanks); - -// lulesh-comm -void CommRecv(Domain& domain, Int_t msgType, Index_t xferFields, Index_t dx, Index_t dy, Index_t dz, bool doRecv, - bool planeOnly); -void CommSend(Domain& domain, Int_t msgType, Index_t xferFields, Domain_member* fieldData, Index_t dx, Index_t dy, - Index_t dz, bool doSend, bool planeOnly); -void CommSBN(Domain& domain, Int_t xferFields, Domain_member* fieldData); -void CommSyncPosVel(Domain& domain); -void CommMonoQ(Domain& domain); - -// lulesh-init -void InitMeshDecomp(Int_t numRanks, Int_t myRank, Int_t* col, Int_t* row, Int_t* plane, Int_t* side); diff --git a/test/lulesh/run_integration_test.sh b/test/lulesh/run_integration_test.sh deleted file mode 100755 index 0c529c4e..00000000 --- a/test/lulesh/run_integration_test.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -exe="$1" -np=$2 -args="$3" -TYPEART_PATH_RT="$4" -TYPEART_PATH_INTERCEPT="$5" - -log_file="$(basename $exe)_out.log" - -if [ -f "$log_file" ]; then - rm "$log_file" -fi - -type_file="$(pwd)/types.yaml" - -echo "Executing integration test: mpiexec -n $np $exe $args with typeart runtime=$TYPEART_PATH_RT and typeart intercept=$TYPEART_PATH_INTERCEPT inside folder: $(pwd)" - -LD_PRELOAD="$TYPEART_PATH_RT/libtypeart-rt.so $TYPEART_PATH_INTERCEPT/libinterceptor-rt.so" TA_EXE_TARGET=$exe TA_TYPE_FILE=${type_file} mpiexec --oversubscribe -n $np $exe $args &> "$log_file" - -app_result=$? - -if [ $app_result -ne 0 ]; then - echo "Application terminated with error code $app_result" - exit 1 -fi - -if [ ! -f "$log_file" ]; then - echo "Integration test broken - no log generated" - exit 1 -fi - -if grep -q "R\[[0-9]*\]\[Error\]" "$log_file"; then - echo "Integration test failed - for details, view $log_file" - exit 1 -fi diff --git a/test/pass/arrays/01_simple_array.c b/test/pass/arrays/01_simple_array.c index 7072d3be..899f32ad 100644 --- a/test/pass/arrays/01_simple_array.c +++ b/test/pass/arrays/01_simple_array.c @@ -1,9 +1,13 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-stack-lifetime=false -S 2>&1 | %filecheck %s --check-prefixes CHECK,ALLOC +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-stack-lifetime=false -S 2>&1 | %filecheck %s --check-prefixes CHECK,ALLOC +// REQUIRES: llvm-14 // clang-format on void test() { int a[100]; } +// CHECK: Malloc{{[ ]*}}:{{[ ]*}}0 +// CHECK: Free{{[ ]*}}:{{[ ]*}}0 +// CHECK: Alloca{{[ ]*}}:{{[ ]*}}1 // CHECK: @test() // CHECK: %__ta_alloca_counter = alloca i32 @@ -11,10 +15,6 @@ void test() { // ALLOC: [[POINTER:%[0-9a-z]+]] = alloca [100 x i32] // ALLOC-NEXT: [[POINTER2:%[0-9a-z]+]] = bitcast [100 x i32]* [[POINTER]] to i8* -// ALLOC-NEXT: call void @__typeart_alloc_stack(i8* [[POINTER2]], i32 2, i64 100) +// ALLOC-NEXT: call void @__typeart_alloc_stack(i8* [[POINTER2]], i32 13, i64 100) // CHECK: call void @__typeart_leave_scope(i32 %__ta_counter_load) - -// CHECK: Malloc{{[ ]*}}:{{[ ]*}}0 -// CHECK: Free{{[ ]*}}:{{[ ]*}}0 -// CHECK: Alloca{{[ ]*}}:{{[ ]*}}1 diff --git a/test/pass/arrays/02_array_to_pointer.c b/test/pass/arrays/02_array_to_pointer.c index 7af81c74..972298db 100644 --- a/test/pass/arrays/02_array_to_pointer.c +++ b/test/pass/arrays/02_array_to_pointer.c @@ -1,21 +1,22 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-analysis-filter-pointer-alloca=false --typeart-stack-lifetime=false -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-analysis-filter-pointer-alloca=false --typeart-stack-lifetime=false -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // clang-format on void test() { int a[100]; int* pa = a; // TODO: Tracking this value should not be necessary? } +// CHECK: Malloc{{[ ]*}}:{{[ ]*}}0 +// CHECK: Free{{[ ]*}}:{{[ ]*}}0 +// CHECK: Alloca{{[ ]*}}:{{[ ]*}}2 + // CHECK: @test() // CHECK: %__ta_alloca_counter = alloca i32 // CHECK-NEXT: store i32 0, i32* %__ta_alloca_counter // CHECK: [[POINTER:%[0-9a-z]+]] = alloca [100 x i32] // CHECK-NEXT: [[POINTER2:%[0-9a-z]+]] = bitcast [100 x i32]* [[POINTER]] to i8* -// CHECK-NEXT: call void @__typeart_alloc_stack(i8* [[POINTER2]], i32 2, i64 100) +// CHECK-NEXT: call void @__typeart_alloc_stack(i8* [[POINTER2]], i32 13, i64 100) // CHECK: call void @__typeart_leave_scope(i32 %__ta_counter_load) - -// CHECK: Malloc{{[ ]*}}:{{[ ]*}}0 -// CHECK: Free{{[ ]*}}:{{[ ]*}}0 -// CHECK: Alloca{{[ ]*}}:{{[ ]*}}2 diff --git a/test/pass/arrays/03_multidim_array.c b/test/pass/arrays/03_multidim_array.c index 707419c9..e68f2c00 100644 --- a/test/pass/arrays/03_multidim_array.c +++ b/test/pass/arrays/03_multidim_array.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true -S 2>&1 | %filecheck %s // clang-format on void test() { const int n = 64; @@ -9,13 +9,12 @@ void test() { int c[n][m]; int d[n][m][n]; } - -// CHECK: call void @__typeart_alloc_stack(i8* %{{[0-9]+}}, i32 2, i64 64) -// CHECK: call void @__typeart_alloc_stack(i8* %{{[0-9]+}}, i32 2, i64 4096) -// CHECK: call void @__typeart_alloc_stack(i8* %{{[0-9]+}}, i32 2, i64 8192) -// CHECK: call void @__typeart_alloc_stack(i8* %{{[0-9]+}}, i32 2, i64 524288) - // CHECK-NOT: Encountered unhandled type // CHECK: Malloc{{[ ]*}}:{{[ ]*}}0 // CHECK: Free{{[ ]*}}:{{[ ]*}}0 // CHECK: Alloca{{[ ]*}}:{{[ ]*}}6 + +// CHECK: call void @__typeart_alloc_stack({{i8\*|ptr}} %{{[0-9a-z]+}}, i32 13, i64 64) +// CHECK: call void @__typeart_alloc_stack({{i8\*|ptr}} %{{[0-9a-z]+}}, i32 13, i64 4096) +// CHECK: call void @__typeart_alloc_stack({{i8\*|ptr}} %{{[0-9a-z]+}}, i32 13, i64 8192) +// CHECK: call void @__typeart_alloc_stack({{i8\*|ptr}} %{{[0-9a-z]+}}, i32 13, i64 524288) diff --git a/test/pass/arrays/04_vla.c b/test/pass/arrays/04_vla.c index 8e2491fb..1ce672c1 100644 --- a/test/pass/arrays/04_vla.c +++ b/test/pass/arrays/04_vla.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-analysis-filter-non-array-alloca=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-analysis-filter-non-array-alloca=true -S 2>&1 | %filecheck %s // clang-format on void test(int n) { int a[n]; diff --git a/test/pass/arrays/05_vector.c b/test/pass/arrays/05_vector.c index 729bcb4e..a688988b 100644 --- a/test/pass/arrays/05_vector.c +++ b/test/pass/arrays/05_vector.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %remove %tu_yaml && %c-to-llvm %s | %apply-typeart --typeart-stack -S 2>&1 | %filecheck %s +// RUN: %remove %tu_yaml && %c-to-llvm %s | %apply-typeart --typeart-stack=true -S 2>&1 | %filecheck %s // clang-format on typedef float float2 __attribute__((ext_vector_type(2))); @@ -8,10 +8,10 @@ void test() { float2 vf = (float2)(1.0f, 2.0f); } -// CHECK-NOT Type is not supported: <2 x float> -// CHECK: alloca <2 x float>, align 8 -// CHECK: call void @__typeart_alloc_stack(i8* %{{[0-9]}}, i32 25{{[0-9]}}, i64 1) - // CHECK: Malloc{{[ ]*}}:{{[ ]*}}0 // CHECK: Free{{[ ]*}}:{{[ ]*}}0 // CHECK: Alloca{{[ ]*}}:{{[ ]*}}1 + +// CHECK-NOT Type is not supported: <2 x float> +// CHECK: alloca <2 x float>, align 8 +// CHECK: call void @__typeart_alloc_stack({{i8\*|ptr}} %{{[0-9a-z]+}}, i32 25{{[0-9]}}, i64 1) diff --git a/test/pass/arrays/06_malloc_of_array.c b/test/pass/arrays/06_malloc_of_array.c index 0a811dd1..e115a5f8 100644 --- a/test/pass/arrays/06_malloc_of_array.c +++ b/test/pass/arrays/06_malloc_of_array.c @@ -6,4 +6,4 @@ void foo(int n) { int(*array)[3] = malloc(2 * sizeof(int[3])); } -// CHECK: @__typeart_alloc(i8* %{{[0-9a-z]+}}, i32 2, i64 6) \ No newline at end of file +// CHECK: @__typeart_alloc({{i8\*|ptr}} %{{[0-9a-z]+}}, i32 13, i64 6) \ No newline at end of file diff --git a/test/pass/arrays/07_avx.c b/test/pass/arrays/07_avx.c index 4a05bc20..600ebed3 100644 --- a/test/pass/arrays/07_avx.c +++ b/test/pass/arrays/07_avx.c @@ -1,5 +1,6 @@ -// RUN: %remove %tu_yaml && %c-to-llvm -mavx %s | %opt -O2 -S | %apply-typeart --typeart-stack -S 2>&1 | %filecheck %s - +// clang-format off +// RUN: %remove %tu_yaml && %c-to-llvm -mavx %s | %opt -O2 -S | %apply-typeart --typeart-stack=true -S 2>&1 | %filecheck %s +// clang-format on #include __m256 vec_result; diff --git a/test/pass/filter/00_ignore_ta_memops.c b/test/pass/filter/00_ignore_ta_memops.c index 96c4fea0..315c1e29 100644 --- a/test/pass/filter/00_ignore_ta_memops.c +++ b/test/pass/filter/00_ignore_ta_memops.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart -S | %apply-typeart --typeart-stack --typeart-heap=false --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart -S | %apply-typeart --typeart-stack=true --typeart-heap=false --typeart-filter=true -S 2>&1 | %filecheck %s // clang-format on #include @@ -15,6 +15,11 @@ int main(int argc, char** argv) { return 0; } +// CHECK: TypeArtPass [Stack] +// CHECK-NEXT Malloc : 0 +// CHECK-NEXT Free : 0 +// CHECK-NEXT Alloca : 0 +// CHECK-NEXT Global : 0 // This is added with legacy type parser: // : call void @__typeart_alloc( @@ -22,9 +27,3 @@ int main(int argc, char** argv) { // CHECK: call void @__typeart_free( // CHECK-NOT: call void @__typeart_leave_scope - -// CHECK: TypeArtPass [Stack] -// CHECK-NEXT Malloc : 0 -// CHECK-NEXT Free : 0 -// CHECK-NEXT Alloca : 0 -// CHECK-NEXT Global : 0 \ No newline at end of file diff --git a/test/pass/filter/01_alloca.c b/test/pass/filter/01_alloca.c index f9eee893..2a906d54 100644 --- a/test/pass/filter/01_alloca.c +++ b/test/pass/filter/01_alloca.c @@ -1,5 +1,6 @@ // Template for alloca.ll.in // RUN: %filecheck %s +// REQUIRES: llvm-14 // XFAIL: * #include diff --git a/test/pass/filter/01_alloca.llin b/test/pass/filter/01_alloca.llin index b27eeef2..5d454a0f 100644 --- a/test/pass/filter/01_alloca.llin +++ b/test/pass/filter/01_alloca.llin @@ -1,5 +1,5 @@ -; RUN: cat %s | %apply-typeart --typeart-stack --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s -; RUN: cat %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s -check-prefix=CHECK-FILTER-EXP +; RUN: cat %s | %apply-typeart --typeart-stack=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s +; RUN: cat %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s -check-prefix=CHECK-FILTER-EXP ; REQUIRES: !dimeta @@ -67,13 +67,13 @@ declare dso_local noalias i8* @malloc(i64) #1 ; CHECK-FILTER-EXP: %__ta_alloca_counter = alloca i{{(64|32)}} ; CHECK-FILTER-EXP-NEXT: store i{{(64|32)}} 0, i{{(64|32)}}* %__ta_alloca_counter ; CHECK-FILTER-EXP: %0 = bitcast i32* %a to i8* -; CHECK-FILTER-EXP-NEXT: call void @__typeart_alloc_stack(i8* %0, i32 2, i64 1) +; CHECK-FILTER-EXP-NEXT: call void @__typeart_alloc_stack(i8* %0, i32 13, i64 1) ; CHECK-FILTER-EXP: %1 = bitcast i32** %c to i8* -; CHECK-FILTER-EXP-NEXT call void @__typeart_alloc_stack(i8* %1, i32 10, i64 1) +; CHECK-FILTER-EXP-NEXT call void @__typeart_alloc_stack(i8* %1, i32 1, i64 1) ; CHECK-FILTER-EXP: %2 = bitcast i32* %d to i8* -; CHECK-FILTER-EXP-NEXT call void @__typeart_alloc_stack(i8* %2, i32 2, i64 1) +; CHECK-FILTER-EXP-NEXT call void @__typeart_alloc_stack(i8* %2, i32 13, i64 1) ; CHECK-FILTER-EXP: %3 = bitcast i32* %x to i8* -; CHECK-FILTER-EXP-NEXT call void @__typeart_alloc_stack(i8* %3, i32 2, i64 1) +; CHECK-FILTER-EXP-NEXT call void @__typeart_alloc_stack(i8* %3, i32 13, i64 1) ; CHECK-FILTER-EXP: %10 = load i{{(64|32)}}, i{{(64|32)}}* %__ta_alloca_counter ; CHECK-FILTER-EXP-NEXT: %11 = add i{{(64|32)}} 4, %10 ; CHECK-FILTER-EXP: call void @__typeart_leave_scope(i{{(64|32)}} %__ta_counter_load) @@ -83,15 +83,15 @@ declare dso_local noalias i8* @malloc(i64) #1 ; CHECK: %__ta_alloca_counter = alloca i{{(64|32)}} ; CHECK-NEXT: store i{{(64|32)}} 0, i{{(64|32)}}* %__ta_alloca_counter ; CHECK: %0 = bitcast i32* %a to i8* -; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %0, i32 2, i64 1) +; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %0, i32 13, i64 1) ; CHECK: %1 = bitcast i32* %b to i8* -; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %1, i32 2, i64 1) +; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %1, i32 13, i64 1) ; CHECK: %2 = bitcast i32** %c to i8* -; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %2, i32 10, i64 1) +; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %2, i32 1, i64 1) ; CHECK: %3 = bitcast i32* %d to i8* -; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %3, i32 2, i64 1) +; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %3, i32 13, i64 1) ; CHECK: %4 = bitcast i32* %x to i8* -; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %4, i32 2, i64 1) +; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %4, i32 13, i64 1) ; CHECK: %11 = load i{{(64|32)}}, i{{(64|32)}}* %__ta_alloca_counter ; CHECK-NEXT: %12 = add i{{(64|32)}} 5, %11 ; CHECK: call void @__typeart_leave_scope(i{{(64|32)}} %__ta_counter_load) diff --git a/test/pass/filter/02_recursion.c b/test/pass/filter/02_recursion.c index bb1f78d4..404c383f 100644 --- a/test/pass/filter/02_recursion.c +++ b/test/pass/filter/02_recursion.c @@ -1,6 +1,6 @@ // Template for recursion.ll.in // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s // clang-format on void bar(int* x) { } diff --git a/test/pass/filter/03_globals.c b/test/pass/filter/03_globals.c index a2f1f2bf..30f7c8fb 100644 --- a/test/pass/filter/03_globals.c +++ b/test/pass/filter/03_globals.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s // clang-format on int a; diff --git a/test/pass/filter/04_cg.c b/test/pass/filter/04_cg.c index 54081ea4..c4fff36d 100644 --- a/test/pass/filter/04_cg.c +++ b/test/pass/filter/04_cg.c @@ -1,6 +1,6 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-filter --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/04_cg.ipcg -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s --check-prefix=CHECK-default +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/04_cg.ipcg -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s --check-prefix=CHECK-default // clang-format on extern void bar(int* ptr); // reaches MPI, see 04_cg.ipcg diff --git a/test/pass/filter/05_correlate_sig.c b/test/pass/filter/05_correlate_sig.c index 25f94df3..03f55bab 100644 --- a/test/pass/filter/05_correlate_sig.c +++ b/test/pass/filter/05_correlate_sig.c @@ -1,6 +1,6 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-default -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-filter --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-cg +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-default +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-cg // clang-format on extern void MPI_Mock(int, int, int); diff --git a/test/pass/filter/06_empty.c b/test/pass/filter/06_empty.c index 4e600829..03668a28 100644 --- a/test/pass/filter/06_empty.c +++ b/test/pass/filter/06_empty.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s // clang-format on extern int d; diff --git a/test/pass/filter/07_lulesh_mock.cpp b/test/pass/filter/07_lulesh_mock.cpp index 99d69f4e..ac2e6e5b 100644 --- a/test/pass/filter/07_lulesh_mock.cpp +++ b/test/pass/filter/07_lulesh_mock.cpp @@ -1,6 +1,6 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-default -// RUN: %c-to-llvm -fno-discard-value-names %s | %opt -O3 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-default-opt +// RUN: %c-to-llvm -fno-discard-value-names %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-default +// RUN: %c-to-llvm -fno-discard-value-names %s | %opt -O3 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-default-opt // clang-format on using Real_t = double; diff --git a/test/pass/filter/08_amg_box_algebra_mock.c b/test/pass/filter/08_amg_box_algebra_mock.c index 99dabbe4..2519c118 100644 --- a/test/pass/filter/08_amg_box_algebra_mock.c +++ b/test/pass/filter/08_amg_box_algebra_mock.c @@ -1,6 +1,6 @@ // This file tests for an specific endless recursion in the filter implementations w.r.t. following store targets // RUN: %c-to-llvm -fno-discard-value-names %s | %opt -O3 -S \ -// RUN: | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 \ +// RUN: | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 \ // RUN: | %filecheck %s --check-prefix=CHECK-exp-default-opt // CHECK-exp-default-opt: TypeArtPass [Heap & Stack] diff --git a/test/pass/filter/09_milc_gauge_stuff_mock.c b/test/pass/filter/09_milc_gauge_stuff_mock.c index f0580817..3b3a747f 100644 --- a/test/pass/filter/09_milc_gauge_stuff_mock.c +++ b/test/pass/filter/09_milc_gauge_stuff_mock.c @@ -1,6 +1,6 @@ // This file tests for an specific endless recursion in the filter implementations w.r.t. following store targets // RUN: %c-to-llvm -fno-discard-value-names %s | %opt -O3 -S \ -// RUN: | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 \ +// RUN: | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 \ // RUN: | %filecheck %s --check-prefix=CHECK-exp-default-opt // CHECK-exp-default-opt: TypeArtPass [Heap & Stack] diff --git a/test/pass/filter/10_omp_empty.c b/test/pass/filter/10_omp_empty.c index 695ecd64..588e64ef 100644 --- a/test/pass/filter/10_omp_empty.c +++ b/test/pass/filter/10_omp_empty.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s // REQUIRES: openmp // clang-format on diff --git a/test/pass/filter/11_omp_mpi_simple.c b/test/pass/filter/11_omp_mpi_simple.c index 81d24f38..eab88c3b 100644 --- a/test/pass/filter/11_omp_mpi_simple.c +++ b/test/pass/filter/11_omp_mpi_simple.c @@ -1,9 +1,9 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix CHECK-alloca-pointer -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix CHECK-alloca-pointer +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=true -S 2>&1 | %filecheck %s --check-prefix CHECK-alloca-pointer -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=true -S 2>&1 | %filecheck %s --check-prefix CHECK-alloca-pointer +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=true -S 2>&1 | %filecheck %s --check-prefix CHECK-alloca-pointer +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=true -S 2>&1 | %filecheck %s --check-prefix CHECK-alloca-pointer // clang-format on // REQUIRES: openmp diff --git a/test/pass/filter/12_omp_correlate.c b/test/pass/filter/12_omp_correlate.c index 84c999d9..899e605c 100644 --- a/test/pass/filter/12_omp_correlate.c +++ b/test/pass/filter/12_omp_correlate.c @@ -1,11 +1,12 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=CHECK-opt -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-cg +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=CHECK-opt +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=CHECK-exp-cg -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst +// REQUIRES: llvm-14 // REQUIRES: openmp // clang-format on @@ -21,7 +22,7 @@ void foo() { // check-inst: define {{.*}} @foo // check-inst: %d = alloca // check-inst: [[POINTER:%[0-9a-z]+]] = bitcast i32* %d to i8* - // check-inst: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 13, i64 1) // check-inst-not: __typeart_alloc_stack_omp int d = 3; int e = 4; diff --git a/test/pass/filter/13_omp_loops.c b/test/pass/filter/13_omp_loops.c index 01a92f63..6859f1a1 100644 --- a/test/pass/filter/13_omp_loops.c +++ b/test/pass/filter/13_omp_loops.c @@ -1,11 +1,12 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg -S 2>&1 +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg -S 2>&1 -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-filter-implementation=cg --typeart-filter-cg-file=%p/05_cg.ipcg -S | %filecheck %s --check-prefix=check-inst +// REQUIRES: llvm-14 // REQUIRES: openmp // clang-format on @@ -21,7 +22,7 @@ void foo(int count) { // check-inst: define {{.*}} @foo // check-inst: %d = alloca // check-inst: [[POINTER:%[0-9a-z]+]] = bitcast i32* %d to i8* - // check-inst: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 13, i64 1) // check-inst-not: __typeart_alloc_stack_omp int d = 3; int e = 4; diff --git a/test/pass/filter/14_omp_nested.c b/test/pass/filter/14_omp_nested.c index e0281089..8991e40a 100644 --- a/test/pass/filter/14_omp_nested.c +++ b/test/pass/filter/14_omp_nested.c @@ -1,9 +1,10 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// REQUIRES: llvm-14 // REQUIRES: openmp // clang-format on extern void MPI_call(void*); @@ -17,7 +18,7 @@ void foo() { // check-inst: define {{.*}} @foo // check-inst: %x = alloca // check-inst: %0 = bitcast i32* %x to i8* - // check-inst: call void @__typeart_alloc_stack(i8* %0, i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack(i8* %0, i32 13, i64 1) // check-inst-not: __typeart_alloc_stack_omp int x; #pragma omp parallel diff --git a/test/pass/filter/15_omp_task.c b/test/pass/filter/15_omp_task.c index 28493c2f..ea3d6105 100644 --- a/test/pass/filter/15_omp_task.c +++ b/test/pass/filter/15_omp_task.c @@ -1,8 +1,9 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s --check-prefix=CHECK-opt +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s --check-prefix=CHECK-opt -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// REQUIRES: llvm-14 // REQUIRES: openmp // clang-format on extern void MPI_call(void*); @@ -11,7 +12,7 @@ void foo() { // check-inst: define {{.*}} @foo // check-inst: %x = alloca // check-inst: %0 = bitcast i32* %x to i8* - // check-inst: call void @__typeart_alloc_stack(i8* %0, i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack(i8* %0, i32 13, i64 1) // check-inst-not: __typeart_alloc_stack_omp int x; #pragma omp parallel diff --git a/test/pass/filter/16_omp_reduction.c b/test/pass/filter/16_omp_reduction.c index a1a51d7d..1fe4a561 100644 --- a/test/pass/filter/16_omp_reduction.c +++ b/test/pass/filter/16_omp_reduction.c @@ -1,9 +1,10 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// REQUIRES: llvm-14 // REQUIRES: openmp // clang-format on @@ -24,7 +25,7 @@ void foo() { // check-inst: define {{.*}} @foo // check-inst: %loc = alloca // check-inst: [[POINTER:%[0-9a-z]+]] = bitcast float* %loc to i8* - // check-inst: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 5, i64 1) + // check-inst: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 23, i64 1) // check-inst-not: __typeart_alloc_stack_omp float loc = sum(array, n); MPI_send((void*)&loc); diff --git a/test/pass/filter/17_omp_sharing_semantics.c b/test/pass/filter/17_omp_sharing_semantics.c index 9ec2d45d..fb6111b1 100644 --- a/test/pass/filter/17_omp_sharing_semantics.c +++ b/test/pass/filter/17_omp_sharing_semantics.c @@ -1,9 +1,10 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// REQUIRES: llvm-14 // REQUIRES: openmp && !dimeta @@ -42,7 +43,7 @@ void bar(int count) { // check-inst: define {{.*}} @.omp_outlined // check-inst: [[ALLOCA1:%d[0-9]]] = alloca i32 // check-inst: [[POINTER1:%[0-9a-z]+]] = bitcast i32* [[ALLOCA1]] to i8* - // check-inst: call void @__typeart_alloc_stack_omp(i8* [[POINTER1]], i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack_omp(i8* [[POINTER1]], i32 12, i64 1) #pragma omp parallel for schedule(dynamic, 1) lastprivate(d) shared(e) for (int i = 0; i < count; ++i) { // Analysis should not filter d, but e... @@ -54,13 +55,13 @@ void bar2(int count) { // check-inst: define {{.*}} @bar2 // check-inst: %d = alloca // check-inst: [[POINTER2:%[0-9a-z]+]] = bitcast i32* %d to i8* - // check-inst: call void @__typeart_alloc_stack(i8* [[POINTER2]], i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack(i8* [[POINTER2]], i32 12, i64 1) int d = 3; float e = 4.f; // check-inst: define {{.*}} @.omp_outlined // check-inst: [[ALLOCA3:%d[0-9]]] = alloca i32 // check-inst: [[POINTER3:%[0-9a-z]+]] = bitcast i32* [[ALLOCA3]] to i8* - // check-inst: call void @__typeart_alloc_stack_omp(i8* [[POINTER3]], i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack_omp(i8* [[POINTER3]], i32 12, i64 1) #pragma omp parallel for schedule(dynamic, 1) lastprivate(d) shared(e) for (int i = 0; i < count; ++i) { // Analysis should not filter d, but e... @@ -79,7 +80,7 @@ void foo_bar(int count) { // check-inst: define {{.*}} @.omp_outlined // check-inst: %d = alloca // check-inst: [[POINTER4:%[0-9a-z]+]] = bitcast i32* %d to i8* - // check-inst: call void @__typeart_alloc_stack_omp(i8* [[POINTER4]], i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack_omp(i8* [[POINTER4]], i32 12, i64 1) #pragma omp parallel for schedule(dynamic, 1) private(d, e) for (int i = 0; i < count; ++i) { MPI_Send((void*)&d, e); diff --git a/test/pass/filter/18_omp_last_priv_nested.c b/test/pass/filter/18_omp_last_priv_nested.c index e445caca..3070c0a2 100644 --- a/test/pass/filter/18_omp_last_priv_nested.c +++ b/test/pass/filter/18_omp_last_priv_nested.c @@ -1,7 +1,7 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst // REQUIRES: openmp && !dimeta // clang-format on @@ -19,7 +19,7 @@ void func(int* x, int* e) { // , and "int x=1;" is thus not tracked. // check-inst: define {{.*}} @func // check-inst: define {{.*}} @.omp_outlined - // check-inst: call void @__typeart_alloc_stack_omp(i8* %{{[0-9]}}, i32 10, i64 1) + // check-inst: call void @__typeart_alloc_stack_omp({{i8\*|ptr}} %{{[0-9a-z]}}, i32 1, i64 1) #pragma omp parallel for lastprivate(x), shared(e) for (int i = 0; i < 10; ++i) { // Analysis should not filter x, but e... @@ -40,7 +40,7 @@ void func_other(int* x, int* e) { // lastprivate - addr(!) value of x is copied to "private_val" (which is tracked) in outlined region // check-inst: define {{.*}} @func_other // check-inst: define {{.*}} @.omp_outlined - // check-inst: call void @__typeart_alloc_stack_omp(i8* %{{[0-9]}}, i32 10, i64 1) + // check-inst: call void @__typeart_alloc_stack_omp({{i8\*|ptr}} %{{[0-9a-z]}}, i32 1, i64 1) #pragma omp parallel for lastprivate(x), shared(e) for (int i = 0; i < 10; ++i) { // Analysis should not filter x, but e... @@ -51,7 +51,7 @@ void func_other(int* x, int* e) { void bar(int x_other) { // check-inst: define {{.*}} @bar - // check-inst: call void @__typeart_alloc_stack(i8* %{{[0-9]}}, i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack({{i8\*|ptr}} %{{[0-9a-z]}}, i32 13, i64 1) int x = x_other; int y = 2; #pragma omp parallel diff --git a/test/pass/filter/19_omp_first_priv_nested.c b/test/pass/filter/19_omp_first_priv_nested.c index fe8674c3..6ac771e8 100644 --- a/test/pass/filter/19_omp_first_priv_nested.c +++ b/test/pass/filter/19_omp_first_priv_nested.c @@ -1,9 +1,9 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst // REQUIRES: openmp // clang-format on @@ -24,7 +24,7 @@ void func(int* x, int* e) { void foo() { // check-inst: define {{.*}} @foo - // check-inst: call void @__typeart_alloc_stack(i8* %0, i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack({{i8\*|ptr}} %{{[a-z0-9]}}, i32 13, i64 1) int x = 1; int y = 2; #pragma omp parallel @@ -45,7 +45,7 @@ void func_other(int* x, int* e) { void bar(int x_other) { // check-inst: define {{.*}} @bar - // check-inst: call void @__typeart_alloc_stack(i8* %0, i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack({{i8\*|ptr}} %{{[a-z0-9]+}}, i32 13, i64 1) int x = x_other; int y = 2; #pragma omp parallel diff --git a/test/pass/filter/20_omp_priv_combi_nested.c b/test/pass/filter/20_omp_priv_combi_nested.c index edff5dbb..80b99331 100644 --- a/test/pass/filter/20_omp_priv_combi_nested.c +++ b/test/pass/filter/20_omp_priv_combi_nested.c @@ -1,9 +1,10 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=check-opt +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s --check-prefix=check-opt -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-opt-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true --typeart-analysis-filter-pointer-alloca=false -S | %filecheck %s --check-prefix=check-opt-inst +// REQUIRES: llvm-14 // REQUIRES: openmp && !dimeta // clang-format on @@ -22,7 +23,7 @@ void func(int* x, int* e) { // check-opt-inst-NOT: call void @__typeart_alloc_stack // check-inst: define {{.*}} @.omp_outlined - // check-inst: call void @__typeart_alloc_stack_omp(i8* %{{[0-9]}}, i32 10, i64 1) + // check-inst: call void @__typeart_alloc_stack_omp(i8* %{{[0-9]}}, i32 1, i64 1) // check-opt-inst: define {{.*}} @.omp_outlined // check-opt-inst-NOT: call void @__typeart_alloc_stack_omp @@ -35,10 +36,10 @@ void func(int* x, int* e) { void foo() { // check-inst: define {{.*}} @foo - // check-inst: call void @__typeart_alloc_stack(i8* %0, i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack(i8* %0, i32 13, i64 1) // check-opt-inst: define {{.*}} @foo - // check-opt-inst: call void @__typeart_alloc_stack(i8* %0, i32 2, i64 1) + // check-opt-inst: call void @__typeart_alloc_stack(i8* %0, i32 13, i64 1) int x = 1; int y = 2; #pragma omp parallel @@ -53,7 +54,7 @@ void func_other(int* x, int* e) { // check-opt-inst-NOT: call void @__typeart_alloc_stack // check-inst: define {{.*}} @.omp_outlined - // check-inst: call void @__typeart_alloc_stack_omp(i8* %{{[0-9]}}, i32 10, i64 1) + // check-inst: call void @__typeart_alloc_stack_omp(i8* %{{[0-9]}}, i32 1, i64 1) // check-opt-inst: define {{.*}} @.omp_outlined // check-opt-inst-NOT: call void @__typeart_alloc_stack_omp @@ -67,10 +68,10 @@ void func_other(int* x, int* e) { void bar(int x_other) { // check-inst: define {{.*}} @bar - // check-inst: call void @__typeart_alloc_stack(i8* %{{[0-9]}}, i32 2, i64 1) + // check-inst: call void @__typeart_alloc_stack(i8* %{{[0-9]}}, i32 13, i64 1) // check-opt-inst: define {{.*}} @bar - // check-opt-inst: call void @__typeart_alloc_stack(i8* %{{[0-9]}}, i32 2, i64 1) + // check-opt-inst: call void @__typeart_alloc_stack(i8* %{{[0-9]}}, i32 13, i64 1) int x = x_other; int y = 2; #pragma omp parallel diff --git a/test/pass/filter/21_omp_task_struct.c b/test/pass/filter/21_omp_task_struct.c index 24857ad3..559f289a 100644 --- a/test/pass/filter/21_omp_task_struct.c +++ b/test/pass/filter/21_omp_task_struct.c @@ -1,9 +1,10 @@ // clang-format off -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s --check-prefix=CHECK-opt +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s --check-prefix=CHECK-opt -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst -// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack --typeart-filter -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// RUN: %c-to-llvm -fno-discard-value-names %omp_c_flags %s | %opt -O2 -S | %apply-typeart --typeart-stack=true --typeart-filter=true -S | %filecheck %s --check-prefix=check-inst +// REQUIRES: llvm-14 // REQUIRES: openmp // clang-format on extern void MPI_call(void*); diff --git a/test/pass/filter/22_omp_ident_offset.llin b/test/pass/filter/22_omp_ident_offset.llin index b73229ed..8983c85c 100644 --- a/test/pass/filter/22_omp_ident_offset.llin +++ b/test/pass/filter/22_omp_ident_offset.llin @@ -1,11 +1,11 @@ -; RUN: cat %s | %apply-typeart --typeart-stack --typeart-filter -S 2>&1 | %filecheck %s +; RUN: cat %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s ; REQUIRES: !dimeta %struct.ident_t = type { i32, i32, i32, i32, i8* } @.str = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 -@0 = private unnamed_addr global %struct.ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8 +@0 = private unnamed_addr global %struct.ident_t { i32 0, i32 12, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8 declare dso_local void @MPI_call(i8*) #2 @@ -25,7 +25,7 @@ entry: ; TEST: the translation to fork_call(%s, %outlined, ...) -> outlined should handle the internal struct.ident_t %s arg when following dataflow ; CHECK: @foo() ; CHECK: [[POINTER:%[0-9a-z]+]] = bitcast i32* %x to i8* -; CHECK: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 2, i64 1) +; CHECK: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 13, i64 1) %x = alloca i32, align 4 %0 = bitcast i32* %x to i8* %s = alloca %struct.ident_t, align 8 diff --git a/test/pass/filter/23_pointer_alloca.c b/test/pass/filter/23_pointer_alloca.c index 6cb30eab..c59d2320 100644 --- a/test/pass/filter/23_pointer_alloca.c +++ b/test/pass/filter/23_pointer_alloca.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-analysis-filter-pointer-alloca=true -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-analysis-filter-pointer-alloca=true -S 2>&1 | %filecheck %s // clang-format on int main(int argc, char** argv) { diff --git a/test/pass/global/01_globals.c b/test/pass/global/01_globals.c index b0069906..39c8d51d 100644 --- a/test/pass/global/01_globals.c +++ b/test/pass/global/01_globals.c @@ -1,4 +1,5 @@ -// RUN: %c-to-llvm %s | %apply-typeart --typeart-global -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-global=true -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 int global; int global_2 = 0; diff --git a/test/pass/global/02_globals.cpp b/test/pass/global/02_globals.cpp index 4183527a..d6ee3ad9 100644 --- a/test/pass/global/02_globals.cpp +++ b/test/pass/global/02_globals.cpp @@ -1,4 +1,5 @@ -// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-global -S 2>&1 | %filecheck %s +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-global=true -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 int global; int global_2 = 0; diff --git a/test/pass/global/03_milc_setup_readin_mock.llin b/test/pass/global/03_milc_setup_readin_mock.llin index e2072f99..f7a7f883 100644 --- a/test/pass/global/03_milc_setup_readin_mock.llin +++ b/test/pass/global/03_milc_setup_readin_mock.llin @@ -1,4 +1,4 @@ -; RUN: cat %s | %apply-typeart --typeart-global -S 2>&1 | %filecheck %s +; RUN: cat %s | %apply-typeart --typeart-global=true -S 2>&1 | %filecheck %s ; REQUIRES: !dimeta diff --git a/test/pass/global/04_const_char.c b/test/pass/global/04_const_char.c index 77575240..6a44a48d 100644 --- a/test/pass/global/04_const_char.c +++ b/test/pass/global/04_const_char.c @@ -1,4 +1,5 @@ -// RUN: %c-to-llvm %s | %apply-typeart --typeart-global -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-global=true -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // REQUIRES: !dimeta diff --git a/test/pass/global/05_asan.c b/test/pass/global/05_asan.c index d59df3c9..02412f81 100644 --- a/test/pass/global/05_asan.c +++ b/test/pass/global/05_asan.c @@ -1,4 +1,5 @@ -// RUN: %c-to-llvm %s -fsanitize=address | %apply-typeart --typeart-global -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s -fsanitize=address | %apply-typeart --typeart-global=true -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // REQUIRES: asan diff --git a/test/pass/global/06_coverage.c b/test/pass/global/06_coverage.c index 01834249..a5f20dfa 100644 --- a/test/pass/global/06_coverage.c +++ b/test/pass/global/06_coverage.c @@ -1,4 +1,5 @@ -// RUN: %c-to-llvm --coverage %s | %apply-typeart --typeart-global -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm --coverage %s | %apply-typeart --typeart-global=true -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 int global; int global_2 = 0; diff --git a/test/pass/global/07_coverage_llvm.c b/test/pass/global/07_coverage_llvm.c index 6b097cbe..0b217b0e 100644 --- a/test/pass/global/07_coverage_llvm.c +++ b/test/pass/global/07_coverage_llvm.c @@ -1,5 +1,6 @@ -// RUN: %c-to-llvm -fprofile-instr-generate -fcoverage-mapping %s | %apply-typeart --typeart-global -S 2>&1 \ +// RUN: %c-to-llvm -fprofile-instr-generate -fcoverage-mapping %s | %apply-typeart --typeart-global=true -S 2>&1 \ // RUN: | %filecheck %s +// REQUIRES: llvm-14 int global; int global_2 = 0; diff --git a/test/pass/global/08_global_skip.c b/test/pass/global/08_global_skip.c index 118bb386..9e4103ee 100644 --- a/test/pass/global/08_global_skip.c +++ b/test/pass/global/08_global_skip.c @@ -1,7 +1,8 @@ -// RUN: %c-to-llvm %s | %apply-typeart --typeart-global -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-global=true -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-global=false -S 2>&1 \ +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-global=false -S 2>&1 \ // RUN: | %filecheck %s --check-prefix CHECK-SKIP +// REQUIRES: llvm-14 int global; int global_2 = 0; diff --git a/test/pass/malloc_free/01_simple_malloc_int.c b/test/pass/malloc_free/01_simple_malloc_int.c index c4fe8c82..7e52a35b 100644 --- a/test/pass/malloc_free/01_simple_malloc_int.c +++ b/test/pass/malloc_free/01_simple_malloc_int.c @@ -1,16 +1,15 @@ // clang-format off // RUN: %c-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on + #include void test() { int* p = (int*)malloc(42 * sizeof(int)); } - -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 2, i64 42) -// CHECK-NEXT: bitcast i8* [[POINTER]] to i32* - // CHECK: TypeArtPass [Heap] // CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}0 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 13, i64 42) diff --git a/test/pass/malloc_free/02_simple_malloc_free_int.c b/test/pass/malloc_free/02_simple_malloc_free_int.c index 6a4bc175..80a58be1 100644 --- a/test/pass/malloc_free/02_simple_malloc_free_int.c +++ b/test/pass/malloc_free/02_simple_malloc_free_int.c @@ -7,15 +7,13 @@ void test() { int* p = (int*)malloc(42 * sizeof(int)); free(p); } - -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], -// CHECK-NEXT: bitcast i8* [[POINTER]] to i32* - -// CHECK: call void @free(i8*{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[POINTER]]) - // CHECK: TypeArtPass [Heap] // CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 13 + +// CHECK: call void @free({{i8\*|ptr}}{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[POINTER]]) diff --git a/test/pass/malloc_free/03_simple_malloc_free_double.c b/test/pass/malloc_free/03_simple_malloc_free_double.c index feb8e98b..79ace56a 100644 --- a/test/pass/malloc_free/03_simple_malloc_free_double.c +++ b/test/pass/malloc_free/03_simple_malloc_free_double.c @@ -6,15 +6,13 @@ void test() { double* p = (double*)malloc(42 * sizeof(double)); free(p); } - -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 6, i64 42) -// CHECK-NEXT: bitcast i8* [[POINTER]] to double* - -// CHECK: call void @free(i8*{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[POINTER]]) - // CHECK: TypeArtPass [Heap] // CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 24, i64 42) + +// CHECK: call void @free({{i8\*|ptr}}{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[POINTER]]) diff --git a/test/pass/malloc_free/04_simple_malloc_int_double.c b/test/pass/malloc_free/04_simple_malloc_int_double.c index 183e22f0..b1326a8a 100644 --- a/test/pass/malloc_free/04_simple_malloc_int_double.c +++ b/test/pass/malloc_free/04_simple_malloc_int_double.c @@ -6,16 +6,13 @@ void test() { int* p = (int*)malloc(42 * sizeof(int)); double* pd = (double*)malloc(42 * sizeof(double)); } - -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], -// CHECK-NEXT: bitcast i8* [[POINTER]] to i32* - -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], -// CHECK-NEXT: bitcast i8* [[POINTER]] to double* - // CHECK: TypeArtPass [Heap] // CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}0 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 24 diff --git a/test/pass/malloc_free/05_simple_malloc_struct.c b/test/pass/malloc_free/05_simple_malloc_struct.c index c5de01f5..d33405d6 100644 --- a/test/pass/malloc_free/05_simple_malloc_struct.c +++ b/test/pass/malloc_free/05_simple_malloc_struct.c @@ -11,15 +11,13 @@ void test() { mystruct* m = (mystruct*)malloc(sizeof(mystruct)); free(m); } - -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 256, i64 1) -// CHECK-NEXT: bitcast i8* [[POINTER]] to %struct.ms* - -// CHECK: call void @free(i8*{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[POINTER]]) - // CHECK: TypeArtPass [Heap] // CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 256, i64 1) + +// CHECK: call void @free({{i8\*|ptr}}{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[POINTER]]) diff --git a/test/pass/malloc_free/06_simple_malloc_void_type.c b/test/pass/malloc_free/06_simple_malloc_void_type.c index 7f44f765..b32686d2 100644 --- a/test/pass/malloc_free/06_simple_malloc_void_type.c +++ b/test/pass/malloc_free/06_simple_malloc_void_type.c @@ -7,9 +7,8 @@ void test() { void* p = malloc(42 * sizeof(int)); // LLVM-IR: lacks a bitcast } -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 0, i64 168) -// CHECK-NOT: bitcast i8* [[POINTER]] to i32* +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 {{(11|3)}}, i64 168) // PASS-OUT: TypeArtPass [Heap] // PASS-OUT-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 diff --git a/test/pass/malloc_free/07_simple_malloc_free_void_type.c b/test/pass/malloc_free/07_simple_malloc_free_void_type.c index 6329395a..5d695236 100644 --- a/test/pass/malloc_free/07_simple_malloc_free_void_type.c +++ b/test/pass/malloc_free/07_simple_malloc_free_void_type.c @@ -8,12 +8,11 @@ void test() { free(p); } -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], -// CHECK-NOT: bitcast i8* [[POINTER]] to i32* +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], -// CHECK: call void @free(i8*{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[POINTER]]) +// CHECK: call void @free({{i8\*|ptr}}{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[POINTER]]) // PASS-OUT: TypeArtPass [Heap] // PASS-OUT-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 diff --git a/test/pass/malloc_free/08_simple_malloc_struct_void.c b/test/pass/malloc_free/08_simple_malloc_struct_void.c index be40bdbe..f2661211 100644 --- a/test/pass/malloc_free/08_simple_malloc_struct_void.c +++ b/test/pass/malloc_free/08_simple_malloc_struct_void.c @@ -13,12 +13,11 @@ void test() { free(m); } -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 0, i64 16) -// CHECK-NOT: bitcast i8* [[POINTER]] to i32* +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 {{3|11}}, i64 16) -// CHECK: call void @free(i8*{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[POINTER]]) +// CHECK: call void @free({{i8\*|ptr}}{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[POINTER]]) // PASS-OUT: TypeArtPass [Heap] // PASS-OUT-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 diff --git a/test/pass/malloc_free/09_malloc_with_disjunct_free.c b/test/pass/malloc_free/09_malloc_with_disjunct_free.c index f6450be5..b4a55d9b 100644 --- a/test/pass/malloc_free/09_malloc_with_disjunct_free.c +++ b/test/pass/malloc_free/09_malloc_with_disjunct_free.c @@ -14,15 +14,13 @@ void foo(double* ptr) { free(ptr); ptr = NULL; } - -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], -// CHECK-NEXT: bitcast i8* [[POINTER]] to double* - -// CHECK: call void @free(i8*{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[POINTER]]) - // CHECK: TypeArtPass [Heap] // CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 24 + +// CHECK: call void @free({{i8\*|ptr}}{{( noundef)?}} [[POINTER:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[POINTER]]) diff --git a/test/pass/malloc_free/10_malloc_multiple_casts.c b/test/pass/malloc_free/10_malloc_multiple_casts.c index a1406a42..2939fff8 100644 --- a/test/pass/malloc_free/10_malloc_multiple_casts.c +++ b/test/pass/malloc_free/10_malloc_multiple_casts.c @@ -1,6 +1,7 @@ // clang-format off // RUN: %c-to-llvm %s | %apply-typeart -S | %filecheck %s // RUN: %c-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s --check-prefix=PASS-OUT +// REQUIRES: llvm-14 // clang-format on #include void test() { @@ -9,8 +10,8 @@ void test() { short* ps = (short*)p; } -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @malloc +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], // PASS-OUT: [Warning]{{.*}}Encountered ambiguous pointer type in function diff --git a/test/pass/malloc_free/11_calloc_realloc.c b/test/pass/malloc_free/11_calloc_realloc.c index ae59ca04..25e3d4d3 100644 --- a/test/pass/malloc_free/11_calloc_realloc.c +++ b/test/pass/malloc_free/11_calloc_realloc.c @@ -14,17 +14,16 @@ int main() { // clang-format off -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @calloc(i64{{( noundef)?}} [[SIZE:[0-9]+]], i64{{( noundef)?}} 8) -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 6, i64 [[SIZE]]) -// CHECK-NEXT: bitcast i8* [[POINTER]] to double* - -// REALLOC: __typeart_free(i8* [[POINTER:%[0-9a-z]+]]) -// REALLOC-NEXT: [[POINTER2:%[0-9a-z]+]] = call{{( align [0-9]+)?}} i8* @realloc(i8*{{( noundef)?}} [[POINTER]], i64{{( noundef)?}} 160) -// REALLOC-NEXT: __typeart_alloc(i8* [[POINTER2]], i32 6, i64 20) - // CHECK: TypeArtPass [Heap] // CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 // CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}0 // CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @calloc(i64{{( noundef)?}} [[SIZE:[0-9]+]], i64{{( noundef)?}} 8) +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 24, i64 [[SIZE]]) + +// REALLOC: __typeart_free({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]]) +// REALLOC-NEXT: [[POINTER2:%[0-9a-z]+]] = call{{( align [0-9]+)?}} {{i8\*|ptr}} @realloc({{i8\*|ptr}}{{( noundef)?}} [[POINTER]], i64{{( noundef)?}} 160) +// REALLOC-NEXT: __typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 24, i64 20) + // clang-format on diff --git a/test/pass/malloc_free/12_malloc_memcpy.c b/test/pass/malloc_free/12_malloc_memcpy.c index e0fa0fc1..641b4343 100644 --- a/test/pass/malloc_free/12_malloc_memcpy.c +++ b/test/pass/malloc_free/12_malloc_memcpy.c @@ -15,10 +15,12 @@ typedef struct { #define taMalloc(type, count) \ ((unsigned int)(count) * sizeof(type)) > 0 ? ((type*)malloc((unsigned int)(sizeof(type) * (count)))) : (type*)NULL +// clang-format off // CHECK-OPT: tail call void @free // CHECK-OPT-NEXT: call void @__typeart_free -// CHECK-OPT: call void @__typeart_alloc(i8* %{{[0-9a-z]+}}, i32 {{(0|2)}}, -// CHECK-OPT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{(align (4|16)[[:space:]])?}}%{{[0-9a-z]+}}, +// CHECK-OPT: call void @__typeart_alloc({{i8\*|ptr}} %{{[0-9a-z]+}}, i32 {{(11|13)}}, +// CHECK-OPT: call void @llvm.memcpy.p0{{(i8)?}}.p0{{(i8)?}}.i64({{i8\*|ptr}} {{(align[[:space:]]?(4|16)[[:space:]])?}}%{{[0-9a-z]+}}, +// clang-format on void setVartypes(struct_grid* pgrid, int nvars, int* vartypes /* = i32 ptr */) { int* new_vartypes; // free(pgrid->vartypes); diff --git a/test/pass/malloc_free/13_calloc_void_type.c b/test/pass/malloc_free/13_calloc_void_type.c index 1b08d561..35018047 100644 --- a/test/pass/malloc_free/13_calloc_void_type.c +++ b/test/pass/malloc_free/13_calloc_void_type.c @@ -11,12 +11,10 @@ void foo(int n) { // clang-format off -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @calloc(i64{{( noundef)?}} [[SIZE:[0-9a-z]+]], i64{{( noundef)?}} 8) -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 0, i64 80) -// CHECK-NOT: bitcast i8* [[POINTER]] to double* +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @calloc(i64{{( noundef)?}} [[SIZE:[0-9a-z]+]], i64{{( noundef)?}} 8) +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 {{(11|3)}}, i64 80) -// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @calloc(i64{{( noundef)?}} [[SIZE2:%[0-9a-z]+]], i64{{( noundef)?}} 8) -// CHECK-NOT: call void @__typeart_alloc(i8* [[POINTER2]], i32 0, i64 [[SIZE2]]) -// CHECK-NOT: bitcast i8* [[POINTER]] to double* +// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @calloc(i64{{( noundef)?}} [[SIZE2:%[0-9a-z]+]], i64{{( noundef)?}} 8) +// CHECK-NOT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 {{(11|3)}}, i64 [[SIZE2]]) // clang-format on diff --git a/test/pass/malloc_free/14_aligned_alloc.c b/test/pass/malloc_free/14_aligned_alloc.c index c125af5e..333336bd 100644 --- a/test/pass/malloc_free/14_aligned_alloc.c +++ b/test/pass/malloc_free/14_aligned_alloc.c @@ -10,12 +10,10 @@ void foo(int n) { } // clang-format off -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @aligned_alloc(i64{{( noundef)?}} 64, i64{{( noundef)?}} 20) -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 2, i64 5) -// CHECK-NEXT: bitcast i8* [[POINTER]] to i32* +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @aligned_alloc(i64{{( noundef)?}} 64, i64{{( noundef)?}} 20) +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 13, i64 5) -// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @aligned_alloc(i64{{( noundef)?}} 128, i64{{( noundef)?}} [[SIZE:%[0-9a-z]+]]) -// CHECK-NOT: call void @__typeart_alloc(i8* [[POINTER2]], i32 2, i64 [[SIZE]]) -// CHECK: call void @__typeart_alloc(i8* [[POINTER2]], i32 2, i64 %{{[0-9a-z]+}}) -// CHECK-NEXT: bitcast i8* [[POINTER2]] to i32* +// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @aligned_alloc(i64{{( noundef)?}} 128, i64{{( noundef)?}} [[SIZE:%[0-9a-z]+]]) +// CHECK-NOT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 13, i64 [[SIZE]]) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 13, i64 %{{[0-9a-z]+}}) // clang-format on diff --git a/test/pass/malloc_free/15_aligned_alloc_void_type.c b/test/pass/malloc_free/15_aligned_alloc_void_type.c index b55f2a63..dca85da5 100644 --- a/test/pass/malloc_free/15_aligned_alloc_void_type.c +++ b/test/pass/malloc_free/15_aligned_alloc_void_type.c @@ -10,11 +10,9 @@ void foo(int n) { } // clang-format off -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @aligned_alloc(i64{{( noundef)?}} 64, i64{{( noundef)?}} 20) -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 0, i64 20) -// CHECK-NOT: bitcast i8* [[POINTER]] to {{.*}}* +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @aligned_alloc(i64{{( noundef)?}} 64, i64{{( noundef)?}} 20) +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 {{(11|3)}}, i64 20) -// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @aligned_alloc(i64{{( noundef)?}} 128, i64{{( noundef)?}} [[SIZE:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER2]], i32 0, i64 [[SIZE]]) -// CHECK-NOT: bitcast i8* [[POINTER]] to {{.*}}* +// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} {{i8\*|ptr}} @aligned_alloc(i64{{( noundef)?}} 128, i64{{( noundef)?}} [[SIZE:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 {{(11|3)}}, i64 [[SIZE]]) // clang-format on diff --git a/test/pass/malloc_free/16_omp_heap.c b/test/pass/malloc_free/16_omp_heap.c index f0787758..13757a04 100644 --- a/test/pass/malloc_free/16_omp_heap.c +++ b/test/pass/malloc_free/16_omp_heap.c @@ -1,5 +1,6 @@ // clang-format off // RUN: %c-to-llvm %omp_c_flags %s | %apply-typeart -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // REQUIRES: openmp // clang-format on @@ -20,24 +21,24 @@ void foo(int** x) { } // clang-format off +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}3 +// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + // CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @calloc(i64{{( noundef)?}} [[SIZE:[0-9a-z]+]], i64{{( noundef)?}} 8) -// CHECK-NEXT: call void @__typeart_alloc_omp(i8* [[POINTER]], i32 6, i64 [[SIZE]]) +// CHECK-NEXT: call void @__typeart_alloc_omp(i8* [[POINTER]], i32 24, i64 [[SIZE]]) // CHECK-NEXT: bitcast i8* [[POINTER]] to double* // CHECK: __typeart_free_omp(i8* [[POINTER:%[0-9a-z]+]]) // CHECK-NEXT: [[POINTER2:%[0-9a-z]+]] = call{{( align [0-9]+)?}} i8* @realloc(i8*{{( noundef)?}} [[POINTER]], i64{{( noundef)?}} 160) -// CHECK-NEXT: __typeart_alloc_omp(i8* [[POINTER2]], i32 6, i64 20) +// CHECK-NEXT: __typeart_alloc_omp(i8* [[POINTER2]], i32 24, i64 20) // CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( align [0-9]+)?}} i8* @malloc -// CHECK-NEXT: call void @__typeart_alloc_omp(i8* [[POINTER]], i32 2, i64 8) +// CHECK-NEXT: call void @__typeart_alloc_omp(i8* [[POINTER]], i32 13, i64 8) // CHECK-NEXT: bitcast i8* [[POINTER]] to i32* // CHECK: call void @free // CHECK-NEXT: call void @__typeart_free_omp -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}3 -// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 - -// clang-format on \ No newline at end of file +// clang-format on diff --git a/test/pass/malloc_free/17_realloc_void.c b/test/pass/malloc_free/17_realloc_void.c new file mode 100644 index 00000000..624bca2c --- /dev/null +++ b/test/pass/malloc_free/17_realloc_void.c @@ -0,0 +1,17 @@ +// clang-format off +// RUN: %c-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s --check-prefix=REALLOC +// clang-format on +#include + +void foo() { + void* pd; + pd = realloc(pd, 20 * sizeof(double)); +} + +// clang-format off + +// REALLOC: __typeart_free({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]]) +// REALLOC-NEXT: [[POINTER2:%[0-9a-z]+]] = call{{( align [0-9]+)?}} {{i8\*|ptr}} @realloc({{i8\*|ptr}}{{( noundef)?}} [[POINTER]], i64{{( noundef)?}} 160) +// REALLOC-NEXT: __typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 {{3|11}}, i64 160) + +// clang-format on diff --git a/test/pass/misc/01_MemInstFinder_Args.c b/test/pass/misc/01_MemInstFinder_Args.c index 7b0c28e2..2c48d8de 100644 --- a/test/pass/misc/01_MemInstFinder_Args.c +++ b/test/pass/misc/01_MemInstFinder_Args.c @@ -1,19 +1,6 @@ // clang-format off // Sanity check for arg names -// RUN: %c-to-llvm %s | %opt -load %transform_pass -typeart \ -// RUN: --typeart-filter \ -// RUN: --typeart-filter-implementation=none \ -// RUN: --typeart-filter-glob=MPI1 \ -// RUN: --typeart-filter-glob-deep=MPI2 \ -// RUN: --typeart-filter-cg-file=/foo/file.cg \ -// RUN: --typeart-analysis-filter-non-array-alloca=true \ -// RUN: --typeart-analysis-filter-heap-alloca=true \ -// RUN: --typeart-analysis-filter-global=true \ -// RUN: --typeart-analysis-filter-pointer-alloca=false \ -// RUN: --typeart-stack-lifetime=false \ -// RUN: --typeart-stats=true \ -// RUN: --typeart-types=typeart_types_args.yaml \ -// RUN: --typeart-config=07_typeart_config_stack.yml +// RUN: %c-to-llvm %s | %opt -load-pass-plugin %transform_pass -passes='typeart' // clang-format on void foo() { diff --git a/test/pass/misc/02_TypeArtPass_Args.c b/test/pass/misc/02_TypeArtPass_Args.c index 5777678c..0f92da44 100644 --- a/test/pass/misc/02_TypeArtPass_Args.c +++ b/test/pass/misc/02_TypeArtPass_Args.c @@ -1,11 +1,6 @@ // clang-format off // Sanity check for arg names -// RUN: %c-to-llvm %s | %opt -load %transform_pass -typeart \ -// RUN: -typeart-stats \ -// RUN: --typeart-heap=true \ -// RUN: --typeart-stack=true \ -// RUN: --typeart-global=false \ -// RUN: -typeart-types=typeart_types.yaml +// RUN: %c-to-llvm %s | %opt -load-pass-plugin %transform_pass -passes='typeart' // clang-format on void foo() { diff --git a/test/pass/misc/03_make_mismatch_callback.c b/test/pass/misc/03_make_mismatch_callback.c index 3786da0a..99a888d0 100644 --- a/test/pass/misc/03_make_mismatch_callback.c +++ b/test/pass/misc/03_make_mismatch_callback.c @@ -1,4 +1,5 @@ -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // XFAIL: * #include diff --git a/test/pass/misc/04_make_callback_match.c b/test/pass/misc/04_make_callback_match.c index e84f7f3e..6085a3c8 100644 --- a/test/pass/misc/04_make_callback_match.c +++ b/test/pass/misc/04_make_callback_match.c @@ -1,4 +1,4 @@ -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true -S 2>&1 | %filecheck %s void __typeart_leave_scope(int alloca_count); diff --git a/test/pass/misc/05_make_all_callbacks.c b/test/pass/misc/05_make_all_callbacks.c index 952dcf5a..0316c9fd 100644 --- a/test/pass/misc/05_make_all_callbacks.c +++ b/test/pass/misc/05_make_all_callbacks.c @@ -1,4 +1,4 @@ -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true -S 2>&1 | %filecheck %s #include "../../../lib/runtime/CallbackInterface.h" diff --git a/test/pass/misc/06_unknown_type.llin b/test/pass/misc/06_unknown_type.llin index 6685cf9a..885935de 100644 --- a/test/pass/misc/06_unknown_type.llin +++ b/test/pass/misc/06_unknown_type.llin @@ -1,4 +1,4 @@ -; RUN: cat %s | %apply-typeart --typeart-stack --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s +; RUN: cat %s | %apply-typeart --typeart-stack=true --typeart-analysis-filter-pointer-alloca=false -S 2>&1 | %filecheck %s define dso_local i32 @main() #0 { ; CHECK-NOT: call @__typeart_alloc_stack diff --git a/test/pass/misc/07_config_file.c b/test/pass/misc/07_config_file.c index 6c207e06..1e9a48ad 100644 --- a/test/pass/misc/07_config_file.c +++ b/test/pass/misc/07_config_file.c @@ -1,17 +1,20 @@ -// RUN: %c-to-llvm %s | %apply-typeart -typeart-config=%S/07_typeart_config_stack.yml 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-config=%S/07_typeart_config_stack.yml 2>&1 | %filecheck %s +// REQUIRES: llvm-14 + +// XFAIL: * #include void test() { int* p = (int*)malloc(42 * sizeof(int)); } -// CHECK: types: types_config.yaml +// CHECK: types: {{.*}} // CHECK-NEXT: heap: false // CHECK-NEXT: stack: true // CHECK-NEXT: global: false -// CHECK-NEXT: stats: false +// CHECK-NEXT: stats: {{.*}} // CHECK-NEXT: stack-lifetime: false -// CHECK-NEXT: typegen: dimeta +// CHECK-NEXT: typegen: {{dimeta|ir}} // CHECK-NEXT: filter: false // CHECK-NEXT: call-filter: // CHECK-NEXT: implementation: std diff --git a/test/pass/misc/08_config_file_default.c b/test/pass/misc/08_config_file_default.c index 3165d694..f5bcf213 100644 --- a/test/pass/misc/08_config_file_default.c +++ b/test/pass/misc/08_config_file_default.c @@ -1,15 +1,15 @@ -// RUN: %c-to-llvm %s | %apply-typeart -typeart-config-dump -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // CHECK-NOT: {{(Error|Fatal)}} -// CHECK: types: types.yaml +// CHECK: types: {{.*}}.yaml // CHECK-NEXT: heap: true // CHECK-NEXT: stack: false // CHECK-NEXT: global: false -// CHECK-NEXT: stats: false +// CHECK-NEXT: stats: true // CHECK-NEXT: stack-lifetime: true -// CHECK-NEXT: typegen: dimeta -// CHECK-NEXT: filter: true +// CHECK-NEXT: typegen: {{dimeta|ir}} +// CHECK-NEXT: filter: false // CHECK-NEXT: call-filter: // CHECK-NEXT: implementation: std // CHECK-NEXT: glob: '*MPI_*' @@ -20,7 +20,6 @@ // CHECK-NEXT: filter-heap-alloca: false // CHECK-NEXT: filter-pointer-alloca: true // CHECK-NEXT: filter-non-array-alloca: false -// CHECK-NEXT: file-format: 1 void test() { } diff --git a/test/pass/misc/09_config_file_cl.c b/test/pass/misc/09_config_file_cl.c index ca67c3f8..f27503e4 100644 --- a/test/pass/misc/09_config_file_cl.c +++ b/test/pass/misc/09_config_file_cl.c @@ -1,11 +1,14 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-heap=true --typeart-stack=false -typeart-config=%S/07_typeart_config_stack.yml -S 2>&1 | %filecheck %s -// RUN: %c-to-llvm %s | %apply-typeart --typeart-heap=true -typeart-config=%S/07_typeart_config_stack.yml -S 2>&1 | %filecheck %s --check-prefix CHECK-HS -// RUN: %c-to-llvm %s | %apply-typeart -typeart-config=%S/07_typeart_config_stack.yml -S 2>&1 | %filecheck %s --check-prefix CHECK-S +// RUN: %c-to-llvm %s | %apply-typeart --typeart-heap=true --typeart-stack=false --typeart-config=%S/07_typeart_config_stack.yml -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-heap=true --typeart-config=%S/07_typeart_config_stack.yml -S 2>&1 | %filecheck %s --check-prefix CHECK-HS +// RUN: %c-to-llvm %s | %apply-typeart --typeart-config=%S/07_typeart_config_stack.yml -S 2>&1 | %filecheck %s --check-prefix CHECK-S +// REQUIRES: llvm-14 // clang-format on // Priority control with command line args vs. config file contents. +// XFAIL: * + #include void test() { int x = 0; diff --git a/test/pass/misc/10_config_file_missing.c b/test/pass/misc/10_config_file_missing.c index 795a9f6c..b018a662 100644 --- a/test/pass/misc/10_config_file_missing.c +++ b/test/pass/misc/10_config_file_missing.c @@ -1,4 +1,5 @@ -// RUN: %c-to-llvm %s | %apply-typeart -typeart-config=%S/missing_config.yml -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-config=%S/missing_config.yml -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // XFAIL: * // CHECK: Fatal diff --git a/test/pass/misc/11_env_flags.c b/test/pass/misc/11_env_flags.c new file mode 100644 index 00000000..5aeceb80 --- /dev/null +++ b/test/pass/misc/11_env_flags.c @@ -0,0 +1,17 @@ +// clang-format off +// RUN: %c-to-llvm %s | TYPEART_OPTIONS="no-heap;no-stack;no-stats;no-stack-lifetime" %apply-typeart 2>&1 | %filecheck %s + +// CHECK: Emitting TypeART configuration content +// CHECK-NEXT: --- +// CHECK-NEXT: types: {{.*}} +// CHECK-NEXT: heap: false +// CHECK-NEXT: stack: false +// CHECK-NEXT: global: false +// CHECK-NEXT: stats: false +// CHECK-NEXT: stack-lifetime: false + +// clang-format on + +void test() { + int a; +} diff --git a/test/pass/misc/12_env_flags_single_override.c b/test/pass/misc/12_env_flags_single_override.c new file mode 100644 index 00000000..15a1f8b1 --- /dev/null +++ b/test/pass/misc/12_env_flags_single_override.c @@ -0,0 +1,17 @@ +// clang-format off +// RUN: %c-to-llvm %s | TYPEART_OPTIONS="no-heap;no-stack;no-stats;no-stack-lifetime" TYPEART_HEAP=true %apply-typeart 2>&1 | %filecheck %s + +// CHECK: Emitting TypeART configuration content +// CHECK-NEXT: --- +// CHECK-NEXT: types: {{.*}} +// CHECK-NEXT: heap: true +// CHECK-NEXT: stack: false +// CHECK-NEXT: global: false +// CHECK-NEXT: stats: false +// CHECK-NEXT: stack-lifetime: false + +// clang-format on + +void test() { + int a; +} diff --git a/test/pass/misc/13_env_flags_phase_heap.c b/test/pass/misc/13_env_flags_phase_heap.c new file mode 100644 index 00000000..5eb78c18 --- /dev/null +++ b/test/pass/misc/13_env_flags_phase_heap.c @@ -0,0 +1,17 @@ +// clang-format off +// RUN: %c-to-llvm %s | TYPEART_OPTIONS_HEAP="stack;no-stats;no-stack-lifetime" %apply-typeart 2>&1 | %filecheck %s + +// CHECK: Emitting TypeART configuration content +// CHECK-NEXT: --- +// CHECK-NEXT: types: {{.*}} +// CHECK-NEXT: heap: true +// CHECK-NEXT: stack: true +// CHECK-NEXT: global: true +// CHECK-NEXT: stats: false +// CHECK-NEXT: stack-lifetime: false + +// clang-format on + +void test() { + int a; +} diff --git a/test/pass/misc/14_env_flags_phase_ignored.c b/test/pass/misc/14_env_flags_phase_ignored.c new file mode 100644 index 00000000..280887bb --- /dev/null +++ b/test/pass/misc/14_env_flags_phase_ignored.c @@ -0,0 +1,15 @@ +// clang-format off +// RUN: %c-to-llvm %s | TYPEART_OPTIONS_STACK="global;stack;no-stats;no-stack-lifetime" %apply-typeart 2>&1 | %filecheck %s + +// CHECK: Emitting TypeART configuration content +// CHECK: heap: true +// CHECK-NOT: stack: true +// CHECK-NOT: {{^}}global: true +// CHECK-NOT: stats: false +// CHECK-NOT: stack-lifetime: false + +// clang-format on + +void test() { + int a; +} diff --git a/test/pass/new_delete/01_inv_simple_new_int.cpp b/test/pass/new_delete/01_inv_simple_new_int.cpp index 64f2c9e3..e2cd9833 100644 --- a/test/pass/new_delete/01_inv_simple_new_int.cpp +++ b/test/pass/new_delete/01_inv_simple_new_int.cpp @@ -2,10 +2,14 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + #include -// CHECK: invoke{{.*}} i8* @_Znwm(i64{{( noundef)?}} 4) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 2, i64 1) -// CHECK-NEXT: bitcast i8* {{.*}}[[POINTER]] to i32* +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znwm(i64{{( noundef)?}} 4) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 13, i64 1) int main() { try { auto s = new int; @@ -14,8 +18,3 @@ int main() { return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/02_inv_simple_int_array.cpp b/test/pass/new_delete/02_inv_simple_int_array.cpp index ee79e6bc..f2893a38 100644 --- a/test/pass/new_delete/02_inv_simple_int_array.cpp +++ b/test/pass/new_delete/02_inv_simple_int_array.cpp @@ -2,10 +2,14 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + #include -// CHECK: invoke{{.*}} i8* @_Znam(i64{{( noundef)?}} 8) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 2, i64 2) -// CHECK-NEXT: bitcast i8* {{.*}}[[POINTER]] to i32* +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 8) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 13, i64 2) int main() { try { auto s = new int[2]; @@ -14,8 +18,3 @@ int main() { return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/03_inv_struct.cpp b/test/pass/new_delete/03_inv_struct.cpp index 1216cd47..09986c9b 100644 --- a/test/pass/new_delete/03_inv_struct.cpp +++ b/test/pass/new_delete/03_inv_struct.cpp @@ -2,6 +2,11 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + #include struct S1 { @@ -9,9 +14,8 @@ struct S1 { virtual ~S1() = default; }; -// CHECK: invoke{{.*}} i8* @_Znwm(i64{{( noundef)?}} 16) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 1) -// CHECK: bitcast i8* [[POINTER]] to %struct.S1* +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znwm(i64{{( noundef)?}} 16) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 1) int main() { try { S1* ss = new S1; @@ -20,8 +24,3 @@ int main() { return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/04_inv_struct_array.cpp b/test/pass/new_delete/04_inv_struct_array.cpp index 1d7b3a8a..da17ee42 100644 --- a/test/pass/new_delete/04_inv_struct_array.cpp +++ b/test/pass/new_delete/04_inv_struct_array.cpp @@ -2,6 +2,11 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + #include struct S1 { @@ -9,9 +14,8 @@ struct S1 { virtual ~S1() = default; }; -// CHECK: invoke{{.*}} i8* @_Znam(i64{{( noundef)?}} 40) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[5-9][0-9]}}, i64 2) -// CHECK: bitcast i8* [[POINTER]] to %struct.S1* +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 40) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[5-9][0-9]}}, i64 2) int main() { try { S1* ss = new S1[2]; @@ -20,8 +24,3 @@ int main() { return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/05_struct_array.cpp b/test/pass/new_delete/05_struct_array.cpp index a295500e..7d6b7b3f 100644 --- a/test/pass/new_delete/05_struct_array.cpp +++ b/test/pass/new_delete/05_struct_array.cpp @@ -2,19 +2,18 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + struct S1 { int x; }; -// CHECK: call{{.*}} i8* @_Znam(i64{{( noundef)?}} 8) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) -// CHECK: bitcast i8* [[POINTER]] to %struct.S1* +// CHECK: call{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 8) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) int main() { S1* ss = new S1[2]; return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/06_struct_array_def_dest.cpp b/test/pass/new_delete/06_struct_array_def_dest.cpp index 89077c1d..dca95502 100644 --- a/test/pass/new_delete/06_struct_array_def_dest.cpp +++ b/test/pass/new_delete/06_struct_array_def_dest.cpp @@ -2,20 +2,19 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + struct S1 { int x; ~S1() = default; }; -// CHECK: call{{.*}} i8* @_Znam(i64{{( noundef)?}} 8) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) -// CHECK: bitcast i8* [[POINTER]] to %struct.S1* +// CHECK: call{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 8) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) int main() { S1* ss = new S1[2]; return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/07_struct_array_userdef_dest.cpp b/test/pass/new_delete/07_struct_array_userdef_dest.cpp index cd8962df..fa6f3961 100644 --- a/test/pass/new_delete/07_struct_array_userdef_dest.cpp +++ b/test/pass/new_delete/07_struct_array_userdef_dest.cpp @@ -1,7 +1,7 @@ // clang-format off // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s -// XFAIL: * // Wrong size is calculated due to using Znam call, instead of bitcast to struct.S1* +// REQUIRES: dimeta // clang-format on struct S1 { @@ -9,15 +9,9 @@ struct S1 { ~S1(){}; }; -// CHECK: call i8* @_Znam(i64{{( noundef)?}} 8) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) -// CHECK: bitcast i8* [[POINTER]] to %struct.S1* +// CHECK: call{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 16) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) int main() { S1* ss = new S1[2]; return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/08_inv_double_array_delete.cpp b/test/pass/new_delete/08_inv_double_array_delete.cpp index ed8d721c..3de48a4b 100644 --- a/test/pass/new_delete/08_inv_double_array_delete.cpp +++ b/test/pass/new_delete/08_inv_double_array_delete.cpp @@ -2,12 +2,16 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 +// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}2 +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + #include -// CHECK: invoke{{.*}} i8* @_Znam(i64{{( noundef)?}} 16) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 6, i64 2) -// CHECK-NEXT: bitcast i8* {{.*}}[[POINTER]] to double* -// CHECK: call void @_ZdaPv(i8*{{( noundef)?}} [[POINTER2:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* {{.*}}[[POINTER2]]) +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 16) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 24, i64 2) +// CHECK: call void @_ZdaPv({{i8\*|ptr}}{{( noundef)?}} [[POINTER2:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} {{.*}}[[POINTER2]]) int main() { try { auto s = new double[2]; @@ -18,11 +22,10 @@ int main() { return 0; } -// CHECK: invoke{{.*}} i8* @_Znam(i64{{( noundef)?}} 16) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 6, i64 2) -// CHECK-NEXT: bitcast i8* {{.*}}[[POINTER]] to double* -// CHECK: call void @_ZdaPv(i8*{{( noundef)?}} [[POINTER2:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* {{.*}}[[POINTER2]]) +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 16) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 24, i64 2) +// CHECK: call void @_ZdaPv({{i8\*|ptr}}{{( noundef)?}} [[POINTER2:%[0-9a-z]+]]) +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} {{.*}}[[POINTER2]]) void foo() { double* b{nullptr}; try { @@ -33,8 +36,3 @@ void foo() { delete[] b; } } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 -// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}2 -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/09_inv_struct_delete.cpp b/test/pass/new_delete/09_inv_struct_delete.cpp index d5138939..0e27e635 100644 --- a/test/pass/new_delete/09_inv_struct_delete.cpp +++ b/test/pass/new_delete/09_inv_struct_delete.cpp @@ -2,6 +2,11 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 +// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + #include struct S1 { @@ -9,9 +14,8 @@ struct S1 { virtual ~S1() = default; }; -// CHECK: invoke{{.*}} i8* @_Znwm(i64{{( noundef)?}} 16) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 1) -// CHECK: bitcast i8* [[POINTER]] to %struct.S1* +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znwm(i64{{( noundef)?}} 16) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 1) void foo() { S1* b{nullptr}; try { @@ -23,9 +27,8 @@ void foo() { } } -// CHECK: invoke{{.*}} i8* @_Znwm(i64{{( noundef)?}} 16) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 1) -// CHECK: bitcast i8* [[POINTER]] to %struct.S1* +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znwm(i64{{( noundef)?}} 16) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 1) int main() { try { S1* ss = new S1; @@ -37,10 +40,5 @@ int main() { } // CHECK: @_ZN2S1D0Ev -// CHECK: call void @_ZdlPv(i8*{{( noundef)?}} [[POINTER2:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* {{.*}}[[POINTER2]]) - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 -// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 +// CHECK: call void @_ZdlPv{{m?}}({{i8\*|ptr}}{{( noundef)?}} [[POINTER2:%[0-9a-z]+]] +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} {{.*}}[[POINTER2]]) diff --git a/test/pass/new_delete/10_inv_struct_array_delete.cpp b/test/pass/new_delete/10_inv_struct_array_delete.cpp index 06dc025c..4ebd4309 100644 --- a/test/pass/new_delete/10_inv_struct_array_delete.cpp +++ b/test/pass/new_delete/10_inv_struct_array_delete.cpp @@ -2,6 +2,11 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 +// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}3 +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + #include struct S1 { @@ -9,11 +14,11 @@ struct S1 { virtual ~S1() = default; }; -// CHECK: invoke{{.*}} i8* @_Znam(i64{{( noundef)?}} 56) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 3) -// CHECK: [[MEMORYBLOB:%[0-9a-z]+]] = getelementptr inbounds i8, i8* [[ARRPTR:%[0-9a-z]+]], i64 -8 -// CHECK: call void @_ZdaPv(i8*{{( noundef)?}} [[MEMORYBLOB]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[ARRPTR]]) +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 56) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 3) +// CHECK: [[MEMORYBLOB:%[0-9a-z]+]] = getelementptr inbounds i8, {{i8\*|ptr}} [[ARRPTR:%[0-9a-z]+]], i64 -8 +// CHECK: call void @_ZdaPv{{m?}}({{i8\*|ptr}}{{( noundef)?}} [[MEMORYBLOB]] +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[ARRPTR]]) void foo() { S1* b{nullptr}; try { @@ -25,11 +30,11 @@ void foo() { } } -// CHECK: invoke{{.*}} i8* @_Znam(i64{{( noundef)?}} 40) -// CHECK: call void @__typeart_alloc(i8* [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) -// CHECK: [[MEMORYBLOB:%[0-9a-z]+]] = getelementptr inbounds i8, i8* [[ARRPTR:%[0-9a-z]+]], i64 -8 -// CHECK: call void @_ZdaPv(i8*{{( noundef)?}} [[MEMORYBLOB]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[ARRPTR]]) +// CHECK: invoke{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 40) +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) +// CHECK: [[MEMORYBLOB:%[0-9a-z]+]] = getelementptr inbounds i8, {{i8\*|ptr}} [[ARRPTR:%[0-9a-z]+]], i64 -8 +// CHECK: call void @_ZdaPv{{m?}}({{i8\*|ptr}}{{( noundef)?}} [[MEMORYBLOB]] +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[ARRPTR]]) int main() { try { S1* ss = new S1[2]; @@ -41,10 +46,5 @@ int main() { } // CHECK: @_ZN2S1D0Ev -// CHECK: call void @_ZdlPv(i8*{{( noundef)?}} [[POINTER2:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_free(i8* [[POINTER2]]) - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 -// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}3 -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 +// CHECK: call void @_ZdlPv{{m?}}({{i8\*|ptr}}{{( noundef)?}} [[POINTER2:%[0-9a-z]+]] +// CHECK-NEXT: call void @__typeart_free({{i8\*|ptr}} [[POINTER2]]) diff --git a/test/pass/new_delete/11_new_nothrow.cpp b/test/pass/new_delete/11_new_nothrow.cpp index a8dec1a0..3af6ca0a 100644 --- a/test/pass/new_delete/11_new_nothrow.cpp +++ b/test/pass/new_delete/11_new_nothrow.cpp @@ -16,8 +16,8 @@ C* bar() { return new (std::nothrow) C; } -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( noundef)?}} i8* @_ZnamRKSt9nothrow_t(i64{{( noundef)?}} 40, -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 [[ID:2[5-9][0-9]]], i64 10) +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( noundef)?}} {{i8\*|ptr}} @_ZnamRKSt9nothrow_t(i64{{( noundef)?}} 40, +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 [[ID:2[5-9][0-9]]], i64 10) -// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( noundef)?}} i8* @_ZnwmRKSt9nothrow_t(i64{{( noundef)?}} 4, -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER2]], i32 [[ID]], i64 1) \ No newline at end of file +// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( noundef)?}} {{i8\*|ptr}} @_ZnwmRKSt9nothrow_t(i64{{( noundef)?}} 4, +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 [[ID]], i64 1) \ No newline at end of file diff --git a/test/pass/new_delete/12_new_aligned.cpp b/test/pass/new_delete/12_new_aligned.cpp index cbe82ad4..62a7ec57 100644 --- a/test/pass/new_delete/12_new_aligned.cpp +++ b/test/pass/new_delete/12_new_aligned.cpp @@ -16,9 +16,10 @@ C* foo() { C* bar() { return new (std::align_val_t(128)) C; } +// clang-format off +// CHECK: [[POINTER:%[0-9a-z]+]] = call{{.*}} {{i8\*|ptr}} @_ZnamSt11align_val_t(i64{{( noundef)?}} 40, i64{{( noundef)?}} 64) +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 [[ID:2[5-9][0-9]]], i64 10) -// CHECK: [[POINTER:%[0-9a-z]+]] = call{{.*}} i8* @_ZnamSt11align_val_t(i64{{( noundef)?}} 40, i64{{( noundef)?}} 64) -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 [[ID:2[5-9][0-9]]], i64 10) - -// CHECK: [[POINTER2:%[0-9a-z]+]] = call{{.*}} i8* @_ZnwmSt11align_val_t(i64{{( noundef)?}} 4, i64{{( noundef)?}} 128) -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER2]], i32 [[ID]], i64 1) \ No newline at end of file +// CHECK: [[POINTER2:%[0-9a-z]+]] = call{{.*}} {{i8\*|ptr}} @_ZnwmSt11align_val_t(i64{{( noundef)?}} 4, i64{{( noundef)?}} 128) +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 [[ID]], i64 1) +// clang-format on diff --git a/test/pass/new_delete/13_new_aligned_nothrow.cpp b/test/pass/new_delete/13_new_aligned_nothrow.cpp index b8059481..ff785cf4 100644 --- a/test/pass/new_delete/13_new_aligned_nothrow.cpp +++ b/test/pass/new_delete/13_new_aligned_nothrow.cpp @@ -2,7 +2,9 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +#ifndef __cpp_aligned_new #define __cpp_aligned_new 1 +#endif #include struct C { @@ -19,10 +21,10 @@ C* bar() { // clang-format off -// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( noundef)?}} i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64{{( noundef)?}} 40, -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER]], i32 [[ID:2[5-9][0-9]]], i64 10) +// CHECK: [[POINTER:%[0-9a-z]+]] = call noalias{{( noundef)?}}{{.*}}{{i8\*|ptr}} @_ZnamSt11align_val_tRKSt9nothrow_t(i64{{( noundef)?}} 40, +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER]], i32 [[ID:2[5-9][0-9]]], i64 10) -// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( noundef)?}} i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64{{( noundef)?}} 4, -// CHECK-NEXT: call void @__typeart_alloc(i8* [[POINTER2]], i32 [[ID]], i64 1) +// CHECK: [[POINTER2:%[0-9a-z]+]] = call noalias{{( noundef)?}}{{.*}}{{i8\*|ptr}} @_ZnwmSt11align_val_tRKSt9nothrow_t(i64{{( noundef)?}} 4, +// CHECK-NEXT: call void @__typeart_alloc({{i8\*|ptr}} [[POINTER2]], i32 [[ID]], i64 1) // clang-format on diff --git a/test/pass/new_delete/14_omp_heap.cpp b/test/pass/new_delete/14_omp_heap.cpp index 8dee1851..bc052efb 100644 --- a/test/pass/new_delete/14_omp_heap.cpp +++ b/test/pass/new_delete/14_omp_heap.cpp @@ -1,8 +1,14 @@ // clang-format off // RUN: %cpp-to-llvm %omp_cpp_flags %s | %apply-typeart -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // REQUIRES: openmp // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 +// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + void foo(int** x) { #pragma omp parallel // transformed to @__kmpc_fork_call { @@ -19,8 +25,3 @@ void foo(int** x) { // CHECK: call void @__typeart_alloc_omp // CHECK: call void @__typeart_free_omp // CHECK: call void @__typeart_alloc_omp - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}2 -// CHECK-NEXT: Free{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 \ No newline at end of file diff --git a/test/pass/new_delete/15_array_cookie.cpp b/test/pass/new_delete/15_array_cookie.cpp index e843f4af..d1ec95fb 100644 --- a/test/pass/new_delete/15_array_cookie.cpp +++ b/test/pass/new_delete/15_array_cookie.cpp @@ -1,22 +1,23 @@ // clang-format off // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s + // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + struct S1 { int x; ~S1(){}; }; -// CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} i8* @_Znam(i64{{( noundef)?}} 16) -// CHECK: [[ARR:%[0-9a-z]+]] = getelementptr inbounds i8, i8* [[MEM]], i64 8 -// CHECK: call void @__typeart_alloc(i8* [[ARR:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) -// CHECK: bitcast i8* [[ARR]] to %struct.S1* +// CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 16) +// CHECK: [[ARR:%[0-9a-z]+]] = getelementptr inbounds i8, {{i8\*|ptr}} [[MEM]], i64 8 +// CHECK: call void @__typeart_alloc({{(i8\*|ptr)}} [[ARR:%[0-9a-z]+]], i32 {{2[0-9]+}}, i64 2) +// CHECK: {{(bitcast i8\* [[ARR]] to %struct.S1\*)?}} int main() { S1* ss = new S1[2]; return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/16_array_cookie_padded.cpp b/test/pass/new_delete/16_array_cookie_padded.cpp index 33de75ff..ab9452f7 100644 --- a/test/pass/new_delete/16_array_cookie_padded.cpp +++ b/test/pass/new_delete/16_array_cookie_padded.cpp @@ -2,21 +2,21 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + struct alignas(16) S1 { int x; ~S1(){}; }; -// CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} i8* @_Znam(i64{{( noundef)?}} 48) -// CHECK: [[ARR:%[0-9a-z]+]] = getelementptr inbounds i8, i8* [[MEM]], i64 16 -// CHECK: call void @__typeart_alloc(i8* [[ARR]], i32 {{2[0-9]+}}, i64 2) -// CHECK: bitcast i8* [[ARR]] to %struct.S1* +// CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} {{i8\*|ptr}} @_Znam(i64{{( noundef)?}} 48) +// CHECK: [[ARR:%[0-9a-z]+]] = getelementptr inbounds i8, {{i8\*|ptr}} [[MEM]], i64 16 +// CHECK: call void @__typeart_alloc({{i8\*|ptr}} [[ARR]], i32 {{2[0-9]+}}, i64 2) +// CHECK: {{(bitcast i8\* [[ARR]] to %struct.S1\*)?}} int main() { S1* ss = new S1[2]; return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/17_array_cookie_dynamic_size.cpp b/test/pass/new_delete/17_array_cookie_dynamic_size.cpp index 98c1ea12..4669cdfc 100644 --- a/test/pass/new_delete/17_array_cookie_dynamic_size.cpp +++ b/test/pass/new_delete/17_array_cookie_dynamic_size.cpp @@ -1,7 +1,13 @@ // clang-format off // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + struct S1 { int x; ~S1(){}; @@ -18,8 +24,3 @@ int main() { S1* ss = new S1[elment_count]; return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/18_array_cookie_delete.cpp b/test/pass/new_delete/18_array_cookie_delete.cpp index 56e0a7d2..4fdaff6e 100644 --- a/test/pass/new_delete/18_array_cookie_delete.cpp +++ b/test/pass/new_delete/18_array_cookie_delete.cpp @@ -2,21 +2,21 @@ // RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s // clang-format on +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + struct S1 { int x; ~S1(){}; }; -// CHECK: [[MEM:%[0-9a-z]+]] = getelementptr inbounds i8, i8* [[ARR:%[0-9a-z]+]], i64 -8 -// CHECK: call void @_ZdaPv(i8*{{( noundef)?}} [[MEM]]) -// CHECK: call void @__typeart_free(i8* [[ARR]]) +// CHECK: [[MEM:%[0-9a-z]+]] = getelementptr inbounds i8, {{i8\*|ptr}} [[ARR:%[0-9a-z]+]], i64 -8 +// CHECK: call void @_ZdaPv{{m?}}({{i8\*|ptr}}{{( noundef)?}} [[MEM]] +// CHECK: call void @__typeart_free({{i8\*|ptr}} [[ARR]]) int main() { S1* ss = new S1[2]; delete[] ss; return 0; } - -// CHECK: TypeArtPass [Heap] -// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 -// CHECK-NEXT: Free -// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 diff --git a/test/pass/new_delete/19_array_cookie_dynamic_size_opaque.cpp b/test/pass/new_delete/19_array_cookie_dynamic_size_opaque.cpp new file mode 100644 index 00000000..0174641d --- /dev/null +++ b/test/pass/new_delete/19_array_cookie_dynamic_size_opaque.cpp @@ -0,0 +1,24 @@ +// clang-format off +// RUN: %cpp-to-llvm %s | %apply-typeart -S 2>&1 | %filecheck %s +// REQUIRES: llvm-18 || llvm-19 +// clang-format on + +// CHECK: TypeArtPass [Heap] +// CHECK-NEXT: Malloc{{[ ]*}}:{{[ ]*}}1 +// CHECK-NEXT: Free +// CHECK-NEXT: Alloca{{[ ]*}}:{{[ ]*}}0 + +struct S1 { + int x; + ~S1(){}; +}; + +// CHECK: [[MEM:%[0-9a-z]+]] = call{{.*}} ptr @_Znam(i64{{( noundef)?}} [[ALLOC:%[0-9a-z]+]]) +// CHECK: store i64 [[COUNT:%[0-9a-z]+]], ptr [[MEM]], align 8 +// CHECK: [[ARR:%[0-9a-z]+]] = getelementptr inbounds i8, ptr [[MEM]], i64 8 +// CHECK: call void @__typeart_alloc(ptr [[ARR]], i32 {{2[0-9]+}}, i64 [[COUNT]]) +int main() { + volatile int elment_count = 2; + S1* ss = new S1[elment_count]; + return 0; +} diff --git a/test/pass/new_delete/20_no_array_cookie_lulesh_ad.llin b/test/pass/new_delete/20_no_array_cookie_lulesh_ad.llin new file mode 100644 index 00000000..03309760 --- /dev/null +++ b/test/pass/new_delete/20_no_array_cookie_lulesh_ad.llin @@ -0,0 +1,236 @@ +; RUN: %apply-typeart -S < %s | %filecheck %s +; REQUIRES: llvm-18 || llvm-19 + +; llvm-reduce on lulesh.cc with culprit chunk.hpp:allocateData() where pattern is similar to array cookie. + +; CHECK: call void @__typeart_alloc(ptr %call, i32 25{{[0-9]}}, i64 0) + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%"struct.codi::ExternalFunction" = type { ptr, ptr, ptr, ptr, ptr } + +declare ptr @_Znam(i64) + +define void @_ZN4codi6Chunk2INS_16ExternalFunctionENS_11ChunkVectorINS0_IdiEENS2_INS_6Chunk1IhEENS_18LinearIndexHandlerIiEEEEE8PositionEE12allocateDataEv() personality ptr null { +entry: + %call = call ptr @_Znam(i64 0), !dbg !191, !heapallocsite !201 + store ptr %call, ptr null, align 8 + ret void + +new.ctorloop: ; No predecessors! + %arrayctor.end = getelementptr %"struct.codi::ExternalFunction", ptr %call, i64 0 + br label %arrayctor.loop + +arrayctor.loop: ; preds = %arrayctor.loop, %new.ctorloop + br label %arrayctor.loop +} + +; uselistorder directives +uselistorder ptr null, { 1, 2, 3, 0 } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!190} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 18.1.8", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !3, imports: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "lulesh.cc", directory: "lulesh", checksumkind: CSK_MD5, checksum: "8d13b4cf5cd37f06475f0790e5054685") +!2 = !{} +!3 = !{!4, !9, !12, !15, !18, !21, !24, !27, !30, !33, !36, !39, !42, !45, !47, !50, !62, !65, !68, !72, !75, !77, !80, !83, !86, !90, !94, !97, !100, !104, !106, !113, !116, !118, !120, !123, !125, !127, !131, !134, !137, !139, !141, !144, !147, !149, !151, !155, !157, !160, !164, !167, !169, !172, !175, !178, !180, !182, !185, !188} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(scope: null, file: !1, line: 167, type: !6, isLocal: true, isDefinition: true) +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 112, elements: !2) +!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8) +!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression()) +!10 = distinct !DIGlobalVariable(scope: null, file: !1, line: 173, type: !11, isLocal: true, isDefinition: true) +!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 176, elements: !2) +!12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression()) +!13 = distinct !DIGlobalVariable(scope: null, file: !1, line: 175, type: !14, isLocal: true, isDefinition: true) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 16, elements: !2) +!15 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression()) +!16 = distinct !DIGlobalVariable(scope: null, file: !1, line: 179, type: !17, isLocal: true, isDefinition: true) +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 56, elements: !2) +!18 = !DIGlobalVariableExpression(var: !19, expr: !DIExpression()) +!19 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2748, type: !20, isLocal: true, isDefinition: true) +!20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 440, elements: !2) +!21 = !DIGlobalVariableExpression(var: !22, expr: !DIExpression()) +!22 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2749, type: !23, isLocal: true, isDefinition: true) +!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 160, elements: !2) +!24 = !DIGlobalVariableExpression(var: !25, expr: !DIExpression()) +!25 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2753, type: !26, isLocal: true, isDefinition: true) +!26 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 264, elements: !2) +!27 = !DIGlobalVariableExpression(var: !28, expr: !DIExpression()) +!28 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2754, type: !29, isLocal: true, isDefinition: true) +!29 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 312, elements: !2) +!30 = !DIGlobalVariableExpression(var: !31, expr: !DIExpression()) +!31 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2755, type: !32, isLocal: true, isDefinition: true) +!32 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 448, elements: !2) +!33 = !DIGlobalVariableExpression(var: !34, expr: !DIExpression()) +!34 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2756, type: !35, isLocal: true, isDefinition: true) +!35 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 496, elements: !2) +!36 = !DIGlobalVariableExpression(var: !37, expr: !DIExpression()) +!37 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2757, type: !38, isLocal: true, isDefinition: true) +!38 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 480, elements: !2) +!39 = !DIGlobalVariableExpression(var: !40, expr: !DIExpression()) +!40 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2758, type: !41, isLocal: true, isDefinition: true) +!41 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 248, elements: !2) +!42 = !DIGlobalVariableExpression(var: !43, expr: !DIExpression()) +!43 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2759, type: !44, isLocal: true, isDefinition: true) +!44 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 344, elements: !2) +!45 = !DIGlobalVariableExpression(var: !46, expr: !DIExpression()) +!46 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2760, type: !26, isLocal: true, isDefinition: true) +!47 = !DIGlobalVariableExpression(var: !48, expr: !DIExpression()) +!48 = distinct !DIGlobalVariable(scope: null, file: !1, line: 2823, type: !49, isLocal: true, isDefinition: true) +!49 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 240, elements: !2) +!50 = !DIGlobalVariableExpression(var: !51, expr: !DIExpression()) +!51 = distinct !DIGlobalVariable(name: "globalTape", linkageName: "_ZN4codi10ActiveRealINS_10JacobiTapeINS_15JacobiTapeTypesINS_16ReverseTapeTypesIddNS_18LinearIndexHandlerIiEEEENS_11ChunkVectorEEEEEE10globalTapeE", scope: !52, file: !53, line: 692, type: !54, isLocal: false, isDefinition: true, declaration: !60) +!52 = !DINamespace(name: "codi", scope: null) +!53 = !DIFile(filename: "../codi/include/codi/activeReal.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "af2b1db89f4df687c9053d3d6b102b1c") +!54 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "JacobiTape >, codi::ChunkVector> >", scope: !52, file: !55, line: 122, size: 2432, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !56, templateParams: !2, identifier: "_ZTSN4codi10JacobiTapeINS_15JacobiTapeTypesINS_16ReverseTapeTypesIddNS_18LinearIndexHandlerIiEEEENS_11ChunkVectorEEEEE") +!55 = !DIFile(filename: "../codi/include/codi/tapes/jacobiTape.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "ef9d6b9a9f5f62a58c9ab1895eafc9b7") +!56 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "TapeBaseModule >, codi::ChunkVector>, codi::JacobiTape >, codi::ChunkVector> > >", scope: !52, file: !57, line: 63, size: 192, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !58, templateParams: !2, identifier: "_ZTSN4codi14TapeBaseModuleINS_15JacobiTapeTypesINS_16ReverseTapeTypesIddNS_18LinearIndexHandlerIiEEEENS_11ChunkVectorEEENS_10JacobiTapeIS7_EEEE") +!57 = !DIFile(filename: "../codi/include/codi/tapes/modules/tapeBaseModule.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "91343b7c0470eb61653deab98d32b277") +!58 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "TapeInterface", scope: !52, file: !59, line: 57, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !58, templateParams: !2, identifier: "_ZTSN4codi13TapeInterfaceIdidEE") +!59 = !DIFile(filename: "../codi/include/codi/tapes/tapeInterface.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "7987cce282380d931a7d112b198b227e") +!60 = !DIDerivedType(tag: DW_TAG_variable, name: "globalTape", scope: !61, file: !53, line: 91, baseType: !54, flags: DIFlagPublic | DIFlagStaticMember) +!61 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "ActiveReal >, codi::ChunkVector> > >", scope: !52, file: !53, line: 80, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, templateParams: !2, identifier: "_ZTSN4codi10ActiveRealINS_10JacobiTapeINS_15JacobiTapeTypesINS_16ReverseTapeTypesIddNS_18LinearIndexHandlerIiEEEENS_11ChunkVectorEEEEEEE") +!62 = !DIGlobalVariableExpression(var: !63, expr: !DIExpression()) +!63 = distinct !DIGlobalVariable(scope: null, file: !64, line: 157, type: !41, isLocal: true, isDefinition: true) +!64 = !DIFile(filename: "../codi/include/codi/tapes/../tools/io.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "6773fbe69b635f6c853ffc0bb505cd1a") +!65 = !DIGlobalVariableExpression(var: !66, expr: !DIExpression()) +!66 = distinct !DIGlobalVariable(scope: null, file: !64, line: 160, type: !67, isLocal: true, isDefinition: true) +!67 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 296, elements: !2) +!68 = !DIGlobalVariableExpression(var: !69, expr: !DIExpression()) +!69 = distinct !DIGlobalVariable(scope: null, file: !70, line: 646, type: !71, isLocal: true, isDefinition: true) +!70 = !DIFile(filename: "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/basic_string.h", directory: "") +!71 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 400, elements: !2) +!72 = !DIGlobalVariableExpression(var: !73, expr: !DIExpression()) +!73 = distinct !DIGlobalVariable(scope: null, file: !64, line: 88, type: !74, isLocal: true, isDefinition: true) +!74 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 152, elements: !2) +!75 = !DIGlobalVariableExpression(var: !76, expr: !DIExpression()) +!76 = distinct !DIGlobalVariable(scope: null, file: !64, line: 90, type: !14, isLocal: true, isDefinition: true) +!77 = !DIGlobalVariableExpression(var: !78, expr: !DIExpression()) +!78 = distinct !DIGlobalVariable(scope: null, file: !70, line: 1473, type: !79, isLocal: true, isDefinition: true) +!79 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 168, elements: !2) +!80 = !DIGlobalVariableExpression(var: !81, expr: !DIExpression()) +!81 = distinct !DIGlobalVariable(scope: null, file: !64, line: 178, type: !82, isLocal: true, isDefinition: true) +!82 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 224, elements: !2) +!83 = !DIGlobalVariableExpression(var: !84, expr: !DIExpression()) +!84 = distinct !DIGlobalVariable(scope: null, file: !64, line: 181, type: !85, isLocal: true, isDefinition: true) +!85 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 288, elements: !2) +!86 = !DIGlobalVariableExpression(var: !87, expr: !DIExpression()) +!87 = distinct !DIGlobalVariable(scope: null, file: !88, line: 455, type: !89, isLocal: true, isDefinition: true) +!88 = !DIFile(filename: "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc", directory: "", checksumkind: CSK_MD5, checksum: "b0d28e6caeb7772f5e6ceabb9e69c4a6") +!89 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 208, elements: !2) +!90 = !DIGlobalVariableExpression(var: !91, expr: !DIExpression()) +!91 = distinct !DIGlobalVariable(scope: null, file: !92, line: 134, type: !93, isLocal: true, isDefinition: true) +!92 = !DIFile(filename: "../codi/include/codi/tapes/indices/linearIndexHandler.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "f6abfadf8c5750cb28567dd3f84fb959") +!93 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 96, elements: !2) +!94 = !DIGlobalVariableExpression(var: !95, expr: !DIExpression()) +!95 = distinct !DIGlobalVariable(scope: null, file: !92, line: 134, type: !96, isLocal: true, isDefinition: true) +!96 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 464, elements: !2) +!97 = !DIGlobalVariableExpression(var: !98, expr: !DIExpression()) +!98 = distinct !DIGlobalVariable(scope: null, file: !92, line: 134, type: !99, isLocal: true, isDefinition: true) +!99 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 680, elements: !2) +!100 = !DIGlobalVariableExpression(var: !101, expr: !DIExpression()) +!101 = distinct !DIGlobalVariable(scope: null, file: !102, line: 63, type: !103, isLocal: true, isDefinition: true) +!102 = !DIFile(filename: "../codi/include/codi/exceptions.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "fe567bd7f938f2b22e10aeba9a33c538") +!103 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 368, elements: !2) +!104 = !DIGlobalVariableExpression(var: !105, expr: !DIExpression()) +!105 = distinct !DIGlobalVariable(scope: null, file: !102, line: 70, type: !14, isLocal: true, isDefinition: true) +!106 = !DIGlobalVariableExpression(var: !107, expr: !DIExpression(DW_OP_constu, 255, DW_OP_stack_value)) +!107 = distinct !DIGlobalVariable(name: "StatementIntInputTag", scope: !52, file: !108, line: 124, type: !109, isLocal: true, isDefinition: true) +!108 = !DIFile(filename: "../codi/include/codi/configure.h", directory: "lulesh", checksumkind: CSK_MD5, checksum: "a5a13b0f34e6e7192dfacd661e37eba0") +!109 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !110) +!110 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_t", file: !111, line: 18, baseType: !112) +!111 = !DIFile(filename: "/shared/apps/clang/18.1.8/lib/clang/18/include/__stddef_size_t.h", directory: "", checksumkind: CSK_MD5, checksum: "2c44e821a2b1951cde2eb0fb2e656867") +!112 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned) +!113 = !DIGlobalVariableExpression(var: !114, expr: !DIExpression()) +!114 = distinct !DIGlobalVariable(scope: null, file: !115, line: 369, type: !49, isLocal: true, isDefinition: true) +!115 = !DIFile(filename: "../medi/include/medi/ampi/../../../generated/medi/../../include/medi/ampi/forwardFunctions.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "ef224abff073c852d1e654f198f7dd2b") +!116 = !DIGlobalVariableExpression(var: !117, expr: !DIExpression()) +!117 = distinct !DIGlobalVariable(scope: null, file: !88, line: 662, type: !89, isLocal: true, isDefinition: true) +!118 = !DIGlobalVariableExpression(var: !119, expr: !DIExpression()) +!119 = distinct !DIGlobalVariable(scope: null, file: !1, line: 1840, type: !41, isLocal: true, isDefinition: true) +!120 = !DIGlobalVariableExpression(var: !121, expr: !DIExpression()) +!121 = distinct !DIGlobalVariable(scope: null, file: !1, line: 1841, type: !122, isLocal: true, isDefinition: true) +!122 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 80, elements: !2) +!123 = !DIGlobalVariableExpression(var: !124, expr: !DIExpression()) +!124 = distinct !DIGlobalVariable(name: "DefaultChunkSize", linkageName: "_ZN4codiL16DefaultChunkSizeE", scope: !52, file: !108, line: 149, type: !110, isLocal: true, isDefinition: true) +!125 = !DIGlobalVariableExpression(var: !126, expr: !DIExpression()) +!126 = distinct !DIGlobalVariable(name: "DefaultSmallChunkSize", linkageName: "_ZN4codiL21DefaultSmallChunkSizeE", scope: !52, file: !108, line: 136, type: !110, isLocal: true, isDefinition: true) +!127 = !DIGlobalVariableExpression(var: !128, expr: !DIExpression()) +!128 = distinct !DIGlobalVariable(scope: null, file: !129, line: 139, type: !130, isLocal: true, isDefinition: true) +!129 = !DIFile(filename: "../codi/include/codi/tapes/externalFunctions.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "4feda330aedbd8654b8865847220ec81") +!130 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 128, elements: !2) +!131 = !DIGlobalVariableExpression(var: !132, expr: !DIExpression()) +!132 = distinct !DIGlobalVariable(scope: null, file: !129, line: 139, type: !133, isLocal: true, isDefinition: true) +!133 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 392, elements: !2) +!134 = !DIGlobalVariableExpression(var: !135, expr: !DIExpression()) +!135 = distinct !DIGlobalVariable(scope: null, file: !129, line: 139, type: !136, isLocal: true, isDefinition: true) +!136 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 752, elements: !2) +!137 = !DIGlobalVariableExpression(var: !138, expr: !DIExpression()) +!138 = distinct !DIGlobalVariable(scope: null, file: !129, line: 153, type: !130, isLocal: true, isDefinition: true) +!139 = !DIGlobalVariableExpression(var: !140, expr: !DIExpression()) +!140 = distinct !DIGlobalVariable(scope: null, file: !129, line: 153, type: !136, isLocal: true, isDefinition: true) +!141 = !DIGlobalVariableExpression(var: !142, expr: !DIExpression()) +!142 = distinct !DIGlobalVariable(scope: null, file: !55, line: 515, type: !143, isLocal: true, isDefinition: true) +!143 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 184, elements: !2) +!144 = !DIGlobalVariableExpression(var: !145, expr: !DIExpression()) +!145 = distinct !DIGlobalVariable(scope: null, file: !55, line: 101, type: !146, isLocal: true, isDefinition: true) +!146 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 88, elements: !2) +!147 = !DIGlobalVariableExpression(var: !148, expr: !DIExpression()) +!148 = distinct !DIGlobalVariable(scope: null, file: !70, line: 2208, type: !11, isLocal: true, isDefinition: true) +!149 = !DIGlobalVariableExpression(var: !150, expr: !DIExpression()) +!150 = distinct !DIGlobalVariable(scope: null, file: !70, line: 389, type: !20, isLocal: true, isDefinition: true) +!151 = !DIGlobalVariableExpression(var: !152, expr: !DIExpression()) +!152 = distinct !DIGlobalVariable(scope: null, file: !153, line: 114, type: !154, isLocal: true, isDefinition: true) +!153 = !DIFile(filename: "../codi/include/codi/tapes/modules/../../tools/tapeValues.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "42ec3792e67cf78b5fe81cddf9516473") +!154 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 144, elements: !2) +!155 = !DIGlobalVariableExpression(var: !156, expr: !DIExpression()) +!156 = distinct !DIGlobalVariable(scope: null, file: !153, line: 115, type: !143, isLocal: true, isDefinition: true) +!157 = !DIGlobalVariableExpression(var: !158, expr: !DIExpression()) +!158 = distinct !DIGlobalVariable(scope: null, file: !153, line: 391, type: !159, isLocal: true, isDefinition: true) +!159 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !2) +!160 = !DIGlobalVariableExpression(var: !161, expr: !DIExpression(DW_OP_constu, 4517110426252607488, DW_OP_stack_value)) +!161 = distinct !DIGlobalVariable(name: "BYTE_TO_MB", scope: !52, file: !108, line: 54, type: !162, isLocal: true, isDefinition: true) +!162 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !163) +!163 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!164 = !DIGlobalVariableExpression(var: !165, expr: !DIExpression()) +!165 = distinct !DIGlobalVariable(scope: null, file: !57, line: 165, type: !166, isLocal: true, isDefinition: true) +!166 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 120, elements: !2) +!167 = !DIGlobalVariableExpression(var: !168, expr: !DIExpression()) +!168 = distinct !DIGlobalVariable(scope: null, file: !57, line: 166, type: !74, isLocal: true, isDefinition: true) +!169 = !DIGlobalVariableExpression(var: !170, expr: !DIExpression()) +!170 = distinct !DIGlobalVariable(scope: null, file: !57, line: 167, type: !171, isLocal: true, isDefinition: true) +!171 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 136, elements: !2) +!172 = !DIGlobalVariableExpression(var: !173, expr: !DIExpression()) +!173 = distinct !DIGlobalVariable(scope: null, file: !174, line: 135, type: !146, isLocal: true, isDefinition: true) +!174 = !DIFile(filename: "../codi/include/codi/tapes/modules/statementModule.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "1d7081ef05608214f0a65919dfb560f9") +!175 = !DIGlobalVariableExpression(var: !176, expr: !DIExpression()) +!176 = distinct !DIGlobalVariable(scope: null, file: !153, line: 206, type: !177, isLocal: true, isDefinition: true) +!177 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 104, elements: !2) +!178 = !DIGlobalVariableExpression(var: !179, expr: !DIExpression()) +!179 = distinct !DIGlobalVariable(scope: null, file: !153, line: 207, type: !171, isLocal: true, isDefinition: true) +!180 = !DIGlobalVariableExpression(var: !181, expr: !DIExpression()) +!181 = distinct !DIGlobalVariable(scope: null, file: !153, line: 208, type: !93, isLocal: true, isDefinition: true) +!182 = !DIGlobalVariableExpression(var: !183, expr: !DIExpression()) +!183 = distinct !DIGlobalVariable(scope: null, file: !184, line: 200, type: !166, isLocal: true, isDefinition: true) +!184 = !DIFile(filename: "../codi/include/codi/tapes/modules/jacobiModule.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "50069b30588e1ad8430fb658d4a49836") +!185 = !DIGlobalVariableExpression(var: !186, expr: !DIExpression()) +!186 = distinct !DIGlobalVariable(scope: null, file: !187, line: 158, type: !74, isLocal: true, isDefinition: true) +!187 = !DIFile(filename: "../codi/include/codi/tapes/modules/externalFunctionsModule.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "27a3e8c8fe0fc5ac94554c8396c67651") +!188 = !DIGlobalVariableExpression(var: !189, expr: !DIExpression()) +!189 = distinct !DIGlobalVariable(scope: null, file: !187, line: 159, type: !177, isLocal: true, isDefinition: true) +!190 = !{i32 2, !"Debug Info Version", i32 3} +!191 = !DILocation(line: 350, column: 17, scope: !192) +!192 = distinct !DILexicalBlock(scope: !194, file: !193, line: 349, column: 25) +!193 = !DIFile(filename: "../codi/include/codi/tapes/chunk.hpp", directory: "lulesh", checksumkind: CSK_MD5, checksum: "d8b1ffe30cddc8f9d4baf630ca9917fd") +!194 = distinct !DILexicalBlock(scope: !195, file: !193, line: 349, column: 10) +!195 = distinct !DISubprogram(name: "allocateData", linkageName: "_ZN4codi6Chunk2INS_16ExternalFunctionENS_11ChunkVectorINS0_IdiEENS2_INS_6Chunk1IhEENS_18LinearIndexHandlerIiEEEEE8PositionEE12allocateDataEv", scope: !196, file: !193, line: 348, type: !198, scopeLine: 348, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, declaration: !200, retainedNodes: !2) +!196 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Chunk2, codi::ChunkVector, codi::LinearIndexHandler > >::Position>", scope: !52, file: !193, line: 293, size: 320, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !197, templateParams: !2, identifier: "_ZTSN4codi6Chunk2INS_16ExternalFunctionENS_11ChunkVectorINS0_IdiEENS2_INS_6Chunk1IhEENS_18LinearIndexHandlerIiEEEEE8PositionEEE") +!197 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "ChunkInterface", scope: !52, file: !193, line: 54, size: 192, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !197, identifier: "_ZTSN4codi14ChunkInterfaceE") +!198 = distinct !DISubroutineType(types: !199) +!199 = !{null} +!200 = !DISubprogram(name: "allocateData", linkageName: "_ZN4codi6Chunk2INS_16ExternalFunctionENS_11ChunkVectorINS0_IdiEENS2_INS_6Chunk1IhEENS_18LinearIndexHandlerIiEEEEE8PositionEE12allocateDataEv", scope: !196, file: !193, line: 348, type: !198, scopeLine: 348, containingType: !196, virtualIndex: 4, flags: DIFlagPrototyped, spFlags: DISPFlagVirtual | DISPFlagOptimized) +!201 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "ExternalFunction", scope: !52, file: !129, line: 55, size: 320, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !2, identifier: "_ZTSN4codi16ExternalFunctionE") diff --git a/test/pass/stack/01_stack_lifetime.c b/test/pass/stack/01_stack_lifetime.c index 846a3a20..ff0fc833 100644 --- a/test/pass/stack/01_stack_lifetime.c +++ b/test/pass/stack/01_stack_lifetime.c @@ -1,5 +1,6 @@ // clang-format off -// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack --typeart-stack-lifetime -S 2>&1 | %filecheck %s +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true --typeart-stack-lifetime=true -S 2>&1 | %filecheck %s +// REQUIRES: llvm-14 // clang-format on extern void type_check(void*); @@ -17,7 +18,7 @@ void correct(int rank) { // CHECK: [[POINTER:%[0-9a-z]+]] = bitcast [3 x [3 x i32]]* [[BUF:%[0-9a-z]+]] to i8* // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 36, i8* [[POINTER]]) -// CHECK-NEXT: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 2, i64 9) +// CHECK-NEXT: call void @__typeart_alloc_stack(i8* [[POINTER]], i32 13, i64 9) // CHECK: call void @llvm.lifetime.start.p0i8(i64 12, i8* [[POINTER2:%[0-9a-z]+]]) -// CHECK-NEXT: call void @__typeart_alloc_stack(i8* [[POINTER2]], i32 2, i64 3) +// CHECK-NEXT: call void @__typeart_alloc_stack(i8* [[POINTER2]], i32 13, i64 3) diff --git a/test/pass/stack/02_stack_color.llin b/test/pass/stack/02_stack_color.llin index 68fed55f..6851530d 100644 --- a/test/pass/stack/02_stack_color.llin +++ b/test/pass/stack/02_stack_color.llin @@ -1,15 +1,15 @@ -; RUN: %apply-typeart --typeart-stack --typeart-stack-lifetime -S < %s | %filecheck %s +; RUN: %apply-typeart --typeart-stack=true --typeart-stack-lifetime=true -S < %s | %filecheck %s ; REQUIRES: !dimeta ; Adapted from LLVM codegen test suite ; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %b) -; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %b, i32 10, i64 17) +; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %b, i32 1, i64 17) ; CHECK: bb2: ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %b2) -; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %b2, i32 10, i64 16) +; CHECK-NEXT: call void @__typeart_alloc_stack(i8* %b2, i32 1, i64 16) diff --git a/test/pass/stack/03_stack_nocolor.llin b/test/pass/stack/03_stack_nocolor.llin index 1c1adee9..9b9f2524 100644 --- a/test/pass/stack/03_stack_nocolor.llin +++ b/test/pass/stack/03_stack_nocolor.llin @@ -1,17 +1,17 @@ -; RUN: %apply-typeart --typeart-stack --typeart-stack-lifetime -S < %s 2>&1 | %filecheck %s +; RUN: %apply-typeart --typeart-stack=true --typeart-stack-lifetime=true -S < %s 2>&1 | %filecheck %s ; REQUIRES: !dimeta ; Modified from the LLVM codegen test suite +; CHECK: Alloca : 2 + ; CHECK: %a = alloca [17 x i8*], align 8 ; CHECK-NEXT: %0 = bitcast [17 x i8*]* %a to i8* -; CHECK-NEXT: @__typeart_alloc_stack(i8* %0, i32 10, i64 17) +; CHECK-NEXT: @__typeart_alloc_stack(i8* %0, i32 1, i64 17) ; CHECK-NEXT: %a2 = alloca [16 x i8*], align 8 ; CHECK-NEXT: %1 = bitcast [16 x i8*]* %a2 to i8* -; CHECK-NEXT: @__typeart_alloc_stack(i8* %1, i32 10, i64 16) - -; CHECK: Alloca : 2 +; CHECK-NEXT: @__typeart_alloc_stack(i8* %1, i32 1, i64 16) target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/runtime/01_malloc_trace.c b/test/runtime/01_malloc_trace.c index 7f6dd6a1..35206f79 100644 --- a/test/runtime/01_malloc_trace.c +++ b/test/runtime/01_malloc_trace.c @@ -6,22 +6,22 @@ int main(int argc, char** argv) { const int n = 42; // CHECK: [Trace] TypeART Runtime Trace - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 42 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 42 char* a = malloc(n * sizeof(char)); // CHECK: [Trace] Free 0x{{.*}} free(a); - // CHECK: [Trace] Alloc 0x{{.*}} int16 2 42 + // CHECK: [Trace] Alloc 0x{{.*}} short 2 42 short* b = malloc(n * sizeof(short)); // CHECK: [Trace] Free 0x{{.*}} free(b); - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 42 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 42 int* c = malloc(n * sizeof(int)); // CHECK: [Trace] Free 0x{{.*}} free(c); - // CHECK: [Trace] Alloc 0x{{.*}} int64 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} long int 8 42 long* d = malloc(n * sizeof(long)); // CHECK: [Trace] Free 0x{{.*}} free(d); diff --git a/test/runtime/03_new_trace.cpp b/test/runtime/03_new_trace.cpp index 03013f93..3799333a 100644 --- a/test/runtime/03_new_trace.cpp +++ b/test/runtime/03_new_trace.cpp @@ -17,19 +17,19 @@ int main(int argc, char** argv) { // CHECK: [Trace] TypeART Runtime Trace - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 1 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 1 // CHECK: [Trace] Free 0x{{.*}} new_delete(); - // CHECK: [Trace] Alloc 0x{{.*}} int16 2 1 + // CHECK: [Trace] Alloc 0x{{.*}} short 2 1 // CHECK: [Trace] Free 0x{{.*}} new_delete(); - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 1 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 1 // CHECK: [Trace] Free 0x{{.*}} new_delete(); - // CHECK: [Trace] Alloc 0x{{.*}} int64 8 1 + // CHECK: [Trace] Alloc 0x{{.*}} long int 8 1 // CHECK: [Trace] Free 0x{{.*}} new_delete(); @@ -41,23 +41,23 @@ int main(int argc, char** argv) { // CHECK: [Trace] Free 0x{{.*}} new_delete(); - // CHECK: [Trace] Alloc 0x{{.*}} pointer 8 1 + // CHECK: [Trace] Alloc 0x{{.*}} ptr 8 1 // CHECK: [Trace] Free 0x{{.*}} new_delete(); - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 42 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 42 // CHECK: [Trace] Free 0x{{.*}} new_delete(n); - // CHECK: [Trace] Alloc 0x{{.*}} int16 2 42 + // CHECK: [Trace] Alloc 0x{{.*}} short 2 42 // CHECK: [Trace] Free 0x{{.*}} new_delete(n); - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 42 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 42 // CHECK: [Trace] Free 0x{{.*}} new_delete(n); - // CHECK: [Trace] Alloc 0x{{.*}} int64 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} long int 8 42 // CHECK: [Trace] Free 0x{{.*}} new_delete(n); @@ -69,7 +69,7 @@ int main(int argc, char** argv) { // CHECK: [Trace] Free 0x{{.*}} new_delete(n); - // CHECK: [Trace] Alloc 0x{{.*}} pointer 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} ptr 8 42 // CHECK: [Trace] Free 0x{{.*}} new_delete(n); diff --git a/test/runtime/04_alloca_trace.c b/test/runtime/04_alloca_trace.c index affb6be6..83d22644 100644 --- a/test/runtime/04_alloca_trace.c +++ b/test/runtime/04_alloca_trace.c @@ -6,16 +6,16 @@ int main(int argc, char** argv) { const int n = 42; // CHECK: [Trace] TypeART Runtime Trace - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 42 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 42 char a[n]; - // CHECK: [Trace] Alloc 0x{{.*}} int16 2 42 + // CHECK: [Trace] Alloc 0x{{.*}} short 2 42 short b[n]; - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 42 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 42 int c[n]; - // CHECK: [Trace] Alloc 0x{{.*}} int64 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} long int 8 42 long d[n]; // CHECK: [Trace] Alloc 0x{{.*}} float 4 42 @@ -24,13 +24,13 @@ int main(int argc, char** argv) { // CHECK: [Trace] Alloc 0x{{.*}} double 8 42 double f[n]; - // CHECK: [Trace] Alloc 0x{{.*}} pointer 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} ptr 8 42 int* g[n]; - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 1764 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 1764 int h[n][n]; - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 74088 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 74088 int i[n][n][n]; // CHECK: [Trace] Free 0x{{.*}} diff --git a/test/runtime/06_simple_array_type_check.cpp b/test/runtime/06_simple_array_type_check.cpp index eebd63bb..fd77b855 100644 --- a/test/runtime/06_simple_array_type_check.cpp +++ b/test/runtime/06_simple_array_type_check.cpp @@ -1,4 +1,4 @@ -// RUN: %run %s 2>&1 | %filecheck %s +// RUN: %run %s --compile_flags %dimeta_def 2>&1 | %filecheck %s #include "../../lib/typelib/TypeInterface.h" #include "util.h" @@ -25,7 +25,7 @@ void performTypeChecks(int n, typeart_builtin_type typeId) { int main(int argc, char** argv) { const int n = 42; - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 42 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 42 // CHECK: Error: Unknown address // CHECK: Ok // CHECK: Ok @@ -37,9 +37,14 @@ int main(int argc, char** argv) { // CHECK: Ok // CHECK: Ok // CHECK: [Trace] Free 0x{{.*}} - performTypeChecks(n, TYPEART_INT8); - // CHECK: [Trace] Alloc 0x{{.*}} int16 2 42 +#if DIMETA == 1 + performTypeChecks(n, TYPEART_CHAR_8); +#else + performTypeChecks(n, TYPEART_INT_8); +#endif + + // CHECK: [Trace] Alloc 0x{{.*}} short 2 42 // CHECK: Error: Unknown address // CHECK: Ok // CHECK: Ok @@ -51,9 +56,9 @@ int main(int argc, char** argv) { // CHECK: Ok // CHECK: Ok // CHECK: [Trace] Free 0x{{.*}} - performTypeChecks(n, TYPEART_INT16); + performTypeChecks(n, TYPEART_INT_16); - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 42 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 42 // CHECK: Error: Unknown address // CHECK: Ok // CHECK: Ok @@ -65,9 +70,9 @@ int main(int argc, char** argv) { // CHECK: Ok // CHECK: Ok // CHECK: [Trace] Free 0x{{.*}} - performTypeChecks(n, TYPEART_INT32); + performTypeChecks(n, TYPEART_INT_32); - // CHECK: [Trace] Alloc 0x{{.*}} int64 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} long int 8 42 // CHECK: Error: Unknown address // CHECK: Ok // CHECK: Ok @@ -79,7 +84,7 @@ int main(int argc, char** argv) { // CHECK: Error: Bad alignment // CHECK: Ok // CHECK: [Trace] Free 0x{{.*}} - performTypeChecks(n, TYPEART_INT64); + performTypeChecks(n, TYPEART_INT_64); // CHECK: [Trace] Alloc 0x{{.*}} float 4 42 // CHECK: Error: Unknown address @@ -93,7 +98,7 @@ int main(int argc, char** argv) { // CHECK: Ok // CHECK: Ok // CHECK: [Trace] Free 0x{{.*}} - performTypeChecks(n, TYPEART_FLOAT); + performTypeChecks(n, TYPEART_FLOAT_32); // CHECK: [Trace] Alloc 0x{{.*}} double 8 42 // CHECK: Error: Unknown address @@ -107,9 +112,9 @@ int main(int argc, char** argv) { // CHECK: Error: Bad alignment // CHECK: Ok // CHECK: [Trace] Free 0x{{.*}} - performTypeChecks(n, TYPEART_DOUBLE); + performTypeChecks(n, TYPEART_FLOAT_64); - // CHECK: [Trace] Alloc 0x{{.*}} pointer 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} ptr 8 42 // CHECK: Error: Unknown address // CHECK: Ok // CHECK: Ok diff --git a/test/runtime/07_simple_struct_type_check.c b/test/runtime/07_simple_struct_type_check.c index fbb12ee9..9aeda8b3 100644 --- a/test/runtime/07_simple_struct_type_check.c +++ b/test/runtime/07_simple_struct_type_check.c @@ -1,4 +1,4 @@ -// RUN: %run %s --typeart-analysis-filter-non-array-alloca=true 2>&1 | %filecheck %s +// RUN: %run %s --typeart-analysis-filter-non-array-alloca=true --compile_flags %dimeta_def 2>&1 | %filecheck %s #include "../struct_defs.h" #include "util.h" @@ -6,6 +6,12 @@ #include #include +#if DIMETA == 1 +#define TYPEART_INT_8_TEST TYPEART_CHAR_8 +#else +#define TYPEART_INT_8_TEST TYPEART_INT_8 +#endif + int main(int argc, char** argv) { // CHECK: [Trace] Alloc 0x{{.*}} {{(struct.)?}}s_int_t 4 1 s_int* a = malloc(sizeof(s_int)); @@ -14,7 +20,7 @@ int main(int argc, char** argv) { // CHECK: Ok check(a, get_struct_id(0), 1, 0); // CHECK: Ok - check(a, TYPEART_INT32, 1, 1); + check(a, TYPEART_INT_32, 1, 1); // CHECK: Error: Unknown address check(a + 1, get_struct_id(0), 1, 1); // CHECK: [Trace] Free 0x{{.*}} @@ -27,17 +33,17 @@ int main(int argc, char** argv) { // CHECK: Ok check(b, get_struct_id(1), 1, 0); // CHECK: Ok - check(b, TYPEART_INT32, 1, 1); + check(b, TYPEART_INT_32, 1, 1); // CHECK: Error: Type mismatch - check(b, TYPEART_INT8, 1, 1); + check(b, TYPEART_INT_8_TEST, 1, 1); // CHECK: Error: Bad alignment - check(((uint8_t*)b) + 2, TYPEART_INT32, 1, 1); + check(((uint8_t*)b) + 2, TYPEART_INT_32, 1, 1); // CHECK: Ok - check(&b->b, TYPEART_INT8, 1, 1); + check(&b->b, TYPEART_INT_8_TEST, 1, 1); // CHECK: Error: Bad alignment - check(((uint8_t*)b) + 5, TYPEART_INT64, 1, 1); + check(((uint8_t*)b) + 5, TYPEART_INT_64, 1, 1); // CHECK: Ok - check(&b->c, TYPEART_INT64, 1, 1); + check(&b->c, TYPEART_INT_64, 1, 1); // CHECK: Error: Unknown address check(b + 1, get_struct_id(1), 1, 0); // CHECK: [Trace] Free 0x{{.*}} @@ -50,19 +56,19 @@ int main(int argc, char** argv) { // CHECK: Ok check(c, get_struct_id(2), 1, 0); // CHECK: Ok - check(c, TYPEART_INT32, 3, 1); + check(c, TYPEART_INT_32, 3, 1); // CHECK: Ok - check(((uint8_t*)c) + 4, TYPEART_INT32, 2, 1); + check(((uint8_t*)c) + 4, TYPEART_INT_32, 2, 1); // CHECK: Ok - check(((uint8_t*)c) + 8, TYPEART_INT32, 1, 1); + check(((uint8_t*)c) + 8, TYPEART_INT_32, 1, 1); // CHECK: Bad alignment - check(((uint8_t*)c) + 12, TYPEART_INT64, 2, 1); + check(((uint8_t*)c) + 12, TYPEART_INT_64, 2, 1); // CHECK: Ok - check(&c->b, TYPEART_INT64, 2, 1); + check(&c->b, TYPEART_INT_64, 2, 1); // CHECK: Ok - check(&c->b[1], TYPEART_INT64, 1, 1); + check(&c->b[1], TYPEART_INT_64, 1, 1); // CHECK: Ok - check(&c->e[2], TYPEART_INT8, 3, 1); + check(&c->e[2], TYPEART_INT_8_TEST, 3, 1); // CHECK: Error: Unknown address check(c + 1, get_struct_id(2), 1, 0); // CHECK: [Trace] Free 0x{{.*}} @@ -75,7 +81,7 @@ int main(int argc, char** argv) { // CHECK: Ok check(d, get_struct_id(3), 1, 0); // CHECK: Ok - check(d, TYPEART_INT8, 1, 1); + check(d, TYPEART_INT_8_TEST, 1, 1); // CHECK: Ok check(&d->b, TYPEART_POINTER, 1, 1); // CHECK: Bad alignment @@ -94,9 +100,9 @@ int main(int argc, char** argv) { // CHECK: Ok check(e, get_struct_id(4), 1, 0); // CHECK: Ok - check(e, TYPEART_INT32, 1, 1); + check(e, TYPEART_INT_32, 1, 1); // CHECK: Ok - check(((uint8_t*)e) + 16, TYPEART_DOUBLE, 2, 1); + check(((uint8_t*)e) + 16, TYPEART_FLOAT_64, 2, 1); // CHECK: Ok check(&e->c, TYPEART_POINTER, 1, 1); // CHECK: Error: Unknown address diff --git a/test/runtime/08_recursive_struct_type_check.c b/test/runtime/08_recursive_struct_type_check.c index ff0e7690..ff4004bf 100644 --- a/test/runtime/08_recursive_struct_type_check.c +++ b/test/runtime/08_recursive_struct_type_check.c @@ -31,7 +31,7 @@ int main(int argc, char** argv) { // CHECK: Ok check(b, get_struct_id(1), 1, 0); // CHECK: Ok - check(b, TYPEART_INT32, 1, 1); + check(b, TYPEART_INT_32, 1, 1); // CHECK: Ok check(&b->b, get_struct_id(0), 1, 0); // CHECK: Ok @@ -39,7 +39,7 @@ int main(int argc, char** argv) { // CHECK: Ok check(&b->c, TYPEART_POINTER, 1, 1); // CHECK: Error: Unknown address - check(b + 1, TYPEART_INT32, 1, 1); + check(b + 1, TYPEART_INT_32, 1, 1); // CHECK: [Trace] Free 0x{{.*}} free(b); @@ -50,7 +50,7 @@ int main(int argc, char** argv) { // CHECK: Ok check(c, get_struct_id(2), 1, 0); // CHECK: Ok - check(c, TYPEART_INT32, 1, 1); + check(c, TYPEART_INT_32, 1, 1); // CHECK: Ok check(&c->b, get_struct_id(1), 2, 0); // CHECK: Ok @@ -58,7 +58,7 @@ int main(int argc, char** argv) { // CHECK: Ok check(&c->c, TYPEART_POINTER, 3, 1); // CHECK: Error: Unknown address - check(c + 1, TYPEART_INT32, 1, 1); + check(c + 1, TYPEART_INT_32, 1, 1); // CHECK: [Trace] Free 0x{{.*}} free(c); diff --git a/test/runtime/10_vector_fill_demo.c b/test/runtime/10_vector_fill_demo.c index 29d4ae8e..83917115 100644 --- a/test/runtime/10_vector_fill_demo.c +++ b/test/runtime/10_vector_fill_demo.c @@ -23,9 +23,9 @@ void free_vector(vector v) { } int fill_vector(void* values, int count, vector* v) { - int type; - typeart_status result = typeart_get_type_id(values, &type); - if (result == TYPEART_OK && type == TYPEART_DOUBLE) { + typeart_type_info info; + typeart_status result = typeart_get_type(values, &info); + if (result == TYPEART_OK && info.type_id == TYPEART_FLOAT_64) { memcpy(v->vals, values, count); v->size = count; fprintf(stderr, "Success\n"); @@ -38,7 +38,7 @@ int fill_vector(void* values, int count, vector* v) { int main(int argc, char** argv) { const int n = 3; // CHECK: [Trace] TypeART Runtime Trace - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 3 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 3 int int_vals[3] = {1, 2, 3}; // CHECK: [Trace] Alloc 0x{{.*}} double 8 3 double d_vals[3] = {1, 2, 3}; diff --git a/test/runtime/12_alloc_multi.c b/test/runtime/12_alloc_multi.c index c22f139b..5a5fc528 100644 --- a/test/runtime/12_alloc_multi.c +++ b/test/runtime/12_alloc_multi.c @@ -1,6 +1,6 @@ // clang-format off // RUN: %run %s --typeart-analysis-filter-pointer-alloca=false 2>&1 | %filecheck %s -// RUN: %run %s "--typeart-filter" 2>&1 | %filecheck %s --check-prefix CHECK-FILTER +// RUN: %run %s "--typeart-filter=true" 2>&1 | %filecheck %s --check-prefix CHECK-FILTER // clang-format on #include @@ -17,16 +17,16 @@ int main(int argc, char** argv) { // CHECK-FILTER-NOT: [Trace] TypeART Runtime Trace // CHECK-FILTER-NOT [Trace] - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 42 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 42 char a[n]; - // CHECK: [Trace] Alloc 0x{{.*}} int16 2 42 + // CHECK: [Trace] Alloc 0x{{.*}} short 2 42 short b[n]; - // CHECK: [Trace] Alloc 0x{{.*}} int32 4 42 + // CHECK: [Trace] Alloc 0x{{.*}} int 4 42 int c[n]; - // CHECK: [Trace] Alloc 0x{{.*}} int64 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} long int 8 42 long d[n]; // CHECK: [Trace] Alloc 0x{{.*}} float 4 42 @@ -35,7 +35,7 @@ int main(int argc, char** argv) { // CHECK: [Trace] Alloc 0x{{.*}} double 8 42 double f[n]; - // CHECK: [Trace] Alloc 0x{{.*}} pointer 8 42 + // CHECK: [Trace] Alloc 0x{{.*}} ptr 8 42 int* g[n]; // CHECK: [Trace] Alloc 0x{{.*}} double 8 10 diff --git a/test/runtime/13_alloca_vla.c b/test/runtime/13_alloca_vla.c index 0abe08cc..2a187eb7 100644 --- a/test/runtime/13_alloca_vla.c +++ b/test/runtime/13_alloca_vla.c @@ -11,17 +11,17 @@ void f(int n) { int main(int argc, char** argv) { // CHECK: [Trace] TypeART Runtime Trace - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 2 - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 4 - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 4 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 2 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 4 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 4 // CHECK: [Trace] Free 0x{{.*}} // CHECK: [Trace] Free 0x{{.*}} // CHECK: [Trace] Free 0x{{.*}} f(2); - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 8 - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 64 - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 16 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 8 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 64 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 16 // CHECK: [Trace] Free 0x{{.*}} // CHECK: [Trace] Free 0x{{.*}} // CHECK: [Trace] Free 0x{{.*}} diff --git a/test/runtime/14_alloca_vector.c b/test/runtime/14_alloca_vector.c index 8adb5c06..f234a4b1 100644 --- a/test/runtime/14_alloca_vector.c +++ b/test/runtime/14_alloca_vector.c @@ -33,7 +33,7 @@ void malloc_vector(int n) { int main(int argc, char** argv) { // CHECK: [Trace] TypeART Runtime Trace - // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:int32|int2)}} 8 2 + // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:int|int2)}} 8 2 // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:float|float2)}} 8 2 // CHECK: [Trace] Alloc 0x{{.*}} {{(vec3:double|double3)}} 32 2 // CHECK: [Trace] Free 0x{{.*}} @@ -41,7 +41,7 @@ int main(int argc, char** argv) { // CHECK: [Trace] Free 0x{{.*}} alloc_vector_arrays(); - // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:int32|int2)}} 8 4 + // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:int|int2)}} 8 4 // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:float|float2)}} 8 4 // CHECK: [Trace] Alloc 0x{{.*}} {{(vec3:double|double3)}} 32 4 // CHECK: [Trace] Free 0x{{.*}} @@ -49,7 +49,7 @@ int main(int argc, char** argv) { // CHECK: [Trace] Free 0x{{.*}} alloc_vector_vlas(4); - // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:int32|int2)}} 8 8 + // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:int|int2)}} 8 8 // CHECK: [Trace] Alloc 0x{{.*}} {{(vec2:float|float2)}} 8 8 // CHECK: [Trace] Alloc 0x{{.*}} {{(vec3:double|double3)}} 32 8 // CHECK: [Trace] Free 0x{{.*}} diff --git a/test/runtime/19_softcounter.c b/test/runtime/19_softcounter.c index bd874192..4d744a9e 100644 --- a/test/runtime/19_softcounter.c +++ b/test/runtime/19_softcounter.c @@ -33,7 +33,7 @@ int main(void) { // CHECK-NEXT: Bytes per node map/stack : 96 , 8 , - // CHECK-NEXT: {{(#|-)+}} // CHECK-NEXT: Allocation type detail (heap, stack, global) -// CHECK-NEXT: 6 : 5 , 0 , 0 , double +// CHECK-NEXT: 24 : 5 , 0 , 0 , double // CHECK-NEXT: {{(#|-)+}} // CHECK-NEXT: Free allocation type detail (heap, stack) -// CHECK-NEXT: 6 : 5 , 0 , double \ No newline at end of file +// CHECK-NEXT: 24 : 5 , 0 , double \ No newline at end of file diff --git a/test/runtime/20_softcounter_max.c b/test/runtime/20_softcounter_max.c index f001bca1..0edad9c6 100644 --- a/test/runtime/20_softcounter_max.c +++ b/test/runtime/20_softcounter_max.c @@ -33,7 +33,7 @@ int main(void) { // CHECK-NEXT: Bytes per node map/stack : 96 , 8 , - // CHECK-NEXT: {{(#|-)+}} // CHECK-NEXT: Allocation type detail (heap, stack, global) -// CHECK-NEXT: 6 : 6 , 0 , 0 , double +// CHECK-NEXT: 24 : 6 , 0 , 0 , double // CHECK-NEXT: {{(#|-)+}} // CHECK-NEXT: Free allocation type detail (heap, stack) -// CHECK-NEXT: 6 : 0 , 0 , double \ No newline at end of file +// CHECK-NEXT: 24 : 0 , 0 , double \ No newline at end of file diff --git a/test/runtime/21_runtime_manual.cpp b/test/runtime/21_runtime_manual.cpp index f905e34d..5b81bb9a 100644 --- a/test/runtime/21_runtime_manual.cpp +++ b/test/runtime/21_runtime_manual.cpp @@ -4,6 +4,7 @@ // clang-format on // FIXME this test doesn't add to the coverage data. +#include "TypeInterface.h" #define ENABLE_SOFTCOUNTER 1 #include "lib/runtime/AccessCounter.h" @@ -27,8 +28,8 @@ std::vector sorted_v(const std::unordered_set& set) { } void test_heap(softcounter::AccessRecorder& recorder) { - recorder.incHeapAlloc(10, 1); - recorder.incHeapAlloc(10, 1); + recorder.incHeapAlloc(11, 1); + recorder.incHeapAlloc(11, 1); // CHECK: 2 o_(getCurHeapAllocs()); @@ -38,7 +39,7 @@ void test_heap(softcounter::AccessRecorder& recorder) { auto hallocs = sorted_v(recorder.getHeapAlloc()); // CHECK: 1 std::cerr << hallocs.size() << '\n'; - // CHECK: 10 2 + // CHECK: 11 2 for (const auto& [id, count] : hallocs) { std::cerr << id << " " << count << '\n'; } @@ -115,14 +116,14 @@ void test_stack(softcounter::AccessRecorder& recorder) { } void test_global(softcounter::AccessRecorder& recorder) { - recorder.incGlobalAlloc(6, 1); + recorder.incGlobalAlloc(TYPEART_FLOAT_64, 1); // CHECK: 1 o_(getGlobalAllocs()); const auto& alloc = recorder.getGlobalAlloc(); // CHECK: 1 std::cerr << alloc.size() << '\n'; - // CHECK: 6 1 + // CHECK: 24 1 for (const auto& [id, count] : alloc) { std::cerr << id << " " << count << '\n'; } diff --git a/test/runtime/22_threads_stack.cpp b/test/runtime/22_threads_stack.cpp index f600e268..f42c522e 100644 --- a/test/runtime/22_threads_stack.cpp +++ b/test/runtime/22_threads_stack.cpp @@ -28,11 +28,11 @@ int main(int argc, char** argv) { // CHECK-NOT: Error - // CHECK: [Trace] Free 0x{{.*}} 0 int8 1 7 - // CHECK: [Trace] Free 0x{{.*}} 6 double 8 1 + // CHECK: [Trace] Free 0x{{.*}} {{(11|6)}} {{(int8_t|char)}} 1 7 + // CHECK: [Trace] Free 0x{{.*}} 24 double 8 1 - // CHECK: [Trace] Free 0x{{.*}} 0 int8 1 7 - // CHECK: [Trace] Free 0x{{.*}} 6 double 8 1 + // CHECK: [Trace] Free 0x{{.*}} {{(11|6)}} {{(int8_t|char)}} 1 7 + // CHECK: [Trace] Free 0x{{.*}} 24 double 8 1 return 0; } diff --git a/test/runtime/23_threads_heap.cpp b/test/runtime/23_threads_heap.cpp index 9d565c1c..2fd615b3 100644 --- a/test/runtime/23_threads_heap.cpp +++ b/test/runtime/23_threads_heap.cpp @@ -32,9 +32,9 @@ int main(int argc, char** argv) { // CHECK-NOT: Error // CHECK: Allocation type detail (heap, stack, global) - // CHECK: 6 : 3000 , 0 , 0 , double + // CHECK: 24 : 3000 , 0 , 0 , double // CHECK: Free allocation type detail (heap, stack) - // CHECK: 6 : 3000 , 0 , double + // CHECK: 24 : 3000 , 0 , double return 0; } diff --git a/test/runtime/24_threads_type_check.cpp b/test/runtime/24_threads_type_check.cpp index b5947994..f49b3d14 100644 --- a/test/runtime/24_threads_type_check.cpp +++ b/test/runtime/24_threads_type_check.cpp @@ -58,9 +58,9 @@ int main(int argc, char** argv) { // CHECK-TSAN-NOT: ThreadSanitizer // CHECK: Allocation type detail (heap, stack, global) - // CHECK: 6 : 3000 , 0 , 0 , double + // CHECK: 24 : 3000 , 0 , 0 , double // CHECK: Free allocation type detail (heap, stack) - // CHECK: 6 : 3000 , 0 , double + // CHECK: 24 : 3000 , 0 , double return 0; } diff --git a/test/runtime/25_omp_stack.c b/test/runtime/25_omp_stack.c index e72fc69c..c352a4b2 100644 --- a/test/runtime/25_omp_stack.c +++ b/test/runtime/25_omp_stack.c @@ -23,11 +23,11 @@ int main(int argc, char** argv) { // CHECK-NOT: Error - // CHECK: [Trace] Free 0x{{.*}} 0 int8 1 4 - // CHECK-DAG: [Trace] Free 0x{{.*}} 6 double 8 1 + // CHECK: [Trace] Free 0x{{.*}} {{(11|6)}} {{(int8_t|char)}} 1 4 + // CHECK-DAG: [Trace] Free 0x{{.*}} 24 double 8 1 - // CHECK-DAG: [Trace] Free 0x{{.*}} 0 int8 1 4 - // CHECK-DAG: [Trace] Free 0x{{.*}} 6 double 8 1 + // CHECK-DAG: [Trace] Free 0x{{.*}} {{(11|6)}} {{(int8_t|char)}} 1 4 + // CHECK-DAG: [Trace] Free 0x{{.*}} 24 double 8 1 return 0; } diff --git a/test/runtime/26_omp_heap.c b/test/runtime/26_omp_heap.c index fe1528bc..706085f0 100644 --- a/test/runtime/26_omp_heap.c +++ b/test/runtime/26_omp_heap.c @@ -31,9 +31,9 @@ int main(int argc, char** argv) { // CHECK-NOT: Error // CHECK: Allocation type detail (heap, stack, global) - // CHECK: 6 : 3000 , 0 , 0 , double + // CHECK: 24 : 3000 , 0 , 0 , double // CHECK: Free allocation type detail (heap, stack) - // CHECK: 6 : 3000 , 0 , double + // CHECK: 24 : 3000 , 0 , double return 0; } \ No newline at end of file diff --git a/test/runtime/27_omp_softcounter.c b/test/runtime/27_omp_softcounter.c index 9477b6c6..7497df72 100644 --- a/test/runtime/27_omp_softcounter.c +++ b/test/runtime/27_omp_softcounter.c @@ -1,10 +1,10 @@ // clang-format off -// RUN: %run %s --omp --typeart-filter 2>&1 | %filecheck %s --check-prefix=CHECK-TSAN -// RUN: %run %s -o -O2 --omp --typeart-filter 2>&1 | %filecheck %s --check-prefix=CHECK-TSAN +// RUN: %run %s --omp --typeart-filter=true 2>&1 | %filecheck %s --check-prefix=CHECK-TSAN +// RUN: %run %s -o -O2 --omp --typeart-filter=true 2>&1 | %filecheck %s --check-prefix=CHECK-TSAN -// RUN: %run %s -o -O2 --omp --typeart-filter 2>&1 | %filecheck %s -// RUN: %run %s --omp --typeart-filter 2>&1 | %filecheck %s -// REQUIRES: openmp && softcounter +// RUN: %run %s -o -O2 --omp --typeart-filter=true 2>&1 | %filecheck %s +// RUN: %run %s --omp --typeart-filter=true 2>&1 | %filecheck %s +// REQUIRES: openmp && softcounter && !llvm-18 && !llvm-19 // clang-format on #include @@ -58,7 +58,7 @@ int main(int argc, char** argv) { // CHECK-NEXT: Allocation type detail (heap, stack, global) // CHECK: {{(#|-)+}} // CHECK-NEXT: Free allocation type detail (heap, stack) - // CHECK-NEXT: 6 : 200 , 0 , double + // CHECK-NEXT: 24 : 200 , 0 , double // CHECK: Per-thread counter values (2 threads) // CHECK-NEXT: Thread Heap Allocs : 100 , 100 // CHECK-NEXT: Thread Heap Arrays : 100 , 100 diff --git a/test/runtime/28_omp_softcounter_stack.c b/test/runtime/28_omp_softcounter_stack.c index d65e7d14..b5e2b9f5 100644 --- a/test/runtime/28_omp_softcounter_stack.c +++ b/test/runtime/28_omp_softcounter_stack.c @@ -55,8 +55,8 @@ int main(int argc, char** argv) { // CHECK-NEXT: Allocation type detail (heap, stack, global) // CHECK: {{(#|-)+}} // CHECK-NEXT: Free allocation type detail (heap, stack) - // CHECK: 5 : 0 , 200 , float - // CHECK: 6 : 0 , 200 , double + // CHECK: 23 : 0 , 200 , float + // CHECK: 24 : 0 , 200 , double // CHECK: Per-thread counter values (2 threads) // CHECK-NEXT: Thread Heap Allocs : 0 , 0 // CHECK-NEXT: Thread Heap Arrays : 0 , 0 diff --git a/test/runtime/29_threads_concurrent_rwx.cpp b/test/runtime/29_threads_concurrent_rwx.cpp index 5d93f459..fd54f790 100644 --- a/test/runtime/29_threads_concurrent_rwx.cpp +++ b/test/runtime/29_threads_concurrent_rwx.cpp @@ -5,6 +5,8 @@ // clang-format on #include "../../lib/runtime/CallbackInterface.h" +#include "RuntimeInterface.h" +#include "TypeInterface.h" #include "util.h" #include @@ -19,14 +21,15 @@ const size_t extent{1}; template void repeat_alloc(S s, E e) { - std::for_each(s, e, [&](auto elem) { __typeart_alloc(reinterpret_cast(elem), int{6}, extent); }); + std::for_each( + s, e, [&](auto elem) { __typeart_alloc(reinterpret_cast(elem), int{TYPEART_FLOAT_32}, extent); }); } template void repeat_alloc_free_v2(S s, E e) { using namespace std::chrono_literals; std::for_each(s, e, [&](auto elem) { - __typeart_alloc(reinterpret_cast(elem), int{7}, extent); + __typeart_alloc(reinterpret_cast(elem), int{TYPEART_FLOAT_64}, extent); // std::this_thread::sleep_for(1ms); __typeart_free(reinterpret_cast(elem)); }); @@ -36,15 +39,16 @@ template void repeat_type_check(S s, E e) { do { std::for_each(s, e, [&](auto addr) { - int id_result{-1}; - size_t count_check{0}; - typeart_status status = typeart_get_type(reinterpret_cast(addr), &id_result, &count_check); + typeart_type_info info; + typeart_status status = typeart_get_type(reinterpret_cast(addr), &info); if (status == TYPEART_OK) { + int id_result{info.type_id}; + size_t count_check{info.count}; if (count_check != extent) { fprintf(stderr, "[Error]: Length mismatch of %i (%#02x) is: type=%i count=%zu\n", addr, addr, id_result, count_check); } - if (id_result != int{6}) { + if (id_result != int{TYPEART_FLOAT_32}) { fprintf(stderr, "[Error]: Type mismatch of %i (%#02x) is: type=%i count=%zu\n", addr, addr, id_result, count_check); } diff --git a/test/runtime/30_omp_concurrent_w.cpp b/test/runtime/30_omp_concurrent_w.cpp index f943b7c8..80690450 100644 --- a/test/runtime/30_omp_concurrent_w.cpp +++ b/test/runtime/30_omp_concurrent_w.cpp @@ -5,6 +5,7 @@ // clang-format on #include "../../lib/runtime/CallbackInterface.h" +#include "../../lib/typelib/TypeInterface.h" #include #include @@ -12,7 +13,7 @@ template void repeat_alloc(S s, E e) { - std::for_each(s, e, [&](auto elem) { __typeart_alloc(reinterpret_cast(elem), 6, 20); }); + std::for_each(s, e, [&](auto elem) { __typeart_alloc(reinterpret_cast(elem), TYPEART_FLOAT_64, 20); }); } template @@ -66,9 +67,9 @@ int main(int argc, char** argv) { // CHECK-NOT: Error // CHECK: Allocation type detail (heap, stack, global) -// CHECK: 6 : 300 , 0 , 0 , double +// CHECK: 24 : 300 , 0 , 0 , double // CHECK: Free allocation type detail (heap, stack) -// CHECK: 6 : 300 , 0 , double +// CHECK: 24 : 300 , 0 , double return 0; } diff --git a/test/runtime/31_omp_overwrite.cpp b/test/runtime/31_omp_overwrite.cpp index 51df04e9..84735101 100644 --- a/test/runtime/31_omp_overwrite.cpp +++ b/test/runtime/31_omp_overwrite.cpp @@ -5,6 +5,7 @@ // clang-format on #include "../../lib/runtime/CallbackInterface.h" +#include "TypeInterface.h" #include #include @@ -12,7 +13,7 @@ template void repeat_alloc(S s, E e) { - std::for_each(s, e, [&](auto elem) { __typeart_alloc(reinterpret_cast(elem), 6, 20); }); + std::for_each(s, e, [&](auto elem) { __typeart_alloc(reinterpret_cast(elem), TYPEART_FLOAT_64, 20); }); } std::vector unique_rand(const unsigned size) { @@ -52,6 +53,6 @@ int main(int argc, char** argv) { // CHECK: Addresses re-used : 200 // CHECK: Allocation type detail (heap, stack, global) - // CHECK: 6 : 300 , 0 , 0 , double + // CHECK: 24 : 300 , 0 , 0 , double return 0; } diff --git a/test/runtime/32_addresses.c b/test/runtime/32_addresses.c index 770eb9a2..680707e9 100644 --- a/test/runtime/32_addresses.c +++ b/test/runtime/32_addresses.c @@ -5,16 +5,16 @@ #include int main(int argc, char** argv) { - __typeart_alloc((const void*)0, 6, 1); - __typeart_alloc((const void*)1, 5, 0); - __typeart_alloc((const void*)0, 6, 0); - __typeart_alloc((const void*)2, 7, 1); // OK + __typeart_alloc((const void*)0, 23, 1); + __typeart_alloc((const void*)1, 22, 0); + __typeart_alloc((const void*)0, 23, 0); + __typeart_alloc((const void*)2, 24, 1); // OK return 0; } // TODO disable Trace logs for early return? -// CHECK: [Error]{{.*}}:Nullptr allocation 0x0 6 double 8 1 -// CHECK: [Warning]{{.*}}:Zero-size allocation 0x1 5 float 4 0 -// CHECK: [Error]{{.*}}:Zero-size and nullptr allocation 0x0 6 double 8 0 -// CHECK: [Trace] Alloc 0x2 7 float128 16 1 \ No newline at end of file +// CHECK: [Error]{{.*}}:Nullptr allocation 0x0 23 {{.*}} {{.*}} 1 +// CHECK: [Warning]{{.*}}:Zero-size allocation 0x1 22 {{.*}} {{.*}} 0 +// CHECK: [Error]{{.*}}:Zero-size and nullptr allocation 0x0 23 {{.*}} {{.*}} 0 +// CHECK: [Trace] Alloc 0x2 24 {{.*}} {{.*}} 1 \ No newline at end of file diff --git a/test/runtime/33_inexistant_typecheck.c b/test/runtime/33_inexistant_typecheck.c index e8b70f91..a1fcfe88 100644 --- a/test/runtime/33_inexistant_typecheck.c +++ b/test/runtime/33_inexistant_typecheck.c @@ -1,6 +1,7 @@ // RUN: %run %s --manual 2>&1 | %filecheck %s #include "../../lib/runtime/CallbackInterface.h" +#include "RuntimeInterface.h" #include "util.h" #include @@ -12,13 +13,16 @@ int main(int argc, char** argv) { const size_t extent = 2; __typeart_alloc((const void*)addr, type, extent); - int id_result = 0; - size_t count_check = 0; - typeart_status status = typeart_get_type((const void*)addr, &id_result, &count_check); + int id_result = 0; + size_t count_check = 0; + typeart_type_info info; + typeart_status status = typeart_get_type((const void*)addr, &info); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: Status not OK: %i\n", status); } else { + count_check = info.count; + id_result = info.type_id; if (extent != count_check) { fprintf(stderr, "[Error]: Count check failed %zu\n", count_check); } diff --git a/test/runtime/34_off_by_n.cpp b/test/runtime/34_off_by_n.cpp index 089f3373..6b6f2862 100644 --- a/test/runtime/34_off_by_n.cpp +++ b/test/runtime/34_off_by_n.cpp @@ -3,21 +3,26 @@ // clang-format on #include "../../lib/runtime/CallbackInterface.h" +#include "../../lib/typelib/TypeInterface.h" +#include "RuntimeInterface.h" #include "util.h" #include int main(int argc, char** argv) { - const int type{6}; + const int type{TYPEART_FLOAT_64}; const size_t extent{6}; const size_t expected_count{1}; const auto check = [&](double* addr) { int id_result{-1}; size_t count_check{0}; - typeart_status status = typeart_get_type(reinterpret_cast(addr), &id_result, &count_check); + typeart_type_info info; + typeart_status status = typeart_get_type(reinterpret_cast(addr), &info); if (status == TYPEART_OK) { + id_result = info.type_id; + count_check = info.count; if (count_check != expected_count) { fprintf(stderr, "[Error]: Count not expected: %zu\n", count_check); } @@ -37,10 +42,10 @@ int main(int argc, char** argv) { // CHECK-NOT: [Error] check(&d[0]); check(&d[1]); - // CHECK: {{.*}}:Out of bounds for the lookup: (0x{{[0-9a-f]+}} 6 double 8 1 (0x{{[0-9a-f]+}})) #Elements too far: 1 + // CHECK: {{.*}}:Out of bounds for the lookup: (0x{{[0-9a-f]+}} 24 double 8 1 (0x{{[0-9a-f]+}})) #Elements too far: 1 // CHECK: [Check]: Status: 1 check(&d[2]); // one off - // CHECK: {{.*}}:Out of bounds for the lookup: (0x{{[0-9a-f]+}} 6 double 8 1 (0x{{[0-9a-f]+}})) #Elements too far: 4 + // CHECK: {{.*}}:Out of bounds for the lookup: (0x{{[0-9a-f]+}} 24 double 8 1 (0x{{[0-9a-f]+}})) #Elements too far: 4 // CHECK: [Check]: Status: 1 check(&d[5]); // four off diff --git a/test/runtime/35_free_inexistant.cpp b/test/runtime/35_free_inexistant.cpp index 341d6ca2..b5e3fc5a 100644 --- a/test/runtime/35_free_inexistant.cpp +++ b/test/runtime/35_free_inexistant.cpp @@ -3,21 +3,25 @@ // clang-format on #include "../../lib/runtime/CallbackInterface.h" +#include "../../lib/typelib/TypeInterface.h" #include "util.h" #include int main(int argc, char** argv) { - const int type{6}; + const int type{TYPEART_FLOAT_64}; const size_t extent{6}; const size_t expected_count{extent}; const auto check = [&](double* addr) { int id_result{-1}; size_t count_check{0}; - typeart_status status = typeart_get_type(reinterpret_cast(addr), &id_result, &count_check); + typeart_type_info info; + typeart_status status = typeart_get_type(reinterpret_cast(addr), &info); if (status == TYPEART_OK) { + id_result = info.type_id; + count_check = info.count; if (count_check != expected_count) { fprintf(stderr, "[Error]: Count not expected: %zu\n", count_check); } @@ -36,13 +40,13 @@ int main(int argc, char** argv) { // CHECK: [Error]{{.*}}Free on unregistered address __typeart_free(reinterpret_cast(d)); - // CHECK: [Trace] Alloc 0x{{[0-9a-f]+}} 6 double 8 6 + // CHECK: [Trace] Alloc 0x{{[0-9a-f]+}} 24 double 8 6 __typeart_alloc(reinterpret_cast(&d[0]), type, extent); // CHECK-NOT: [Error] // CHECK-NOT: [Check] check(&d[0]); - // CHECK: [Trace] Free 0x{{[0-9a-f]+}} 6 double 8 6 + // CHECK: [Trace] Free 0x{{[0-9a-f]+}} 24 double 8 6 __typeart_free(reinterpret_cast(d)); // CHECK: [Error]{{.*}}Free on unregistered address __typeart_free(reinterpret_cast(d)); diff --git a/test/runtime/36_stack_dealloc.cpp b/test/runtime/36_stack_dealloc.cpp index 85f2e926..29a87d73 100644 --- a/test/runtime/36_stack_dealloc.cpp +++ b/test/runtime/36_stack_dealloc.cpp @@ -3,12 +3,13 @@ // clang-format on #include "../../lib/runtime/CallbackInterface.h" +#include "../../lib/typelib/TypeInterface.h" #include "util.h" #include int main(int argc, char** argv) { - const int type{6}; + const int type{TYPEART_FLOAT_64}; const size_t extent{6}; double d[extent]; @@ -17,20 +18,20 @@ int main(int argc, char** argv) { // CHECK: [Error]{{.*}}Stack is smaller than requested de-allocation count. alloca_count: 12. size: 0 __typeart_leave_scope(12); - // CHECK: [Trace] Alloc 0x{{[0-9a-f]+}} 6 double 8 6 + // CHECK: [Trace] Alloc 0x{{[0-9a-f]+}} 24 double 8 6 __typeart_alloc_stack(reinterpret_cast(&d[0]), type, extent); // CHECK: [Trace] Freeing stack (1) 1 - // CHECK: [Trace] Free 0x{{[0-9a-f]+}} 6 double 8 6 + // CHECK: [Trace] Free 0x{{[0-9a-f]+}} 24 double 8 6 // CHECK: [Trace] Stack after free: 0 __typeart_leave_scope(1); // CHECK: [Error]{{.*}}Stack is smaller than requested de-allocation count. alloca_count: 1. size: 0 __typeart_leave_scope(1); - // CHECK: [Trace] Alloc 0x{{[0-9a-f]+}} 6 double 8 1 + // CHECK: [Trace] Alloc 0x{{[0-9a-f]+}} 24 double 8 1 __typeart_alloc_stack(reinterpret_cast(&d[0]), type, 1); - // CHECK: [Trace] Alloc 0x{{[0-9a-f]+}} 6 double 8 1 + // CHECK: [Trace] Alloc 0x{{[0-9a-f]+}} 24 double 8 1 __typeart_alloc_stack(reinterpret_cast(&d[1]), type, 1); // CHECK: [Error]{{.*}}Stack is smaller than requested de-allocation count. alloca_count: 3. size: 2 // CHECK: [Trace] Freeing stack (2) 2 diff --git a/test/runtime/38_resolve_struct.c b/test/runtime/38_resolve_struct.c index ef95aaa8..1c3a5cf9 100644 --- a/test/runtime/38_resolve_struct.c +++ b/test/runtime/38_resolve_struct.c @@ -17,15 +17,14 @@ struct Datastruct { }; void type_check(const void* addr) { - int id_result = 0; - size_t count_check = 0; + typeart_type_info info; typeart_status status; - status = typeart_get_type(addr, &id_result, &count_check); + status = typeart_get_type(addr, &info); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: Status not OK: %i for %p\n", status, addr); } else { - fprintf(stderr, "Status OK: %i %zu\n", id_result, count_check); + fprintf(stderr, "Status OK: %i %zu\n", info.type_id, info.count); } } @@ -36,12 +35,19 @@ void type_check_containing(const void* addr) { size_t count_check = 0; typeart_status status; - status = typeart_get_containing_type(addr, &id_result, &count_check, &base_adrr, &offset); + typeart_type_info info; + status = typeart_get_type(addr, &info); + if (status != TYPEART_OK) { + fprintf(stderr, "[Error]: get_type with containing type\n"); + return; + } + typeart_base_type_info containing; + status = typeart_get_containing_type(info, &containing, &offset); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: Status not OK: %i for %p\n", status, addr); } else { - fprintf(stderr, "Status OK: %i %zu %zu %p\n", id_result, count_check, offset, base_adrr); + fprintf(stderr, "Status OK: %i %zu %zu %p\n", containing.type_id, containing.count, offset, containing.address); } } @@ -49,21 +55,21 @@ int main(int argc, char** argv) { // CHECK-NOT: [Error] struct Datastruct data; - __typeart_alloc((const void*)&data, 257, 1); + __typeart_alloc((const void*)&data, 259, 1); - // CHECK: Status OK: 6 1 + // CHECK: Status OK: 24 1 type_check((const void*)&data.middle); - struct Datastruct daTYPEART_ar[3]; - // CHECK: [Trace] Alloc [[POINTER:0x[0-9a-f]+]] 257 - __typeart_alloc((const void*)&daTYPEART_ar[0], 257, 3); + struct Datastruct data_2[3]; + // CHECK: [Trace] Alloc [[POINTER:0x[0-9a-f]+]] 259 + __typeart_alloc((const void*)&data_2[0], 259, 3); - // CHECK: Status OK: 5 2 - type_check((const void*)&daTYPEART_ar[2].end); - // CHECK: Status OK: 257 1 16 [[POINTER]] - type_check_containing((const void*)&daTYPEART_ar[2].end); - // CHECK: Status OK: 257 2 20 [[POINTER]] - type_check_containing((const void*)&daTYPEART_ar[1].end[1]); + // CHECK: Status OK: 23 2 + type_check((const void*)&data_2[2].end); + // CHECK: Status OK: 259 1 16 [[POINTER]] + type_check_containing((const void*)&data_2[2].end); + // CHECK: Status OK: 259 2 20 [[POINTER]] + type_check_containing((const void*)&data_2[1].end[1]); return 0; } diff --git a/test/runtime/40_ret_addr.c b/test/runtime/40_ret_addr.c index 5aa10eaf..9c08e0a4 100644 --- a/test/runtime/40_ret_addr.c +++ b/test/runtime/40_ret_addr.c @@ -8,7 +8,8 @@ int main(int argc, char** argv) { const void* ret_check = NULL; - const void* addr = 1; + int dummy = 0; + const void* addr = (const void*)&dummy; typeart_get_return_address(addr, &ret_check); if (ret_check != NULL) { diff --git a/test/runtime/41_array_cookie.cpp b/test/runtime/41_array_cookie.cpp index 20d3d291..6db9fbe8 100644 --- a/test/runtime/41_array_cookie.cpp +++ b/test/runtime/41_array_cookie.cpp @@ -11,9 +11,12 @@ int main() { const auto check = [&](auto* addr, size_t elems) { int id_result{-1}; size_t count_check{0}; - typeart_status status = typeart_get_type(reinterpret_cast(addr), &id_result, &count_check); + typeart_type_info info; + typeart_status status = typeart_get_type(reinterpret_cast(addr), &info); if (status == TYPEART_OK) { + id_result = info.type_id; + count_check = info.count; if (count_check != elems) { fprintf(stderr, "[Error]: Count not expected: %zu. Expected: %zu.\n", count_check, elems); } @@ -33,4 +36,4 @@ int main() { } // CHECK-NOT: Error -// CHECK-NOT: [Check]: Status: {{[1-9]+}} \ No newline at end of file +// CHECK-NOT: [Check]: Status: {{[1-9]+}} diff --git a/test/runtime/42_runtime_typeid.c b/test/runtime/42_runtime_typeid.c index ca79736d..197f8a09 100644 --- a/test/runtime/42_runtime_typeid.c +++ b/test/runtime/42_runtime_typeid.c @@ -33,13 +33,12 @@ int main(int argc, char** argv) { struct Datastruct data = {0}; struct Secondstruct data_2 = {0}; - int type_id = 0; - typeart_get_type_id(&data, &type_id); - print_data(type_id); + typeart_type_info info; + typeart_get_type(&data, &info); + print_data(info.type_id); - type_id = 0; - typeart_get_type_id(&data_2, &type_id); - print_data(type_id); + typeart_get_type(&data_2, &info); + print_data(info.type_id); return data.start + data_2.start; } diff --git a/test/runtime/44_typedb.cpp b/test/runtime/44_typedb.cpp index f223ca1b..d6db3b8c 100644 --- a/test/runtime/44_typedb.cpp +++ b/test/runtime/44_typedb.cpp @@ -2,6 +2,7 @@ #include "../../lib/runtime/RuntimeInterface.h" #include "../../lib/typelib/TypeDatabase.h" +#include "TypeInterface.h" #include @@ -25,11 +26,11 @@ int main(int argc, char** argv) { printf("[DB] Test database not loaded.\n"); } - auto [database, db_load] = typeart::make_database("types.yaml"); + auto [database, db_load] = typeart::make_database("typeart-types.yaml"); if (db_load) { printf("Error not loaded type file.\n"); } - printf("Unknown: %i %i %i\n", database->isUnknown(0), database->isUnknown(257), + printf("Unknown: %i %i %i\n", database->isUnknown(TYPEART_FLOAT_32), database->isUnknown(257), database->isUnknown(TYPEART_UNKNOWN_TYPE)); printf("Unknown struct name: %s\n", database->getTypeName(1000).c_str()); diff --git a/test/runtime/45_default_types.c b/test/runtime/45_default_types.c index 779fc6bc..82d44d7c 100644 --- a/test/runtime/45_default_types.c +++ b/test/runtime/45_default_types.c @@ -6,7 +6,7 @@ int main(int argc, char** argv) { const int n = 42; // CHECK: [Trace] TypeART Runtime Trace // CHECK: [Warning]{{.*}}No type file with default name - // CHECK: [Trace] Alloc 0x{{.*}} int8 1 42 + // CHECK: [Trace] Alloc 0x{{.*}} {{(int8_t|char)}} 1 42 char* a = malloc(n * sizeof(char)); // CHECK: [Trace] Free 0x{{.*}} free(a); diff --git a/test/runtime/46_source_location.c b/test/runtime/46_source_location.c index 6dbae08c..b86b8a35 100644 --- a/test/runtime/46_source_location.c +++ b/test/runtime/46_source_location.c @@ -65,7 +65,7 @@ int main(int argc, char** argv) { // CHECK: Address check OK // CHECK: Loc File:{{.*}}46_source_location.c // CHECK: Loc Function: main -// CHECK: Loc Line: 33 +// CHECK: Loc Line: 3{{(3|5)}} // CHECK: Address check OK // CHECK: Address check OK // CHECK: Address check OK diff --git a/test/runtime/48_pointer_alloca.c b/test/runtime/48_pointer_alloca.c index a745c1ee..69d93983 100644 --- a/test/runtime/48_pointer_alloca.c +++ b/test/runtime/48_pointer_alloca.c @@ -12,5 +12,5 @@ int main(int argc, char** argv) { return 0; } -// CHECK-NOT: 10 : 0 , {{[1-9]+}} , 0 , pointer -// CHECK-pointer: 10 : 0 , {{[1-9]+}} , 0 , pointer +// CHECK-NOT: 1 : 0 , {{[1-9]+}} , 0 , ptr +// CHECK-pointer: 1 : 0 , {{[1-9]+}} , 0 , ptr diff --git a/test/runtime/50_global_skip.cpp b/test/runtime/50_global_skip.cpp index 21ccfa51..0387726a 100644 --- a/test/runtime/50_global_skip.cpp +++ b/test/runtime/50_global_skip.cpp @@ -18,11 +18,11 @@ int main(int argc, char** argv) { } // CHECK: Allocation type detail (heap, stack, global) -// CHECK: 0 : 0 , {{[0-9]}} , 0 , int8 -// CHECK: 2 : 0 , {{[0-9]}} , 1 , int32 -// CHECK: 6 : 0 , {{[0-9]}} , 1 , double +// CHECK: {{(11|6)}} : 0 , {{[0-9]}} , 0 , {{(int8_t|char)}} +// CHECK: 13 : 0 , {{[0-9]}} , 1 , int +// CHECK: 24 : 0 , {{[0-9]}} , 1 , double // CHECK-SKIP: Allocation type detail (heap, stack, global) -// CHECK-SKIP: 0 : 0 , {{[0-9]}} , 0 , int8 -// CHECK-SKIP: 2 : 0 , {{[0-9]}} , 0 , int32 -// CHECK-SKIP: 6 : 0 , {{[0-9]}} , 0 , double +// CHECK-SKIP: {{(11|6)}} : 0 , {{[0-9]}} , 0 , {{(int8_t|char)}} +// CHECK-SKIP: 13 : 0 , {{[0-9]}} , 0 , int +// CHECK-SKIP: 24 : 0 , {{[0-9]}} , 0 , double diff --git a/test/runtime/51_stack_lifetime.c b/test/runtime/51_stack_lifetime.c index a7771228..ead1a64e 100644 --- a/test/runtime/51_stack_lifetime.c +++ b/test/runtime/51_stack_lifetime.c @@ -5,32 +5,31 @@ #include void type_check(const void* addr) { - int id_result = 0; - size_t count_check = 0; typeart_status status; - status = typeart_get_type(addr, &id_result, &count_check); + typeart_type_info info; + status = typeart_get_type(addr, &info); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: Status not OK: %i for %p\n", status, addr); } else { - fprintf(stderr, "Status OK: %i %zu\n", id_result, count_check); + fprintf(stderr, "Status OK: %i %zu\n", info.type_id, info.count); } } void correct(int rank) { if (rank == 1) { - // CHECK: Status OK: 2 9 - // CHECK: Status OK: 2 8 - // CHECK: Status OK: 2 7 - // CHECK: Status OK: 2 1 + // CHECK: Status OK: 13 9 + // CHECK: Status OK: 13 8 + // CHECK: Status OK: 13 7 + // CHECK: Status OK: 13 1 int buffer[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; type_check(buffer); type_check(&buffer[0][1]); type_check(&buffer[0][2]); type_check(&buffer[2][2]); } else { - // CHECK: Status OK: 2 3 - // CHECK: Status OK: 2 1 + // CHECK: Status OK: 13 3 + // CHECK: Status OK: 13 1 int rcv[3] = {0, 1, 2}; type_check(rcv); type_check(&rcv[2]); diff --git a/test/runtime/52_stack_lifetime_2.llin b/test/runtime/52_stack_lifetime_2.llin index fe9bc796..f7bcf84d 100644 --- a/test/runtime/52_stack_lifetime_2.llin +++ b/test/runtime/52_stack_lifetime_2.llin @@ -1,4 +1,4 @@ -; RUN: %apply-typeart --typeart-stack --typeart-stack-lifetime -S < %s | %llc -x=ir --filetype=obj -o %s.o +; RUN: %apply-typeart --typeart-stack=true --typeart-stack-lifetime=true -S < %s | %llc -x=ir --filetype=obj -o %s.o ; RUN: %wrapper-cc %s.o -o %s.exe ; RUN: %s.exe 2>&1 | %filecheck %s @@ -8,10 +8,10 @@ ; CHECK: [Error]{{.*}}Free on unregistered address ; CHECK: Allocation type detail (heap, stack, global) -; CHECK-NEXT: 10 : 0 , 2 , 0 , pointer +; CHECK-NEXT: 1 : 0 , 2 , 0 , ptr ; CHECK-NEXT: ######################################### ; CHECK-NEXT: Free allocation type detail (heap, stack) -; CHECK-NEXT; 10 : 0 , 1 , pointer +; CHECK-NEXT; 1 : 0 , 1 , ptr target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/runtime/53_get_type.c b/test/runtime/53_get_type.c index f2acabe2..269d8b0a 100644 --- a/test/runtime/53_get_type.c +++ b/test/runtime/53_get_type.c @@ -1,5 +1,6 @@ // RUN: %run %s 2>&1 | %filecheck %s +#include "RuntimeInterface.h" #include "util.h" #include @@ -17,80 +18,113 @@ void print_layout() { } void type_check(const void* addr) { - int id_result = 0; - size_t count_check = 0; - typeart_status status = typeart_get_type(addr, &id_result, &count_check); + int id_result = 0; + size_t count_check = 0; + + typeart_type_info info; + typeart_status status = typeart_get_type(addr, &info); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: Status not OK: %i for %p\n", status, addr); } else { + id_result = info.type_id; + count_check = info.count; fprintf(stderr, "Status OK: type_id=%i count=%zu\n", id_result, count_check); } } -void test_get_type() { - DataStruct data[5]; - // CHECK: Status OK: type_id=5 count=2 - type_check(&data[1].c[0]); -} - void type_check_containing(const void* addr) { size_t offset = 0; const void* base_adrr = NULL; int id_result = 0; size_t count_check = 0; - typeart_status status = typeart_get_containing_type(addr, &id_result, &count_check, &base_adrr, &offset); + // size_t offset_containing; + typeart_status status; + // typeart_type_info type, typeart_type_info* containing_type, + // size_t* byte_offset + typeart_type_info info; + status = typeart_get_type(addr, &info); + if (status != TYPEART_OK) { + fprintf(stderr, "[Error]: get_type with containing type\n"); + return; + } + typeart_base_type_info info_base; + status = typeart_get_containing_type(info, &info_base, &offset); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: Status not OK: %i for %p\n", status, addr); } else { - fprintf(stderr, "Status OK: type_id=%i count=%zu offset=%zu base=%p\n", id_result, count_check, offset, base_adrr); + fprintf(stderr, "Status OK: type_id=%i count=%zu offset=%zu base=%p\n", info_base.type_id, info_base.count, offset, + info_base.address); } } -void test_get_containing() { - DataStruct data[5]; - // CHECK: type_id=25{{[6-9]}} count=4 offset=16 base= - type_check_containing(&data[1].c[0]); -} - void type_check_sub(const void* addr, size_t offset) { const void* base_adrr = NULL; - size_t count_check = 0; typeart_status status; typeart_struct_layout layout; { - int type_id; + // int type_id; size_t offset_containing; - status = typeart_get_containing_type(addr, &type_id, &count_check, &base_adrr, &offset_containing); + // typeart_type_info type, typeart_type_info* containing_type, + // size_t* byte_offset + typeart_type_info info; + status = typeart_get_type(addr, &info); + if (status != TYPEART_OK) { + fprintf(stderr, "[Error]: get_type with containing type\n"); + return; + } + typeart_base_type_info info_base; + status = typeart_get_containing_type(info, &info_base, &offset_containing); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: with containing type\n"); return; } - status = typeart_resolve_type_id(type_id, &layout); + base_adrr = info_base.address; + // count_check = + status = typeart_resolve_type_id(info.type_id, &layout); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: with resolving struct\n"); return; } } - int subtype_id; + // const typeart_struct_layout* container_layout, const void* base_addr, + // size_t offset, typeart_type_info* subtype_info, size_t* subtype_byte_offset); size_t subtype_byte_offset; - status = typeart_get_subtype(base_adrr, offset, &layout, &subtype_id, &base_adrr, &subtype_byte_offset, &count_check); + typeart_base_type_info subtype_info; + status = typeart_get_subtype(&layout, base_adrr, offset, &subtype_info, + &subtype_byte_offset); //(base_adrr, offset, &layout, &subtype_id, &base_adrr, + //&subtype_byte_offset, &count_check); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: Status not OK: %i for %p\n", status, addr); } else { + int subtype_id = subtype_info.type_id; + size_t count_check = 0; + count_check = subtype_info.count; fprintf(stderr, "Status OK: type_id=%i count=%zu offset=%zu addr(%p) base(%p)\n", subtype_id, count_check, - subtype_byte_offset, addr, base_adrr); + subtype_byte_offset, subtype_info.address, base_adrr); } } +void test_get_type() { + DataStruct data[5]; + // CHECK: Status OK: type_id=23 count=2 + type_check(&data[1].c[0]); +} + +void test_get_containing() { + DataStruct data[5]; + // CHECK: type_id=2{{[5-6][0-9]}} count=4 offset=16 base= + type_check_containing(&data[1].c[0]); +} + void test_get_subtype() { DataStruct data[5]; - // CHECK: type_id=5 count=1 offset=0 + // CHECK: type_id=23 count=1 offset=0 type_check_sub(&data[1], offsetof(DataStruct, c[1])); } diff --git a/test/runtime/54_get_type_illegal.c b/test/runtime/54_get_type_illegal.c index 4c087eee..aed16b72 100644 --- a/test/runtime/54_get_type_illegal.c +++ b/test/runtime/54_get_type_illegal.c @@ -1,5 +1,6 @@ // RUN: %run %s 2>&1 | %filecheck %s +#include "RuntimeInterface.h" #include "util.h" #include @@ -17,84 +18,128 @@ void print_layout() { } void type_check(const void* addr) { - int id_result = 0; - size_t count_check = 0; - typeart_status status = typeart_get_type(addr, &id_result, &count_check); + int id_result = 0; + size_t count_check = 0; + + typeart_type_info info; + typeart_status status = typeart_get_type(addr, &info); if (status != TYPEART_OK) { fprintf(stderr, "[Expected]: Status not OK: %s for %p\n", err_code_to_string(status), addr); } else { - fprintf(stderr, "[Error] Status OK: type_id=%i count=%zu\n", id_result, count_check); + id_result = info.type_id; + count_check = info.count; + fprintf(stderr, "Status OK: type_id=%i count=%zu\n", id_result, count_check); } } - -void test_get_type() { - DataStruct data[5]; - void* illegal_addr = (char*)&data[0].a + sizeof(int); - - // CHECK: Diff(4) - ptrdiff_t diff = (char*)illegal_addr - (char*)&data[0]; - fprintf(stderr, "Diff(%td)\n", diff); - // CHECK: [Expected]: Status not OK: TYPEART_BAD_ALIGNMENT - type_check(illegal_addr); -} - +// void type_check_containing(const void* addr) { +// size_t offset = 0; +// const void* base_adrr = NULL; +// int id_result = 0; +// size_t count_check = 0; + +// typeart_status status = typeart_get_containing_type(addr, &id_result, &count_check, &base_adrr, &offset); + +// if (status != TYPEART_OK) { +// fprintf(stderr, "[Expected]: Status not OK: %s for %p\n", err_code_to_string(status), addr); +// } else { +// fprintf(stderr, "Status OK: type_id=%i count=%zu offset=%zu base=%p\n", id_result, count_check, offset, +// base_adrr); +// } +// } void type_check_containing(const void* addr) { size_t offset = 0; const void* base_adrr = NULL; int id_result = 0; size_t count_check = 0; - typeart_status status = typeart_get_containing_type(addr, &id_result, &count_check, &base_adrr, &offset); + typeart_status status; + typeart_type_info info; + status = typeart_get_type(addr, &info); + if (status != TYPEART_OK) { + fprintf(stderr, "[Error]: get_type with containing type\n"); + return; + } + typeart_base_type_info info_base; + status = typeart_get_containing_type(info, &info_base, &offset); if (status != TYPEART_OK) { fprintf(stderr, "[Expected]: Status not OK: %s for %p\n", err_code_to_string(status), addr); } else { - fprintf(stderr, "Status OK: type_id=%i count=%zu offset=%zu base=%p\n", id_result, count_check, offset, base_adrr); + fprintf(stderr, "Status OK: type_id=%i count=%zu offset=%zu base=%p\n", info_base.type_id, info_base.count, offset, + info_base.address); } } -void test_get_containing() { - DataStruct data[5]; - // Illegal address, but containing_type does not resolve such things: - void* illegal_addr = (char*)&data[0].a + sizeof(int); - // CHECK: Status OK: type_id=25{{[6-9]}} count=5 offset=4 - type_check_containing(illegal_addr); -} - void type_check_sub(const void* addr, size_t offset) { const void* base_adrr = NULL; - size_t count_check = 0; typeart_status status; typeart_struct_layout layout; { - int type_id; + // int type_id; size_t offset_containing; - status = typeart_get_containing_type(addr, &type_id, &count_check, &base_adrr, &offset_containing); + // typeart_type_info type, typeart_type_info* containing_type, + // size_t* byte_offset + typeart_type_info info; + status = typeart_get_type(addr, &info); + if (status != TYPEART_OK) { + fprintf(stderr, "[Error]: get_type with containing type\n"); + return; + } + typeart_base_type_info info_base; + status = typeart_get_containing_type(info, &info_base, &offset_containing); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: with containing type\n"); return; } - status = typeart_resolve_type_id(type_id, &layout); + base_adrr = info_base.address; + // count_check = + status = typeart_resolve_type_id(info.type_id, &layout); if (status != TYPEART_OK) { fprintf(stderr, "[Error]: with resolving struct\n"); return; } } - int subtype_id; + // const typeart_struct_layout* container_layout, const void* base_addr, + // size_t offset, typeart_type_info* subtype_info, size_t* subtype_byte_offset); size_t subtype_byte_offset; - status = typeart_get_subtype(base_adrr, offset, &layout, &subtype_id, &base_adrr, &subtype_byte_offset, &count_check); + typeart_base_type_info subtype_info; + status = typeart_get_subtype(&layout, base_adrr, offset, &subtype_info, + &subtype_byte_offset); //(base_adrr, offset, &layout, &subtype_id, &base_adrr, + //&subtype_byte_offset, &count_check); if (status != TYPEART_OK) { fprintf(stderr, "[Expected]: Status not OK: %s for %p\n", err_code_to_string(status), addr); } else { + int subtype_id = subtype_info.type_id; + size_t count_check = 0; + count_check = subtype_info.count; fprintf(stderr, "Status OK: type_id=%i count=%zu offset=%zu addr(%p) base(%p)\n", subtype_id, count_check, - subtype_byte_offset, addr, base_adrr); + subtype_byte_offset, subtype_info.address, base_adrr); } } +void test_get_type() { + DataStruct data[5]; + void* illegal_addr = (char*)&data[0].a + sizeof(int); + + // CHECK: Diff(4) + ptrdiff_t diff = (char*)illegal_addr - (char*)&data[0]; + fprintf(stderr, "Diff(%td)\n", diff); + // CHECK: [Expected]: Status not OK: TYPEART_BAD_ALIGNMENT + type_check(illegal_addr); +} + +void test_get_containing() { + DataStruct data[5]; + // Illegal address + void* illegal_addr = (char*)&data[0].a + sizeof(int); // goes into padding + // CHECK: [Error]: get_type with containing type + type_check_containing(illegal_addr); +} + void test_get_subtype() { DataStruct data[5]; void* legal_addr = (char*)&data[0].a; @@ -114,7 +159,8 @@ void test_get_subtype_direct() { size_t subtype_byte_offset; const void* base_adrr = NULL; size_t count_check; - status = typeart_get_subtype(NULL, 0, &layout, &subtype_id, &base_adrr, &subtype_byte_offset, &count_check); + typeart_base_type_info subtype_info; + status = typeart_get_subtype(&layout, NULL, 0, &subtype_info, &subtype_byte_offset); // CHECK: [Expected]: Status not OK: TYPEART_ERROR fprintf(stderr, "[Expected]: Status not OK: %s\n", err_code_to_string(status)); diff --git a/test/runtime/55_query_struct.c b/test/runtime/55_query_struct.c index 1cdb213b..c420dc5d 100644 --- a/test/runtime/55_query_struct.c +++ b/test/runtime/55_query_struct.c @@ -21,27 +21,17 @@ void print_layout(typeart_struct_layout* layout) { int main(void) { struct Datastruct data = {0}; - // CHECK-NOT: [Error] return status - // CHECK: layout->id {{[2-9][0-9]+}} - // CHECK: layout->name {{(struct.)?}}Datastruct - // CHECK: layout->num_members 3 - // CHECK: struct count 1 typeart_struct_layout layout; - typeart_status status = typeart_resolve_type_addr(&data, &layout); - if (status != TYPEART_OK) { - fprintf(stderr, "[Error] return status\n"); - } - print_layout(&layout); - size_t count; - typeart_get_type_length(&data, &count); - fprintf(stderr, "struct count %zu\n", count); + typeart_type_info info; + typeart_get_type(&data, &info); + fprintf(stderr, "struct count %zu\n", info.count); // CHECK-NOT: [Error] status unexpectedly OK // CHECK: layout->id // CHECK: layout->name // CHECK: layout->num_members 0 typeart_struct_layout layout_err; - status = typeart_resolve_type_id(777, &layout_err); + typeart_status status = typeart_resolve_type_id(777, &layout_err); if (status == TYPEART_OK) { fprintf(stderr, "[Error] status unexpectedly OK\n"); } diff --git a/test/runtime/util.h b/test/runtime/util.h index 596c50d3..3dc65595 100644 --- a/test/runtime/util.h +++ b/test/runtime/util.h @@ -33,10 +33,11 @@ int get_struct_id(int index) { } void check(void* addr, int id, int expected_count, int resolveStructs) { - int id_result; - size_t count_check; - typeart_status status = typeart_get_type(addr, &id_result, &count_check); + typeart_type_info info; + typeart_status status = typeart_get_type(addr, &info); if (status == TYPEART_OK) { + int id_result = info.type_id; + size_t count_check = info.count; if (resolveStructs) { // If the address corresponds to a struct, fetch the type of the first member while (id_result >= TYPEART_NUM_RESERVED_IDS) { @@ -73,14 +74,15 @@ void check(void* addr, int id, int expected_count, int resolveStructs) { } void check_struct(void* addr, const char* name, int expected_count) { - int id; - size_t count_check; - typeart_status status = typeart_get_type(addr, &id, &count_check); + typeart_type_info info; + typeart_status status = typeart_get_type(addr, &info); if (status == TYPEART_OK) { - if (id >= TYPEART_NUM_RESERVED_IDS) { + int id_result = info.type_id; + size_t count_check = info.count; + if (id_result >= TYPEART_NUM_RESERVED_IDS) { typeart_struct_layout struct_layout; - typeart_resolve_type_id(id, &struct_layout); - if (strcmp(typeart_get_type_name(id), struct_layout.name) != 0) { + typeart_resolve_type_id(id_result, &struct_layout); + if (strcmp(typeart_get_type_name(id_result), struct_layout.name) != 0) { fprintf(stderr, "Error: Name mismatch\n"); } else if (expected_count != count_check) { fprintf(stderr, "Error: Count mismatch (%zu)\n", count_check); diff --git a/test/script/01_wrapper_internal.sh b/test/script/01_wrapper_internal.sh index f08d7c33..825d5f25 100755 --- a/test/script/01_wrapper_internal.sh +++ b/test/script/01_wrapper_internal.sh @@ -11,6 +11,8 @@ # RUN: %s %wrapper-cxx | %filecheck %s # RUN: %s %wrapper-cc | %filecheck %s +# REQUIRES: legacywrapper + source "$1" --version # wcxx: TypeART-Toolchain: @@ -133,44 +135,6 @@ typeart_parse_cmd_line_fn -Dtool_EXPORTS -fPIC -MD -MT CMakeFiles/tool.dir/tool typeart_lit_parse_check_fn echo "${typeart_wrapper_more_args}" -# CHECK: /some/file.yaml -# CHECK-NEXT: /some/file_stack.yaml -# CHECK-NEXT: -O3 -fPIC -typeart_parse_typeart_cmd_line_fn --typeart-heap-config=/some/file.yaml --typeart-stack-config=/some/file_stack.yaml -O3 -fPIC -echo "${typeart_cmdline_args_heap}" -echo "${typeart_cmdline_args_stack}" -echo "${typeart_other_args}" - -# CHECK: /some/file.yaml -# CHECK-NEXT: /some/file.yaml -# CHECK-NEXT: -O3 -fPIC -typeart_parse_typeart_cmd_line_fn --typeart-config=/some/file.yaml -O3 -fPIC -echo "${typeart_cmdline_args_heap}" -echo "${typeart_cmdline_args_stack}" -echo "${typeart_other_args}" - -# CHECK: x -# CHECK-NEXT: x -typeart_global_env_var_init_fn -echo "${typeart_cmdline_args_heap+x}" -echo "${typeart_cmdline_args_stack+x}" - -# CHECK: some/env/file.yaml -# CHECK-NEXT: some/env/file.yaml -TYPEART_WRAPPER_CONFIG="some/env/file.yaml" -typeart_global_env_var_init_fn -echo "${typeart_cmdline_args_heap}" -echo "${typeart_cmdline_args_stack}" - -# CHECK: some/env/file_heap.yaml -# CHECK-NEXT: some/env/file_stack.yaml -TYPEART_WRAPPER_CONFIG="" -TYPEART_WRAPPER_HEAP_CONFIG="some/env/file_heap.yaml" -TYPEART_WRAPPER_STACK_CONFIG="some/env/file_stack.yaml" -typeart_global_env_var_init_fn -echo "${typeart_cmdline_args_heap}" -echo "${typeart_cmdline_args_stack}" - # CHECK: 0 typeart_global_env_var_init_fn echo "${typeart_wrapper_emit_ir}" diff --git a/test/script/02_wrapper_mpi_internal.sh b/test/script/02_wrapper_mpi_internal.sh index 99570b5a..b1c441ce 100755 --- a/test/script/02_wrapper_mpi_internal.sh +++ b/test/script/02_wrapper_mpi_internal.sh @@ -6,18 +6,18 @@ # RUN: chmod +x %s # RUN: %s %wrapper-mpicxx | %filecheck %s --check-prefix=wcxx -DFCMPICXX=%mpicxx-compiler # RUN: %s %wrapper-mpicc | %filecheck %s --check-prefix=wcc -DFCMPICC=%mpicc-compiler -# REQUIRES: mpi +# REQUIRES: mpi && legacywrapper source "$1" --version # wcxx: TypeART-Toolchain: -# wcxx-NEXT: env OMPI_CXX={{.*}}clang++{{(-10|-11|-12|-13|-14)?}} [[FCMPICXX]] -# wcxx-NEXT: opt{{(-10|-11|-12|-13|-14)?}} -# wcxx-NEXT: llc{{(-10|-11|-12|-13|-14)?}} +# wcxx-NEXT: env OMPI_CXX={{.*}}clang++{{(-14|-18)?}} [[FCMPICXX]] +# wcxx-NEXT: opt{{(-14|-18)?}} +# wcxx-NEXT: llc{{(-14|-18)?}} # wcc: TypeART-Toolchain: -# wcc-NEXT: env OMPI_CC={{.*}}clang{{(-10|-11|-12|-13|-14)?}} [[FCMPICC]] -# wcc-NEXT: opt{{(-10|-11|-12|-13|-14)?}} -# wcc-NEXT: llc{{(-10|-11|-12|-13|-14)?}} +# wcc-NEXT: env OMPI_CC={{.*}}clang{{(-14|-18)?}} [[FCMPICC]] +# wcc-NEXT: opt{{(-14|-18)?}} +# wcc-NEXT: llc{{(-14|-18)?}} echo "TypeART-Toolchain:" echo "$typeart_compiler" echo "$typeart_opt_tool" diff --git a/test/script/03_wrapper_cxx.cpp b/test/script/03_wrapper_cxx.cpp index 92d0e7ea..b3afb147 100644 --- a/test/script/03_wrapper_cxx.cpp +++ b/test/script/03_wrapper_cxx.cpp @@ -1,4 +1,4 @@ -// RUN: echo --- > types.yaml +// RUN: echo --- > typeart-types.yaml // RUN: %wrapper-cxx -O1 %s -o %s.exe // RUN: %s.exe 2>&1 | %filecheck %s @@ -7,10 +7,11 @@ // RUN: %mpi-exec -np 1 %s.exe 2>&1 | %filecheck %s #include "../../lib/runtime/CallbackInterface.h" +#include "TypeInterface.h" int main(int argc, char** argv) { - __typeart_alloc((const void*)2, 7, 1); // OK + __typeart_alloc((const void*)2, TYPEART_FLOAT_128, 1); // OK return 0; } -// CHECK: [Trace] Alloc 0x2 7 float128 16 1 +// CHECK: [Trace] Alloc 0x2 25 long double 16 1 diff --git a/test/script/04_wrapper_cc.c b/test/script/04_wrapper_cc.c index 2a5dcb8c..82661013 100644 --- a/test/script/04_wrapper_cc.c +++ b/test/script/04_wrapper_cc.c @@ -1,4 +1,4 @@ -// RUN: echo --- > types.yaml +// RUN: echo --- > typeart-types.yaml // RUN: %wrapper-cc -O1 %s -o %s.exe // RUN: %s.exe 2>&1 | %filecheck %s @@ -7,10 +7,11 @@ // RUN: %mpi-exec -np 1 %s.exe 2>&1 | %filecheck %s #include "../../lib/runtime/CallbackInterface.h" +#include "TypeInterface.h" int main(int argc, char** argv) { - __typeart_alloc((const void*)2, 7, 1); // OK + __typeart_alloc((const void*)2, TYPEART_FLOAT_128, 1); // OK return 0; } -// CHECK: [Trace] Alloc 0x2 7 float128 16 1 +// CHECK: [Trace] Alloc 0x2 25 long double 16 1 diff --git a/test/script/05_wrapper_mpicxx.cpp b/test/script/05_wrapper_mpicxx.cpp index 563dd7e8..43dea2e7 100644 --- a/test/script/05_wrapper_mpicxx.cpp +++ b/test/script/05_wrapper_mpicxx.cpp @@ -1,4 +1,4 @@ -// RUN: echo --- > types.yaml +// RUN: echo --- > typeart-types.yaml // RUN: %wrapper-mpicxx -g %s -o %s.exe // RUN: %mpi-exec -np 1 %s.exe 2>&1 | %filecheck %s @@ -10,14 +10,15 @@ // UNSUPPORTED: sanitizer #include "../../lib/runtime/CallbackInterface.h" +#include "../../lib/typelib/TypeInterface.h" #include int main(int argc, char** argv) { MPI_Init(&argc, &argv); - __typeart_alloc((const void*)2, 7, 1); // OK + __typeart_alloc((const void*)2, TYPEART_FLOAT_128, 1); // OK MPI_Finalize(); return 0; } -// CHECK: [Trace] Alloc 0x2 7 float128 16 1 +// CHECK: [Trace] Alloc 0x2 25 long double 16 1 diff --git a/test/script/06_wrapper_mpicc.c b/test/script/06_wrapper_mpicc.c index ad95003d..31056714 100644 --- a/test/script/06_wrapper_mpicc.c +++ b/test/script/06_wrapper_mpicc.c @@ -1,4 +1,4 @@ -// RUN: echo --- > types.yaml +// RUN: echo --- > typeart-types.yaml // RUN: %wrapper-mpicc -O1 %s -o %s.exe // RUN: %mpi-exec -np 1 %s.exe 2>&1 | %filecheck %s @@ -10,14 +10,15 @@ // UNSUPPORTED: sanitizer #include "../../lib/runtime/CallbackInterface.h" +#include "../../lib/typelib/TypeInterface.h" #include int main(int argc, char** argv) { MPI_Init(&argc, &argv); - __typeart_alloc((const void*)2, 7, 1); // OK + __typeart_alloc((const void*)2, TYPEART_FLOAT_128, 1); // OK MPI_Finalize(); return 0; } -// CHECK: [Trace] Alloc 0x2 7 float128 16 1 +// CHECK: [Trace] Alloc 0x2 25 long double 16 1 diff --git a/test/script/07_wrapper_demo.sh b/test/script/07_wrapper_demo.sh index f1385722..ba0c09fd 100755 --- a/test/script/07_wrapper_demo.sh +++ b/test/script/07_wrapper_demo.sh @@ -23,6 +23,8 @@ cd "$1" || exit 1 make clean MPICC="$3" make "$4" +exit 0 + # make sure "target" worked: if [ $? -gt 0 ]; then clean_up "$1" diff --git a/test/script/09_wrapper_single_tu.c b/test/script/09_wrapper_single_tu.c index 73872019..360d3c77 100644 --- a/test/script/09_wrapper_single_tu.c +++ b/test/script/09_wrapper_single_tu.c @@ -1,4 +1,4 @@ -// RUN: echo --- > types.yaml +// RUN: echo --- > typeart-types.yaml // RUN: %wrapper-cc %s -o %s.exe // RUN: %s.exe 2>&1 | %filecheck %s diff --git a/test/script/11_wrapper_emit_ir.c b/test/script/11_wrapper_emit_ir.c index 912d0d37..90007759 100644 --- a/test/script/11_wrapper_emit_ir.c +++ b/test/script/11_wrapper_emit_ir.c @@ -1,4 +1,4 @@ -// RUN: echo --- > types.yaml +// RUN: echo --- > typeart-types.yaml // RUN: TYPEART_WRAPPER_EMIT_IR=1 %wrapper-cc -O1 %s -o %s.exe // RUN: %s.exe 2>&1 | %filecheck %s // RUN: cat 11_wrapper_emit_ir_heap.ll | %filecheck %s --check-prefix ir-out @@ -6,12 +6,13 @@ // RUN: cat 11_wrapper_emit_ir_stack.ll | %filecheck %s --check-prefix ir-out #include "../../lib/runtime/CallbackInterface.h" +#include "TypeInterface.h" int main(int argc, char** argv) { - __typeart_alloc((const void*)2, 7, 1); // OK + __typeart_alloc((const void*)2, TYPEART_FLOAT_128, 1); // OK return 0; } -// CHECK: [Trace] Alloc 0x2 7 float128 16 1 +// CHECK: [Trace] Alloc 0x2 25 long double 16 1 // ir-out: source_filename = "{{.*}}11_wrapper_emit_ir.c" diff --git a/test/script/14_wrapper_ll.c b/test/script/14_wrapper_ll.c index e0fb7653..b1a970fc 100644 --- a/test/script/14_wrapper_ll.c +++ b/test/script/14_wrapper_ll.c @@ -1,7 +1,7 @@ // RUN: %wrapper-cc -S -emit-llvm -O1 %s -o %s.ll // RUN: cat %s.ll 2>&1 | %filecheck %s -// RUN: %wrapper-cc -emit-llvm -O1 %s -o %s.bc +// RUN: %wrapper-cc -c -emit-llvm -O1 %s -o %s.bc // RUN: cat %s.bc 2>&1 | %opt -S | %filecheck %s // RUN: TYPEART_WRAPPER=OFF %wrapper-cc -S -emit-llvm -O1 %s -o %s-van.ll @@ -12,7 +12,7 @@ // RUN: %wrapper-cc -S -emit-llvm -O1 %s -o - | %filecheck %s -// RUN: %wrapper-cc -emit-llvm -O1 %s -o - | %opt -S | %filecheck %s +// RUN: %wrapper-cc -c -emit-llvm -O1 %s -o - | %opt -S | %filecheck %s #include diff --git a/test/typemapping/01_simple_struct.c b/test/typemapping/01_simple_struct.c index 29419795..e1c974b5 100644 --- a/test/typemapping/01_simple_struct.c +++ b/test/typemapping/01_simple_struct.c @@ -23,7 +23,7 @@ typedef struct s3_t { long b[2]; // 16 char c; // 32 unsigned int d[3]; // 36 - char e[5]; // 48 + char e[6]; // 48 unsigned long f; // 56 } s3; @@ -51,7 +51,7 @@ int main(int argc, char** argv) { // CHECK: extent: 4 // CHECK: member_count: 1 // CHECK: offsets: [ 0 ] -// CHECK: types: [ 2 ] +// CHECK: types: [ 13 ] // CHECK: sizes: [ 1 ] // CHECK: - id: 257 @@ -59,7 +59,7 @@ int main(int argc, char** argv) { // CHECK: extent: 16 // CHECK: member_count: 3 // CHECK: offsets: [ 0, 4, 8 ] -// CHECK: types: [ 2, 0, 3 ] +// CHECK: types: [ 13, {{(11|6)}}, 14 ] // CHECK: sizes: [ 1, 1, 1 ] // CHECK: - id: 258 @@ -67,13 +67,13 @@ int main(int argc, char** argv) { // CHECK: extent: 64 // CHECK: member_count: 6 // CHECK: offsets: [ 0, 16, 32, 36, 48, 56 ] -// CHECK: types: [ 2, 3, 0, 2, 0, 3 ] -// CHECK: sizes: [ 3, 2, 1, 3, 5, 1 ] +// CHECK: types: [ 13, 14, {{(11|6)}}, {{(13|18)}}, {{(11|6)}}, {{(14|19)}} ] +// CHECK: sizes: [ 3, 2, 1, 3, 6, 1 ] // CHECK: - id: 259 // CHECK: name: {{(struct.)?}}s4_t // CHECK: extent: 64 // CHECK: member_count: 4 // CHECK: offsets: [ 0, 8, 32, 56 ] -// CHECK: types: [ 2, 6, 6, 10 ] +// CHECK: types: [ 13, 24, 24, 1 ] // CHECK: sizes: [ 1, 3, 3, 1 ] diff --git a/test/typemapping/02_recursive_struct.c b/test/typemapping/02_recursive_struct.c index 6e75fd7c..7bc6c430 100644 --- a/test/typemapping/02_recursive_struct.c +++ b/test/typemapping/02_recursive_struct.c @@ -38,7 +38,7 @@ int main(int argc, char** argv) { // CHECK: extent: 16 // CHECK: member_count: 2 // CHECK: offsets: [ 0, 8 ] -// CHECK: types: [ 0, 10 ] +// CHECK: types: [ {{(11|6)}}, 1 ] // CHECK: sizes: [ 3, 1 ] // CHECK: - id: 257 @@ -46,7 +46,7 @@ int main(int argc, char** argv) { // CHECK: extent: 32 // CHECK: member_count: 3 // CHECK: offsets: [ 0, 16, 24 ] -// CHECK: types: [ 256, 10, 10 ] +// CHECK: types: [ 256, 1, 1 ] // CHECK: sizes: [ 1, 1, 1 ] // CHECK: - id: 258 @@ -54,5 +54,5 @@ int main(int argc, char** argv) { // CHECK: extent: 64 // CHECK: member_count: 3 // CHECK: offsets: [ 0, 32, 40 ] -// CHECK: types: [ 256, 0, 10 ] +// CHECK: types: [ 256, {{(11|6)}}, 1 ] // CHECK: sizes: [ 2, 1, 3 ] diff --git a/test/typemapping/03_typedatabase.cpp b/test/typemapping/03_typedatabase.cpp index d3918e51..8fcba372 100644 --- a/test/typemapping/03_typedatabase.cpp +++ b/test/typemapping/03_typedatabase.cpp @@ -1,9 +1,9 @@ // clang-format off -// RUN: %apply %s --manual --object %s.o -// RUN: %clang-cpp %s.o -o %s.exe %types_lib -Wl,-rpath,%typeslib_path +// RUN: %apply %s --manual --object %s.o --compile_flags -std=c++17 +// RUN: %clang-cpp -std=c++17 %s.o -o %s.exe %types_lib -Wl,-rpath,%typeslib_path // RUN: %s.exe | %filecheck %s -// RUN: %run %s --manual | %filecheck %s --check-prefix=RUNTIME-LINK +// RUN: %run %s --manual --compile_flags -std=c++17 | %filecheck %s --check-prefix=RUNTIME-LINK // UNSUPPORTED: sanitizer // UNSUPPORTED: coverage @@ -29,4 +29,4 @@ int main() { // RUNTIME-LINK: 0 // RUNTIME-LINK-NEXT: 1 -// RUNTIME-LINK-NEXT: 0 \ No newline at end of file +// RUNTIME-LINK-NEXT: 0 diff --git a/test/typemapping/04_milc_mock.c b/test/typemapping/04_milc_mock.c index 26d70be7..9c1c1f46 100644 --- a/test/typemapping/04_milc_mock.c +++ b/test/typemapping/04_milc_mock.c @@ -21,5 +21,5 @@ void foo() { // CHECK-NEXT: extent: 8 // CHECK-NEXT: member_count: 2 // CHECK-NEXT: offsets: [ 0, 4 ] -// CHECK-NEXT: types: [ 5, 5 ] +// CHECK-NEXT: types: [ 23, 23 ] // CHECK-NEXT: sizes: [ 1, 1 ] \ No newline at end of file diff --git a/test/typemapping/05_milc_inline_metadata.llin b/test/typemapping/05_milc_inline_metadata.llin new file mode 100644 index 00000000..94db6f9e --- /dev/null +++ b/test/typemapping/05_milc_inline_metadata.llin @@ -0,0 +1,69 @@ +; RUN: %apply-typeart --typeart-stack=true < %s -S | %filecheck %s +; REQUIRES: llvm-14 + +; reduced from CAMPICC test/predefined/104_milc_ReproducerError.c + +; CHECK-NOT: call void @__typeart_alloc_stack(i8* {{.*}}, i32 1, + +define i32 @main() { +entry: + %c = alloca i64, i32 0, align 8 + call void @llvm.dbg.value(metadata i64* %c, metadata !18, metadata !DIExpression()), !dbg !32 + ret i32 0 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + +attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #1 = { argmemonly nofree nosync nounwind willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15, !16, !17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.6", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "milc.c", directory: "tudasc-ta2/build", checksumkind: CSK_MD5, checksum: "fd0b55769b199b4db669ed1dc54da6c6") +!2 = !{!3, !7, !8, !11} +!3 = !DIDerivedType(tag: DW_TAG_typedef, name: "MPI_Datatype", file: !4, line: 424, baseType: !5) +!4 = !DIFile(filename: "/usr/lib/x86_64-linux-gnu/openmpi/include/mpi.h", directory: "", checksumkind: CSK_MD5, checksum: "58b77b3315301c271bf9a6de605bbb3a") +!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) +!6 = !DICompositeType(tag: DW_TAG_structure_type, name: "ompi_datatype_t", file: !4, line: 424, flags: DIFlagFwdDecl) +!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "MPI_Op", file: !4, line: 429, baseType: !9) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!10 = !DICompositeType(tag: DW_TAG_structure_type, name: "ompi_op_t", file: !4, line: 429, flags: DIFlagFwdDecl) +!11 = !DIDerivedType(tag: DW_TAG_typedef, name: "MPI_Comm", file: !4, line: 423, baseType: !12) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) +!13 = !DICompositeType(tag: DW_TAG_structure_type, name: "ompi_communicator_t", file: !4, line: 423, flags: DIFlagFwdDecl) +!14 = !{i32 7, !"Dwarf Version", i32 5} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{i32 7, !"uwtable", i32 1} +!18 = !DILocalVariable(name: "cpt", arg: 1, scope: !19, file: !20, line: 11, type: !23) +!19 = distinct !DISubprogram(name: "g_complexsum", scope: !20, file: !20, line: 11, type: !21, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !30) +!20 = !DIFile(filename: "test/staging/milc.c", directory: "tudasc-ta2", checksumkind: CSK_MD5, checksum: "fd0b55769b199b4db669ed1dc54da6c6") +!21 = !DISubroutineType(types: !22) +!22 = !{null, !23} +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64) +!24 = !DIDerivedType(tag: DW_TAG_typedef, name: "complex", file: !20, line: 9, baseType: !25) +!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !20, line: 6, size: 64, elements: !26) +!26 = !{!27, !29} +!27 = !DIDerivedType(tag: DW_TAG_member, name: "imag", scope: !25, file: !20, line: 7, baseType: !28, size: 32) +!28 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!29 = !DIDerivedType(tag: DW_TAG_member, name: "real", scope: !25, file: !20, line: 8, baseType: !28, size: 32, offset: 32) +!30 = !{!18, !31} +!31 = !DILocalVariable(name: "work", scope: !19, file: !20, line: 12, type: !24) +!32 = !DILocation(line: 0, scope: !19, inlinedAt: !33) +!33 = distinct !DILocation(line: 24, column: 3, scope: !34) +!34 = distinct !DISubprogram(name: "main", scope: !20, file: !20, line: 17, type: !35, scopeLine: 17, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !41) +!35 = !DISubroutineType(types: !36) +!36 = !{!37, !37, !38} +!37 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!38 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !39, size: 64) +!39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64) +!40 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!41 = !{!42, !43, !44, !45} +!42 = !DILocalVariable(name: "argc", arg: 1, scope: !34, file: !20, line: 17, type: !37) +!43 = !DILocalVariable(name: "argv", arg: 2, scope: !34, file: !20, line: 17, type: !38) +!44 = !DILocalVariable(name: "rank", scope: !34, file: !20, line: 19, type: !37) +!45 = !DILocalVariable(name: "c", scope: !34, file: !20, line: 23, type: !24) diff --git a/test/typemapping/07_no_ebo_heap_multi_inheritance.cpp b/test/typemapping/07_no_ebo_heap_multi_inheritance.cpp new file mode 100644 index 00000000..f1f7e8bf --- /dev/null +++ b/test/typemapping/07_no_ebo_heap_multi_inheritance.cpp @@ -0,0 +1,40 @@ +// RUN: %remove %tu_yaml +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: cat %tu_yaml | %filecheck %s + +struct Base { + static double s_mem; + double s_mem_2; + static double s_mem_3; +}; + +struct BaseTwo { + double s_mem; +}; + +struct Derived : public Base, BaseTwo { + double pad; + int* c; +}; + +void foo() { + Derived d; +} + +// CHECK: name: {{(_ZTS7Derived|struct.Derived)}} +// CHECK-NEXT: extent: 32 +// CHECK-NEXT: member_count: 4 +// CHECK-NEXT: offsets: [ 0, 8, 16, 24 ] +// CHECK-NEXT: types: [ 25{{[6-9]}}, 25{{[6-9]}}, 24, 1 ] +// CHECK-NEXT: sizes: [ 1, 1, 1, 1 ] +// CHECK-NEXT: flags: 1 + +// 0 | struct Derived +// 0 | struct Base (base) +// 0 | double s_mem_2 +// 8 | struct BaseTwo (base) +// 8 | double s_mem +// 16 | double pad +// 24 | int * c +// | [sizeof=32, dsize=32, align=8, +// | nvsize=32, nvalign=8] diff --git a/test/typemapping/08_ebo_only_heap_multi_inheritance.cpp b/test/typemapping/08_ebo_only_heap_multi_inheritance.cpp new file mode 100644 index 00000000..9c9e8cea --- /dev/null +++ b/test/typemapping/08_ebo_only_heap_multi_inheritance.cpp @@ -0,0 +1,29 @@ +// RUN: %remove %tu_yaml +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: cat %tu_yaml | %filecheck %s + +struct Base { + static double s_mem; + static double s_mem_2; + static double s_mem_3; +}; + +struct BaseTwo { + static double other_s_mem; +}; + +struct Derived : public Base, BaseTwo { + double pad; + int* c; +}; + +void foo() { + Derived d; +} + +// CHECK: name: {{(_ZTS7Derived|struct.Derived)}} +// CHECK-NEXT: extent: 16 +// CHECK-NEXT: member_count: 2 +// CHECK-NEXT: offsets: [ 0, 8 ] +// CHECK-NEXT: types: [ 24, 1 ] +// CHECK-NEXT: sizes: [ 1, 1 ] diff --git a/test/typemapping/09_stack_class_inheritance_virtual.cpp b/test/typemapping/09_stack_class_inheritance_virtual.cpp new file mode 100644 index 00000000..4b0009c4 --- /dev/null +++ b/test/typemapping/09_stack_class_inheritance_virtual.cpp @@ -0,0 +1,54 @@ +// RUN: %remove %tu_yaml +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: cat %tu_yaml | %filecheck %s + +// REQUIRES: dimeta + +class Base { + public: + double x; + + virtual double foo() { + return x; + } +}; + +class X : public Base { + public: + int y; + char c; + unsigned char d; + + double foo() { + return y; + } +}; +int foo() { + X class_x; + return class_x.y; +} + +// CHECK: name: _ZTS1X +// CHECK-NEXT: extent: 24 +// CHECK-NEXT: member_count: 4 +// CHECK-NEXT: offsets: [ 0, 16, 20, 21 ] +// CHECK-NEXT: types: [ 25{{[0-9]}}, 13, 6, 7 ] +// CHECK-NEXT: sizes: [ 1, 1, 1, 1 ] +// CHECK-NEXT: flags: 1 + +// *** Dumping AST Record Layout +// 0 | class Base +// 0 | (Base vtable pointer) +// 8 | double x +// | [sizeof=16, dsize=16, align=8, +// | nvsize=16, nvalign=8] +// *** Dumping AST Record Layout +// 0 | class X +// 0 | class Base (primary base) +// 0 | (Base vtable pointer) +// 8 | double x +// 16 | int y +// 20 | char c +// 21 | unsigned char d +// | [sizeof=24, dsize=22, align=8, +// | nvsize=22, nvalign=8] diff --git a/test/typemapping/10_multi_inheritance_virtual.cpp b/test/typemapping/10_multi_inheritance_virtual.cpp new file mode 100644 index 00000000..1a303dac --- /dev/null +++ b/test/typemapping/10_multi_inheritance_virtual.cpp @@ -0,0 +1,57 @@ +// RUN: %remove %tu_yaml +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: cat %tu_yaml | %filecheck %s + +// REQUIRES: dimeta + +class Base { + public: + double x; + + virtual void foo(){}; +}; + +class X { + public: + int y; + + virtual int bar() { + return y; + }; +}; + +class Y : public X, public Base { + public: + float z; +}; + +void foo() { + Y class_y; +} + +// CHECK: name: _ZTS1X +// CHECK-NEXT: extent: 16 +// CHECK-NEXT: member_count: 2 +// CHECK-NEXT: offsets: [ 0, 8 ] +// CHECK-NEXT: types: [ 2, 13 ] +// CHECK-NEXT: sizes: [ 1, 1 ] +// CHECK-NEXT: flags: 1 + +// CHECK: name: _ZTS1Y +// CHECK-NEXT: extent: 40 +// CHECK-NEXT: member_count: 3 +// CHECK-NEXT: offsets: [ 0, 16, 32 ] +// CHECK-NEXT: types: [ 25{{[6-9]}}, 25{{[6-9]}}, 23 ] +// CHECK-NEXT: sizes: [ 1, 1, 1 ] +// CHECK-NEXT: flags: 1 + +// 0 | class Y +// 0 | class X (primary base) +// 0 | (X vtable pointer) +// 8 | int y +// 16 | class Base (base) +// 16 | (Base vtable pointer) +// 24 | double x +// 32 | float z +// | [sizeof=40, dsize=36, align=8, +// | nvsize=36, nvalign=8] diff --git a/test/typemapping/11_void_nullptr.cpp b/test/typemapping/11_void_nullptr.cpp new file mode 100644 index 00000000..1e3d6f30 --- /dev/null +++ b/test/typemapping/11_void_nullptr.cpp @@ -0,0 +1,32 @@ +// RUN: %remove %tu_yaml +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: cat %tu_yaml | %filecheck %s + +// REQUIRES: dimeta + +#include + +class Y { + public: + std::nullptr_t null_pointer; + void* void_pointer; + int* other_pointer; +}; + +void foo() { + Y class_y; +} + +// CHECK: name: _ZTS1Y +// CHECK-NEXT: extent: 24 +// CHECK-NEXT: member_count: 3 +// CHECK-NEXT: offsets: [ 0, 8, 16 ] +// CHECK-NEXT: types: [ 4, 3, 1 ] +// CHECK-NEXT: sizes: [ 1, 1, 1 ] + +// 0 | class Y +// 0 | std::nullptr_t null_pointer +// 8 | void * void_pointer +// 16 | int * other_pointer +// | [sizeof=24, dsize=24, align=8, +// | nvsize=24, nvalign=8] diff --git a/test/typemapping/12_complex.cpp b/test/typemapping/12_complex.cpp new file mode 100644 index 00000000..a3c93951 --- /dev/null +++ b/test/typemapping/12_complex.cpp @@ -0,0 +1,56 @@ +// RUN: %remove %tu_yaml +// RUN: %cpp-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: cat %tu_yaml | %filecheck %s + +// REQUIRES: dimeta + +#include + +class Y { + public: + std::complex f_cplx; + std::complex d_cplx; + std::complex ld_cplx; +}; + +void foo() { + Y class_y; +} + +// CHECK: name: _ZTSSt7complexIfE +// CHECK-NEXT: extent: 8 +// CHECK-NEXT: member_count: 1 +// CHECK-NEXT: offsets: [ 0 ] +// CHECK-NEXT: types: [ 26 ] +// CHECK-NEXT: sizes: [ 1 ] + +// CHECK: name: _ZTSSt7complexIdE +// CHECK-NEXT: extent: 16 +// CHECK-NEXT: member_count: 1 +// CHECK-NEXT: offsets: [ 0 ] +// CHECK-NEXT: types: [ 27 ] +// CHECK-NEXT: sizes: [ 1 ] + +// CHECK: name: _ZTSSt7complexIeE +// CHECK-NEXT: extent: 32 +// CHECK-NEXT: member_count: 1 +// CHECK-NEXT: offsets: [ 0 ] +// CHECK-NEXT: types: [ 28 ] +// CHECK-NEXT: sizes: [ 1 ] + +// CHECK: name: _ZTS1Y +// CHECK-NEXT: extent: 64 +// CHECK-NEXT: member_count: 3 +// CHECK-NEXT: offsets: [ 0, 8, 32 ] +// CHECK-NEXT: types: [ 25{{[0-9]}}, 25{{[0-9]}}, 25{{[0-9]}} ] +// CHECK-NEXT: sizes: [ 1, 1, 1 ] + +// 0 | class Y +// 0 | class std::complex f_cplx +// 0 | _ComplexT _M_value +// 8 | class std::complex d_cplx +// 8 | _ComplexT _M_value +// 32 | class std::complex ld_cplx +// 32 | _ComplexT _M_value +// | [sizeof=64, dsize=64, align=16, +// | nvsize=64, nvalign=16] diff --git a/test/typemapping/13_complex.c b/test/typemapping/13_complex.c new file mode 100644 index 00000000..532bbd52 --- /dev/null +++ b/test/typemapping/13_complex.c @@ -0,0 +1,24 @@ +// RUN: %remove %tu_yaml +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: cat %tu_yaml | %filecheck %s + +// REQUIRES: llvm-18 || llvm-19 + +#include + +typedef struct CplxY { + float complex f_cplx; + double complex d_cplx; + long double complex ld_cplx; +} Y; + +void foo() { + Y struct_y; +} + +// CHECK: name: {{(CplxY|struct.CplxY)}} +// CHECK-NEXT: extent: 64 +// CHECK-NEXT: member_count: 3 +// CHECK-NEXT: offsets: [ 0, 8, 32 ] +// CHECK-NEXT: types: [ 26, 27, 28 ] +// CHECK-NEXT: sizes: [ 1, 1, 1 ] diff --git a/test/typemapping/14_union.c b/test/typemapping/14_union.c new file mode 100644 index 00000000..4deb27de --- /dev/null +++ b/test/typemapping/14_union.c @@ -0,0 +1,19 @@ +// RUN: %remove %tu_yaml +// RUN: %c-to-llvm %s | %apply-typeart --typeart-stack=true +// RUN: cat %tu_yaml | %filecheck %s + +// REQUIRES: llvm-18 || llvm-19 + +union UnionTy { + float a; + int b; +}; + +void foo() { + union UnionTy union_stack; +} + +// CHECK: offsets: [ 0, 0 ] +// CHECK-NEXT: types: [ 23, 13 ] +// CHECK-NEXT: sizes: [ 1, 1 ] +// CHECK-NEXT: flags: 8